diff options
74 files changed, 855 insertions, 280 deletions
diff --git a/.gitignore b/.gitignore index f1ce903a11..736abbedc3 100644 --- a/.gitignore +++ b/.gitignore @@ -36,6 +36,12 @@ details-*.json uptime-*.json *.full_url *.last_modified +# Core files +core +core.* +!core/ +# ccls file that can be per directory. +*.ccls # / /Makefile @@ -73,6 +79,7 @@ uptime-*.json /Tor*Bundle.dmg /tor-*-win32.exe /warning_flags +/compile_commands.json /coverage_html/ /callgraph/ diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 176c71f8f0..ba61c71b2b 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -37,7 +37,7 @@ variables: paths: - artifacts/ -# This template +# This template should be usable on any system that's based on apt. .apt-template: &apt-template | export LC_ALL=C.UTF-8 echo Etc/UTC > /etc/timezone @@ -54,6 +54,7 @@ variables: apt-get update -qq apt-get upgrade -qy +# This template sets us up for Debian system in particular. .debian-template: &debian-template <<: *artifacts-template variables: @@ -88,10 +89,12 @@ variables: - if [ "$DOXYGEN" = yes ]; then apt-get install doxygen; fi - if [ "$STEM" = yes ]; then apt-get install timelimit; fi - if [ "$CC" = clang ]; then apt-get install clang; fi + - if [ "$NSS" = yes ]; then apt-get install libnss3 libnss3-dev; fi # TODO: This next line should not be debian-only. - if [ "$STEM" = yes ]; then git clone --depth 1 https://git.torproject.org/stem.git ; export STEM_PATH="$(pwd)/stem"; fi # TODO: This next line should not be debian-only. - if [ "$CHUTNEY" = yes ]; then git clone --depth 1 https://git.torproject.org/chutney.git ; export CHUTNEY_PATH="$(pwd)/chutney"; fi + - if [ "$TRACING" = yes ]; then apt install liblttng-ust-dev; fi # Minmal check on debian: just make, make check. # @@ -110,6 +113,7 @@ debian-hardened: image: debian:testing <<: *debian-template variables: + ALL_BUGS_ARE_FATAL: "yes" HARDENING: "yes" CC: "clang" script: @@ -152,6 +156,73 @@ debian-integration: variables: CHECK: "no" CHUTNEY: "yes" + CHUTNEY_MAKE_TARGET: "test-network-all" STEM: "yes" + ALL_BUGS_ARE_FATAL: "yes" + script: + - ./scripts/ci/ci-driver.sh + +##### +# Tracing build on Debian stable. +debian-tracing: + image: debian:stable + <<: *debian-template + variables: + TRACING: "yes" + CHECK: "no" + script: + - ./scripts/ci/ci-driver.sh + # Ensure that we only run tracing when it's implemented. + # + # Once versions before 0.4.5 are obsolete, we can remove this test. + rules: + # This first "if" check prevents us from running a duplicate version of + # this pipeline whenever we push and create an MR. I don't understand why + # it is necessary, though the following URL purports to explain: + # + # https://docs.gitlab.com/ee/ci/yaml/#prevent-duplicate-pipelines + - if: '$CI_PIPELINE_SOURCE == "push"' + exists: + - src/lib/trace/trace_sys.c + +##### +# No-authority mode +debian-disable-dirauth: + image: debian:stable + <<: *debian-template + variables: + DISABLE_DIRAUTH: "yes" + script: + - ./scripts/ci/ci-driver.sh + +##### +# No-relay mode +debian-disable-relay: + image: debian:stable + <<: *debian-template + variables: + DISABLE_RELAY: "yes" + script: + - ./scripts/ci/ci-driver.sh + # Ensure that we only run tracing when it's implemented. + # + # Once versions before 0.4.3 are obsolete, we can remove this test. + rules: + # This first "if" check prevents us from running a duplicate version of + # this pipeline whenever we push and create an MR. I don't understand why + # it is necessary, though the following URL purports to explain: + # + # https://docs.gitlab.com/ee/ci/yaml/#prevent-duplicate-pipelines + - if: '$CI_PIPELINE_SOURCE == "push"' + exists: + - src/feature/relay/relay_stub.c + +##### +# NSS check on debian +debian-nss: + image: debian:stable + <<: *debian-template + variables: + NSS: "yes" script: - ./scripts/ci/ci-driver.sh diff --git a/Makefile.am b/Makefile.am index a868be7362..c7bc514287 100644 --- a/Makefile.am +++ b/Makefile.am @@ -470,3 +470,17 @@ show-libs: show-testing-libs: @echo $(TOR_INTERNAL_TESTING_LIBS) + +# Note here that we hardcode this -j2 because if the user would pass too many +# cores, bear actually chockes and dies :S. For this to work, a make clean +# needs to be done else bear will miss some compile flags. +lsp: + @if test -x "`which bear 2>&1;true`"; then \ + echo "Generating LSP compile_commands.json. Might take few minutes..."; \ + $(MAKE) clean 2>&1 >/dev/null; \ + bear >/dev/null 2>&1 -- $(MAKE) -j2 2>&1 >/dev/null; \ + echo "Generating .ccls file..."; \ + ./scripts/maint/gen_ccls_file.sh \ + else \ + echo "No bear command found. On debian, apt install bear"; \ + fi diff --git a/changes/40241 b/changes/40241 new file mode 100644 index 0000000000..c9b2e2c011 --- /dev/null +++ b/changes/40241 @@ -0,0 +1,4 @@ + o Minor bugfixes (compilation): + - Fix a compilation warning about unreachable fallthrough annotations + when building with "--enable-all-bugs-are-fatal" on some compilers. + Fixes bug 40241; bugfix on 0.3.5.4-alpha. diff --git a/changes/40241_v2 b/changes/40241_v2 new file mode 100644 index 0000000000..85038297f7 --- /dev/null +++ b/changes/40241_v2 @@ -0,0 +1,4 @@ + o Minor bugfixes (compilation): + - Fix another warning about unreachable fallthrough annotations + when building with "--enable-all-bugs-are-fatal" on some compilers. + Fixes bug 40241; bugfix on 0.4.5.3-rc. diff --git a/changes/bug32588 b/changes/bug32588 new file mode 100644 index 0000000000..f31f2ce1ad --- /dev/null +++ b/changes/bug32588 @@ -0,0 +1,4 @@ + o Minor bugfixes (relays): + - Stop advertising incorrect IPv6 ORPorts in relay and bridge descriptors, + when the IPv6 port was configured as "auto". + Fixes bug 32588; bugfix on 0.2.3.9-alpha diff --git a/changes/bug40080 b/changes/bug40080 new file mode 100644 index 0000000000..8162466354 --- /dev/null +++ b/changes/bug40080 @@ -0,0 +1,6 @@ + o Minor bugfixes (security): + - When completing a channel, relays now check more thoroughly to make + sure that it matches any pending circuits before attaching those + circuits. Previously, address correctness and Ed25519 identities were not + checked in this case, but only when extending circuits on an existing + channel. Fixes bug 40080; bugfix on 0.2.7.2-alpha. diff --git a/changes/bug40113 b/changes/bug40113 new file mode 100644 index 0000000000..adf4634097 --- /dev/null +++ b/changes/bug40113 @@ -0,0 +1,3 @@ + o Minor bugfixes (compilation): + - Resolve a compilation warning that could occur in test_connection.c. + Fixes bug 40113; bugfix on 0.2.9.3-alpha. diff --git a/changes/bug40179_part1 b/changes/bug40179_part1 new file mode 100644 index 0000000000..c302373534 --- /dev/null +++ b/changes/bug40179_part1 @@ -0,0 +1,4 @@ + o Minor bugfixes (testing, portability): + - Fix our Python reference-implementation for the v3 onion service + handshake so that it works correctly with the version of hashlib provided + by Python 3.9. Fixes part of bug 40179; bugfix on 0.3.1.6-rc. diff --git a/changes/log_32868 b/changes/log_32868 new file mode 100644 index 0000000000..34476078b2 --- /dev/null +++ b/changes/log_32868 @@ -0,0 +1,4 @@ + o Minor features (debugging, directory system): + - Don't crash when we find a non-guard with a guard-fraction value set. + Instead, log a bug warning, in an attempt to figure out how this + happened. Diagnostic for ticket 32868. diff --git a/changes/parallel_unit_test b/changes/parallel_unit_test new file mode 100644 index 0000000000..79de28636d --- /dev/null +++ b/changes/parallel_unit_test @@ -0,0 +1,4 @@ + o Minor features (tests): + - Our "make check" target now runs the unit tests in 8 parallel chunks. + Doing this speeds up hardened CI builds by more than a factor of two. + Closes ticket 40098. diff --git a/changes/ticket33747 b/changes/ticket33747 new file mode 100644 index 0000000000..57c72e9d0a --- /dev/null +++ b/changes/ticket33747 @@ -0,0 +1,7 @@ + o Minor bugfixes (rate limiting, bridges, pluggable transports): + - On a bridge, treat all connections from an ExtORPort as remote + by default for the purposes of rate-limiting. Previously, + bridges would treat the connection as local unless they explicitly + received a "USERADDR" command. ExtORPort connections still + count as local if there is a USERADDR command with an explicit local + address. Fixes bug 33747; bugfix on 0.2.5.1-alpha. diff --git a/changes/ticket33880 b/changes/ticket33880 new file mode 100644 index 0000000000..c1889bb134 --- /dev/null +++ b/changes/ticket33880 @@ -0,0 +1,6 @@ + o Minor bugfixes (relay, usability): + - Adjust the rules for when to warn about having too many connections + to other relays. Previously we'd tolerate up to 1.5 connections + per relay on average. Now we tolerate more connections for directory + authorities, and raise the number of total connections we need + to see before we warn. Fixes bug 33880; bugfix on 0.3.1.1-alpha. diff --git a/changes/ticket40003 b/changes/ticket40003 new file mode 100644 index 0000000000..240f464353 --- /dev/null +++ b/changes/ticket40003 @@ -0,0 +1,3 @@ + o Deprecated features (onion service v2): + - Add deprecation warning for onion service version 2. Tor now logs a + warning once if a version 2 service is configured. Closes ticket 40003. diff --git a/changes/ticket40035 b/changes/ticket40035 new file mode 100644 index 0000000000..8cdd447199 --- /dev/null +++ b/changes/ticket40035 @@ -0,0 +1,5 @@ + o Major bugfixes (NSS): + - When running with NSS enabled, make sure that NSS knows to expect + nonblocking sockets. Previously, we set our TCP sockets as blocking, + but did not tell NSS about the fact, which in turn could lead to + unexpected blocking behavior. Fixes bug 40035; bugfix on 0.3.5.1-alpha. diff --git a/changes/ticket40073 b/changes/ticket40073 new file mode 100644 index 0000000000..30b028c042 --- /dev/null +++ b/changes/ticket40073 @@ -0,0 +1,3 @@ + o Minor bugfixes (relay configuration, crash): + - Avoid a fatal assert() when failing to create a listener connection for an + address that was in use. Fixes bug 40073; bugfix on 0.3.5.1-alpha. diff --git a/changes/ticket40081 b/changes/ticket40081 new file mode 100644 index 0000000000..683ae33518 --- /dev/null +++ b/changes/ticket40081 @@ -0,0 +1,6 @@ + o Minor features (security): + - Channels using obsolete versions of the Tor link protocol are no + longer allowed to circumvent address-canonicity checks. + (This is only a minor issue, since such channels have no way to + set ed25519 keys, and therefore should always be rejected.) + Closes ticket 40081. diff --git a/changes/ticket40125 b/changes/ticket40125 new file mode 100644 index 0000000000..c68e3ce7b3 --- /dev/null +++ b/changes/ticket40125 @@ -0,0 +1,4 @@ + o Testing (onion service v2): + - Fix a rendezvous cache unit test that was triggering an underflow on the + global rend cache allocation. Fixes bug 40125; bugfix on + 0.2.8.1-alpha. diff --git a/changes/ticket40126 b/changes/ticket40126 new file mode 100644 index 0000000000..1f5806e6cb --- /dev/null +++ b/changes/ticket40126 @@ -0,0 +1,4 @@ + o Testing (onion service v2): + - Fix another rendezvous cache unit test that was triggering an underflow on the + global rend cache allocation. Fixes bug 40126; bugfix on + 0.2.8.1-alpha. diff --git a/changes/ticket40133 b/changes/ticket40133 new file mode 100644 index 0000000000..8bbe00b6b2 --- /dev/null +++ b/changes/ticket40133 @@ -0,0 +1,5 @@ + o Minor features (protocol simplification): + - Tor no longer allows subprotocol versions larger than 63. Previously + versions up to UINT32_MAX were allowed, which significantly complicated + our code. + Implements proposal 318; closes ticket 40133. diff --git a/changes/ticket40135 b/changes/ticket40135 new file mode 100644 index 0000000000..9b60b4f655 --- /dev/null +++ b/changes/ticket40135 @@ -0,0 +1,3 @@ + o Minor bugfix (logging): + - Remove a debug logging statement that uselessly spam the logs. Fixes bug + 40135; bugfix on 0.3.5.0-alpha. diff --git a/changes/ticket40165 b/changes/ticket40165 new file mode 100644 index 0000000000..a8dd0a339b --- /dev/null +++ b/changes/ticket40165 @@ -0,0 +1,5 @@ + o Minor features (compilation): + - Disable deprecation warnings when building with OpenSSL 3.0.0 or later. + There are a number of newly deprecated APIs in OpenSSL 3.0.0 that Tor + still requires. (A later version of Tor will try to stop depending on + these.) Closes ticket 40165. diff --git a/changes/ticket40170 b/changes/ticket40170 new file mode 100644 index 0000000000..cc1c8dbad1 --- /dev/null +++ b/changes/ticket40170 @@ -0,0 +1,3 @@ + o Minor bugfixes (tests): + - Fix the "tortls/openssl/log_one_error" test to work with OpenSSL 3.0.0. + Fixes bug 40170; bugfix on 0.2.8.1-alpha. diff --git a/changes/ticket40227 b/changes/ticket40227 new file mode 100644 index 0000000000..e5efad0f95 --- /dev/null +++ b/changes/ticket40227 @@ -0,0 +1,4 @@ + o Minor feature (build system): + - New "make lsp" command to auto generate the compile_commands.json file + used by the ccls server. The "bear" program is needed for this. Closes + ticket 40227. diff --git a/configure.ac b/configure.ac index f30a7efa91..c7bda74c8b 100644 --- a/configure.ac +++ b/configure.ac @@ -4,7 +4,7 @@ dnl Copyright (c) 2007-2019, The Tor Project, Inc. dnl See LICENSE for licensing information AC_PREREQ([2.63]) -AC_INIT([tor],[0.3.5.11-dev]) +AC_INIT([tor],[0.3.5.13]) AC_CONFIG_SRCDIR([src/app/main/tor_main.c]) AC_CONFIG_MACRO_DIR([m4]) @@ -937,13 +937,30 @@ LIBS="$TOR_OPENSSL_LIBS $LIBS" LDFLAGS="$TOR_LDFLAGS_openssl $LDFLAGS" CPPFLAGS="$TOR_CPPFLAGS_openssl $CPPFLAGS" +dnl Tor currently uses a number of APIs that are deprecated in OpenSSL 3.0.0 +dnl and later. We want to migrate away from them, but that will be a lot of +dnl work. (See ticket tor#40166.) For now, we disable the deprecation +dnl warnings. + +AC_MSG_CHECKING([for OpenSSL >= 3.0.0]) +AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[ +#include <openssl/opensslv.h> +#if !defined(LIBRESSL_VERSION_NUMBER) && OPENSSL_VERSION_NUMBER <= 0x30000000L +#error "you_have_version_3" +#endif + ]], [[]])], + [ AC_MSG_RESULT([no]) ], + [ AC_MSG_RESULT([yes]); + AC_DEFINE(OPENSSL_SUPPRESS_DEPRECATED, 1, [disable openssl deprecated-function warnings]) ]) + +AC_MSG_CHECKING([for OpenSSL < 1.0.1]) AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[ #include <openssl/opensslv.h> #if !defined(LIBRESSL_VERSION_NUMBER) && OPENSSL_VERSION_NUMBER < 0x1000100fL #error "too old" #endif ]], [[]])], - [ : ], + [ AC_MSG_RESULT([no]) ], [ AC_MSG_ERROR([OpenSSL is too old. We require 1.0.1 or later. You can specify a path to a newer one with --with-openssl-dir.]) ]) AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[ diff --git a/contrib/win32build/tor-mingw.nsi.in b/contrib/win32build/tor-mingw.nsi.in index 638754153b..04a720a171 100644 --- a/contrib/win32build/tor-mingw.nsi.in +++ b/contrib/win32build/tor-mingw.nsi.in @@ -8,7 +8,7 @@ !include "LogicLib.nsh" !include "FileFunc.nsh" !insertmacro GetParameters -!define VERSION "0.3.5.11-dev" +!define VERSION "0.3.5.13" !define INSTALLER "tor-${VERSION}-win32.exe" !define WEBSITE "https://www.torproject.org/" !define LICENSE "LICENSE" diff --git a/scripts/ci/ci-driver.sh b/scripts/ci/ci-driver.sh index 527bba82e5..67a95a1f61 100755 --- a/scripts/ci/ci-driver.sh +++ b/scripts/ci/ci-driver.sh @@ -33,6 +33,11 @@ COVERAGE="${COVERAGE:-no}" RUST="${RUST:-no}" DOXYGEN="${DOXYGEN:-no}" ASCIIDOC="${ASCIIDOC:-no}" +TRACING="${TRACING:-no}" +ALL_BUGS_ARE_FATAL="${ALL_BUGS_ARE_FATAL:-no}" +DISABLE_DIRAUTH="${DISABLE_DIRAUTH:-no}" +DISABLE_RELAY="${DISABLE_RELAY:-no}" +NSS="${NSS:-no}" # Options for which tests to run. All should be yes/no. CHECK="${CHECK:-yes}" @@ -191,6 +196,11 @@ yes_or_no COVERAGE yes_or_no RUST yes_or_no DOXYGEN yes_or_no ASCIIDOC +yes_or_no TRACING +yes_or_no ALL_BUGS_ARE_FATAL +yes_or_no DISABLE_DIRAUTH +yes_or_no DISABLE_RELAY +yes_or_no NSS yes_or_no RUN_STAGE_CONFIGURE yes_or_no RUN_STAGE_BUILD @@ -241,6 +251,21 @@ fi if [[ "$ASCIIDOC" != "yes" ]]; then configure_options+=("--disable-asciidoc") fi +if [[ "$TRACING" == "yes" ]]; then + configure_options+=("--enable-tracing-instrumentation-lttng") +fi +if [[ "$ALL_BUGS_ARE_FATAL" == "yes" ]]; then + configure_options+=("--enable-all-bugs-are-fatal") +fi +if [[ "$DISABLE_DIRAUTH" == "yes" ]]; then + configure_options+=("--disable-module-dirauth") +fi +if [[ "$DISABLE_RELAY" == "yes" ]]; then + configure_options+=("--disable-module-relay") +fi +if [[ "$NSS" == "yes" ]]; then + configure_options+=("--enable-nss") +fi ############################################################################# # Tell the user about our versions of different tools and packages. diff --git a/scripts/maint/gen_ccls_file.sh b/scripts/maint/gen_ccls_file.sh new file mode 100755 index 0000000000..899e4e9603 --- /dev/null +++ b/scripts/maint/gen_ccls_file.sh @@ -0,0 +1,20 @@ +#!/bin/sh + +############################################################################## +# THIS MUST BE CALLED FROM THE ROOT DIRECTORY. IT IS USED BY THE MAKEFILE SO # +# IN THEORY, YOU SHOULD NEVER CALL THIS. # +############################################################################## + +set -e + +CCLS_FILE=".ccls" + +# Get all #define *_PRIVATE from our source. We need to list them in our .ccls +# file and enable them otherwise ccls will not find their definition thinking +# that they are dead code. +PRIVATE_DEFS=$(grep -r --include \*.h "_PRIVATE" | grep "#ifdef" | cut -d' ' -f2 | sort | uniq) + +echo "clang" > "$CCLS_FILE" +for p in $PRIVATE_DEFS; do + echo "-D$p" >> "$CCLS_FILE" +done diff --git a/src/app/config/config.c b/src/app/config/config.c index 1d61b76310..c1f1f153e7 100644 --- a/src/app/config/config.c +++ b/src/app/config/config.c @@ -809,9 +809,6 @@ static int normalize_nickname_list(config_line_t **normalized_out, char **msg); static char *get_bindaddr_from_transport_listen_line(const char *line, const char *transport); -static int parse_ports(or_options_t *options, int validate_only, - char **msg_out, int *n_ports_out, - int *world_writable_control_socket); static int check_server_ports(const smartlist_t *ports, const or_options_t *options, int *num_low_ports_out); @@ -7375,7 +7372,7 @@ count_real_listeners(const smartlist_t *ports, int listenertype, * If <b>validate_only</b> is false, set configured_client_ports to the * new list of ports parsed from <b>options</b>. **/ -static int +STATIC int parse_ports(or_options_t *options, int validate_only, char **msg, int *n_ports_out, int *world_writable_control_socket) diff --git a/src/app/config/config.h b/src/app/config/config.h index 301faf7067..6852d352dc 100644 --- a/src/app/config/config.h +++ b/src/app/config/config.h @@ -295,6 +295,10 @@ STATIC int open_and_add_file_log(const log_severity_list_t *severity, const char *fname, int truncate_log); +STATIC int parse_ports(or_options_t *options, int validate_only, + char **msg, int *n_ports_out, + int *world_writable_control_socket); + #endif /* defined(CONFIG_PRIVATE) */ #endif /* !defined(TOR_CONFIG_H) */ diff --git a/src/core/mainloop/connection.c b/src/core/mainloop/connection.c index 3595bba85c..21d4332758 100644 --- a/src/core/mainloop/connection.c +++ b/src/core/mainloop/connection.c @@ -379,8 +379,12 @@ or_connection_new(int type, int socket_family) connection_or_set_canonical(or_conn, 0); - if (type == CONN_TYPE_EXT_OR) + if (type == CONN_TYPE_EXT_OR) { + /* If we aren't told an address for this connection, we should + * presume it isn't local, and should be rate-limited. */ + TO_CONN(or_conn)->always_rate_limit_as_remote = 1; connection_or_set_ext_or_identifier(or_conn); + } return or_conn; } @@ -2923,7 +2927,14 @@ retry_all_listeners(smartlist_t *new_conns, int close_all_noncontrol) &skip, &addr_in_use); } - tor_assert(new_conn); + /* There are many reasons why we can't open a new listener port so in case + * we hit those, bail early so tor can stop. */ + if (!new_conn) { + log_warn(LD_NET, "Unable to create listener port: %s:%d", + fmt_addr(&r->new_port->addr), r->new_port->port); + retval = -1; + break; + } smartlist_add(new_conns, new_conn); @@ -3025,6 +3036,7 @@ connection_is_rate_limited(connection_t *conn) if (conn->linked) return 0; /* Internal connection */ else if (! options->CountPrivateBandwidth && + ! conn->always_rate_limit_as_remote && (tor_addr_family(&conn->addr) == AF_UNSPEC || /* no address */ tor_addr_family(&conn->addr) == AF_UNIX || /* no address */ tor_addr_is_internal(&conn->addr, 0))) diff --git a/src/core/or/channel.c b/src/core/or/channel.c index 3886906875..9649bdf278 100644 --- a/src/core/or/channel.c +++ b/src/core/or/channel.c @@ -72,6 +72,7 @@ #include "core/or/relay.h" #include "core/or/scheduler.h" #include "feature/client/entrynodes.h" +#include "feature/nodelist/dirlist.h" #include "feature/nodelist/networkstatus.h" #include "feature/nodelist/nodelist.h" #include "feature/nodelist/routerlist.h" @@ -663,7 +664,7 @@ channel_find_by_global_id(uint64_t global_identifier) /** Return true iff <b>chan</b> matches <b>rsa_id_digest</b> and <b>ed_id</b>. * as its identity keys. If either is NULL, do not check for a match. */ -static int +int channel_remote_identity_matches(const channel_t *chan, const char *rsa_id_digest, const ed25519_public_key_t *ed_id) @@ -749,6 +750,7 @@ channel_check_for_duplicates(void) { channel_idmap_entry_t **iter; channel_t *chan; + int total_dirauth_connections = 0, total_dirauths = 0; int total_relay_connections = 0, total_relays = 0, total_canonical = 0; int total_half_canonical = 0; int total_gt_one_connection = 0, total_gt_two_connections = 0; @@ -756,13 +758,18 @@ channel_check_for_duplicates(void) HT_FOREACH(iter, channel_idmap, &channel_identity_map) { int connections_to_relay = 0; + const char *id_digest = (char *) (*iter)->digest; /* Only consider relay connections */ - if (!connection_or_digest_is_known_relay((char*)(*iter)->digest)) + if (!connection_or_digest_is_known_relay(id_digest)) continue; total_relays++; + const bool is_dirauth = router_digest_is_trusted_dir(id_digest); + if (is_dirauth) + total_dirauths++; + for (chan = TOR_LIST_FIRST(&(*iter)->channel_list); chan; chan = channel_next_with_rsa_identity(chan)) { @@ -771,11 +778,12 @@ channel_check_for_duplicates(void) connections_to_relay++; total_relay_connections++; + if (is_dirauth) + total_dirauth_connections++; - if (chan->is_canonical(chan, 0)) total_canonical++; + if (chan->is_canonical(chan)) total_canonical++; - if (!chan->is_canonical_to_peer && chan->is_canonical(chan, 0) - && chan->is_canonical(chan, 1)) { + if (!chan->is_canonical_to_peer && chan->is_canonical(chan)) { total_half_canonical++; } } @@ -785,11 +793,28 @@ channel_check_for_duplicates(void) if (connections_to_relay > 4) total_gt_four_connections++; } -#define MIN_RELAY_CONNECTIONS_TO_WARN 5 + /* Don't bother warning about excessive connections unless we have + * at least this many connections, total. + */ +#define MIN_RELAY_CONNECTIONS_TO_WARN 25 + /* If the average number of connections for a regular relay is more than + * this, that's too high. + */ +#define MAX_AVG_RELAY_CONNECTIONS 1.5 + /* If the average number of connections for a dirauth is more than + * this, that's too high. + */ +#define MAX_AVG_DIRAUTH_CONNECTIONS 4 + + /* How many connections total would be okay, given the number of + * relays and dirauths that we have connections to? */ + const int max_tolerable_connections = (int)( + (total_relays-total_dirauths) * MAX_AVG_RELAY_CONNECTIONS + + total_dirauths * MAX_AVG_DIRAUTH_CONNECTIONS); /* If we average 1.5 or more connections per relay, something is wrong */ if (total_relays > MIN_RELAY_CONNECTIONS_TO_WARN && - total_relay_connections >= 1.5*total_relays) { + total_relay_connections > max_tolerable_connections) { log_notice(LD_OR, "Your relay has a very large number of connections to other relays. " "Is your outbound address the same as your relay address? " @@ -2431,21 +2456,9 @@ channel_get_for_extend(const char *rsa_id_digest, continue; } - /* Never return a non-canonical connection using a recent link protocol - * if the address is not what we wanted. - * - * The channel_is_canonical_is_reliable() function asks the lower layer - * if we should trust channel_is_canonical(). The below is from the - * comments of the old circuit_or_get_for_extend() and applies when - * the lower-layer transport is channel_tls_t. - * - * (For old link protocols, we can't rely on is_canonical getting - * set properly if we're talking to the right address, since we might - * have an out-of-date descriptor, and we will get no NETINFO cell to - * tell us about the right address.) - */ + /* Only return canonical connections or connections where the address + * is the address we wanted. */ if (!channel_is_canonical(chan) && - channel_is_canonical_is_reliable(chan) && !channel_matches_target_addr_for_extend(chan, target_addr)) { ++n_noncanonical; continue; @@ -2587,16 +2600,12 @@ channel_dump_statistics, (channel_t *chan, int severity)) /* Handle marks */ tor_log(severity, LD_GENERAL, - " * Channel %"PRIu64 " has these marks: %s %s %s " - "%s %s %s", + " * Channel %"PRIu64 " has these marks: %s %s %s %s %s", (chan->global_identifier), channel_is_bad_for_new_circs(chan) ? "bad_for_new_circs" : "!bad_for_new_circs", channel_is_canonical(chan) ? "canonical" : "!canonical", - channel_is_canonical_is_reliable(chan) ? - "is_canonical_is_reliable" : - "!is_canonical_is_reliable", channel_is_client(chan) ? "client" : "!client", channel_is_local(chan) ? @@ -2955,22 +2964,7 @@ channel_is_canonical(channel_t *chan) tor_assert(chan); tor_assert(chan->is_canonical); - return chan->is_canonical(chan, 0); -} - -/** - * Test if the canonical flag is reliable. - * - * This function asks if the lower layer thinks it's safe to trust the - * result of channel_is_canonical(). - */ -int -channel_is_canonical_is_reliable(channel_t *chan) -{ - tor_assert(chan); - tor_assert(chan->is_canonical); - - return chan->is_canonical(chan, 1); + return chan->is_canonical(chan); } /** diff --git a/src/core/or/channel.h b/src/core/or/channel.h index 97aa000337..d41f0d70bb 100644 --- a/src/core/or/channel.h +++ b/src/core/or/channel.h @@ -351,12 +351,10 @@ struct channel_s { /** Check if the lower layer has queued writes */ int (*has_queued_writes)(channel_t *); /** - * If the second param is zero, ask the lower layer if this is - * 'canonical', for a transport-specific definition of canonical; if - * it is 1, ask if the answer to the preceding query is safe to rely - * on. + * Ask the lower layer if this is 'canonical', for a transport-specific + * definition of canonical. */ - int (*is_canonical)(channel_t *, int); + int (*is_canonical)(channel_t *); /** Check if this channel matches a specified extend_info_t */ int (*matches_extend_info)(channel_t *, extend_info_t *); /** Check if this channel matches a target address when extending */ @@ -733,7 +731,6 @@ int channel_has_queued_writes(channel_t *chan); int channel_is_bad_for_new_circs(channel_t *chan); void channel_mark_bad_for_new_circs(channel_t *chan); int channel_is_canonical(channel_t *chan); -int channel_is_canonical_is_reliable(channel_t *chan); int channel_is_client(const channel_t *chan); int channel_is_local(channel_t *chan); int channel_is_incoming(channel_t *chan); @@ -741,6 +738,9 @@ int channel_is_outgoing(channel_t *chan); void channel_mark_client(channel_t *chan); void channel_clear_client(channel_t *chan); int channel_matches_extend_info(channel_t *chan, extend_info_t *extend_info); +int channel_remote_identity_matches(const channel_t *chan, + const char *rsa_id_digest, + const ed25519_public_key_t *ed_id); int channel_matches_target_addr_for_extend(channel_t *chan, const tor_addr_t *target); unsigned int channel_num_circuits(channel_t *chan); diff --git a/src/core/or/channeltls.c b/src/core/or/channeltls.c index f874e39946..18025ff73a 100644 --- a/src/core/or/channeltls.c +++ b/src/core/or/channeltls.c @@ -106,7 +106,7 @@ channel_tls_get_transport_name_method(channel_t *chan, char **transport_out); static const char * channel_tls_get_remote_descr_method(channel_t *chan, int flags); static int channel_tls_has_queued_writes_method(channel_t *chan); -static int channel_tls_is_canonical_method(channel_t *chan, int req); +static int channel_tls_is_canonical_method(channel_t *chan); static int channel_tls_matches_extend_info_method(channel_t *chan, extend_info_t *extend_info); @@ -643,12 +643,11 @@ channel_tls_has_queued_writes_method(channel_t *chan) /** * Tell the upper layer if we're canonical. * - * This implements the is_canonical method for channel_tls_t; if req is zero, - * it returns whether this is a canonical channel, and if it is one it returns - * whether that can be relied upon. + * This implements the is_canonical method for channel_tls_t: + * it returns whether this is a canonical channel. */ static int -channel_tls_is_canonical_method(channel_t *chan, int req) +channel_tls_is_canonical_method(channel_t *chan) { int answer = 0; channel_tls_t *tlschan = BASE_CHAN_TO_TLS(chan); @@ -656,24 +655,13 @@ channel_tls_is_canonical_method(channel_t *chan, int req) tor_assert(tlschan); if (tlschan->conn) { - switch (req) { - case 0: - answer = tlschan->conn->is_canonical; - break; - case 1: - /* - * Is the is_canonical bit reliable? In protocols version 2 and up - * we get the canonical address from a NETINFO cell, but in older - * versions it might be based on an obsolete descriptor. - */ - answer = (tlschan->conn->link_proto >= 2); - break; - default: - /* This shouldn't happen; channel.c is broken if it does */ - tor_assert_nonfatal_unreached_once(); - } + /* If this bit is set to 0, and link_proto is sufficiently old, then we + * can't actually _rely_ on this being a non-canonical channel. + * Nonetheless, we're going to believe that this is a non-canonical + * channel in this case, since nobody should be using these link protocols + * any more. */ + answer = tlschan->conn->is_canonical; } - /* else return 0 for tlschan->conn == NULL */ return answer; } @@ -1237,8 +1225,7 @@ channel_tls_handle_var_cell(var_cell_t *var_cell, or_connection_t *conn) * the v2 and v3 handshakes. */ /* But that should be happening any longer've disabled bufferevents. */ tor_assert_nonfatal_unreached_once(); - - FALLTHROUGH; + FALLTHROUGH_UNLESS_ALL_BUGS_ARE_FATAL; case OR_CONN_STATE_TLS_SERVER_RENEGOTIATING: if (!(command_allowed_before_handshake(var_cell->command))) { log_fn(LOG_PROTOCOL_WARN, LD_PROTOCOL, diff --git a/src/core/or/circuitbuild.c b/src/core/or/circuitbuild.c index f3a5791d6c..70b5d8215a 100644 --- a/src/core/or/circuitbuild.c +++ b/src/core/or/circuitbuild.c @@ -623,21 +623,37 @@ circuit_n_chan_done(channel_t *chan, int status, int close_origin_circuits) circ->state != CIRCUIT_STATE_CHAN_WAIT) continue; - if (tor_digest_is_zero(circ->n_hop->identity_digest)) { + const char *rsa_ident = NULL; + const ed25519_public_key_t *ed_ident = NULL; + if (! tor_digest_is_zero(circ->n_hop->identity_digest)) { + rsa_ident = circ->n_hop->identity_digest; + } + if (! ed25519_public_key_is_zero(&circ->n_hop->ed_identity)) { + ed_ident = &circ->n_hop->ed_identity; + } + + if (rsa_ident == NULL && ed_ident == NULL) { /* Look at addr/port. This is an unkeyed connection. */ if (!channel_matches_extend_info(chan, circ->n_hop)) continue; } else { - /* We expected a key. See if it's the right one. */ - if (tor_memneq(chan->identity_digest, - circ->n_hop->identity_digest, DIGEST_LEN)) + /* We expected a key or keys. See if they matched. */ + if (!channel_remote_identity_matches(chan, rsa_ident, ed_ident)) + continue; + + /* If the channel is canonical, great. If not, it needs to match + * the requested address exactly. */ + if (! chan->is_canonical && + ! channel_matches_extend_info(chan, circ->n_hop)) { continue; + } } if (!status) { /* chan failed; close circ */ log_info(LD_CIRC,"Channel failed; closing circ."); circuit_mark_for_close(circ, END_CIRC_REASON_CHANNEL_CLOSED); continue; } + if (close_origin_circuits && CIRCUIT_IS_ORIGIN(circ)) { log_info(LD_CIRC,"Channel deprecated for origin circs; closing circ."); circuit_mark_for_close(circ, END_CIRC_REASON_CHANNEL_CLOSED); @@ -707,6 +723,8 @@ circuit_deliver_create_cell(circuit_t *circ, const create_cell_t *create_cell, goto error; } + tor_assert_nonfatal_once(circ->n_chan->is_canonical); + memset(&cell, 0, sizeof(cell_t)); r = relayed ? create_cell_format_relayed(&cell, create_cell) : create_cell_format(&cell, create_cell); diff --git a/src/core/or/circuitlist.c b/src/core/or/circuitlist.c index 03d495cdfd..ccf3041bb4 100644 --- a/src/core/or/circuitlist.c +++ b/src/core/or/circuitlist.c @@ -787,7 +787,7 @@ circuit_purpose_to_controller_hs_state_string(uint8_t purpose) "Unrecognized circuit purpose: %d", (int)purpose); tor_fragile_assert(); - FALLTHROUGH; + FALLTHROUGH_UNLESS_ALL_BUGS_ARE_FATAL; case CIRCUIT_PURPOSE_OR: case CIRCUIT_PURPOSE_C_GENERAL: diff --git a/src/core/or/connection_st.h b/src/core/or/connection_st.h index d1430eda14..c197a81340 100644 --- a/src/core/or/connection_st.h +++ b/src/core/or/connection_st.h @@ -64,6 +64,9 @@ struct connection_t { /** True if connection_handle_write is currently running on this connection. */ unsigned int in_connection_handle_write:1; + /** If true, then we treat this connection as remote for the purpose of + * rate-limiting, no matter what its address is. */ + unsigned int always_rate_limit_as_remote:1; /* For linked connections: */ diff --git a/src/core/or/protover.c b/src/core/or/protover.c index 17979d04ea..dfb0e9e303 100644 --- a/src/core/or/protover.c +++ b/src/core/or/protover.c @@ -113,13 +113,13 @@ proto_entry_free_(proto_entry_t *entry) } /** The largest possible protocol version. */ -#define MAX_PROTOCOL_VERSION (UINT32_MAX-1) +#define MAX_PROTOCOL_VERSION (63) /** * Given a string <b>s</b> and optional end-of-string pointer * <b>end_of_range</b>, parse the protocol range and store it in * <b>low_out</b> and <b>high_out</b>. A protocol range has the format U, or - * U-U, where U is an unsigned 32-bit integer. + * U-U, where U is an unsigned integer between 0 and 63 inclusive. */ static int parse_version_range(const char *s, const char *end_of_range, diff --git a/src/feature/client/entrynodes.c b/src/feature/client/entrynodes.c index 8d9230b66b..6c7f8057bd 100644 --- a/src/feature/client/entrynodes.c +++ b/src/feature/client/entrynodes.c @@ -2263,7 +2263,7 @@ entry_guards_note_guard_success(guard_selection_t *gs, break; default: tor_assert_nonfatal_unreached(); - FALLTHROUGH; + FALLTHROUGH_UNLESS_ALL_BUGS_ARE_FATAL; case GUARD_CIRC_STATE_USABLE_IF_NO_BETTER_GUARD: if (guard->is_primary) { /* XXXX #20832 -- I don't actually like this logic. It seems to make diff --git a/src/feature/hs_common/shared_random_client.c b/src/feature/hs_common/shared_random_client.c index 5772034c6d..3d6be94080 100644 --- a/src/feature/hs_common/shared_random_client.c +++ b/src/feature/hs_common/shared_random_client.c @@ -255,10 +255,6 @@ sr_state_get_start_time_of_current_protocol_run(void) protocol run */ time_t time_elapsed_since_start_of_run = curr_round_slot * voting_interval; - log_debug(LD_GENERAL, "Current SRV proto run: Start of current round: %u. " - "Time elapsed: %u (%d)", (unsigned) beginning_of_curr_round, - (unsigned) time_elapsed_since_start_of_run, voting_interval); - return beginning_of_curr_round - time_elapsed_since_start_of_run; } diff --git a/src/feature/nodelist/node_select.c b/src/feature/nodelist/node_select.c index e31abb247f..7b9e241e5b 100644 --- a/src/feature/nodelist/node_select.c +++ b/src/feature/nodelist/node_select.c @@ -540,6 +540,51 @@ bridge_get_advertised_bandwidth_bounded(routerinfo_t *router) return result; } +/** + * We have found an instance of bug 32868: log our best guess about where the + * routerstatus was found. + **/ +static void +log_buggy_rs_source(const routerstatus_t *rs) +{ + static ratelim_t buggy_rs_ratelim = RATELIM_INIT(1200); + char *m; + if ((m = rate_limit_log(&buggy_rs_ratelim, approx_time()))) { + log_warn(LD_BUG, + "Found a routerstatus %p with has_guardfraction=%u " + " and guardfraction_percentage=%u, but is_possible_guard=%u.%s", + rs, + rs->has_guardfraction, + rs->guardfraction_percentage, + rs->is_possible_guard, + m); + tor_free(m); + networkstatus_t *ns; + int in_ns_count = 0; + if ((ns = networkstatus_get_latest_consensus_by_flavor(FLAV_NS))) { + int pos = smartlist_pos(ns->routerstatus_list, rs); + if (pos >= 0) { + ++in_ns_count; + log_warn(LD_BUG, "Found the routerstatus at position %d of the " + "NS consensus.", pos); + } + } + if ((ns = networkstatus_get_latest_consensus_by_flavor(FLAV_MICRODESC))) { + int pos = smartlist_pos(ns->routerstatus_list, rs); + if (pos >= 0) { + ++in_ns_count; + log_warn(LD_BUG, "Found the routerstatus at position %d of the " + "MD consensus.", pos); + } + } + if (in_ns_count == 0) { + log_warn(LD_BUG, "Could not find the routerstatus in any " + "latest consensus."); + } + tor_assert_nonfatal_unreached(); + } +} + /** Given a list of routers and a weighting rule as in * smartlist_choose_node_by_bandwidth_weights, compute weighted bandwidth * values for each node and store them in a freshly allocated @@ -715,10 +760,11 @@ compute_weighted_bandwidths(const smartlist_t *sl, * choose N proportionally to F*Wpf*B + (1-F)*Wpn*B. */ if (node->rs && node->rs->has_guardfraction && rule != WEIGHT_FOR_GUARD) { - /* XXX The assert should actually check for is_guard. However, - * that crashes dirauths because of #13297. This should be - * equivalent: */ - tor_assert(node->rs->is_possible_guard); + /* We should only have guardfraction set if the node has the Guard + flag. */ + if (! node->rs->is_possible_guard) { + log_buggy_rs_source(node->rs); + } guard_get_guardfraction_bandwidth(&guardfraction_bw, this_bw, diff --git a/src/feature/relay/ext_orport.c b/src/feature/relay/ext_orport.c index 56c5bb96f5..136aee3084 100644 --- a/src/feature/relay/ext_orport.c +++ b/src/feature/relay/ext_orport.c @@ -494,6 +494,10 @@ connection_ext_or_handle_cmd_useraddr(connection_t *conn, } conn->address = tor_addr_to_str_dup(&addr); + /* Now that we know the address, we don't have to manually override rate + * limiting. */ + conn->always_rate_limit_as_remote = 0; + return 0; } @@ -659,4 +663,3 @@ ext_orport_free_all(void) if (ext_or_auth_cookie) /* Free the auth cookie */ tor_free(ext_or_auth_cookie); } - diff --git a/src/feature/relay/router.c b/src/feature/relay/router.c index e91550a78c..283f7c326b 100644 --- a/src/feature/relay/router.c +++ b/src/feature/relay/router.c @@ -1433,6 +1433,50 @@ router_get_advertised_or_port_by_af(const or_options_t *options, return port; } +/** As router_get_advertised_or_port(), but returns the IPv6 address and + * port in ipv6_ap_out, which must not be NULL. Returns a null address and + * zero port, if no ORPort is found. */ +void +router_get_advertised_ipv6_or_ap(const or_options_t *options, + tor_addr_port_t *ipv6_ap_out) +{ + /* Bug in calling function, we can't return a sensible result, and it + * shouldn't use the NULL pointer once we return. */ + tor_assert(ipv6_ap_out); + + /* If there is no valid IPv6 ORPort, return a null address and port. */ + tor_addr_make_null(&ipv6_ap_out->addr, AF_INET6); + ipv6_ap_out->port = 0; + + const tor_addr_t *addr = get_first_advertised_addr_by_type_af( + CONN_TYPE_OR_LISTENER, + AF_INET6); + const uint16_t port = router_get_advertised_or_port_by_af( + options, + AF_INET6); + + if (!addr || port == 0) { + log_info(LD_CONFIG, "There is no advertised IPv6 ORPort."); + return; + } + + /* If the relay is configured using the default authorities, disallow + * internal IPs. Otherwise, allow them. For IPv4 ORPorts and DirPorts, + * this check is done in resolve_my_address(). See #33681. */ + const int default_auth = using_default_dir_authorities(options); + if (tor_addr_is_internal(addr, 0) && default_auth) { + log_warn(LD_CONFIG, + "Unable to use configured IPv6 ORPort \"%s\" in a " + "descriptor. Skipping it. " + "Try specifying a globally reachable address explicitly.", + fmt_addrport(addr, port)); + return; + } + + tor_addr_copy(&ipv6_ap_out->addr, addr); + ipv6_ap_out->port = port; +} + /** Return the port that we should advertise as our DirPort; * this is one of three possibilities: * The one that is passed as <b>dirport</b> if the DirPort option is 0, or @@ -1848,34 +1892,11 @@ router_build_fresh_descriptor(routerinfo_t **r, extrainfo_t **e) sizeof(curve25519_public_key_t)); /* For now, at most one IPv6 or-address is being advertised. */ - { - const port_cfg_t *ipv6_orport = NULL; - SMARTLIST_FOREACH_BEGIN(get_configured_ports(), const port_cfg_t *, p) { - if (p->type == CONN_TYPE_OR_LISTENER && - ! p->server_cfg.no_advertise && - ! p->server_cfg.bind_ipv4_only && - tor_addr_family(&p->addr) == AF_INET6) { - /* Like IPv4, if the relay is configured using the default - * authorities, disallow internal IPs. Otherwise, allow them. */ - const int default_auth = using_default_dir_authorities(options); - if (! tor_addr_is_internal(&p->addr, 0) || ! default_auth) { - ipv6_orport = p; - break; - } else { - char addrbuf[TOR_ADDR_BUF_LEN]; - log_warn(LD_CONFIG, - "Unable to use configured IPv6 address \"%s\" in a " - "descriptor. Skipping it. " - "Try specifying a globally reachable address explicitly.", - tor_addr_to_str(addrbuf, &p->addr, sizeof(addrbuf), 1)); - } - } - } SMARTLIST_FOREACH_END(p); - if (ipv6_orport) { - tor_addr_copy(&ri->ipv6_addr, &ipv6_orport->addr); - ri->ipv6_orport = ipv6_orport->port; - } - } + tor_addr_port_t ipv6_orport; + router_get_advertised_ipv6_or_ap(options, &ipv6_orport); + /* If there is no valud IPv6 ORPort, the address and port are null. */ + tor_addr_copy(&ri->ipv6_addr, &ipv6_orport.addr); + ri->ipv6_orport = ipv6_orport.port; ri->identity_pkey = crypto_pk_dup_key(get_server_identity_key()); if (BUG(crypto_pk_get_digest(ri->identity_pkey, diff --git a/src/feature/relay/router.h b/src/feature/relay/router.h index bd6a8a012e..ab1f771017 100644 --- a/src/feature/relay/router.h +++ b/src/feature/relay/router.h @@ -59,6 +59,8 @@ int init_keys_client(void); uint16_t router_get_active_listener_port_by_type_af(int listener_type, sa_family_t family); uint16_t router_get_advertised_or_port(const or_options_t *options); +void router_get_advertised_ipv6_or_ap(const or_options_t *options, + tor_addr_port_t *ipv6_ap_out); uint16_t router_get_advertised_or_port_by_af(const or_options_t *options, sa_family_t family); uint16_t router_get_advertised_dir_port(const or_options_t *options, diff --git a/src/feature/rend/rendclient.c b/src/feature/rend/rendclient.c index 5c9dbea8e3..6e95142c0b 100644 --- a/src/feature/rend/rendclient.c +++ b/src/feature/rend/rendclient.c @@ -819,7 +819,7 @@ rend_client_report_intro_point_failure(extend_info_t *failed_intro, log_warn(LD_BUG, "Unknown failure type %u. Removing intro point.", failure_type); tor_fragile_assert(); - FALLTHROUGH; + FALLTHROUGH_UNLESS_ALL_BUGS_ARE_FATAL; case INTRO_POINT_FAILURE_GENERIC: rend_cache_intro_failure_note(failure_type, (uint8_t *)failed_intro->identity_digest, diff --git a/src/feature/rend/rendservice.c b/src/feature/rend/rendservice.c index c96ecec308..eaf0432a7d 100644 --- a/src/feature/rend/rendservice.c +++ b/src/feature/rend/rendservice.c @@ -130,6 +130,22 @@ static smartlist_t *rend_service_list = NULL; * service on config reload. */ static smartlist_t *rend_service_staging_list = NULL; +/** Helper: log the deprecation warning for version 2 only once. */ +static void +log_once_deprecation_warning(void) +{ + static bool logged_once = false; + if (!logged_once) { + log_warn(LD_REND, "DEPRECATED: Onion service version 2 are deprecated. " + "Please use version 3 which is the default now. " + "Currently, version 2 is planned to be obsolete in " + "the Tor version 0.4.6 stable series."); + logged_once = true; + } +} +/** Macro to make it very explicit that we are warning about deprecation. */ +#define WARN_ONCE_DEPRECATION() log_once_deprecation_warning() + /* Like rend_get_service_list_mutable, but returns a read-only list. */ static const smartlist_t* rend_get_service_list(const smartlist_t* substitute_service_list) @@ -731,6 +747,9 @@ rend_config_service(const config_line_t *line_, tor_assert(options); tor_assert(config); + /* We are about to configure a version 2 service. Warn of deprecation. */ + WARN_ONCE_DEPRECATION(); + /* Use the staging service list so that we can check then do the pruning * process using the main list at the end. */ if (rend_service_staging_list == NULL) { diff --git a/src/lib/crypt_ops/compat_openssl.h b/src/lib/crypt_ops/compat_openssl.h index 9c10386c34..6605d01045 100644 --- a/src/lib/crypt_ops/compat_openssl.h +++ b/src/lib/crypt_ops/compat_openssl.h @@ -32,10 +32,6 @@ #define OPENSSL_1_1_API #endif /* OPENSSL_VERSION_NUMBER >= OPENSSL_V_SERIES(1,1,0) && ... */ -#ifndef OPENSSL_VERSION -#define OPENSSL_VERSION SSLEAY_VERSION -#endif - #ifndef OPENSSL_1_1_API #define OpenSSL_version(v) SSLeay_version(v) #define OpenSSL_version_num() SSLeay() @@ -54,4 +50,3 @@ #endif /* defined(ENABLE_OPENSSL) */ #endif /* !defined(TOR_COMPAT_OPENSSL_H) */ - diff --git a/src/lib/crypt_ops/crypto_openssl_mgt.c b/src/lib/crypt_ops/crypto_openssl_mgt.c index c97815f9a4..e7d6084f6c 100644 --- a/src/lib/crypt_ops/crypto_openssl_mgt.c +++ b/src/lib/crypt_ops/crypto_openssl_mgt.c @@ -101,13 +101,22 @@ static char *crypto_openssl_version_str = NULL; const char * crypto_openssl_get_version_str(void) { +#ifdef OPENSSL_VERSION + const int query = OPENSSL_VERSION; +#else + /* This old name was changed around OpenSSL 1.1.0 */ + const int query = SSLEAY_VERSION; +#endif + if (crypto_openssl_version_str == NULL) { - const char *raw_version = OpenSSL_version(OPENSSL_VERSION); + const char *raw_version = OpenSSL_version(query); crypto_openssl_version_str = parse_openssl_version_str(raw_version); } return crypto_openssl_version_str; } +#undef QUERY_OPENSSL_VERSION + static char *crypto_openssl_header_version_str = NULL; /* Return a human-readable version of the compile-time openssl version * number. */ @@ -208,7 +217,7 @@ crypto_openssl_early_init(void) setup_openssl_threading(); unsigned long version_num = OpenSSL_version_num(); - const char *version_str = OpenSSL_version(OPENSSL_VERSION); + const char *version_str = crypto_openssl_get_version_str(); if (version_num == OPENSSL_VERSION_NUMBER && !strcmp(version_str, OPENSSL_VERSION_TEXT)) { log_info(LD_CRYPTO, "OpenSSL version matches version from headers " diff --git a/src/lib/crypt_ops/crypto_openssl_mgt.h b/src/lib/crypt_ops/crypto_openssl_mgt.h index a3dd03aa04..8dbadfc9d2 100644 --- a/src/lib/crypt_ops/crypto_openssl_mgt.h +++ b/src/lib/crypt_ops/crypto_openssl_mgt.h @@ -16,8 +16,7 @@ #include "orconfig.h" #ifdef ENABLE_OPENSSL -#include <openssl/engine.h> - +#include <openssl/opensslv.h> /* Macro to create an arbitrary OpenSSL version number as used by OPENSSL_VERSION_NUMBER or SSLeay(), since the actual numbers are a bit hard diff --git a/src/lib/log/util_bug.h b/src/lib/log/util_bug.h index 2a4d68127e..17e8d0c5a7 100644 --- a/src/lib/log/util_bug.h +++ b/src/lib/log/util_bug.h @@ -215,6 +215,17 @@ IF_BUG_ONCE__(ASSERT_PREDICT_UNLIKELY_(cond), \ IF_BUG_ONCE_VARNAME__(__LINE__)) +/** + * Use this macro after a nonfatal assertion, and before a case statement + * where you would want to fall through. + */ +#ifdef ALL_BUGS_ARE_FATAL +#define FALLTHROUGH_UNLESS_ALL_BUGS_ARE_FATAL \ + abort() +#else +#define FALLTHROUGH_UNLESS_ALL_BUGS_ARE_FATAL FALLTHROUGH +#endif + /** Define this if you want Tor to crash when any problem comes up, * so you can get a coredump and track things down. */ // #define tor_fragile_assert() tor_assert_unreached(0) diff --git a/src/lib/tls/tortls_nss.c b/src/lib/tls/tortls_nss.c index 1436442e1c..6f6c47674e 100644 --- a/src/lib/tls/tortls_nss.c +++ b/src/lib/tls/tortls_nss.c @@ -418,6 +418,16 @@ tor_tls_new(tor_socket_t sock, int is_server) return NULL; } + /* even if though the socket is already nonblocking, we need to tell NSS + * about the fact, so that it knows what to do when it says EAGAIN. */ + PRSocketOptionData data; + data.option = PR_SockOpt_Nonblocking; + data.value.non_blocking = 1; + if (PR_SetSocketOption(ssl, &data) != PR_SUCCESS) { + PR_Close(ssl); + return NULL; + } + tor_tls_t *tls = tor_malloc_zero(sizeof(tor_tls_t)); tls->magic = TOR_TLS_MAGIC; tls->context = ctx; diff --git a/src/rust/protover/errors.rs b/src/rust/protover/errors.rs index dc0d8735f4..04397ac4fe 100644 --- a/src/rust/protover/errors.rs +++ b/src/rust/protover/errors.rs @@ -36,7 +36,7 @@ impl Display for ProtoverError { ProtoverError::Unparseable => write!(f, "The protover string was unparseable."), ProtoverError::ExceedsMax => write!( f, - "The high in a (low, high) protover range exceeds u32::MAX." + "The high in a (low, high) protover range exceeds 63." ), ProtoverError::ExceedsExpansionLimit => write!( f, diff --git a/src/rust/protover/protoset.rs b/src/rust/protover/protoset.rs index 3b283983c8..0ab94457c5 100644 --- a/src/rust/protover/protoset.rs +++ b/src/rust/protover/protoset.rs @@ -294,6 +294,10 @@ impl ProtoSet { } } +/// Largest allowed protocol version. +/// C_RUST_COUPLED: protover.c `MAX_PROTOCOL_VERSION` +const MAX_PROTOCOL_VERSION: Version = 63; + impl FromStr for ProtoSet { type Err = ProtoverError; @@ -370,7 +374,7 @@ impl FromStr for ProtoSet { let pieces: ::std::str::Split<char> = version_string.split(','); for p in pieces { - if p.contains('-') { + let (lo,hi) = if p.contains('-') { let mut pair = p.splitn(2, '-'); let low = pair.next().ok_or(ProtoverError::Unparseable)?; @@ -379,12 +383,17 @@ impl FromStr for ProtoSet { let lo: Version = low.parse().or(Err(ProtoverError::Unparseable))?; let hi: Version = high.parse().or(Err(ProtoverError::Unparseable))?; - pairs.push((lo, hi)); + (lo,hi) } else { let v: u32 = p.parse().or(Err(ProtoverError::Unparseable))?; - pairs.push((v, v)); + (v, v) + }; + + if lo > MAX_PROTOCOL_VERSION || hi > MAX_PROTOCOL_VERSION { + return Err(ProtoverError::ExceedsMax); } + pairs.push((lo, hi)); } ProtoSet::from_slice(&pairs[..]) @@ -674,12 +683,11 @@ mod test { #[test] fn test_protoset_into_vec() { - let ps: ProtoSet = "1-13,42,9001,4294967294".parse().unwrap(); + let ps: ProtoSet = "1-13,42".parse().unwrap(); let v: Vec<Version> = ps.into(); assert!(v.contains(&7)); - assert!(v.contains(&9001)); - assert!(v.contains(&4294967294)); + assert!(v.contains(&42)); } } diff --git a/src/rust/protover/protover.rs b/src/rust/protover/protover.rs index 06fdf56c69..536667f61b 100644 --- a/src/rust/protover/protover.rs +++ b/src/rust/protover/protover.rs @@ -866,12 +866,12 @@ mod test { #[test] fn test_protoentry_from_str_allowed_number_of_versions() { - assert_protoentry_is_parseable!("Desc=1-4294967294"); + assert_protoentry_is_parseable!("Desc=1-63"); } #[test] fn test_protoentry_from_str_too_many_versions() { - assert_protoentry_is_unparseable!("Desc=1-4294967295"); + assert_protoentry_is_unparseable!("Desc=1-64"); } #[test] @@ -910,10 +910,10 @@ mod test { #[test] fn test_protoentry_all_supported_unsupported_high_version() { - let protocols: UnvalidatedProtoEntry = "HSDir=12-100".parse().unwrap(); + let protocols: UnvalidatedProtoEntry = "HSDir=12-60".parse().unwrap(); let unsupported: Option<UnvalidatedProtoEntry> = protocols.all_supported(); assert_eq!(true, unsupported.is_some()); - assert_eq!("HSDir=12-100", &unsupported.unwrap().to_string()); + assert_eq!("HSDir=12-60", &unsupported.unwrap().to_string()); } #[test] @@ -962,7 +962,7 @@ mod test { ProtoSet::from_str(&versions).unwrap().to_string() ); - versions = "1-3,500"; + versions = "1-3,50"; assert_eq!( String::from(versions), ProtoSet::from_str(&versions).unwrap().to_string() diff --git a/src/rust/protover/tests/protover.rs b/src/rust/protover/tests/protover.rs index 942fe3c6ab..d563202d87 100644 --- a/src/rust/protover/tests/protover.rs +++ b/src/rust/protover/tests/protover.rs @@ -98,10 +98,10 @@ fn protocol_all_supported_with_unsupported_protocol() { #[test] fn protocol_all_supported_with_unsupported_versions() { - let protocols: UnvalidatedProtoEntry = "Link=3-999".parse().unwrap(); + let protocols: UnvalidatedProtoEntry = "Link=3-63".parse().unwrap(); let unsupported: Option<UnvalidatedProtoEntry> = protocols.all_supported(); assert_eq!(true, unsupported.is_some()); - assert_eq!("Link=6-999", &unsupported.unwrap().to_string()); + assert_eq!("Link=6-63", &unsupported.unwrap().to_string()); } #[test] @@ -114,10 +114,10 @@ fn protocol_all_supported_with_unsupported_low_version() { #[test] fn protocol_all_supported_with_unsupported_high_version() { - let protocols: UnvalidatedProtoEntry = "Cons=1-2,999".parse().unwrap(); + let protocols: UnvalidatedProtoEntry = "Cons=1-2,60".parse().unwrap(); let unsupported: Option<UnvalidatedProtoEntry> = protocols.all_supported(); assert_eq!(true, unsupported.is_some()); - assert_eq!("Cons=999", &unsupported.unwrap().to_string()); + assert_eq!("Cons=60", &unsupported.unwrap().to_string()); } #[test] @@ -195,27 +195,27 @@ fn protover_compute_vote_returns_protocols_that_it_doesnt_currently_support() { #[test] fn protover_compute_vote_returns_matching_for_mix() { - let protocols: &[UnvalidatedProtoEntry] = &["Link=1-10,500 Cons=1,3-7,8".parse().unwrap()]; + let protocols: &[UnvalidatedProtoEntry] = &["Link=1-10,50 Cons=1,3-7,8".parse().unwrap()]; let listed = ProtoverVote::compute(protocols, &1); - assert_eq!("Cons=1,3-8 Link=1-10,500", listed.to_string()); + assert_eq!("Cons=1,3-8 Link=1-10,50", listed.to_string()); } #[test] fn protover_compute_vote_returns_matching_for_longer_mix() { let protocols: &[UnvalidatedProtoEntry] = &[ - "Desc=1-10,500 Cons=1,3-7,8".parse().unwrap(), - "Link=123-456,78 Cons=2-6,8 Desc=9".parse().unwrap(), + "Desc=1-10,50 Cons=1,3-7,8".parse().unwrap(), + "Link=12-45,8 Cons=2-6,8 Desc=9".parse().unwrap(), ]; let listed = ProtoverVote::compute(protocols, &1); - assert_eq!("Cons=1-8 Desc=1-10,500 Link=78,123-456", listed.to_string()); + assert_eq!("Cons=1-8 Desc=1-10,50 Link=8,12-45", listed.to_string()); } #[test] fn protover_compute_vote_returns_matching_for_longer_mix_with_threshold_two() { let protocols: &[UnvalidatedProtoEntry] = &[ - "Desc=1-10,500 Cons=1,3-7,8".parse().unwrap(), - "Link=123-456,78 Cons=2-6,8 Desc=9".parse().unwrap(), + "Desc=1-10,50 Cons=1,3-7,8".parse().unwrap(), + "Link=8,12-45 Cons=2-6,8 Desc=9".parse().unwrap(), ]; let listed = ProtoverVote::compute(protocols, &2); @@ -320,30 +320,20 @@ fn protocol_all_supported_with_single_protocol_and_protocol_range() { assert_eq!(true, unsupported.is_none()); } -// By allowing us to add to votes, the C implementation allows us to -// exceed the limit. -#[test] -fn protover_compute_vote_may_exceed_limit() { - let proto1: UnvalidatedProtoEntry = "Sleen=1-65535".parse().unwrap(); - let proto2: UnvalidatedProtoEntry = "Sleen=100000".parse().unwrap(); - - let _result: UnvalidatedProtoEntry = ProtoverVote::compute(&[proto1, proto2], &1); -} - #[test] fn protover_all_supported_should_exclude_versions_we_actually_do_support() { - let proto: UnvalidatedProtoEntry = "Link=3-999".parse().unwrap(); + let proto: UnvalidatedProtoEntry = "Link=3-63".parse().unwrap(); let result: String = proto.all_supported().unwrap().to_string(); - assert_eq!(result, "Link=6-999".to_string()); + assert_eq!(result, "Link=6-63".to_string()); } #[test] fn protover_all_supported_should_exclude_versions_we_actually_do_support_complex1() { - let proto: UnvalidatedProtoEntry = "Link=1-3,345-666".parse().unwrap(); + let proto: UnvalidatedProtoEntry = "Link=1-3,30-63".parse().unwrap(); let result: String = proto.all_supported().unwrap().to_string(); - assert_eq!(result, "Link=345-666".to_string()); + assert_eq!(result, "Link=30-63".to_string()); } #[test] @@ -356,26 +346,10 @@ fn protover_all_supported_should_exclude_versions_we_actually_do_support_complex #[test] fn protover_all_supported_should_exclude_some_versions_and_entire_protocols() { - let proto: UnvalidatedProtoEntry = "Link=1-3,5-12 Quokka=9000-9001".parse().unwrap(); - let result: String = proto.all_supported().unwrap().to_string(); - - assert_eq!(result, "Link=6-12 Quokka=9000-9001".to_string()); -} - -#[test] -fn protover_all_supported_should_not_dos_anyones_computer() { - let proto: UnvalidatedProtoEntry = "Link=1-2147483648".parse().unwrap(); - let result: String = proto.all_supported().unwrap().to_string(); - - assert_eq!(result, "Link=6-2147483648".to_string()); -} - -#[test] -fn protover_all_supported_should_not_dos_anyones_computer_max_versions() { - let proto: UnvalidatedProtoEntry = "Link=1-4294967294".parse().unwrap(); + let proto: UnvalidatedProtoEntry = "Link=1-3,5-12 Quokka=50-51".parse().unwrap(); let result: String = proto.all_supported().unwrap().to_string(); - assert_eq!(result, "Link=6-4294967294".to_string()); + assert_eq!(result, "Link=6-12 Quokka=50-51".to_string()); } #[test] diff --git a/src/test/hs_ntor_ref.py b/src/test/hs_ntor_ref.py index 1b9772a5d6..d58ac3ca23 100644 --- a/src/test/hs_ntor_ref.py +++ b/src/test/hs_ntor_ref.py @@ -65,14 +65,16 @@ except ImportError: try: # Pull the sha3 functions in. from hashlib import sha3_256, shake_256 - shake_squeeze = shake_256.digest + def shake_squeeze(obj, n): + return obj.digest(n) except ImportError: if hasattr(sha3, "SHA3256"): # If this happens, then we have the old "sha3" module which # hashlib and pysha3 superseded. sha3_256 = sha3.SHA3256 shake_256 = sha3.SHAKE256 - shake_squeeze = shake_256.squeeze + def shake_squeeze(obj, n): + return obj.squeeze(n) else: # error code 77 tells automake to skip this test sys.exit(77) diff --git a/src/test/include.am b/src/test/include.am index ecb7689579..75861fb9ef 100644 --- a/src/test/include.am +++ b/src/test/include.am @@ -23,7 +23,15 @@ TESTSCRIPTS = \ src/test/test_workqueue_pipe.sh \ src/test/test_workqueue_pipe2.sh \ src/test/test_workqueue_socketpair.sh \ - src/test/test_switch_id.sh + src/test/test_switch_id.sh \ + src/test/unittest_part1.sh \ + src/test/unittest_part2.sh \ + src/test/unittest_part3.sh \ + src/test/unittest_part4.sh \ + src/test/unittest_part5.sh \ + src/test/unittest_part6.sh \ + src/test/unittest_part7.sh \ + src/test/unittest_part8.sh if USE_RUST TESTSCRIPTS += \ @@ -35,7 +43,7 @@ TESTSCRIPTS += src/test/test_ntor.sh src/test/test_hs_ntor.sh src/test/test_bt.s TESTSCRIPTS += src/test/test_rebind.sh endif -TESTS += src/test/test src/test/test-slow src/test/test-memwipe \ +TESTS += src/test/test-slow src/test/test-memwipe \ src/test/test_workqueue \ src/test/test_keygen.sh \ src/test/test_key_expiration.sh \ @@ -369,7 +377,15 @@ EXTRA_DIST += \ src/test/test_workqueue_efd2.sh \ src/test/test_workqueue_pipe.sh \ src/test/test_workqueue_pipe2.sh \ - src/test/test_workqueue_socketpair.sh + src/test/test_workqueue_socketpair.sh \ + src/test/unittest_part1.sh \ + src/test/unittest_part2.sh \ + src/test/unittest_part3.sh \ + src/test/unittest_part4.sh \ + src/test/unittest_part5.sh \ + src/test/unittest_part6.sh \ + src/test/unittest_part7.sh \ + src/test/unittest_part8.sh test-rust: $(TESTS_ENVIRONMENT) "$(abs_top_srcdir)/src/test/test_rust.sh" diff --git a/src/test/test_channel.c b/src/test/test_channel.c index e55b9b0750..afb7db813c 100644 --- a/src/test/test_channel.c +++ b/src/test/test_channel.c @@ -46,7 +46,6 @@ static int dump_statistics_mock_matches = 0; static int test_close_called = 0; static int test_chan_should_be_canonical = 0; static int test_chan_should_match_target = 0; -static int test_chan_canonical_should_be_reliable = 0; static int test_chan_listener_close_fn_called = 0; static int test_chan_listener_fn_called = 0; @@ -357,14 +356,10 @@ scheduler_release_channel_mock(channel_t *ch) } static int -test_chan_is_canonical(channel_t *chan, int req) +test_chan_is_canonical(channel_t *chan) { tor_assert(chan); - if (req && test_chan_canonical_should_be_reliable) { - return 1; - } - if (test_chan_should_be_canonical) { return 1; } @@ -1381,6 +1376,9 @@ test_channel_for_extend(void *arg) /* Make it older than chan1. */ chan2->timestamp_created = chan1->timestamp_created - 1; + /* Say it's all canonical. */ + test_chan_should_be_canonical = 1; + /* Set channel identities and add it to the channel map. The last one to be * added is made the first one in the list so the lookup will always return * that one first. */ @@ -1475,8 +1473,8 @@ test_channel_for_extend(void *arg) chan2->is_bad_for_new_circs = 0; /* Non canonical channels. */ + test_chan_should_be_canonical = 0; test_chan_should_match_target = 0; - test_chan_canonical_should_be_reliable = 1; ret_chan = channel_get_for_extend(digest, &ed_id, &addr, &msg, &launch); tt_assert(!ret_chan); tt_str_op(msg, OP_EQ, "Connections all too old, or too non-canonical. " @@ -1567,4 +1565,3 @@ struct testcase_t channel_tests[] = { NULL, NULL }, END_OF_TESTCASES }; - diff --git a/src/test/test_config.c b/src/test/test_config.c index 855725411a..d648666f6e 100644 --- a/src/test/test_config.c +++ b/src/test/test_config.c @@ -4861,6 +4861,71 @@ test_config_parse_port_config__ports__server_options(void *data) } static void +test_config_get_first_advertised(void *data) +{ + (void)data; + int r, w=0, n=0; + char *msg=NULL; + or_options_t *opts = options_new(); + int port; + const tor_addr_t *addr; + + // no ports are configured? We get NULL. + port = get_first_advertised_port_by_type_af(CONN_TYPE_OR_LISTENER, + AF_INET); + tt_int_op(port, OP_EQ, 0); + addr = get_first_advertised_addr_by_type_af(CONN_TYPE_OR_LISTENER, + AF_INET); + tt_ptr_op(addr, OP_EQ, NULL); + + port = get_first_advertised_port_by_type_af(CONN_TYPE_OR_LISTENER, + AF_INET6); + tt_int_op(port, OP_EQ, 0); + addr = get_first_advertised_addr_by_type_af(CONN_TYPE_OR_LISTENER, + AF_INET6); + tt_ptr_op(addr, OP_EQ, NULL); + + config_line_append(&opts->ORPort_lines, "ORPort", "[1234::5678]:8080"); + config_line_append(&opts->ORPort_lines, "ORPort", + "1.2.3.4:9999 noadvertise"); + config_line_append(&opts->ORPort_lines, "ORPort", + "5.6.7.8:9911 nolisten"); + + r = parse_ports(opts, 0, &msg, &n, &w); + tt_assert(r == 0); + + // UNSPEC gets us nothing. + port = get_first_advertised_port_by_type_af(CONN_TYPE_OR_LISTENER, + AF_UNSPEC); + tt_int_op(port, OP_EQ, 0); + addr = get_first_advertised_addr_by_type_af(CONN_TYPE_OR_LISTENER, + AF_UNSPEC); + tt_ptr_op(addr, OP_EQ, NULL); + + // Try AF_INET. + port = get_first_advertised_port_by_type_af(CONN_TYPE_OR_LISTENER, + AF_INET); + tt_int_op(port, OP_EQ, 9911); + addr = get_first_advertised_addr_by_type_af(CONN_TYPE_OR_LISTENER, + AF_INET); + tt_ptr_op(addr, OP_NE, NULL); + tt_str_op(fmt_addrport(addr,port), OP_EQ, "5.6.7.8:9911"); + + // Try AF_INET6 + port = get_first_advertised_port_by_type_af(CONN_TYPE_OR_LISTENER, + AF_INET6); + tt_int_op(port, OP_EQ, 8080); + addr = get_first_advertised_addr_by_type_af(CONN_TYPE_OR_LISTENER, + AF_INET6); + tt_ptr_op(addr, OP_NE, NULL); + tt_str_op(fmt_addrport(addr,port), OP_EQ, "[1234::5678]:8080"); + + done: + or_options_free(opts); + config_free_all(); +} + +static void test_config_parse_log_severity(void *data) { int ret; @@ -5920,6 +5985,7 @@ struct testcase_t config_tests[] = { CONFIG_TEST(parse_port_config__ports__no_ports_given, 0), CONFIG_TEST(parse_port_config__ports__server_options, 0), CONFIG_TEST(parse_port_config__ports__ports_given, 0), + CONFIG_TEST(get_first_advertised, TT_FORK), CONFIG_TEST(parse_log_severity, 0), CONFIG_TEST(include_limit, 0), CONFIG_TEST(include_does_not_exist, 0), diff --git a/src/test/test_connection.c b/src/test/test_connection.c index ebe7c6d36f..6f716f5758 100644 --- a/src/test/test_connection.c +++ b/src/test/test_connection.c @@ -592,7 +592,8 @@ test_conn_download_status(void *arg) connection_t *ap_conn = NULL; const struct testcase_t *tc = arg; - consensus_flavor_t usable_flavor = (consensus_flavor_t)tc->setup_data; + consensus_flavor_t usable_flavor = + networkstatus_parse_flavor_name((const char*) tc->setup_data); /* The "other flavor" trick only works if there are two flavors */ tor_assert(N_CONSENSUS_FLAVORS == 2); @@ -893,9 +894,9 @@ struct testcase_t connection_tests[] = { CONNECTION_TESTCASE(get_rend, TT_FORK, test_conn_get_rend_st), CONNECTION_TESTCASE(get_rsrc, TT_FORK, test_conn_get_rsrc_st), CONNECTION_TESTCASE_ARG(download_status, TT_FORK, - test_conn_download_status_st, FLAV_MICRODESC), + test_conn_download_status_st, "microdesc"), CONNECTION_TESTCASE_ARG(download_status, TT_FORK, - test_conn_download_status_st, FLAV_NS), + test_conn_download_status_st, "ns"), //CONNECTION_TESTCASE(func_suffix, TT_FORK, setup_func_pair), { "failed_orconn_tracker", test_failed_orconn_tracker, TT_FORK, NULL, NULL }, END_OF_TESTCASES diff --git a/src/test/test_protover.c b/src/test/test_protover.c index 63c508bd13..b4689045cf 100644 --- a/src/test/test_protover.c +++ b/src/test/test_protover.c @@ -25,7 +25,7 @@ test_protover_parse(void *arg) #else char *re_encoded = NULL; - const char *orig = "Foo=1,3 Bar=3 Baz= Quux=9-12,14,15-16,900"; + const char *orig = "Foo=1,3 Bar=3 Baz= Quux=9-12,14,15-16"; smartlist_t *elts = parse_protocol_list(orig); tt_assert(elts); @@ -61,7 +61,7 @@ test_protover_parse(void *arg) e = smartlist_get(elts, 3); tt_str_op(e->name, OP_EQ, "Quux"); - tt_int_op(smartlist_len(e->ranges), OP_EQ, 4); + tt_int_op(smartlist_len(e->ranges), OP_EQ, 3); { r = smartlist_get(e->ranges, 0); tt_int_op(r->low, OP_EQ, 9); @@ -74,10 +74,6 @@ test_protover_parse(void *arg) r = smartlist_get(e->ranges, 2); tt_int_op(r->low, OP_EQ, 15); tt_int_op(r->high, OP_EQ, 16); - - r = smartlist_get(e->ranges, 3); - tt_int_op(r->low, OP_EQ, 900); - tt_int_op(r->high, OP_EQ, 900); } re_encoded = encode_protocol_list(elts); @@ -149,14 +145,14 @@ test_protover_vote(void *arg) tt_str_op(result, OP_EQ, ""); tor_free(result); - smartlist_add(lst, (void*) "Foo=1-10,500 Bar=1,3-7,8"); + smartlist_add(lst, (void*) "Foo=1-10,63 Bar=1,3-7,8"); result = protover_compute_vote(lst, 1); - tt_str_op(result, OP_EQ, "Bar=1,3-8 Foo=1-10,500"); + tt_str_op(result, OP_EQ, "Bar=1,3-8 Foo=1-10,63"); tor_free(result); - smartlist_add(lst, (void*) "Quux=123-456,78 Bar=2-6,8 Foo=9"); + smartlist_add(lst, (void*) "Quux=12-45 Bar=2-6,8 Foo=9"); result = protover_compute_vote(lst, 1); - tt_str_op(result, OP_EQ, "Bar=1-8 Foo=1-10,500 Quux=78,123-456"); + tt_str_op(result, OP_EQ, "Bar=1-8 Foo=1-10,63 Quux=12-45"); tor_free(result); result = protover_compute_vote(lst, 2); @@ -194,45 +190,16 @@ test_protover_vote(void *arg) /* Just below the threshold: Rust */ smartlist_clear(lst); - smartlist_add(lst, (void*) "Sleen=1-500"); + smartlist_add(lst, (void*) "Sleen=1-50"); result = protover_compute_vote(lst, 1); - tt_str_op(result, OP_EQ, "Sleen=1-500"); + tt_str_op(result, OP_EQ, "Sleen=1-50"); tor_free(result); /* Just below the threshold: C */ smartlist_clear(lst); - smartlist_add(lst, (void*) "Sleen=1-65536"); - result = protover_compute_vote(lst, 1); - tt_str_op(result, OP_EQ, "Sleen=1-65536"); - tor_free(result); - - /* Large protover lists that exceed the threshold */ - - /* By adding two votes, C allows us to exceed the limit */ - smartlist_add(lst, (void*) "Sleen=1-65536"); - smartlist_add(lst, (void*) "Sleen=100000"); - result = protover_compute_vote(lst, 1); - tt_str_op(result, OP_EQ, "Sleen=1-65536,100000"); - tor_free(result); - - /* Large integers */ - smartlist_clear(lst); - smartlist_add(lst, (void*) "Sleen=4294967294"); + smartlist_add(lst, (void*) "Sleen=1-63"); result = protover_compute_vote(lst, 1); - tt_str_op(result, OP_EQ, "Sleen=4294967294"); - tor_free(result); - - /* This parses, but fails at the vote stage */ - smartlist_clear(lst); - smartlist_add(lst, (void*) "Sleen=4294967295"); - result = protover_compute_vote(lst, 1); - tt_str_op(result, OP_EQ, ""); - tor_free(result); - - smartlist_clear(lst); - smartlist_add(lst, (void*) "Sleen=4294967296"); - result = protover_compute_vote(lst, 1); - tt_str_op(result, OP_EQ, ""); + tt_str_op(result, OP_EQ, "Sleen=1-63"); tor_free(result); /* Protocol name too long */ @@ -272,8 +239,8 @@ test_protover_all_supported(void *arg) tt_assert(! protover_all_supported("Wombat=9", &msg)); tt_str_op(msg, OP_EQ, "Wombat=9"); tor_free(msg); - tt_assert(! protover_all_supported("Link=999", &msg)); - tt_str_op(msg, OP_EQ, "Link=999"); + tt_assert(! protover_all_supported("Link=60", &msg)); + tt_str_op(msg, OP_EQ, "Link=60"); tor_free(msg); // Mix of things we support and things we don't @@ -283,11 +250,11 @@ test_protover_all_supported(void *arg) /* Mix of things we support and don't support within a single protocol * which we do support */ - tt_assert(! protover_all_supported("Link=3-999", &msg)); - tt_str_op(msg, OP_EQ, "Link=6-999"); + tt_assert(! protover_all_supported("Link=3-60", &msg)); + tt_str_op(msg, OP_EQ, "Link=6-60"); tor_free(msg); - tt_assert(! protover_all_supported("Link=1-3,345-666", &msg)); - tt_str_op(msg, OP_EQ, "Link=345-666"); + tt_assert(! protover_all_supported("Link=1-3,50-63", &msg)); + tt_str_op(msg, OP_EQ, "Link=50-63"); tor_free(msg); tt_assert(! protover_all_supported("Link=1-3,5-12", &msg)); tt_str_op(msg, OP_EQ, "Link=6-12"); @@ -295,18 +262,8 @@ test_protover_all_supported(void *arg) /* Mix of protocols we do support and some we don't, where the protocols * we do support have some versions we don't support. */ - tt_assert(! protover_all_supported("Link=1-3,5-12 Quokka=9000-9001", &msg)); - tt_str_op(msg, OP_EQ, "Link=6-12 Quokka=9000-9001"); - tor_free(msg); - - /* We shouldn't be able to DoS ourselves parsing a large range. */ - tt_assert(! protover_all_supported("Sleen=1-2147483648", &msg)); - tt_str_op(msg, OP_EQ, "Sleen=1-2147483648"); - tor_free(msg); - - /* This case is allowed. */ - tt_assert(! protover_all_supported("Sleen=1-4294967294", &msg)); - tt_str_op(msg, OP_EQ, "Sleen=1-4294967294"); + tt_assert(! protover_all_supported("Link=1-3,5-12 Quokka=40-41", &msg)); + tt_str_op(msg, OP_EQ, "Link=6-12 Quokka=40-41"); tor_free(msg); /* If we get a (barely) valid (but unsupported list, we say "yes, that's @@ -566,9 +523,9 @@ test_protover_vote_roundtrip(void *args) /* Will fail because of 4294967295. */ { "Foo=1,3 Bar=3 Baz= Quux=9-12,14,15-16,900 Zn=1,4294967295", NULL }, - { "Foo=1,3 Bar=3 Baz= Quux=9-12,14,15-16,900 Zn=1,4294967294", - "Bar=3 Foo=1,3 Quux=9-12,14-16,900 Zn=1,4294967294" }, - { "Zu16=1,65536", "Zu16=1,65536" }, + { "Foo=1,3 Bar=3 Baz= Quux=9-12,14,15-16,50 Zn=1,42", + "Bar=3 Foo=1,3 Quux=9-12,14-16,50 Zn=1,42" }, + { "Zu16=1,63", "Zu16=1,63" }, { "N-1=1,2", "N-1=1-2" }, { "-1=4294967295", NULL }, { "-1=3", "-1=3" }, @@ -602,12 +559,8 @@ test_protover_vote_roundtrip(void *args) /* Large integers */ { "Link=4294967296", NULL }, /* Large range */ - { "Sleen=1-501", "Sleen=1-501" }, + { "Sleen=1-63", "Sleen=1-63" }, { "Sleen=1-65537", NULL }, - /* Both C/Rust implementations should be able to handle this mild DoS. */ - { "Sleen=1-2147483648", NULL }, - /* Rust tests are built in debug mode, so ints are bounds-checked. */ - { "Sleen=1-4294967295", NULL }, }; unsigned u; smartlist_t *votes = smartlist_new(); diff --git a/src/test/test_rendcache.c b/src/test/test_rendcache.c index 93f9f82953..8b0e2df485 100644 --- a/src/test/test_rendcache.c +++ b/src/test/test_rendcache.c @@ -954,6 +954,7 @@ test_rend_cache_free_all(void *data) one->parsed = desc_one; desc_one->timestamp = time(NULL) + TIME_IN_THE_PAST; desc_one->pk = pk_generate(0); + rend_cache_increment_allocation(rend_cache_entry_allocation(one)); strmap_set_lc(rend_cache, "foo1", one); rend_cache_free_all(); @@ -978,11 +979,13 @@ test_rend_cache_entry_free(void *data) // Handles NULL descriptor correctly e = tor_malloc_zero(sizeof(rend_cache_entry_t)); + rend_cache_increment_allocation(rend_cache_entry_allocation(e)); rend_cache_entry_free(e); // Handles non-NULL descriptor correctly e = tor_malloc_zero(sizeof(rend_cache_entry_t)); e->desc = tor_malloc(10); + rend_cache_increment_allocation(rend_cache_entry_allocation(e)); rend_cache_entry_free(e); /* done: */ diff --git a/src/test/test_router.c b/src/test/test_router.c index 601881a124..e0d3adfdbd 100644 --- a/src/test/test_router.c +++ b/src/test/test_router.c @@ -7,9 +7,12 @@ * \brief Unittests for code in router.c **/ +#define CONFIG_PRIVATE +#define CONNECTION_PRIVATE #include "core/or/or.h" #include "app/config/config.h" #include "core/mainloop/mainloop.h" +#include "core/mainloop/connection.h" #include "feature/hibernate/hibernate.h" #include "feature/nodelist/routerinfo_st.h" #include "feature/nodelist/routerlist.h" @@ -17,6 +20,9 @@ #include "feature/stats/rephist.h" #include "lib/crypt_ops/crypto_curve25519.h" #include "lib/crypt_ops/crypto_ed25519.h" +#include "lib/encoding/confline.h" + +#include "core/or/listener_connection_st.h" /* Test suite stuff */ #include "test/test.h" @@ -231,11 +237,124 @@ test_router_check_descriptor_bandwidth_changed(void *arg) UNMOCK(we_are_hibernating); } +static smartlist_t *fake_connection_array = NULL; +static smartlist_t * +mock_get_connection_array(void) +{ + return fake_connection_array; +} + +static void +test_router_get_advertised_or_port(void *arg) +{ + (void)arg; + int r, w=0, n=0; + char *msg=NULL; + or_options_t *opts = options_new(); + listener_connection_t *listener = NULL; + tor_addr_port_t ipv6; + + // Test one failing case of router_get_advertised_ipv6_or_ap(). + router_get_advertised_ipv6_or_ap(opts, &ipv6); + tt_str_op(fmt_addrport(&ipv6.addr, ipv6.port), OP_EQ, "[::]:0"); + + // And one failing case of router_get_advertised_or_port(). + tt_int_op(0, OP_EQ, router_get_advertised_or_port_by_af(opts, AF_INET)); + tt_int_op(0, OP_EQ, router_get_advertised_or_port(opts)); + + // Set up a couple of configured ports. + config_line_append(&opts->ORPort_lines, "ORPort", "[1234::5678]:auto"); + config_line_append(&opts->ORPort_lines, "ORPort", "5.6.7.8:9999"); + r = parse_ports(opts, 0, &msg, &n, &w); + tt_assert(r == 0); + + // There are no listeners, so the "auto" case will turn up no results. + tt_int_op(0, OP_EQ, router_get_advertised_or_port_by_af(opts, AF_INET6)); + router_get_advertised_ipv6_or_ap(opts, &ipv6); + tt_str_op(fmt_addrport(&ipv6.addr, ipv6.port), OP_EQ, "[::]:0"); + + // This will return the matching value from the configured port. + tt_int_op(9999, OP_EQ, router_get_advertised_or_port_by_af(opts, AF_INET)); + tt_int_op(9999, OP_EQ, router_get_advertised_or_port(opts)); + + // Now set up a dummy listener. + MOCK(get_connection_array, mock_get_connection_array); + fake_connection_array = smartlist_new(); + listener = listener_connection_new(CONN_TYPE_OR_LISTENER, AF_INET6); + TO_CONN(listener)->port = 54321; + smartlist_add(fake_connection_array, TO_CONN(listener)); + + // We should get a port this time. + tt_int_op(54321, OP_EQ, router_get_advertised_or_port_by_af(opts, AF_INET6)); + + // Test one succeeding case of router_get_advertised_ipv6_or_ap(). + router_get_advertised_ipv6_or_ap(opts, &ipv6); + tt_str_op(fmt_addrport(&ipv6.addr, ipv6.port), OP_EQ, + "[1234::5678]:54321"); + + // This will return the matching value from the configured port. + tt_int_op(9999, OP_EQ, router_get_advertised_or_port_by_af(opts, AF_INET)); + tt_int_op(9999, OP_EQ, router_get_advertised_or_port(opts)); + + done: + or_options_free(opts); + config_free_all(); + smartlist_free(fake_connection_array); + connection_free_minimal(TO_CONN(listener)); + UNMOCK(get_connection_array); +} + +static void +test_router_get_advertised_or_port_localhost(void *arg) +{ + (void)arg; + int r, w=0, n=0; + char *msg=NULL; + or_options_t *opts = options_new(); + tor_addr_port_t ipv6; + + // Set up a couple of configured ports on localhost. + config_line_append(&opts->ORPort_lines, "ORPort", "[::1]:9999"); + config_line_append(&opts->ORPort_lines, "ORPort", "127.0.0.1:8888"); + r = parse_ports(opts, 0, &msg, &n, &w); + tt_assert(r == 0); + + // We should refuse to advertise them, since we have default dirauths. + router_get_advertised_ipv6_or_ap(opts, &ipv6); + tt_str_op(fmt_addrport(&ipv6.addr, ipv6.port), OP_EQ, "[::]:0"); + // But the lower-level function should still report the correct value + tt_int_op(9999, OP_EQ, router_get_advertised_or_port_by_af(opts, AF_INET6)); + + // The IPv4 checks are done in resolve_my_address(), which doesn't use + // ORPorts so we can't test them here. (See #33681.) Both these lower-level + // functions should still report the correct value. + tt_int_op(8888, OP_EQ, router_get_advertised_or_port_by_af(opts, AF_INET)); + tt_int_op(8888, OP_EQ, router_get_advertised_or_port(opts)); + + // Now try with a fake authority set up. + config_line_append(&opts->DirAuthorities, "DirAuthority", + "127.0.0.1:1066 " + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"); + + tt_int_op(9999, OP_EQ, router_get_advertised_or_port_by_af(opts, AF_INET6)); + router_get_advertised_ipv6_or_ap(opts, &ipv6); + tt_str_op(fmt_addrport(&ipv6.addr, ipv6.port), OP_EQ, "[::1]:9999"); + + tt_int_op(8888, OP_EQ, router_get_advertised_or_port_by_af(opts, AF_INET)); + tt_int_op(8888, OP_EQ, router_get_advertised_or_port(opts)); + + done: + or_options_free(opts); + config_free_all(); +} + #define ROUTER_TEST(name, flags) \ { #name, test_router_ ## name, flags, NULL, NULL } struct testcase_t router_tests[] = { ROUTER_TEST(check_descriptor_bandwidth_changed, TT_FORK), ROUTER_TEST(dump_router_to_string_no_bridge_distribution_method, TT_FORK), + ROUTER_TEST(get_advertised_or_port, TT_FORK), + ROUTER_TEST(get_advertised_or_port_localhost, TT_FORK), END_OF_TESTCASES }; diff --git a/src/test/test_tortls_openssl.c b/src/test/test_tortls_openssl.c index f039980a25..f4e3430dac 100644 --- a/src/test/test_tortls_openssl.c +++ b/src/test/test_tortls_openssl.c @@ -283,8 +283,7 @@ test_tortls_log_one_error(void *ignored) mock_clean_saved_logs(); tor_tls_log_one_error(tls, ERR_PACK(1, 2, 3), LOG_WARN, 0, NULL); - expect_log_msg("TLS error with 127.hello: " - "BN lib (in unknown library:(null):---)\n"); + expect_log_msg_containing("TLS error with 127.hello"); mock_clean_saved_logs(); tor_tls_log_one_error(tls, ERR_PACK(1, 2, SSL_R_HTTP_REQUEST), diff --git a/src/test/testing_common.c b/src/test/testing_common.c index 2c9c4538b9..daa7aa524a 100644 --- a/src/test/testing_common.c +++ b/src/test/testing_common.c @@ -278,6 +278,8 @@ main(int c, const char **v) control_initialize_event_queue(); configure_backtrace_handler(get_version()); + unsigned num=1, den=1; + for (i_out = i = 1; i < c; ++i) { if (!strcmp(v[i], "--warn")) { loglevel = LOG_WARN; @@ -289,6 +291,19 @@ main(int c, const char **v) loglevel = LOG_DEBUG; } else if (!strcmp(v[i], "--accel")) { accel_crypto = 1; + } else if (!strcmp(v[i], "--fraction")) { + if (i+1 == c) { + printf("--fraction needs an argument.\n"); + return 1; + } + const char *fracstr = v[++i]; + char ch; + if (sscanf(fracstr, "%u/%u%c", &num, &den, &ch) != 2) { + printf("--fraction expects a fraction as an input.\n"); + } + if (den == 0 || num == 0 || num > den) { + printf("--fraction expects a valid fraction as an input.\n"); + } } else { v[i_out++] = v[i]; } @@ -363,6 +378,33 @@ main(int c, const char **v) smartlist_free(skip); } + if (den != 1) { + // count the tests. Linear but fast. + unsigned n_tests = 0; + struct testgroup_t *tg; + struct testcase_t *tc; + for (tg = testgroups; tg->prefix != NULL; ++tg) { + for (tc = tg->cases; tc->name != NULL; ++tc) { + ++n_tests; + } + } + // Which tests should we run? This can give iffy results if den is huge + // but it doesn't actually matter in practice. + unsigned tests_per_chunk = CEIL_DIV(n_tests, den); + unsigned start_at = (num-1) * tests_per_chunk; + + // Skip the tests that are outside of the range. + unsigned idx = 0; + for (tg = testgroups; tg->prefix != NULL; ++tg) { + for (tc = tg->cases; tc->name != NULL; ++tc) { + if (idx < start_at || idx >= start_at + tests_per_chunk) { + tc->flags |= TT_SKIP; + } + ++idx; + } + } + } + int have_failed = (tinytest_main(c, v, testgroups) != 0); free_pregenerated_keys(); diff --git a/src/test/unittest_part1.sh b/src/test/unittest_part1.sh new file mode 100755 index 0000000000..5be0f499f9 --- /dev/null +++ b/src/test/unittest_part1.sh @@ -0,0 +1,3 @@ +#!/bin/sh + +"${abs_top_builddir:-.}/src/test/test" --fraction 1/8 diff --git a/src/test/unittest_part2.sh b/src/test/unittest_part2.sh new file mode 100755 index 0000000000..9a614eb8c1 --- /dev/null +++ b/src/test/unittest_part2.sh @@ -0,0 +1,3 @@ +#!/bin/sh + +"${abs_top_builddir:-.}/src/test/test" --fraction 2/8 diff --git a/src/test/unittest_part3.sh b/src/test/unittest_part3.sh new file mode 100755 index 0000000000..5cbc3fe495 --- /dev/null +++ b/src/test/unittest_part3.sh @@ -0,0 +1,3 @@ +#!/bin/sh + +"${abs_top_builddir:-.}/src/test/test" --fraction 3/8 diff --git a/src/test/unittest_part4.sh b/src/test/unittest_part4.sh new file mode 100755 index 0000000000..bc6fe01f68 --- /dev/null +++ b/src/test/unittest_part4.sh @@ -0,0 +1,3 @@ +#!/bin/sh + +"${abs_top_builddir:-.}/src/test/test" --fraction 4/8 diff --git a/src/test/unittest_part5.sh b/src/test/unittest_part5.sh new file mode 100755 index 0000000000..9bbff34fb8 --- /dev/null +++ b/src/test/unittest_part5.sh @@ -0,0 +1,3 @@ +#!/bin/sh + +"${abs_top_builddir:-.}/src/test/test" --fraction 5/8 diff --git a/src/test/unittest_part6.sh b/src/test/unittest_part6.sh new file mode 100755 index 0000000000..2d5eaa8a28 --- /dev/null +++ b/src/test/unittest_part6.sh @@ -0,0 +1,3 @@ +#!/bin/sh + +"${abs_top_builddir:-.}/src/test/test" --fraction 6/8 diff --git a/src/test/unittest_part7.sh b/src/test/unittest_part7.sh new file mode 100755 index 0000000000..5e6ce2aea5 --- /dev/null +++ b/src/test/unittest_part7.sh @@ -0,0 +1,3 @@ +#!/bin/sh + +"${abs_top_builddir:-.}/src/test/test" --fraction 7/8 diff --git a/src/test/unittest_part8.sh b/src/test/unittest_part8.sh new file mode 100755 index 0000000000..7fea9c9c7f --- /dev/null +++ b/src/test/unittest_part8.sh @@ -0,0 +1,3 @@ +#!/bin/sh + +"${abs_top_builddir:-.}/src/test/test" --fraction 8/8 diff --git a/src/win32/orconfig.h b/src/win32/orconfig.h index ec7a5b2429..1c0ce18e73 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.5.11-dev" +#define VERSION "0.3.5.13" |