summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.travis.yml5
-rw-r--r--ChangeLog99
-rw-r--r--ReleaseNotes101
-rw-r--r--changes/bug316694
-rw-r--r--changes/bug330326
-rw-r--r--changes/bug330877
-rw-r--r--changes/bug331313
-rw-r--r--changes/bug336085
-rw-r--r--changes/bug336684
-rw-r--r--changes/bug336736
-rw-r--r--changes/bug336744
-rw-r--r--changes/bug338999
-rw-r--r--changes/bug339003
-rw-r--r--changes/bug339175
-rw-r--r--changes/bug339774
-rw-r--r--changes/bug341304
-rw-r--r--changes/bug342334
-rw-r--r--changes/doc341336
-rw-r--r--changes/ticket316344
-rw-r--r--changes/ticket325423
-rw-r--r--changes/ticket328736
-rw-r--r--changes/ticket334916
-rw-r--r--changes/ticket336336
-rw-r--r--changes/ticket336435
-rw-r--r--changes/ticket33643_part23
-rw-r--r--changes/ticket336794
-rw-r--r--changes/ticket337793
-rw-r--r--changes/ticket337894
-rw-r--r--changes/ticket3381712
-rw-r--r--changes/ticket339014
-rw-r--r--changes/ticket339565
-rw-r--r--changes/ticket34255_0433
-rw-r--r--configure.ac18
-rw-r--r--doc/HACKING/EndOfLifeTor.md48
-rw-r--r--doc/HACKING/ReleaseSeriesLifecycle.md113
-rw-r--r--doc/tor.1.txt49
-rwxr-xr-xscripts/maint/format_changelog.py2
-rw-r--r--scripts/maint/practracker/exceptions.txt39
-rwxr-xr-xscripts/maint/practracker/includes.py90
-rwxr-xr-xscripts/maint/rectify_include_paths.py12
-rwxr-xr-xscripts/maint/rename_c_identifier.py3
-rwxr-xr-xscripts/maint/run_check_subsystem_order.sh17
-rw-r--r--src/app/config/config.c298
-rw-r--r--src/app/config/config.h8
-rw-r--r--src/app/config/include.am2
-rw-r--r--src/app/config/quiet_level.c2
-rw-r--r--src/app/config/resolve_addr.c308
-rw-r--r--src/app/config/resolve_addr.h28
-rw-r--r--src/app/main/subsysmgr.c14
-rw-r--r--src/app/main/subsysmgr.h2
-rw-r--r--src/core/mainloop/connection.c7
-rw-r--r--src/core/mainloop/cpuworker.c2
-rw-r--r--src/core/mainloop/mainloop_sys.c1
-rw-r--r--src/core/or/channel.c90
-rw-r--r--src/core/or/channel.h12
-rw-r--r--src/core/or/channeltls.c19
-rw-r--r--src/core/or/circuitbuild.c291
-rw-r--r--src/core/or/circuitbuild.h20
-rw-r--r--src/core/or/circuitlist.c2
-rw-r--r--src/core/or/circuituse.c5
-rw-r--r--src/core/or/command.c1
-rw-r--r--src/core/or/connection_edge.c14
-rw-r--r--src/core/or/connection_or.c30
-rw-r--r--src/core/or/connection_or.h4
-rw-r--r--src/core/or/crypt_path.c2
-rw-r--r--src/core/or/onion.c53
-rw-r--r--src/core/or/onion.h10
-rw-r--r--src/core/or/or.h2
-rw-r--r--src/core/or/or_sys.c1
-rw-r--r--src/core/or/policies.c6
-rw-r--r--src/core/or/reasons.c2
-rw-r--r--src/core/or/relay.c11
-rw-r--r--src/core/or/scheduler.c4
-rw-r--r--src/core/or/sendme.c2
-rw-r--r--src/core/or/versions.c2
-rw-r--r--src/core/proto/proto_socks.c14
-rw-r--r--src/core/stA1RajU0
-rw-r--r--src/core/stiysZNDbin0 -> 19083264 bytes
-rw-r--r--src/ext/csiphash.c14
-rw-r--r--src/ext/ed25519/donna/ed25519_tor.c4
-rw-r--r--src/ext/ed25519/donna/modm-donna-32bit.h48
-rw-r--r--src/ext/ed25519/donna/modm-donna-64bit.h24
-rw-r--r--src/feature/client/addressmap.c2
-rw-r--r--src/feature/client/entrynodes.c2
-rw-r--r--src/feature/client/transports.c1
-rw-r--r--src/feature/control/btrack.c1
-rw-r--r--src/feature/control/btrack_orconn_cevent.c1
-rw-r--r--src/feature/control/control_cmd.c2
-rw-r--r--src/feature/control/control_getinfo.c19
-rw-r--r--src/feature/control/control_hs.c9
-rw-r--r--src/feature/dirauth/dirauth_config.c1
-rw-r--r--src/feature/dirauth/dirauth_stub.c1
-rw-r--r--src/feature/dirauth/dirauth_sys.c1
-rw-r--r--src/feature/dirauth/dirvote.c1
-rw-r--r--src/feature/dirauth/keypin.c2
-rw-r--r--src/feature/dirauth/shared_random_state.c3
-rw-r--r--src/feature/dircache/conscache.c2
-rw-r--r--src/feature/dircache/dircache.c1
-rw-r--r--src/feature/dirclient/dirclient.c3
-rw-r--r--src/feature/dirclient/dirclient_modes.c1
-rw-r--r--src/feature/dirparse/parsecommon.c2
-rw-r--r--src/feature/hs/hs_circuit.c26
-rw-r--r--src/feature/hs/hs_client.c125
-rw-r--r--src/feature/hs/hs_client.h3
-rw-r--r--src/feature/hs/hs_descriptor.c8
-rw-r--r--src/feature/hs/hs_dos.c4
-rw-r--r--src/feature/hs/hs_ob.c12
-rw-r--r--src/feature/hs/hs_opts_st.h2
-rw-r--r--src/feature/hs/hs_service.c16
-rw-r--r--src/feature/hs/hs_service.h16
-rw-r--r--src/feature/nodelist/dirlist.c1
-rw-r--r--src/feature/nodelist/nodelist.c10
-rw-r--r--src/feature/nodelist/nodelist.h8
-rw-r--r--src/feature/nodelist/routerinfo_st.h3
-rw-r--r--src/feature/relay/circuitbuild_relay.c549
-rw-r--r--src/feature/relay/circuitbuild_relay.h87
-rw-r--r--src/feature/relay/dns.c4
-rw-r--r--src/feature/relay/include.am4
-rw-r--r--src/feature/relay/relay_config.c2
-rw-r--r--src/feature/relay/relay_find_addr.c133
-rw-r--r--src/feature/relay/relay_find_addr.h23
-rw-r--r--src/feature/relay/relay_stub.c1
-rw-r--r--src/feature/relay/relay_sys.c1
-rw-r--r--src/feature/relay/router.c141
-rw-r--r--src/feature/relay/router.h10
-rw-r--r--src/feature/relay/selftest.c36
-rw-r--r--src/feature/relay/selftest.h27
-rw-r--r--src/feature/rend/rendclient.c2
-rw-r--r--src/feature/rend/rendservice.c5
-rw-r--r--src/lib/buf/buffers.c30
-rw-r--r--src/lib/buf/buffers.h3
-rw-r--r--src/lib/cc/compat_compiler.h6
-rw-r--r--src/lib/compress/compress.c1
-rw-r--r--src/lib/conf/confdecl.h6
-rw-r--r--src/lib/container/smartlist.c2
-rw-r--r--src/lib/crypt_ops/crypto_digest_nss.c28
-rw-r--r--src/lib/crypt_ops/crypto_digest_openssl.c10
-rw-r--r--src/lib/crypt_ops/crypto_init.c1
-rw-r--r--src/lib/crypt_ops/crypto_rand_numeric.c4
-rw-r--r--src/lib/crypt_ops/crypto_rsa_openssl.c8
-rw-r--r--src/lib/encoding/confline.c5
-rw-r--r--src/lib/err/torerr_sys.c1
-rw-r--r--src/lib/evloop/evloop_sys.c1
-rw-r--r--src/lib/fs/conffile.c1
-rw-r--r--src/lib/llharden/winprocess_sys.c1
-rw-r--r--src/lib/log/log_sys.c1
-rw-r--r--src/lib/log/util_bug.h23
-rw-r--r--src/lib/net/address.c83
-rw-r--r--src/lib/net/address.h24
-rw-r--r--src/lib/net/buffers_net.c12
-rw-r--r--src/lib/net/network_sys.c1
-rw-r--r--src/lib/net/socks5_status.h1
-rw-r--r--src/lib/process/process_sys.c1
-rw-r--r--src/lib/sandbox/sandbox.c15
-rw-r--r--src/lib/string/compat_ctype.c1
-rw-r--r--src/lib/subsys/subsys.h13
-rw-r--r--src/lib/thread/compat_threads.c1
-rw-r--r--src/lib/time/time_sys.c1
-rw-r--r--src/lib/tls/buffers_tls.c8
-rw-r--r--src/lib/tls/tortls.c1
-rw-r--r--src/lib/wallclock/approx_time.c1
-rw-r--r--src/lib/wallclock/time_to_tm.c1
-rw-r--r--src/mainpage.md3
-rw-r--r--src/test/conf_examples/empty_3/expected_log2
-rw-r--r--src/test/conf_examples/include_1/expected_log2
-rw-r--r--src/test/conf_examples/include_bug_31408/expected_log2
-rw-r--r--src/test/include.am4
-rw-r--r--src/test/test_addr.c134
-rw-r--r--src/test/test_address.c4
-rw-r--r--src/test/test_cell_formats.c78
-rw-r--r--src/test/test_channel.c39
-rw-r--r--src/test/test_channeltls.c1
-rw-r--r--src/test/test_circuitbuild.c1381
-rw-r--r--src/test/test_config.c2
-rw-r--r--src/test/test_connection.h2
-rw-r--r--src/test/test_dir.c4
-rw-r--r--src/test/test_hs_client.c76
-rw-r--r--src/test/test_hs_control.c14
-rw-r--r--src/test/test_hs_intropoint.c2
-rw-r--r--src/test/test_hs_service.c2
-rw-r--r--src/test/test_socks.c2
-rw-r--r--src/tools/tor-resolve.c2
182 files changed, 4170 insertions, 1293 deletions
diff --git a/.travis.yml b/.travis.yml
index 01343e65d9..cbbff2d942 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -210,7 +210,10 @@ install:
## If we're running chutney, install it.
- if [[ "$CHUTNEY" != "" ]]; then git clone --depth 1 https://github.com/torproject/chutney.git ; export CHUTNEY_PATH="$(pwd)/chutney"; fi
## If we're running stem, install it.
- - if [[ "$TEST_STEM" != "" ]]; then git clone --depth 1 https://github.com/torproject/stem.git ; export STEM_SOURCE_DIR=`pwd`/stem; fi
+ ## XXXX We are temporarily fixing the version at d1174a83 to work around
+ ## https://github.com/torproject/stem/issues/63 .
+ ## - if [[ "$TEST_STEM" != "" ]]; then git clone --no-tags --depth 1 https://github.com/torproject/stem.git; export STEM_SOURCE_DIR=`pwd`/stem; fi
+ - if [[ "$TEST_STEM" != "" ]]; then git clone https://github.com/torproject/stem.git && ( cd ./stem && git checkout d1174a83c2dcb7b855d8fc986be3ab8f8d88d68c) ; export STEM_SOURCE_DIR=`pwd`/stem; fi
##
## Finally, list installed package versions
- if [[ "$TRAVIS_OS_NAME" == "linux" ]]; then dpkg-query --show; fi
diff --git a/ChangeLog b/ChangeLog
index 15dd22a930..1efcbcf00f 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,102 @@
+Changes in version 0.4.3.4-rc - 2020-04-13
+ Tor 0.4.3.4-rc is the first release candidate in its series. It fixes
+ several bugs from earlier versions, including one affecting DoS
+ defenses on bridges using pluggable transports.
+
+ o Major bugfixes (DoS defenses, bridges, pluggable transport):
+ - Fix a bug that was preventing DoS defenses from running on bridges
+ with a pluggable transport. Previously, the DoS subsystem was not
+ given the transport name of the client connection, thus failed to
+ find the GeoIP cache entry for that client address. Fixes bug
+ 33491; bugfix on 0.3.3.2-alpha.
+
+ o Minor feature (sendme, flow control):
+ - Default to sending SENDME version 1 cells. (Clients are already
+ sending these, because of a consensus parameter telling them to do
+ so: this change only affects what clients would do if the
+ consensus didn't contain a recommendation.) Closes ticket 33623.
+
+ o Minor features (testing):
+ - The unit tests now support a "TOR_SKIP_TESTCASES" environment
+ variable to specify a list of space-separated test cases that
+ should not be executed. We will use this to disable certain tests
+ that are failing on Appveyor because of mismatched OpenSSL
+ libraries. Part of ticket 33643.
+
+ o Minor bugfixes (--disable-module-relay):
+ - Fix an assertion failure when Tor is built without the relay
+ module, and then invoked with the "User" option. Fixes bug 33668;
+ bugfix on 0.4.3.1-alpha.
+
+ o Minor bugfixes (--disable-module-relay,--disable-module-dirauth):
+ - Set some output arguments in the relay and dirauth module stubs,
+ to guard against future stub argument handling bugs like 33668.
+ Fixes bug 33674; bugfix on 0.4.3.1-alpha.
+
+ o Minor bugfixes (build system):
+ - Correctly output the enabled module in the configure summary.
+ Before that, the list shown was just plain wrong. Fixes bug 33646;
+ bugfix on 0.4.3.2-alpha.
+
+ o Minor bugfixes (client, IPv6):
+ - Stop forcing all non-SocksPorts to prefer IPv6 exit connections.
+ Instead, prefer IPv6 connections by default, but allow users to
+ change their configs using the "NoPreferIPv6" port flag. Fixes bug
+ 33608; bugfix on 0.4.3.1-alpha.
+ - Revert PreferIPv6 set by default on the SocksPort because it broke
+ the torsocks use case. Tor doesn't have a way for an application
+ to request the hostname to be resolved for a specific IP version,
+ but torsocks requires that. Up until now, IPv4 was used by default
+ so torsocks is expecting that, and can't handle a possible IPv6
+ being returned. Fixes bug 33804; bugfix on 0.4.3.1-alpha.
+
+ o Minor bugfixes (key portability):
+ - When reading PEM-encoded key data, tolerate CRLF line-endings even
+ if we are not running on Windows. Previously, non-Windows hosts
+ would reject these line-endings in certain positions, making
+ certain key files hard to move from one host to another. Fixes bug
+ 33032; bugfix on 0.3.5.1-alpha.
+
+ o Minor bugfixes (logging):
+ - Flush stderr, stdout, and file logs during shutdown, if supported
+ by the OS. This change helps make sure that any final logs are
+ recorded. Fixes bug 33087; bugfix on 0.4.1.6.
+ - Stop closing stderr and stdout during shutdown. Closing these file
+ descriptors can hide sanitiser logs. Fixes bug 33087; bugfix
+ on 0.4.1.6.
+
+ o Minor bugfixes (onion services v3):
+ - Relax severity of a log message that can appear naturally when
+ decoding onion service descriptors as a relay. Also add some
+ diagnostics to debug any future bugs in that area. Fixes bug
+ 31669; bugfix on 0.3.0.1-alpha.
+ - Block a client-side assertion by disallowing the registration of
+ an x25519 client auth key that's all zeroes. Fixes bug 33545;
+ bugfix on 0.4.3.1-alpha. Based on patch from "cypherpunks".
+
+ o Code simplification and refactoring:
+ - Disable our coding standards best practices tracker in our git
+ hooks. (0.4.3 branches only.) Closes ticket 33678.
+
+ o Testing:
+ - Avoid conflicts between the fake sockets in tor's unit tests, and
+ real file descriptors. Resolves issues running unit tests with
+ GitHub Actions, where the process that embeds or launches the
+ tests has already opened a large number of file descriptors. Fixes
+ bug 33782; bugfix on 0.2.8.1-alpha. Found and fixed by
+ Putta Khunchalee.
+
+ o Testing (CI):
+ - In our Appveyor Windows CI, copy required DLLs to test and app
+ directories, before running tor's tests. This ensures that tor.exe
+ and test*.exe use the correct version of each DLL. This fix is not
+ required, but we hope it will avoid DLL search issues in future.
+ Fixes bug 33673; bugfix on 0.3.4.2-alpha.
+ - On Appveyor, skip the crypto/openssl_version test, which is
+ failing because of a mismatched library installation. Fix
+ for 33643.
+
+
Changes in version 0.4.3.3-alpha - 2020-03-18
Tor 0.4.3.3-alpha fixes several bugs in previous releases, including
TROVE-2020-002, a major denial-of-service vulnerability that affected
diff --git a/ReleaseNotes b/ReleaseNotes
index a9adbfe342..a241da3027 100644
--- a/ReleaseNotes
+++ b/ReleaseNotes
@@ -2,107 +2,6 @@ This document summarizes new features and bugfixes in each stable
release of Tor. If you want to see more detailed descriptions of the
changes in each development snapshot, see the ChangeLog file.
-Changes in version 0.4.3.3-alpha - 2020-03-18
- Tor 0.4.3.3-alpha fixes several bugs in previous releases, including
- TROVE-2020-002, a major denial-of-service vulnerability that affected
- all released Tor instances since 0.2.1.5-alpha. Using this
- vulnerability, an attacker could cause Tor instances to consume a huge
- amount of CPU, disrupting their operations for several seconds or
- minutes. This attack could be launched by anybody against a relay, or
- by a directory cache against any client that had connected to it. The
- attacker could launch this attack as much as they wanted, thereby
- disrupting service or creating patterns that could aid in traffic
- analysis. This issue was found by OSS-Fuzz, and is also tracked
- as CVE-2020-10592.
-
- We do not have reason to believe that this attack is currently being
- exploited in the wild, but nonetheless we advise everyone to upgrade
- as soon as packages are available.
-
- o Major bugfixes (security, denial-of-service):
- - Fix a denial-of-service bug that could be used by anyone to
- consume a bunch of CPU on any Tor relay or authority, or by
- directories to consume a bunch of CPU on clients or hidden
- services. Because of the potential for CPU consumption to
- introduce observable timing patterns, we are treating this as a
- high-severity security issue. Fixes bug 33119; bugfix on
- 0.2.1.5-alpha. Found by OSS-Fuzz. We are also tracking this issue
- as TROVE-2020-002 and CVE-2020-10592.
-
- o Major bugfixes (circuit padding, memory leak):
- - Avoid a remotely triggered memory leak in the case that a circuit
- padding machine is somehow negotiated twice on the same circuit.
- Fixes bug 33619; bugfix on 0.4.0.1-alpha. Found by Tobias Pulls.
- This is also tracked as TROVE-2020-004 and CVE-2020-10593.
-
- o Major bugfixes (directory authority):
- - Directory authorities will now send a 503 (not enough bandwidth)
- code to clients when under bandwidth pressure. Known relays and
- other authorities will always be answered regardless of the
- bandwidth situation. Fixes bug 33029; bugfix on 0.1.2.5-alpha.
-
- o Minor features (diagnostic):
- - Improve assertions and add some memory-poisoning code to try to
- track down possible causes of a rare crash (32564) in the EWMA
- code. Closes ticket 33290.
-
- o Minor features (directory authorities):
- - Directory authorities now reject descriptors from relays running
- Tor versions from the 0.2.9 and 0.4.0 series. The 0.3.5 series is
- still allowed. Resolves ticket 32672. Patch by Neel Chauhan.
-
- o Minor features (usability):
- - Include more information when failing to parse a configuration
- value. This should make it easier to tell what's going wrong when
- a configuration file doesn't parse. Closes ticket 33460.
-
- o Minor bugfix (relay, configuration):
- - Warn if the ContactInfo field is not set, and tell the relay
- operator that not having a ContactInfo field set might cause their
- relay to get rejected in the future. Fixes bug 33361; bugfix
- on 0.1.1.10-alpha.
-
- o Minor bugfixes (coding best practices checks):
- - Allow the "practracker" script to read unicode files when using
- Python 2. We made the script use unicode literals in 0.4.3.1-alpha,
- but didn't change the codec for opening files. Fixes bug 33374;
- bugfix on 0.4.3.1-alpha.
-
- o Minor bugfixes (continuous integration):
- - Remove the buggy and unused mirroring job. Fixes bug 33213; bugfix
- on 0.3.2.2-alpha.
-
- o Minor bugfixes (onion service v3, client):
- - Remove a BUG() warning that would cause a stack trace if an onion
- service descriptor was freed while we were waiting for a
- rendezvous circuit to complete. Fixes bug 28992; bugfix
- on 0.3.2.1-alpha.
-
- o Minor bugfixes (onion services v3):
- - Fix an assertion failure that could result from a corrupted
- ADD_ONION control port command. Found by Saibato. Fixes bug 33137;
- bugfix on 0.3.3.1-alpha. This issue is also tracked
- as TROVE-2020-003.
-
- o Documentation (manpage):
- - Alphabetize the Server and Directory server sections of the tor
- manpage. Also split Statistics options into their own section of
- the manpage. Closes ticket 33188. Work by Swati Thacker as part of
- Google Season of Docs.
- - Document the __OwningControllerProcess torrc option and specify
- its polling interval. Resolves issue 32971.
-
- o Testing (Travis CI):
- - Remove a redundant distcheck job. Closes ticket 33194.
- - Sort the Travis jobs in order of speed: putting the slowest jobs
- first takes full advantage of Travis job concurrency. Closes
- ticket 33194.
- - Stop allowing the Chutney IPv6 Travis job to fail. This job was
- previously configured to fast_finish (which requires
- allow_failure), to speed up the build. Closes ticket 33195.
- - When a Travis chutney job fails, use chutney's new "diagnostics.sh"
- tool to produce detailed diagnostic output. Closes ticket 32792.
-
Changes in version 0.4.2.7 - 2020-03-18
This is the third stable release in the 0.4.2.x series. It backports
diff --git a/changes/bug31669 b/changes/bug31669
deleted file mode 100644
index 8079c98f62..0000000000
--- a/changes/bug31669
+++ /dev/null
@@ -1,4 +0,0 @@
- o Minor bugfixes (onion services v3):
- - Relax severity of a log message that can appear naturally when decoding
- onion service descriptors as a relay. Also add some diagnostics to debug
- any future bugs in that area. Fixes bug 31669; bugfix on 0.3.0.1-alpha. \ No newline at end of file
diff --git a/changes/bug33032 b/changes/bug33032
deleted file mode 100644
index 0c665f25df..0000000000
--- a/changes/bug33032
+++ /dev/null
@@ -1,6 +0,0 @@
- o Minor bugfixes (key portability):
- - When reading PEM-encoded key data, tolerate CRLF line-endings even if
- we are not running on Windows. Previously, non-Windows hosts
- would reject these line-endings in certain positions, making
- certain key files hard to move from one host to another.
- Fixes bug 33032; bugfix on 0.3.5.1-alpha.
diff --git a/changes/bug33087 b/changes/bug33087
deleted file mode 100644
index ab6df58cc6..0000000000
--- a/changes/bug33087
+++ /dev/null
@@ -1,7 +0,0 @@
- o Minor bugfixes (logging):
- - Stop closing stderr and stdout during shutdown. Closing these file
- descriptors can hide sanitiser logs.
- Fixes bug 33087; bugfix on 0.4.1.6.
- - Flush stderr, stdout, and file logs during shutdown, if supported by the
- OS. This change helps make sure that any final logs are recorded.
- Fixes bug 33087; bugfix on 0.4.1.6.
diff --git a/changes/bug33131 b/changes/bug33131
new file mode 100644
index 0000000000..bc5ef7bc2d
--- /dev/null
+++ b/changes/bug33131
@@ -0,0 +1,3 @@
+ o Minor bugfixes (mainloop):
+ - Better guard against growing a buffer past its maximum 2GB in size.
+ Fixes bug 33131; bugfix on 0.3.0.4-rc.
diff --git a/changes/bug33608 b/changes/bug33608
deleted file mode 100644
index 0e82a8eec9..0000000000
--- a/changes/bug33608
+++ /dev/null
@@ -1,5 +0,0 @@
- o Minor bugfixes (client IPv6):
- - Stop forcing all non-SOCKSPorts to prefer IPv6 exit connections. Instead,
- prefer IPv6 connections by default, but allow users to change their
- configs using the "NoPreferIPv6" port flag.
- Fixes bug 33608; bugfix on 0.4.3.1-alpha.
diff --git a/changes/bug33668 b/changes/bug33668
deleted file mode 100644
index 2b0830d6d8..0000000000
--- a/changes/bug33668
+++ /dev/null
@@ -1,4 +0,0 @@
- o Minor bugfixes (--disable-module-relay):
- - Fix an assertion failure when Tor is build without the relay module,
- and then invoked with the "User" option. Fixes bug 33668; bugfix on
- 0.4.3.1-alpha.
diff --git a/changes/bug33673 b/changes/bug33673
deleted file mode 100644
index 37c00f2e6e..0000000000
--- a/changes/bug33673
+++ /dev/null
@@ -1,6 +0,0 @@
- o Testing:
- - In our Appveyor Windows CI, copy required DLLs to test and app, before
- running tor's tests. This ensures that tor.exe and test*.exe use the
- correct version of each DLL. This fix is not required, but we hope it
- will avoid DLL search issues in future.
- Fixes bug 33673; bugfix on 0.3.4.2-alpha.
diff --git a/changes/bug33674 b/changes/bug33674
deleted file mode 100644
index bcc3fcab03..0000000000
--- a/changes/bug33674
+++ /dev/null
@@ -1,4 +0,0 @@
- o Minor bugfixes (--disable-module-relay,--disable-module-dirauth):
- - Set some output arguments in the relay and dirauth module stubs, to
- guard against future stub argument handling bugs like 33668.
- Fixes bug 33674; bugfix on 0.4.3.1-alpha.
diff --git a/changes/bug33899 b/changes/bug33899
new file mode 100644
index 0000000000..b9b7d7cf13
--- /dev/null
+++ b/changes/bug33899
@@ -0,0 +1,9 @@
+ o Minor bugfixes (IPv6, relay):
+ - Consider IPv6 addresses when checking if a connection is canonical.
+ In 17604, relays assumed that a remote relay could consider an IPv6
+ connection canonical, but did not set the canonical flag on their side
+ of the connection. Fixes bug 33899; bugfix on 0.3.1.1-alpha.
+ - Log IPv6 addresses on connections where this relay is the responder.
+ Previously, responding relays would replace the remote IPv6 address with
+ the IPv4 address from the consensus.
+ Fixes bug 33899; bugfix on 0.3.1.1-alpha.
diff --git a/changes/bug33900 b/changes/bug33900
new file mode 100644
index 0000000000..c1649d2284
--- /dev/null
+++ b/changes/bug33900
@@ -0,0 +1,3 @@
+ o Minor bugfixes (IPv4, relay):
+ - Check for invalid zero IPv4 addresses and ports, when sending and
+ receiving extend cells. Fixes bug 33900; bugfix on 0.2.4.8-alpha.
diff --git a/changes/bug33917 b/changes/bug33917
new file mode 100644
index 0000000000..6a8daa9e26
--- /dev/null
+++ b/changes/bug33917
@@ -0,0 +1,5 @@
+ o Minor bugfixes (logging, testing):
+ - Make all of tor's assertion macros support the ALL_BUGS_ARE_FATAL and
+ DISABLE_ASSERTS_IN_UNIT_TESTS debugging modes. Implements these modes
+ for IF_BUG_ONCE(). (It used to log a non-fatal warning, regardless of
+ the debugging mode.) Fixes bug 33917; bugfix on 0.2.9.1-alpha.
diff --git a/changes/bug33977 b/changes/bug33977
new file mode 100644
index 0000000000..b424a811a2
--- /dev/null
+++ b/changes/bug33977
@@ -0,0 +1,4 @@
+ o Minor bugfix (refactoring):
+ - Lift circuit_build_times_disabled out of circuit_expire_building loop to
+ save CPU time with many circuits open. Fixes bug 33977; bugfix on
+ 0.3.5.9.
diff --git a/changes/bug34130 b/changes/bug34130
new file mode 100644
index 0000000000..b1e5715fdf
--- /dev/null
+++ b/changes/bug34130
@@ -0,0 +1,4 @@
+ o Minor bugfixes (linux seccomp sandbox nss):
+ - Fix startup crash when tor is compiled with --enable-nss and
+ sandbox support is enabled. Fixes bug 34130; bugfix on
+ 0.3.5.1-alpha. Patch by Daniel Pinto.
diff --git a/changes/bug34233 b/changes/bug34233
new file mode 100644
index 0000000000..24c7869783
--- /dev/null
+++ b/changes/bug34233
@@ -0,0 +1,4 @@
+ o Minor bugfixes (portability):
+ - Fix a portability error in the configure script, where we
+ were using "==" instead of "=". Fixes bug 34233; bugfix on
+ 0.4.3.5.
diff --git a/changes/doc34133 b/changes/doc34133
new file mode 100644
index 0000000000..abe9db6148
--- /dev/null
+++ b/changes/doc34133
@@ -0,0 +1,6 @@
+ o Documentation:
+ - Correctly document that we search for a system torrc file before
+ Document the limitations of using %include on config files with
+ seccomp sandbox enabled. No new files can be added to the
+ %included directories. Fixes documentation bug 34133; bugfix
+ on 0.3.1.1-alpha. Patch by Daniel Pinto.
diff --git a/changes/ticket31634 b/changes/ticket31634
new file mode 100644
index 0000000000..2777595036
--- /dev/null
+++ b/changes/ticket31634
@@ -0,0 +1,4 @@
+ o Minor features (testing, architeture):
+ - Our test scripts now double-check that subsystem initialization order
+ is consistent with the inter-module dependencies established by our
+ .may_include files. Implements ticket 31634.
diff --git a/changes/ticket32542 b/changes/ticket32542
new file mode 100644
index 0000000000..c52335b059
--- /dev/null
+++ b/changes/ticket32542
@@ -0,0 +1,3 @@
+ o Minor feature (onion service client, SOCKS5):
+ - Add 3 new SocksPort ExtendedErrors (F2, F3, F7) that reports back new type
+ of onion service connection failures. Closes ticket 32542.
diff --git a/changes/ticket32873 b/changes/ticket32873
new file mode 100644
index 0000000000..65ea1f64ad
--- /dev/null
+++ b/changes/ticket32873
@@ -0,0 +1,6 @@
+ o Minor features (control port):
+ - Return a descriptive error message from the 'GETINFO
+ status/fresh-relay-descs' command on the control port.
+ Previously, we returned a generic error of "Error
+ generating descriptor". Closes ticket 32873. Patch by
+ Neel Chauhan.
diff --git a/changes/ticket33491 b/changes/ticket33491
deleted file mode 100644
index 595ea863ea..0000000000
--- a/changes/ticket33491
+++ /dev/null
@@ -1,6 +0,0 @@
- o Major bugfixes (DoS defenses, bridges, pluggable transport):
- - DoS subsystem was not given the transport name of the client connection
- when tor is a bridge and thus failing to find the GeoIP cache entry for
- that client address. This resulted in failing to apply DoS defenses on
- bridges with a pluggable transport. Fixes bug 33491; bugfix on
- 0.3.3.2-alpha.
diff --git a/changes/ticket33633 b/changes/ticket33633
new file mode 100644
index 0000000000..de030a6000
--- /dev/null
+++ b/changes/ticket33633
@@ -0,0 +1,6 @@
+ o Code simplification and refactoring:
+ - Move the circuit extend code to the relay module.
+ Split the circuit extend function into smaller functions.
+ Closes ticket 33633.
+ - Move LOG_PROTOCOL_WARN to app/config.c. Resolves a dependency inversion.
+ Closes ticket 33633.
diff --git a/changes/ticket33643 b/changes/ticket33643
deleted file mode 100644
index 7fddab74eb..0000000000
--- a/changes/ticket33643
+++ /dev/null
@@ -1,5 +0,0 @@
- o Minor features (testing):
- - The unit tests now support a "TOR_SKIP_TESTCASES" environment variable
- to specify a list of space-separated test cases that should not be
- executed. We will use this to disable certain tests that are failing on
- Appveyor because of mismatched OpenSSL libraries. Part of ticket 33643.
diff --git a/changes/ticket33643_part2 b/changes/ticket33643_part2
deleted file mode 100644
index 28193d2af5..0000000000
--- a/changes/ticket33643_part2
+++ /dev/null
@@ -1,3 +0,0 @@
- o Testing (CI):
- - On appveyor, skip the crypto/openssl_version test, which is failing
- because of a mismatched library installation. Fix for 33643.
diff --git a/changes/ticket33679 b/changes/ticket33679
new file mode 100644
index 0000000000..d37842d065
--- /dev/null
+++ b/changes/ticket33679
@@ -0,0 +1,4 @@
+ o Minor features (IPv6 Support, address.c):
+ - Adds IPv6 support to tor_addr_is_valid(). Adds tests for the
+ above changes and tor_addr_is_null(). Closes ticket 33679.
+ Patch by MrSquanchee.
diff --git a/changes/ticket33779 b/changes/ticket33779
new file mode 100644
index 0000000000..d4bc769ebb
--- /dev/null
+++ b/changes/ticket33779
@@ -0,0 +1,3 @@
+ o Minor bugfixes (onion service, logging):
+ - Typo in a log info level when PublishHidServDescriptors is set to 0.
+ Fixes bug 33779; bugfix on 0.3.2.1-alpha.
diff --git a/changes/ticket33789 b/changes/ticket33789
new file mode 100644
index 0000000000..a7e69793e6
--- /dev/null
+++ b/changes/ticket33789
@@ -0,0 +1,4 @@
+ o Code simplification and refactoring (relay address):
+ - Move a series of functions related to address resolving into their own
+ files. Closes ticket 33789.
+
diff --git a/changes/ticket33817 b/changes/ticket33817
new file mode 100644
index 0000000000..9c22d084eb
--- /dev/null
+++ b/changes/ticket33817
@@ -0,0 +1,12 @@
+ o Major features (IPv6, relay):
+ - Relays may extend circuits over IPv6, if the relay has an IPv6 ORPort,
+ and the client supplies the other relay's IPv6 ORPort in the EXTEND2
+ cell. IPv6 extends will be used by the relay IPv6 ORPort self-tests in
+ 33222. Closes ticket 33817.
+ - Consider IPv6-only EXTEND2 cells valid on relays. Log a protocol warning
+ if the IPv4 or IPv6 address is an internal address, and internal
+ addresses are not allowed. But continue to use the other address, if it
+ is valid. Closes ticket 33817.
+ - If a relay can extend over IPv4 and IPv6, it chooses between them
+ uniformly at random. Closes ticket 33817.
+ - Re-use existing IPv6 connections for circuit extends. Closes ticket 33817.
diff --git a/changes/ticket33901 b/changes/ticket33901
new file mode 100644
index 0000000000..b824cc5b07
--- /dev/null
+++ b/changes/ticket33901
@@ -0,0 +1,4 @@
+ o Minor features (IPv6, relay):
+ - Allow clients and relays to send dual-stack and IPv6-only EXTEND2 cells.
+ Parse dual-stack and IPv6-only EXTEND2 cells on relays.
+ Closes ticket 33901.
diff --git a/changes/ticket33956 b/changes/ticket33956
new file mode 100644
index 0000000000..7ad802797d
--- /dev/null
+++ b/changes/ticket33956
@@ -0,0 +1,5 @@
+ o Code simplification and refactoring:
+ - Define and use a new constant TOR_ADDRPORT_BUF_LEN which is like
+ TOR_ADDR_BUF_LEN but includes enough space for an IP address,
+ brackets, seperating colon, and port number. Closes ticket 33956.
+ Patch by Neel Chauhan.
diff --git a/changes/ticket34255_043 b/changes/ticket34255_043
new file mode 100644
index 0000000000..5cfec1d48d
--- /dev/null
+++ b/changes/ticket34255_043
@@ -0,0 +1,3 @@
+ o Documentation:
+ - Fix several doxygen warnings related to imbalanced groups.
+ Closes ticket 34255.
diff --git a/configure.ac b/configure.ac
index 87e7ea0cad..6942db159f 100644
--- a/configure.ac
+++ b/configure.ac
@@ -434,6 +434,22 @@ if test "$tor_cv_c_c99_designated_init" != "yes"; then
AC_MSG_ERROR([Your compiler doesn't support c99 designated initializers. This is required as of Tor 0.2.6.x])
fi
+saved_CFLAGS="$CFLAGS"
+CFLAGS="$CFLAGS -Werror"
+AC_CACHE_CHECK([for __attribute__((fallthrough))],
+ tor_cv_c_attr_fallthrough,
+ [AC_COMPILE_IFELSE(
+ [AC_LANG_PROGRAM([extern int x; void fn(void) ;],
+ [[ switch (x) { case 1: fn(); __attribute__((fallthrough));
+ case 2: fn(); break; } ]])],
+ [tor_cv_c_attr_fallthrough=yes],
+ [tor_cv_c_attr_fallthrough=no] )])
+CFLAGS="$saved_CFLAGS"
+
+if test "$tor_cv_c_attr_fallthrough" = "yes"; then
+ AC_DEFINE(HAVE_ATTR_FALLTHROUGH, [1], [defined if we have the fallthrough attribute.])
+fi
+
TORUSER=_tor
AC_ARG_WITH(tor-user,
AS_HELP_STRING(--with-tor-user=NAME, [specify username for tor daemon]),
@@ -2673,7 +2689,7 @@ PPRINT_SUBTITLE([Modules])
m4_foreach_w([mname], MODULES,
[
- test "xenable_module_mname" != "xno" && value=1 || value=0
+ AM_COND_IF(m4_join([], [BUILD_MODULE_], m4_toupper([]mname[])), value=1, value=0)
PPRINT_PROP_BOOL([mname (--disable-module-mname)], $value)
]
)
diff --git a/doc/HACKING/EndOfLifeTor.md b/doc/HACKING/EndOfLifeTor.md
deleted file mode 100644
index 0735dc311a..0000000000
--- a/doc/HACKING/EndOfLifeTor.md
+++ /dev/null
@@ -1,48 +0,0 @@
-# End of Life on an old release series
-
-Here are the steps that the maintainer should take when an old Tor release
-series reaches End of Life. Note that they are _only_ for entire series that
-have reached their planned EOL: they do not apply to security-related
-deprecations of individual versions.
-
-## 0. Preliminaries
-
-0. A few months before End of Life:
- Write a deprecation announcement.
- Send the announcement out with every new release announcement.
-
-1. A month before End of Life:
- Send the announcement to tor-announce, tor-talk, tor-relays, and the
- packagers.
-
-## 1. On the day
-
-1. Open tickets to remove the release from:
- - the jenkins builds
- - tor's Travis CI cron jobs
- - chutney's Travis CI tests (#)
- - stem's Travis CI tests (#)
-
-2. Close the milestone in Trac. To do this, go to Trac, log in,
- select "Admin" near the top of the screen, then select "Milestones" from
- the menu on the left. Click on the milestone for this version, and
- select the "Completed" checkbox. By convention, we select the date as
- the End of Life date.
-
-3. Replace NNN-backport with NNN-unreached-backport in all open trac tickets.
-
-4. If there are any remaining tickets in the milestone:
- - merge_ready tickets are for backports:
- - if there are no supported releases for the backport, close the ticket
- - if there is an earlier (LTS) release for the backport, move the ticket
- to that release
- - other tickets should be closed (if we won't fix them) or moved to a
- supported release (if we will fix them)
-
-5. Mail the end of life announcement to tor-announce, the packagers list,
- and tor-relays. The current list of packagers is in ReleasingTor.md.
-
-6. Ask at least two of weasel/arma/Sebastian to remove the old version
- number from their approved versions list.
-
-7. Update the CoreTorReleases wiki page.
diff --git a/doc/HACKING/ReleaseSeriesLifecycle.md b/doc/HACKING/ReleaseSeriesLifecycle.md
new file mode 100644
index 0000000000..e4068ed806
--- /dev/null
+++ b/doc/HACKING/ReleaseSeriesLifecycle.md
@@ -0,0 +1,113 @@
+# Release Series Lifecycle
+
+
+## End Of Life On An Old Release Series
+
+Here are the steps that the maintainer should take when an old Tor release
+series reaches End of Life.
+
+Note that they are _only_ for an entire series that has reached its planned
+EOL: they do not apply to security-related deprecations of individual
+patch versions.
+
+
+### 1. Preliminaries
+
+1. A few months before End of Life:
+ Write a deprecation announcement.
+ Send the announcement out with every new release announcement.
+
+2. A month before End of Life:
+ Send the announcement to tor-announce, tor-talk, tor-relays, and the
+ packagers.
+
+
+### 2. On The Day
+
+1. Open tickets to remove the release from:
+ - the jenkins builds
+ - tor's Travis CI cron jobs
+ - chutney's Travis CI tests
+ - sbws' Travis CI tests
+ - stem's Travis CI tests (but see
+ https://github.com/torproject/stem/issues/51)
+ - tor's scripts/git/gist-list-tor-branches.sh script
+
+2. Close the milestone in Trac. To do this, go to Trac, log in,
+ select "Admin" near the top of the screen, then select "Milestones" from
+ the menu on the left. Click on the milestone for this version, and
+ select the "Completed" checkbox. By convention, we select the date as
+ the End of Life date.
+
+3. Replace NNN-backport with NNN-unreached-backport in all open trac tickets.
+
+4. If there are any remaining tickets in the milestone:
+ - merge_ready tickets are for backports:
+ - if there are no supported releases for the backport, close the ticket
+ - if there is an earlier (LTS) release for the backport, move the ticket
+ to that release
+ - other tickets should be closed (if we won't fix them) or moved to a
+ supported release (if we will fix them)
+
+5. Mail the end of life announcement to tor-announce, the packagers list,
+ and tor-relays. The current list of packagers is in ReleasingTor.md.
+
+6. Ask at least two of weasel/arma/Sebastian to remove the old version
+ number from their approved versions list.
+
+7. Update the CoreTorReleases wiki page.
+
+8. Open a ticket (if there is not one already) for authorities to
+ start rejecting relays that are running that release series.
+ This ticket should be targeted for at least a month or two
+ after the series is officially EOL, unless there is an important
+ reason to un-list relays early.
+
+9. (LTS end-of-life only) Open a ticket (if appropriate) for updates to the
+ set of required and recommended subprotocol versions. (For the process
+ here, see proposal 303.)
+
+10. (LTS end-of-life only) Open a ticket to remove no-longer-needed
+ consensus methods. (For the process here, see proposal 290.)
+
+11. (All EOL) Open a ticket to grep for obsolete series names (e.g., "0.2.9"
+ and "029") in tor, chutney, sbws, fallback-scripts, and so on. These
+ should be updated or removed.
+
+12. Finally, make sure this document is up to date with our latest
+ process.
+
+## Starting A New Release Series
+
+Here are the steps that the maintainer should take to start new maint and
+release branches for a stable release.
+
+Note that they are _only_ for an entire series, when it first becomes stable:
+they do not apply to security-related patch release versions.
+
+(Ideally, do this immediately after a release.)
+
+1. Start a new maint-x.y.z branch based on master, and a new
+ release-x.y.z branch based on master. They should have the same
+ starting point.
+
+ Push both of these branches to the master git repository.
+
+2. In master, change the version to "0.x.y.0-alpha-dev". Run the
+ update_versions.py script, and commit this version bump.
+
+3. Tag the version bump with "tor-0.x.y.0-alpha-dev". Push the tag
+ and master.
+
+4. Open tickets for connecting the new branches to various other
+ places. See section 2 above for a list of affected locations.
+
+5. Stop running practracker on maintainence and release branches:
+ * Remove "check-best-practices" from the check-local Makefile
+ target in the maint-x.y.z branch only.
+ * Delete the file scripts/maint/practracker/.enable_practracker_in_hooks
+ in the maint-x.y.z branch only.
+ * Merge to release-x.y.z, but do not forward-port to master.
+
+6. Finally, make sure this document is up to date with our latest
+ process.
diff --git a/doc/tor.1.txt b/doc/tor.1.txt
index e87385f857..3dd7f5a64a 100644
--- a/doc/tor.1.txt
+++ b/doc/tor.1.txt
@@ -186,6 +186,13 @@ The following options in this section are only recognized on the
ISO-8601 format. For example, the output sent to stdout will be
of the form: "signing-cert-expiry: 2017-07-25 08:30:15 UTC"
+[[opt-dbg]] **--dbg-**...::
+ Tor may support other options beginning with the string "dbg". These
+ are intended for use by developers to debug and test Tor. They are
+ not supported or guaranteed to be stable, and you should probably
+ not use them.
+
+
[[conf-format]]
== THE CONFIGURATION FILE FORMAT
@@ -204,6 +211,8 @@ file will be parsed as if they were written where the %include option is. If
the path is a folder, all files on that folder will be parsed following lexical
order. Files starting with a dot are ignored. Files on subfolders are ignored.
The %include option can be used recursively.
+New configuration files or directories cannot be added to already running Tor
+instance if **Sandbox** is enabled.
By default, an option on the command line overrides an option found in the
configuration file, and an option in a configuration file overrides one in
@@ -525,9 +534,9 @@ forward slash (/) in the configuration file and on the command line.
[[ExtendByEd25519ID]] **ExtendByEd25519ID** **0**|**1**|**auto**::
If this option is set to 1, we always try to include a relay's Ed25519 ID
- when telling the proceeding relay in a circuit to extend to it.
+ when telling the preceding relay in a circuit to extend to it.
If this option is set to 0, we never include Ed25519 IDs when extending
- circuits. If the option is set to "default", we obey a
+ circuits. If the option is set to "auto", we obey a
parameter in the consensus document. (Default: auto)
[[ExtORPort]] **ExtORPort** ['address'**:**]{empty}__port__|**auto**::
@@ -848,6 +857,10 @@ forward slash (/) in the configuration file and on the command line.
and **ORPort** are not allowed). Currently, if **Sandbox** is 1,
**ControlPort** command "GETINFO address" will not work. +
+
+ When using %include in the tor configuration files, reloading the tor
+ configuration is not supported after adding new configuration files or
+ directories. +
+ +
(Default: 0)
[[Schedulers]] **Schedulers** **KIST**|**KISTLite**|**Vanilla**::
@@ -1556,15 +1569,13 @@ The following options are useful only for clients (that is, if
X'F2' Onion Service Introduction Failed
- Client failed to introduce to the service meaning the descriptor
- was found but the service is not connected anymore to the
- introduction point. The service has likely changed its descriptor
- or is not running. (v3 only)
+ All introduction attempts failed either due to a combination of
+ NACK by the intro point or time out. (v3 only)
X'F3' Onion Service Rendezvous Failed
- Client failed to rendezvous with the service which means that the
- client is unable to finalize the connection. (v3 only)
+ Every rendezvous circuit has timed out and thus the client is
+ unable to rendezvous with the service. (v3 only)
X'F4' Onion Service Missing Client Authorization
@@ -1585,6 +1596,11 @@ The following options are useful only for clients (that is, if
error is returned: address checksum doesn't match, ed25519 public
key is invalid or the encoding is invalid. (v3 only)
+ X'F7' Onion Service Introduction Timed Out
+
+ Similar to X'F2' code but in this case, all introduction attempts
+ have failed due to a time out. (v3 only)
+
// Anchor only for formatting, not visible in the man page.
[[SocksPortFlagsMisc]]::
Flags are processed left to right. If flags conflict, the last flag on the
@@ -3714,14 +3730,15 @@ __DataDirectory__/**`hashed-fingerprint`**::
identity key. (That is, the hash of the hash of the identity key.)
__DataDirectory__/**`approved-routers`**::
- Only used by authoritative directory servers. This file lists the status
- and a fingerprint/pubkey. Each line lists a status and a fingerprint
- separated by whitespace. See your **fingerprint** file in the
- __DataDirectory__ for an example fingerprint line. If the status is
- **!reject** then descriptors from the given identity (fingerprint/pubkey)
- are rejected by this server. If it is **!invalid** then descriptors are
- accepted but marked in the directory as not valid, that is, not
- recommended.
+ Only used by authoritative directory servers. Each line lists a status and
+ an identity, separated by whitespace. Identities can be hex-encoded RSA
+ fingerprints, or base-64 encoded ed25519 public keys. See the
+ **fingerprint** file in a tor relay's __DataDirectory__ for an example
+ fingerprint line. If the status is **!reject**, then descriptors from the
+ given identity are rejected by this server. If it is **!invalid** then
+ descriptors are accepted, but marked in the directory as not valid, that
+ is, not recommended. In either case, the corresponding relays are not
+ included in the consensus.
__DataDirectory__/**`v3-status-votes`**::
Only for v3 authoritative directory servers. This file contains status
diff --git a/scripts/maint/format_changelog.py b/scripts/maint/format_changelog.py
index 7cf55a0d96..b37ece04c0 100755
--- a/scripts/maint/format_changelog.py
+++ b/scripts/maint/format_changelog.py
@@ -291,7 +291,7 @@ class ChangeLog(object):
self.curgraf.append(line)
else:
- assert "This" is "unreachable" # noqa: F632
+ assert False # This should be unreachable.
def lint_head(self, line, head):
m = re.match(r'^ *o ([^\(]+)((?:\([^\)]+\))?):', head)
diff --git a/scripts/maint/practracker/exceptions.txt b/scripts/maint/practracker/exceptions.txt
index f41a8f4c81..fc9a05c84f 100644
--- a/scripts/maint/practracker/exceptions.txt
+++ b/scripts/maint/practracker/exceptions.txt
@@ -33,20 +33,20 @@
#
# Remember: It is better to fix the problem than to add a new exception!
-problem file-size /src/app/config/config.c 7527
+problem file-size /src/app/config/config.c 7525
problem include-count /src/app/config/config.c 80
problem function-size /src/app/config/config.c:options_act() 381
-problem function-size /src/app/config/config.c:resolve_my_address() 191
problem function-size /src/app/config/config.c:options_validate_cb() 794
-problem function-size /src/app/config/config.c:options_init_from_torrc() 188
+problem function-size /src/app/config/config.c:options_init_from_torrc() 192
problem function-size /src/app/config/config.c:options_init_from_string() 103
problem function-size /src/app/config/config.c:options_init_logs() 125
problem function-size /src/app/config/config.c:parse_bridge_line() 104
problem function-size /src/app/config/config.c:pt_parse_transport_line() 190
problem function-size /src/app/config/config.c:parse_dir_authority_line() 150
problem function-size /src/app/config/config.c:parse_dir_fallback_line() 101
-problem function-size /src/app/config/config.c:port_parse_config() 450
+problem function-size /src/app/config/config.c:port_parse_config() 435
problem function-size /src/app/config/config.c:parse_ports() 132
+problem function-size /src/app/config/resolve_addr.c:resolve_my_address() 191
problem file-size /src/app/config/or_options_st.h 1050
problem include-count /src/app/main/main.c 68
problem function-size /src/app/main/main.c:dumpstats() 102
@@ -60,15 +60,15 @@ problem dependency-violation /src/core/crypto/onion_crypto.c 5
problem dependency-violation /src/core/crypto/onion_fast.c 1
problem dependency-violation /src/core/crypto/onion_tap.c 3
problem dependency-violation /src/core/crypto/relay_crypto.c 9
-problem file-size /src/core/mainloop/connection.c 5680
+problem file-size /src/core/mainloop/connection.c 5700
problem include-count /src/core/mainloop/connection.c 65
problem function-size /src/core/mainloop/connection.c:connection_free_minimal() 181
-problem function-size /src/core/mainloop/connection.c:connection_listener_new() 324
+problem function-size /src/core/mainloop/connection.c:connection_listener_new() 325
problem function-size /src/core/mainloop/connection.c:connection_handle_listener_read() 161
problem function-size /src/core/mainloop/connection.c:connection_read_proxy_handshake() 153
problem function-size /src/core/mainloop/connection.c:retry_listener_ports() 112
problem function-size /src/core/mainloop/connection.c:connection_handle_read_impl() 111
-problem function-size /src/core/mainloop/connection.c:connection_buf_read_from_socket() 180
+problem function-size /src/core/mainloop/connection.c:connection_buf_read_from_socket() 186
problem function-size /src/core/mainloop/connection.c:connection_handle_write_impl() 241
problem function-size /src/core/mainloop/connection.c:assert_connection_ok() 143
problem dependency-violation /src/core/mainloop/connection.c 47
@@ -83,9 +83,9 @@ problem dependency-violation /src/core/mainloop/netstatus.c 4
problem dependency-violation /src/core/mainloop/periodic.c 2
problem dependency-violation /src/core/or/address_set.c 1
problem dependency-violation /src/core/or/cell_queue_st.h 1
-problem file-size /src/core/or/channel.c 3464
+problem file-size /src/core/or/channel.c 3500
problem dependency-violation /src/core/or/channel.c 9
-problem file-size /src/core/or/channel.h 775
+problem file-size /src/core/or/channel.h 800
problem dependency-violation /src/core/or/channel.h 1
problem dependency-violation /src/core/or/channelpadding.c 6
problem function-size /src/core/or/channeltls.c:channel_tls_handle_var_cell() 160
@@ -94,9 +94,8 @@ problem function-size /src/core/or/channeltls.c:channel_tls_process_netinfo_cell
problem function-size /src/core/or/channeltls.c:channel_tls_process_certs_cell() 246
problem function-size /src/core/or/channeltls.c:channel_tls_process_authenticate_cell() 202
problem dependency-violation /src/core/or/channeltls.c 11
-problem include-count /src/core/or/circuitbuild.c 54
+problem include-count /src/core/or/circuitbuild.c 53
problem function-size /src/core/or/circuitbuild.c:get_unique_circ_id_by_chan() 128
-problem function-size /src/core/or/circuitbuild.c:circuit_extend() 147
problem function-size /src/core/or/circuitbuild.c:choose_good_exit_server_general() 206
problem dependency-violation /src/core/or/circuitbuild.c 25
problem include-count /src/core/or/circuitlist.c 55
@@ -129,7 +128,7 @@ problem function-size /src/core/or/circuituse.c:connection_ap_handshake_attach_c
problem dependency-violation /src/core/or/circuituse.c 24
problem function-size /src/core/or/command.c:command_process_create_cell() 156
problem function-size /src/core/or/command.c:command_process_relay_cell() 132
-problem dependency-violation /src/core/or/command.c 8
+problem dependency-violation /src/core/or/command.c 9
problem file-size /src/core/or/connection_edge.c 4655
problem include-count /src/core/or/connection_edge.c 65
problem function-size /src/core/or/connection_edge.c:connection_ap_expire_beginning() 117
@@ -147,7 +146,7 @@ problem function-size /src/core/or/connection_or.c:connection_or_client_learned_
problem dependency-violation /src/core/or/connection_or.c 21
problem dependency-violation /src/core/or/dos.c 6
problem dependency-violation /src/core/or/onion.c 2
-problem file-size /src/core/or/or.h 1107
+problem file-size /src/core/or/or.h 1105
problem include-count /src/core/or/or.h 48
problem dependency-violation /src/core/or/or.h 1
problem dependency-violation /src/core/or/or_periodic.c 1
@@ -156,7 +155,7 @@ problem function-size /src/core/or/policies.c:policy_summarize() 107
problem dependency-violation /src/core/or/policies.c 14
problem function-size /src/core/or/protover.c:protover_all_supported() 117
problem dependency-violation /src/core/or/reasons.c 2
-problem file-size /src/core/or/relay.c 3264
+problem file-size /src/core/or/relay.c 3300
problem function-size /src/core/or/relay.c:circuit_receive_relay_cell() 127
problem function-size /src/core/or/relay.c:relay_send_command_from_edge_() 109
problem function-size /src/core/or/relay.c:connection_ap_process_end_not_open() 192
@@ -164,7 +163,7 @@ problem function-size /src/core/or/relay.c:connection_edge_process_relay_cell_no
problem function-size /src/core/or/relay.c:handle_relay_cell_command() 369
problem function-size /src/core/or/relay.c:connection_edge_package_raw_inbuf() 128
problem function-size /src/core/or/relay.c:circuit_resume_edge_reading_helper() 146
-problem dependency-violation /src/core/or/relay.c 16
+problem dependency-violation /src/core/or/relay.c 17
problem dependency-violation /src/core/or/scheduler.c 1
problem function-size /src/core/or/scheduler_kist.c:kist_scheduler_run() 171
problem dependency-violation /src/core/or/scheduler_kist.c 2
@@ -243,13 +242,11 @@ problem function-size /src/feature/hs/hs_cell.c:hs_cell_build_establish_intro()
problem function-size /src/feature/hs/hs_cell.c:hs_cell_parse_introduce2() 134
problem function-size /src/feature/hs/hs_client.c:send_introduce1() 108
problem function-size /src/feature/hs/hs_common.c:hs_get_responsible_hsdirs() 102
-problem function-size /src/feature/hs/hs_config.c:config_service_v3() 128
-problem function-size /src/feature/hs/hs_config.c:config_generic_service() 138
problem function-size /src/feature/hs/hs_descriptor.c:decrypt_desc_layer() 111
problem function-size /src/feature/hs/hs_descriptor.c:decode_introduction_point() 122
problem function-size /src/feature/hs/hs_descriptor.c:desc_decode_superencrypted_v3() 107
problem function-size /src/feature/hs/hs_descriptor.c:desc_decode_encrypted_v3() 109
-problem file-size /src/feature/hs/hs_service.c 4247
+problem file-size /src/feature/hs/hs_service.c 4300
problem function-size /src/feature/keymgt/loadkey.c:ed_key_init_from_file() 326
problem function-size /src/feature/nodelist/authcert.c:trusted_dirs_load_certs_from_string() 123
problem function-size /src/feature/nodelist/authcert.c:authority_certs_fetch_missing() 295
@@ -285,9 +282,9 @@ problem function-size /src/feature/rend/rendcommon.c:rend_encode_v2_descriptors(
problem function-size /src/feature/rend/rendmid.c:rend_mid_establish_intro_legacy() 105
problem function-size /src/feature/rend/rendparse.c:rend_parse_v2_service_descriptor() 181
problem function-size /src/feature/rend/rendparse.c:rend_parse_introduction_points() 129
-problem file-size /src/feature/rend/rendservice.c 4522
+problem file-size /src/feature/rend/rendservice.c 4504
problem function-size /src/feature/rend/rendservice.c:rend_service_prune_list_impl_() 107
-problem function-size /src/feature/rend/rendservice.c:rend_config_service() 162
+problem function-size /src/feature/rend/rendservice.c:rend_config_service() 143
problem function-size /src/feature/rend/rendservice.c:rend_service_load_auth_keys() 178
problem function-size /src/feature/rend/rendservice.c:rend_service_receive_introduction() 334
problem function-size /src/feature/rend/rendservice.c:rend_service_parse_intro_for_v3() 111
@@ -308,7 +305,7 @@ problem function-size /src/lib/encoding/confline.c:parse_config_line_from_str_ve
problem function-size /src/lib/encoding/cstring.c:unescape_string() 108
problem function-size /src/lib/fs/dir.c:check_private_dir() 230
problem function-size /src/lib/math/prob_distr.c:sample_uniform_interval() 145
-problem function-size /src/lib/net/address.c:tor_addr_parse_mask_ports() 194
+problem function-size /src/lib/net/address.c:tor_addr_parse_mask_ports() 195
problem function-size /src/lib/net/address.c:tor_addr_compare_masked() 110
problem function-size /src/lib/net/inaddr.c:tor_inet_pton() 107
problem function-size /src/lib/net/socketpair.c:tor_ersatz_socketpair() 102
diff --git a/scripts/maint/practracker/includes.py b/scripts/maint/practracker/includes.py
index e9b02c35b0..a5ee728824 100755
--- a/scripts/maint/practracker/includes.py
+++ b/scripts/maint/practracker/includes.py
@@ -59,6 +59,8 @@ ALLOWED_PATTERNS = [
re.compile(r'^micro-revision.i$'),
]
+TOPDIR = "src"
+
def pattern_is_normal(s):
for p in ALLOWED_PATTERNS:
if p.match(s):
@@ -136,6 +138,29 @@ class Rules(object):
return allowed
+
+def normalize_srcdir(fname):
+ """given the name of a source directory or file, return its name
+ relative to `src` in a unix-like format.
+ """
+ orig = fname
+ dirname, dirfile = os.path.split(fname)
+ if re.match(r'.*\.[ch]$', dirfile):
+ fname = dirname
+
+ # Now we have a directory.
+ dirname, result = os.path.split(fname)
+ for _ in range(100):
+ # prevent excess looping in case I missed a tricky case
+ dirname, dirpart = os.path.split(dirname)
+ if dirpart == 'src' or dirname == "":
+ #print(orig,"=>",result)
+ return result
+ result = "{}/{}".format(dirpart,result)
+
+ print("No progress!")
+ assert False
+
include_rules_cache = {}
def load_include_rules(fname):
@@ -173,6 +198,27 @@ def remove_self_edges(graph):
for k in list(graph):
graph[k] = [ d for d in graph[k] if d != k ]
+def closure(graph):
+ """Takes a directed graph in as an adjacency mapping (a mapping from
+ node to a list of the nodes to which it connects), and completes
+ its closure.
+ """
+ graph = graph.copy()
+ changed = False
+ for k in graph.keys():
+ graph[k] = set(graph[k])
+ while True:
+ for k in graph.keys():
+ sz = len(graph[k])
+ for v in list(graph[k]):
+ graph[k].update(graph.get(v, []))
+ if sz != len(graph[k]):
+ changed = True
+
+ if not changed:
+ return graph
+ changed = False
+
def toposort(graph, limit=100):
"""Takes a directed graph in as an adjacency mapping (a mapping from
node to a list of the nodes to which it connects). Tries to
@@ -233,8 +279,38 @@ def walk_c_files(topdir="src"):
for err in consider_include_rules(fullpath, f):
yield err
+def open_or_stdin(fname):
+ if fname == '-':
+ return sys.stdin
+ else:
+ return open(fname)
+
+def check_subsys_file(fname, uses_dirs):
+ if not uses_dirs:
+ # We're doing a distcheck build, or for some other reason there are
+ # no .may_include files.
+ print("SKIPPING")
+ return False
+
+ uses_dirs = { normalize_srcdir(k) : { normalize_srcdir(d) for d in v }
+ for (k,v) in uses_dirs.items() }
+ uses_closure = closure(uses_dirs)
+ ok = True
+ previous_subsystems = []
+
+ with open_or_stdin(fname) as f:
+ for line in f:
+ _, name, fname = line.split()
+ fname = normalize_srcdir(fname)
+ for prev in previous_subsystems:
+ if fname in uses_closure[prev]:
+ print("INVERSION: {} uses {}".format(prev,fname))
+ ok = False
+ previous_subsystems.append(fname)
+ return not ok
+
def run_check_includes(topdir, list_unused=False, log_sorted_levels=False,
- list_advisories=False):
+ list_advisories=False, check_subsystem_order=None):
trouble = False
for err in walk_c_files(topdir):
@@ -259,6 +335,11 @@ def run_check_includes(topdir, list_unused=False, log_sorted_levels=False,
uses_dirs[rules.incpath] = rules.getAllowedDirectories()
remove_self_edges(uses_dirs)
+
+ if check_subsystem_order:
+ if check_subsys_file(check_subsystem_order, uses_dirs):
+ sys.exit(1)
+
all_levels = toposort(uses_dirs)
if log_sorted_levels:
@@ -282,14 +363,19 @@ def main(argv):
help="List unused lines in .may_include files.")
parser.add_argument("--list-advisories", action="store_true",
help="List advisories as well as forbidden includes")
+ parser.add_argument("--check-subsystem-order", action="store",
+ help="Check a list of subsystems for ordering")
parser.add_argument("topdir", default="src", nargs="?",
help="Top-level directory for the tor source")
args = parser.parse_args(argv[1:])
+ global TOPDIR
+ TOPDIR = args.topdir
run_check_includes(topdir=args.topdir,
log_sorted_levels=args.toposort,
list_unused=args.list_unused,
- list_advisories=args.list_advisories)
+ list_advisories=args.list_advisories,
+ check_subsystem_order=args.check_subsystem_order)
if __name__ == '__main__':
main(sys.argv)
diff --git a/scripts/maint/rectify_include_paths.py b/scripts/maint/rectify_include_paths.py
index c6c5026711..6c7b252535 100755
--- a/scripts/maint/rectify_include_paths.py
+++ b/scripts/maint/rectify_include_paths.py
@@ -29,6 +29,12 @@ def get_include_map():
exclude(["ext", "win32"], dirnames)
for fname in fnames:
+ # Avoid editor temporary files
+ if fname.startswith("."):
+ continue
+ if fname.startswith("#"):
+ continue
+
if fname.endswith(".h"):
if fname in includes:
warn("Multiple headers named %s"%fname)
@@ -63,6 +69,12 @@ for dirpath,dirnames,fnames in os.walk("src"):
exclude(["trunnel"], dirnames)
for fname in fnames:
+ # Avoid editor temporary files
+ if fname.startswith("."):
+ continue
+ if fname.startswith("#"):
+ continue
+
if fname.endswith(".c") or fname.endswith(".h"):
fname = os.path.join(dirpath, fname)
tmpfile = fname+".tmp"
diff --git a/scripts/maint/rename_c_identifier.py b/scripts/maint/rename_c_identifier.py
index 6e0c1d8cf1..77802e10f3 100755
--- a/scripts/maint/rename_c_identifier.py
+++ b/scripts/maint/rename_c_identifier.py
@@ -44,7 +44,8 @@ def is_c_file(fn):
False
"""
fn = os.path.split(fn)[1]
- if fn.startswith("."):
+ # Avoid editor temporary files
+ if fn.startswith(".") or fn.startswith("#"):
return False
ext = os.path.splitext(fn)[1]
return ext in {".c", ".h", ".i", ".inc"}
diff --git a/scripts/maint/run_check_subsystem_order.sh b/scripts/maint/run_check_subsystem_order.sh
new file mode 100755
index 0000000000..4ec73bfd56
--- /dev/null
+++ b/scripts/maint/run_check_subsystem_order.sh
@@ -0,0 +1,17 @@
+#!/usr/bin/env bash
+
+set -e
+
+TOR="${abs_top_builddir:-.}/src/app/tor"
+
+INCLUDES_PY="${abs_top_srcdir:-.}/scripts/maint/practracker/includes.py"
+
+if ! test -x "${INCLUDES_PY}" ; then
+ echo "skip"
+ exit 77
+fi
+
+"${TOR}" --dbg-dump-subsystem-list | \
+ "${INCLUDES_PY}" --check-subsystem-order - "${abs_top_srcdir}/src"
+
+echo ok
diff --git a/src/app/config/config.c b/src/app/config/config.c
index 4becae4756..71f8c18ca2 100644
--- a/src/app/config/config.c
+++ b/src/app/config/config.c
@@ -2498,6 +2498,9 @@ static const struct {
.command=CMD_IMMEDIATE },
{ .name="--nt-service" },
{ .name="-nt-service" },
+ { .name="--dbg-dump-subsystem-list",
+ .command=CMD_IMMEDIATE,
+ .quiet=QUIET_HUSH },
{ .name=NULL },
};
@@ -2719,23 +2722,6 @@ list_enabled_modules(void)
// test variants in test_parseconf.sh to no useful purpose.
}
-/** Last value actually set by resolve_my_address. */
-static uint32_t last_resolved_addr = 0;
-
-/** Accessor for last_resolved_addr from outside this file. */
-uint32_t
-get_last_resolved_addr(void)
-{
- return last_resolved_addr;
-}
-
-/** Reset last_resolved_addr from outside this file. */
-void
-reset_last_resolved_addr(void)
-{
- last_resolved_addr = 0;
-}
-
/* Return true if <b>options</b> is using the default authorities, and false
* if any authority-related option has been overridden. */
int
@@ -2744,278 +2730,6 @@ using_default_dir_authorities(const or_options_t *options)
return (!options->DirAuthorities && !options->AlternateDirAuthority);
}
-/**
- * Attempt getting our non-local (as judged by tor_addr_is_internal()
- * function) IP address using following techniques, listed in
- * order from best (most desirable, try first) to worst (least
- * desirable, try if everything else fails).
- *
- * First, attempt using <b>options-\>Address</b> to get our
- * non-local IP address.
- *
- * If <b>options-\>Address</b> represents a non-local IP address,
- * consider it ours.
- *
- * If <b>options-\>Address</b> is a DNS name that resolves to
- * a non-local IP address, consider this IP address ours.
- *
- * If <b>options-\>Address</b> is NULL, fall back to getting local
- * hostname and using it in above-described ways to try and
- * get our IP address.
- *
- * In case local hostname cannot be resolved to a non-local IP
- * address, try getting an IP address of network interface
- * in hopes it will be non-local one.
- *
- * Fail if one or more of the following is true:
- * - DNS name in <b>options-\>Address</b> cannot be resolved.
- * - <b>options-\>Address</b> is a local host address.
- * - Attempt at getting local hostname fails.
- * - Attempt at getting network interface address fails.
- *
- * Return 0 if all is well, or -1 if we can't find a suitable
- * public IP address.
- *
- * If we are returning 0:
- * - Put our public IP address (in host order) into *<b>addr_out</b>.
- * - If <b>method_out</b> is non-NULL, set *<b>method_out</b> to a static
- * string describing how we arrived at our answer.
- * - "CONFIGURED" - parsed from IP address string in
- * <b>options-\>Address</b>
- * - "RESOLVED" - resolved from DNS name in <b>options-\>Address</b>
- * - "GETHOSTNAME" - resolved from a local hostname.
- * - "INTERFACE" - retrieved from a network interface.
- * - If <b>hostname_out</b> is non-NULL, and we resolved a hostname to
- * get our address, set *<b>hostname_out</b> to a newly allocated string
- * holding that hostname. (If we didn't get our address by resolving a
- * hostname, set *<b>hostname_out</b> to NULL.)
- *
- * XXXX ipv6
- */
-int
-resolve_my_address(int warn_severity, const or_options_t *options,
- uint32_t *addr_out,
- const char **method_out, char **hostname_out)
-{
- struct in_addr in;
- uint32_t addr; /* host order */
- char hostname[256];
- const char *method_used;
- const char *hostname_used;
- int explicit_ip=1;
- int explicit_hostname=1;
- int from_interface=0;
- char *addr_string = NULL;
- const char *address = options->Address;
- int notice_severity = warn_severity <= LOG_NOTICE ?
- LOG_NOTICE : warn_severity;
-
- tor_addr_t myaddr;
- tor_assert(addr_out);
-
- /*
- * Step one: Fill in 'hostname' to be our best guess.
- */
-
- if (address && *address) {
- strlcpy(hostname, address, sizeof(hostname));
- } else { /* then we need to guess our address */
- explicit_ip = 0; /* it's implicit */
- explicit_hostname = 0; /* it's implicit */
-
- if (tor_gethostname(hostname, sizeof(hostname)) < 0) {
- log_fn(warn_severity, LD_NET,"Error obtaining local hostname");
- return -1;
- }
- log_debug(LD_CONFIG, "Guessed local host name as '%s'", hostname);
- }
-
- /*
- * Step two: Now that we know 'hostname', parse it or resolve it. If
- * it doesn't parse or resolve, look at the interface address. Set 'addr'
- * to be our (host-order) 32-bit answer.
- */
-
- if (tor_inet_aton(hostname, &in) == 0) {
- /* then we have to resolve it */
- explicit_ip = 0;
- if (tor_lookup_hostname(hostname, &addr)) { /* failed to resolve */
- uint32_t interface_ip; /* host order */
-
- if (explicit_hostname) {
- log_fn(warn_severity, LD_CONFIG,
- "Could not resolve local Address '%s'. Failing.", hostname);
- return -1;
- }
- log_fn(notice_severity, LD_CONFIG,
- "Could not resolve guessed local hostname '%s'. "
- "Trying something else.", hostname);
- if (get_interface_address(warn_severity, &interface_ip)) {
- log_fn(warn_severity, LD_CONFIG,
- "Could not get local interface IP address. Failing.");
- return -1;
- }
- from_interface = 1;
- addr = interface_ip;
- log_fn(notice_severity, LD_CONFIG, "Learned IP address '%s' for "
- "local interface. Using that.", fmt_addr32(addr));
- strlcpy(hostname, "<guessed from interfaces>", sizeof(hostname));
- } else { /* resolved hostname into addr */
- tor_addr_from_ipv4h(&myaddr, addr);
-
- if (!explicit_hostname &&
- tor_addr_is_internal(&myaddr, 0)) {
- tor_addr_t interface_ip;
-
- log_fn(notice_severity, LD_CONFIG, "Guessed local hostname '%s' "
- "resolves to a private IP address (%s). Trying something "
- "else.", hostname, fmt_addr32(addr));
-
- if (get_interface_address6(warn_severity, AF_INET, &interface_ip)<0) {
- log_fn(warn_severity, LD_CONFIG,
- "Could not get local interface IP address. Too bad.");
- } else if (tor_addr_is_internal(&interface_ip, 0)) {
- log_fn(notice_severity, LD_CONFIG,
- "Interface IP address '%s' is a private address too. "
- "Ignoring.", fmt_addr(&interface_ip));
- } else {
- from_interface = 1;
- addr = tor_addr_to_ipv4h(&interface_ip);
- log_fn(notice_severity, LD_CONFIG,
- "Learned IP address '%s' for local interface."
- " Using that.", fmt_addr32(addr));
- strlcpy(hostname, "<guessed from interfaces>", sizeof(hostname));
- }
- }
- }
- } else {
- addr = ntohl(in.s_addr); /* set addr so that addr_string is not
- * illformed */
- }
-
- /*
- * Step three: Check whether 'addr' is an internal IP address, and error
- * out if it is and we don't want that.
- */
-
- tor_addr_from_ipv4h(&myaddr,addr);
-
- addr_string = tor_dup_ip(addr);
- if (tor_addr_is_internal(&myaddr, 0)) {
- /* make sure we're ok with publishing an internal IP */
- if (using_default_dir_authorities(options)) {
- /* if they are using the default authorities, disallow internal IPs
- * always. For IPv6 ORPorts, this check is done in
- * router_get_advertised_ipv6_or_ap(). See #33681. */
- log_fn(warn_severity, LD_CONFIG,
- "Address '%s' resolves to private IP address '%s'. "
- "Tor servers that use the default DirAuthorities must have "
- "public IP addresses.", hostname, addr_string);
- tor_free(addr_string);
- return -1;
- }
- if (!explicit_ip) {
- /* even if they've set their own authorities, require an explicit IP if
- * they're using an internal address. */
- log_fn(warn_severity, LD_CONFIG, "Address '%s' resolves to private "
- "IP address '%s'. Please set the Address config option to be "
- "the IP address you want to use.", hostname, addr_string);
- tor_free(addr_string);
- return -1;
- }
- }
-
- /*
- * Step four: We have a winner! 'addr' is our answer for sure, and
- * 'addr_string' is its string form. Fill out the various fields to
- * say how we decided it.
- */
-
- log_debug(LD_CONFIG, "Resolved Address to '%s'.", addr_string);
-
- if (explicit_ip) {
- method_used = "CONFIGURED";
- hostname_used = NULL;
- } else if (explicit_hostname) {
- method_used = "RESOLVED";
- hostname_used = hostname;
- } else if (from_interface) {
- method_used = "INTERFACE";
- hostname_used = NULL;
- } else {
- method_used = "GETHOSTNAME";
- hostname_used = hostname;
- }
-
- *addr_out = addr;
- if (method_out)
- *method_out = method_used;
- if (hostname_out)
- *hostname_out = hostname_used ? tor_strdup(hostname_used) : NULL;
-
- /*
- * Step five: Check if the answer has changed since last time (or if
- * there was no last time), and if so call various functions to keep
- * us up-to-date.
- */
-
- if (last_resolved_addr && last_resolved_addr != *addr_out) {
- /* Leave this as a notice, regardless of the requested severity,
- * at least until dynamic IP address support becomes bulletproof. */
- log_notice(LD_NET,
- "Your IP address seems to have changed to %s "
- "(METHOD=%s%s%s). Updating.",
- addr_string, method_used,
- hostname_used ? " HOSTNAME=" : "",
- hostname_used ? hostname_used : "");
- ip_address_changed(0);
- }
-
- if (last_resolved_addr != *addr_out) {
- control_event_server_status(LOG_NOTICE,
- "EXTERNAL_ADDRESS ADDRESS=%s METHOD=%s%s%s",
- addr_string, method_used,
- hostname_used ? " HOSTNAME=" : "",
- hostname_used ? hostname_used : "");
- }
- last_resolved_addr = *addr_out;
-
- /*
- * And finally, clean up and return success.
- */
-
- tor_free(addr_string);
- return 0;
-}
-
-/** Return true iff <b>addr</b> is judged to be on the same network as us, or
- * on a private network.
- */
-MOCK_IMPL(int,
-is_local_addr, (const tor_addr_t *addr))
-{
- if (tor_addr_is_internal(addr, 0))
- return 1;
- /* Check whether ip is on the same /24 as we are. */
- if (get_options()->EnforceDistinctSubnets == 0)
- return 0;
- if (tor_addr_family(addr) == AF_INET) {
- uint32_t ip = tor_addr_to_ipv4h(addr);
-
- /* It's possible that this next check will hit before the first time
- * resolve_my_address actually succeeds. (For clients, it is likely that
- * resolve_my_address will never be called at all). In those cases,
- * last_resolved_addr will be 0, and so checking to see whether ip is on
- * the same /24 as last_resolved_addr will be the same as checking whether
- * it was on net 0, which is already done by tor_addr_is_internal.
- */
- if ((last_resolved_addr & (uint32_t)0xffffff00ul)
- == (ip & (uint32_t)0xffffff00ul))
- return 1;
- }
- return 0;
-}
-
/** Return a new empty or_options_t. Used for testing. */
or_options_t *
options_new(void)
@@ -4604,6 +4318,10 @@ options_init_from_torrc(int argc, char **argv)
list_deprecated_options();
return 1;
}
+ if (config_line_find(cmdline_only_options, "--dbg-dump-subsystem-list")) {
+ subsystems_dump_list();
+ return 1;
+ }
if (config_line_find(cmdline_only_options, "--version")) {
printf("Tor version %s.\n",get_version());
@@ -6441,7 +6159,7 @@ port_parse_config(smartlist_t *out,
portname);
goto err;
}
- if ( has_used_unix_socket_only_option && ! unix_socket_path) {
+ if (has_used_unix_socket_only_option && !unix_socket_path) {
log_warn(LD_CONFIG, "You have a %sPort entry with GroupWritable, "
"WorldWritable, or RelaxDirModeCheck, but it is not a "
"unix socket.", portname);
diff --git a/src/app/config/config.h b/src/app/config/config.h
index 311e27917a..17caa0e3ff 100644
--- a/src/app/config/config.h
+++ b/src/app/config/config.h
@@ -42,6 +42,8 @@ const char *escaped_safe_str(const char *address);
void init_protocol_warning_severity_level(void);
int get_protocol_warning_severity_level(void);
+#define LOG_PROTOCOL_WARN (get_protocol_warning_severity_level())
+
/** An error from options_trial_assign() or options_init_from_string(). */
typedef enum setopt_err_t {
SETOPT_OK = 0,
@@ -53,12 +55,6 @@ typedef enum setopt_err_t {
setopt_err_t options_trial_assign(struct config_line_t *list, unsigned flags,
char **msg);
-uint32_t get_last_resolved_addr(void);
-void reset_last_resolved_addr(void);
-int resolve_my_address(int warn_severity, const or_options_t *options,
- uint32_t *addr_out,
- const char **method_out, char **hostname_out);
-MOCK_DECL(int, is_local_addr, (const tor_addr_t *addr));
void options_init(or_options_t *options);
#define OPTIONS_DUMP_MINIMAL 1
diff --git a/src/app/config/include.am b/src/app/config/include.am
index 5d625efecf..14320a6b11 100644
--- a/src/app/config/include.am
+++ b/src/app/config/include.am
@@ -3,6 +3,7 @@
LIBTOR_APP_A_SOURCES += \
src/app/config/config.c \
src/app/config/quiet_level.c \
+ src/app/config/resolve_addr.c \
src/app/config/statefile.c
# ADD_C_FILE: INSERT HEADERS HERE.
@@ -11,6 +12,7 @@ noinst_HEADERS += \
src/app/config/or_options_st.h \
src/app/config/or_state_st.h \
src/app/config/quiet_level.h \
+ src/app/config/resolve_addr.h \
src/app/config/statefile.h \
src/app/config/tor_cmdline_mode.h
diff --git a/src/app/config/quiet_level.c b/src/app/config/quiet_level.c
index 4e17978228..e04faaef3a 100644
--- a/src/app/config/quiet_level.c
+++ b/src/app/config/quiet_level.c
@@ -31,7 +31,7 @@ add_default_log_for_quiet_level(quiet_level_t quiet)
/* --hush: log at warning or higher. */
add_default_log(LOG_WARN);
break;
- case QUIET_NONE: /* fall through */
+ case QUIET_NONE: FALLTHROUGH;
default:
add_default_log(LOG_NOTICE);
}
diff --git a/src/app/config/resolve_addr.c b/src/app/config/resolve_addr.c
new file mode 100644
index 0000000000..b551615c02
--- /dev/null
+++ b/src/app/config/resolve_addr.c
@@ -0,0 +1,308 @@
+/* Copyright (c) 2020, The Tor Project, Inc. */
+/* See LICENSE for licensing information */
+
+/**
+ * \file resolve_addr.c
+ * \brief Implement resolving address functions
+ **/
+
+#define RESOLVE_ADDR_PRIVATE
+
+#include "app/config/config.h"
+#include "app/config/resolve_addr.h"
+
+#include "core/mainloop/mainloop.h"
+
+#include "feature/control/control_events.h"
+
+#include "lib/net/gethostname.h"
+#include "lib/net/resolve.h"
+
+/** Last value actually set by resolve_my_address. */
+static uint32_t last_resolved_addr = 0;
+
+/** Accessor for last_resolved_addr from outside this file. */
+uint32_t
+get_last_resolved_addr(void)
+{
+ return last_resolved_addr;
+}
+
+/** Reset last_resolved_addr from outside this file. */
+void
+reset_last_resolved_addr(void)
+{
+ last_resolved_addr = 0;
+}
+
+/**
+ * Attempt getting our non-local (as judged by tor_addr_is_internal()
+ * function) IP address using following techniques, listed in
+ * order from best (most desirable, try first) to worst (least
+ * desirable, try if everything else fails).
+ *
+ * First, attempt using <b>options-\>Address</b> to get our
+ * non-local IP address.
+ *
+ * If <b>options-\>Address</b> represents a non-local IP address,
+ * consider it ours.
+ *
+ * If <b>options-\>Address</b> is a DNS name that resolves to
+ * a non-local IP address, consider this IP address ours.
+ *
+ * If <b>options-\>Address</b> is NULL, fall back to getting local
+ * hostname and using it in above-described ways to try and
+ * get our IP address.
+ *
+ * In case local hostname cannot be resolved to a non-local IP
+ * address, try getting an IP address of network interface
+ * in hopes it will be non-local one.
+ *
+ * Fail if one or more of the following is true:
+ * - DNS name in <b>options-\>Address</b> cannot be resolved.
+ * - <b>options-\>Address</b> is a local host address.
+ * - Attempt at getting local hostname fails.
+ * - Attempt at getting network interface address fails.
+ *
+ * Return 0 if all is well, or -1 if we can't find a suitable
+ * public IP address.
+ *
+ * If we are returning 0:
+ * - Put our public IP address (in host order) into *<b>addr_out</b>.
+ * - If <b>method_out</b> is non-NULL, set *<b>method_out</b> to a static
+ * string describing how we arrived at our answer.
+ * - "CONFIGURED" - parsed from IP address string in
+ * <b>options-\>Address</b>
+ * - "RESOLVED" - resolved from DNS name in <b>options-\>Address</b>
+ * - "GETHOSTNAME" - resolved from a local hostname.
+ * - "INTERFACE" - retrieved from a network interface.
+ * - If <b>hostname_out</b> is non-NULL, and we resolved a hostname to
+ * get our address, set *<b>hostname_out</b> to a newly allocated string
+ * holding that hostname. (If we didn't get our address by resolving a
+ * hostname, set *<b>hostname_out</b> to NULL.)
+ *
+ * XXXX ipv6
+ */
+int
+resolve_my_address(int warn_severity, const or_options_t *options,
+ uint32_t *addr_out,
+ const char **method_out, char **hostname_out)
+{
+ struct in_addr in;
+ uint32_t addr; /* host order */
+ char hostname[256];
+ const char *method_used;
+ const char *hostname_used;
+ int explicit_ip=1;
+ int explicit_hostname=1;
+ int from_interface=0;
+ char *addr_string = NULL;
+ const char *address = options->Address;
+ int notice_severity = warn_severity <= LOG_NOTICE ?
+ LOG_NOTICE : warn_severity;
+
+ tor_addr_t myaddr;
+ tor_assert(addr_out);
+
+ /*
+ * Step one: Fill in 'hostname' to be our best guess.
+ */
+
+ if (address && *address) {
+ strlcpy(hostname, address, sizeof(hostname));
+ } else { /* then we need to guess our address */
+ explicit_ip = 0; /* it's implicit */
+ explicit_hostname = 0; /* it's implicit */
+
+ if (tor_gethostname(hostname, sizeof(hostname)) < 0) {
+ log_fn(warn_severity, LD_NET,"Error obtaining local hostname");
+ return -1;
+ }
+ log_debug(LD_CONFIG, "Guessed local host name as '%s'", hostname);
+ }
+
+ /*
+ * Step two: Now that we know 'hostname', parse it or resolve it. If
+ * it doesn't parse or resolve, look at the interface address. Set 'addr'
+ * to be our (host-order) 32-bit answer.
+ */
+
+ if (tor_inet_aton(hostname, &in) == 0) {
+ /* then we have to resolve it */
+ explicit_ip = 0;
+ if (tor_lookup_hostname(hostname, &addr)) { /* failed to resolve */
+ uint32_t interface_ip; /* host order */
+
+ if (explicit_hostname) {
+ log_fn(warn_severity, LD_CONFIG,
+ "Could not resolve local Address '%s'. Failing.", hostname);
+ return -1;
+ }
+ log_fn(notice_severity, LD_CONFIG,
+ "Could not resolve guessed local hostname '%s'. "
+ "Trying something else.", hostname);
+ if (get_interface_address(warn_severity, &interface_ip)) {
+ log_fn(warn_severity, LD_CONFIG,
+ "Could not get local interface IP address. Failing.");
+ return -1;
+ }
+ from_interface = 1;
+ addr = interface_ip;
+ log_fn(notice_severity, LD_CONFIG, "Learned IP address '%s' for "
+ "local interface. Using that.", fmt_addr32(addr));
+ strlcpy(hostname, "<guessed from interfaces>", sizeof(hostname));
+ } else { /* resolved hostname into addr */
+ tor_addr_from_ipv4h(&myaddr, addr);
+
+ if (!explicit_hostname &&
+ tor_addr_is_internal(&myaddr, 0)) {
+ tor_addr_t interface_ip;
+
+ log_fn(notice_severity, LD_CONFIG, "Guessed local hostname '%s' "
+ "resolves to a private IP address (%s). Trying something "
+ "else.", hostname, fmt_addr32(addr));
+
+ if (get_interface_address6(warn_severity, AF_INET, &interface_ip)<0) {
+ log_fn(warn_severity, LD_CONFIG,
+ "Could not get local interface IP address. Too bad.");
+ } else if (tor_addr_is_internal(&interface_ip, 0)) {
+ log_fn(notice_severity, LD_CONFIG,
+ "Interface IP address '%s' is a private address too. "
+ "Ignoring.", fmt_addr(&interface_ip));
+ } else {
+ from_interface = 1;
+ addr = tor_addr_to_ipv4h(&interface_ip);
+ log_fn(notice_severity, LD_CONFIG,
+ "Learned IP address '%s' for local interface."
+ " Using that.", fmt_addr32(addr));
+ strlcpy(hostname, "<guessed from interfaces>", sizeof(hostname));
+ }
+ }
+ }
+ } else {
+ addr = ntohl(in.s_addr); /* set addr so that addr_string is not
+ * illformed */
+ }
+
+ /*
+ * Step three: Check whether 'addr' is an internal IP address, and error
+ * out if it is and we don't want that.
+ */
+
+ tor_addr_from_ipv4h(&myaddr,addr);
+
+ addr_string = tor_dup_ip(addr);
+ if (tor_addr_is_internal(&myaddr, 0)) {
+ /* make sure we're ok with publishing an internal IP */
+ if (using_default_dir_authorities(options)) {
+ /* if they are using the default authorities, disallow internal IPs
+ * always. For IPv6 ORPorts, this check is done in
+ * router_get_advertised_ipv6_or_ap(). See #33681. */
+ log_fn(warn_severity, LD_CONFIG,
+ "Address '%s' resolves to private IP address '%s'. "
+ "Tor servers that use the default DirAuthorities must have "
+ "public IP addresses.", hostname, addr_string);
+ tor_free(addr_string);
+ return -1;
+ }
+ if (!explicit_ip) {
+ /* even if they've set their own authorities, require an explicit IP if
+ * they're using an internal address. */
+ log_fn(warn_severity, LD_CONFIG, "Address '%s' resolves to private "
+ "IP address '%s'. Please set the Address config option to be "
+ "the IP address you want to use.", hostname, addr_string);
+ tor_free(addr_string);
+ return -1;
+ }
+ }
+
+ /*
+ * Step four: We have a winner! 'addr' is our answer for sure, and
+ * 'addr_string' is its string form. Fill out the various fields to
+ * say how we decided it.
+ */
+
+ log_debug(LD_CONFIG, "Resolved Address to '%s'.", addr_string);
+
+ if (explicit_ip) {
+ method_used = "CONFIGURED";
+ hostname_used = NULL;
+ } else if (explicit_hostname) {
+ method_used = "RESOLVED";
+ hostname_used = hostname;
+ } else if (from_interface) {
+ method_used = "INTERFACE";
+ hostname_used = NULL;
+ } else {
+ method_used = "GETHOSTNAME";
+ hostname_used = hostname;
+ }
+
+ *addr_out = addr;
+ if (method_out)
+ *method_out = method_used;
+ if (hostname_out)
+ *hostname_out = hostname_used ? tor_strdup(hostname_used) : NULL;
+
+ /*
+ * Step five: Check if the answer has changed since last time (or if
+ * there was no last time), and if so call various functions to keep
+ * us up-to-date.
+ */
+
+ if (last_resolved_addr && last_resolved_addr != *addr_out) {
+ /* Leave this as a notice, regardless of the requested severity,
+ * at least until dynamic IP address support becomes bulletproof. */
+ log_notice(LD_NET,
+ "Your IP address seems to have changed to %s "
+ "(METHOD=%s%s%s). Updating.",
+ addr_string, method_used,
+ hostname_used ? " HOSTNAME=" : "",
+ hostname_used ? hostname_used : "");
+ ip_address_changed(0);
+ }
+
+ if (last_resolved_addr != *addr_out) {
+ control_event_server_status(LOG_NOTICE,
+ "EXTERNAL_ADDRESS ADDRESS=%s METHOD=%s%s%s",
+ addr_string, method_used,
+ hostname_used ? " HOSTNAME=" : "",
+ hostname_used ? hostname_used : "");
+ }
+ last_resolved_addr = *addr_out;
+
+ /*
+ * And finally, clean up and return success.
+ */
+
+ tor_free(addr_string);
+ return 0;
+}
+
+/** Return true iff <b>addr</b> is judged to be on the same network as us, or
+ * on a private network.
+ */
+MOCK_IMPL(int,
+is_local_addr, (const tor_addr_t *addr))
+{
+ if (tor_addr_is_internal(addr, 0))
+ return 1;
+ /* Check whether ip is on the same /24 as we are. */
+ if (get_options()->EnforceDistinctSubnets == 0)
+ return 0;
+ if (tor_addr_family(addr) == AF_INET) {
+ uint32_t ip = tor_addr_to_ipv4h(addr);
+
+ /* It's possible that this next check will hit before the first time
+ * resolve_my_address actually succeeds. (For clients, it is likely that
+ * resolve_my_address will never be called at all). In those cases,
+ * last_resolved_addr will be 0, and so checking to see whether ip is on
+ * the same /24 as last_resolved_addr will be the same as checking whether
+ * it was on net 0, which is already done by tor_addr_is_internal.
+ */
+ if ((last_resolved_addr & (uint32_t)0xffffff00ul)
+ == (ip & (uint32_t)0xffffff00ul))
+ return 1;
+ }
+ return 0;
+}
diff --git a/src/app/config/resolve_addr.h b/src/app/config/resolve_addr.h
new file mode 100644
index 0000000000..3747546402
--- /dev/null
+++ b/src/app/config/resolve_addr.h
@@ -0,0 +1,28 @@
+/* Copyright (c) 2020, The Tor Project, Inc. */
+/* See LICENSE for licensing information */
+
+/**
+ * \file resolve_addr.h
+ * \brief Header file for resolve_addr.c.
+ **/
+
+#ifndef TOR_CONFIG_RESOLVE_ADDR_H
+#define TOR_CONFIG_RESOLVE_ADDR_H
+
+#include "app/config/or_options_st.h"
+
+int resolve_my_address(int warn_severity, const or_options_t *options,
+ uint32_t *addr_out,
+ const char **method_out, char **hostname_out);
+
+uint32_t get_last_resolved_addr(void);
+void reset_last_resolved_addr(void);
+
+MOCK_DECL(int, is_local_addr, (const tor_addr_t *addr));
+
+#ifdef RESOLVE_ADDR_PRIVATE
+
+#endif /* RESOLVE_ADDR_PRIVATE */
+
+#endif /* TOR_CONFIG_RESOLVE_ADDR_H */
+
diff --git a/src/app/main/subsysmgr.c b/src/app/main/subsysmgr.c
index 5807cbbaa4..de601d28cd 100644
--- a/src/app/main/subsysmgr.c
+++ b/src/app/main/subsysmgr.c
@@ -294,6 +294,20 @@ subsystems_thread_cleanup(void)
}
/**
+ * Dump a human- and machine-readable list of all the subsystems to stdout,
+ * in their initialization order, prefixed with their level.
+ **/
+void
+subsystems_dump_list(void)
+{
+ for (unsigned i = 0; i < n_tor_subsystems - 1; ++i) {
+ const subsys_fns_t *sys = tor_subsystems[i];
+ printf("% 4d\t%16s\t%s\n", sys->level, sys->name,
+ sys->location?sys->location:"");
+ }
+}
+
+/**
* Register all subsystem-declared options formats in <b>mgr</b>.
*
* Return 0 on success, -1 on failure.
diff --git a/src/app/main/subsysmgr.h b/src/app/main/subsysmgr.h
index 35635a756e..ae0b3df469 100644
--- a/src/app/main/subsysmgr.h
+++ b/src/app/main/subsysmgr.h
@@ -31,6 +31,8 @@ void subsystems_prefork(void);
void subsystems_postfork(void);
void subsystems_thread_cleanup(void);
+void subsystems_dump_list(void);
+
struct config_mgr_t;
int subsystems_register_options_formats(struct config_mgr_t *mgr);
int subsystems_register_state_formats(struct config_mgr_t *mgr);
diff --git a/src/core/mainloop/connection.c b/src/core/mainloop/connection.c
index 9602978458..a8417e46d9 100644
--- a/src/core/mainloop/connection.c
+++ b/src/core/mainloop/connection.c
@@ -67,6 +67,7 @@
*/
#define CHANNEL_OBJECT_PRIVATE
#include "app/config/config.h"
+#include "app/config/resolve_addr.h"
#include "core/mainloop/connection.h"
#include "core/mainloop/mainloop.h"
#include "core/mainloop/netstatus.h"
@@ -3814,6 +3815,12 @@ connection_buf_read_from_socket(connection_t *conn, ssize_t *max_to_read,
at_most = connection_bucket_read_limit(conn, approx_time());
}
+ /* Do not allow inbuf to grow past BUF_MAX_LEN. */
+ const ssize_t maximum = BUF_MAX_LEN - buf_datalen(conn->inbuf);
+ if (at_most > maximum) {
+ at_most = maximum;
+ }
+
slack_in_buf = buf_slack(conn->inbuf);
again:
if ((size_t)at_most > slack_in_buf && slack_in_buf >= 1024) {
diff --git a/src/core/mainloop/cpuworker.c b/src/core/mainloop/cpuworker.c
index abd48f886c..485ddb9741 100644
--- a/src/core/mainloop/cpuworker.c
+++ b/src/core/mainloop/cpuworker.c
@@ -19,7 +19,6 @@
**/
#include "core/or/or.h"
#include "core/or/channel.h"
-#include "core/or/circuitbuild.h"
#include "core/or/circuitlist.h"
#include "core/or/connection_or.h"
#include "app/config/config.h"
@@ -27,6 +26,7 @@
#include "lib/crypt_ops/crypto_rand.h"
#include "lib/crypt_ops/crypto_util.h"
#include "core/or/onion.h"
+#include "feature/relay/circuitbuild_relay.h"
#include "feature/relay/onion_queue.h"
#include "feature/stats/rephist.h"
#include "feature/relay/router.h"
diff --git a/src/core/mainloop/mainloop_sys.c b/src/core/mainloop/mainloop_sys.c
index 4b78c90b96..884bae1c59 100644
--- a/src/core/mainloop/mainloop_sys.c
+++ b/src/core/mainloop/mainloop_sys.c
@@ -78,6 +78,7 @@ mainloop_flush_state(void *arg)
const struct subsys_fns_t sys_mainloop = {
.name = "mainloop",
+ SUBSYS_DECLARE_LOCATION(),
.supported = true,
.level = 5,
.initialize = subsys_mainloop_initialize,
diff --git a/src/core/or/channel.c b/src/core/or/channel.c
index 160ab587f5..a05554472f 100644
--- a/src/core/or/channel.c
+++ b/src/core/or/channel.c
@@ -1,4 +1,3 @@
-
/* * Copyright (c) 2012-2020, The Tor Project, Inc. */
/* See LICENSE for licensing information */
@@ -84,6 +83,13 @@
#include "core/or/cell_queue_st.h"
+/* Static function prototypes */
+
+static bool channel_matches_target_addr_for_extend(
+ channel_t *chan,
+ const tor_addr_t *target_ipv4_addr,
+ const tor_addr_t *target_ipv6_addr);
+
/* Global lists of channels */
/* All channel_t instances */
@@ -2335,7 +2341,7 @@ channel_is_better(channel_t *a, channel_t *b)
if (!a->is_canonical_to_peer && b->is_canonical_to_peer) return 0;
/*
- * Okay, if we're here they tied on canonicity, the prefer the older
+ * Okay, if we're here they tied on canonicity. Prefer the older
* connection, so that the adversary can't create a new connection
* and try to switch us over to it (which will leak information
* about long-lived circuits). Additionally, switching connections
@@ -2360,19 +2366,23 @@ channel_is_better(channel_t *a, channel_t *b)
/**
* Get a channel to extend a circuit.
*
- * Pick a suitable channel to extend a circuit to given the desired digest
- * the address we believe is correct for that digest; this tries to see
- * if we already have one for the requested endpoint, but if there is no good
- * channel, set *msg_out to a message describing the channel's state
- * and our next action, and set *launch_out to a boolean indicated whether
- * the caller should try to launch a new channel with channel_connect().
+ * Given the desired relay identity, pick a suitable channel to extend a
+ * circuit to the target IPv4 or IPv6 address requsted by the client. Search
+ * for an existing channel for the requested endpoint. Make sure the channel
+ * is usable for new circuits, and matches one of the target addresses.
+ *
+ * Try to return the best channel. But if there is no good channel, set
+ * *msg_out to a message describing the channel's state and our next action,
+ * and set *launch_out to a boolean indicated whether the caller should try to
+ * launch a new channel with channel_connect().
*/
-channel_t *
-channel_get_for_extend(const char *rsa_id_digest,
- const ed25519_public_key_t *ed_id,
- const tor_addr_t *target_addr,
- const char **msg_out,
- int *launch_out)
+MOCK_IMPL(channel_t *,
+channel_get_for_extend,(const char *rsa_id_digest,
+ const ed25519_public_key_t *ed_id,
+ const tor_addr_t *target_ipv4_addr,
+ const tor_addr_t *target_ipv6_addr,
+ const char **msg_out,
+ int *launch_out))
{
channel_t *chan, *best = NULL;
int n_inprogress_goodaddr = 0, n_old = 0;
@@ -2383,9 +2393,7 @@ channel_get_for_extend(const char *rsa_id_digest,
chan = channel_find_by_remote_identity(rsa_id_digest, ed_id);
- /* Walk the list, unrefing the old one and refing the new at each
- * iteration.
- */
+ /* Walk the list of channels */
for (; chan; chan = channel_next_with_rsa_identity(chan)) {
tor_assert(tor_memeq(chan->identity_digest,
rsa_id_digest, DIGEST_LEN));
@@ -2404,11 +2412,15 @@ channel_get_for_extend(const char *rsa_id_digest,
continue;
}
+ const bool matches_target =
+ channel_matches_target_addr_for_extend(chan,
+ target_ipv4_addr,
+ target_ipv6_addr);
/* Never return a non-open connection. */
if (!CHANNEL_IS_OPEN(chan)) {
/* If the address matches, don't launch a new connection for this
* circuit. */
- if (channel_matches_target_addr_for_extend(chan, target_addr))
+ if (matches_target)
++n_inprogress_goodaddr;
continue;
}
@@ -2419,22 +2431,21 @@ 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.
+ /* If the connection is using a recent link protocol, only return canonical
+ * connections, when the address is one of the addresses 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
+ * if we should trust channel_is_canonical(). It only applies when
* the lower-layer transport is channel_tls_t.
*
- * (For old link protocols, we can't rely on is_canonical getting
+ * 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.)
+ * tell us about the right address.
*/
if (!channel_is_canonical(chan) &&
channel_is_canonical_is_reliable(chan) &&
- !channel_matches_target_addr_for_extend(chan, target_addr)) {
+ !matches_target) {
++n_noncanonical;
continue;
}
@@ -2820,8 +2831,8 @@ channel_get_actual_remote_address(channel_t *chan)
* Subsequent calls to channel_get_{actual,canonical}_remote_{address,descr}
* may invalidate the return value from this function.
*/
-const char *
-channel_get_canonical_remote_descr(channel_t *chan)
+MOCK_IMPL(const char *,
+channel_get_canonical_remote_descr,(channel_t *chan))
{
tor_assert(chan);
tor_assert(chan->get_remote_descr);
@@ -3297,20 +3308,33 @@ channel_matches_extend_info(channel_t *chan, extend_info_t *extend_info)
}
/**
- * Check if a channel matches a given target address; return true iff we do.
+ * Check if a channel matches the given target IPv4 or IPv6 addresses.
+ * If either address matches, return true. If neither address matches,
+ * return false.
+ *
+ * Both addresses can't be NULL.
*
* This function calls into the lower layer and asks if this channel thinks
- * it matches a given target address for circuit extension purposes.
+ * it matches the target addresses for circuit extension purposes.
*/
-int
+static bool
channel_matches_target_addr_for_extend(channel_t *chan,
- const tor_addr_t *target)
+ const tor_addr_t *target_ipv4_addr,
+ const tor_addr_t *target_ipv6_addr)
{
tor_assert(chan);
tor_assert(chan->matches_target);
- tor_assert(target);
- return chan->matches_target(chan, target);
+ IF_BUG_ONCE(!target_ipv4_addr && !target_ipv6_addr)
+ return false;
+
+ if (target_ipv4_addr && chan->matches_target(chan, target_ipv4_addr))
+ return true;
+
+ if (target_ipv6_addr && chan->matches_target(chan, target_ipv6_addr))
+ return true;
+
+ return false;
}
/**
diff --git a/src/core/or/channel.h b/src/core/or/channel.h
index 2e2936a69a..4968c8714a 100644
--- a/src/core/or/channel.h
+++ b/src/core/or/channel.h
@@ -658,11 +658,13 @@ channel_t * channel_connect(const tor_addr_t *addr, uint16_t port,
const char *rsa_id_digest,
const struct ed25519_public_key_t *ed_id);
-channel_t * channel_get_for_extend(const char *rsa_id_digest,
+MOCK_DECL(channel_t *, channel_get_for_extend,(
+ const char *rsa_id_digest,
const struct ed25519_public_key_t *ed_id,
- const tor_addr_t *target_addr,
+ const tor_addr_t *target_ipv4_addr,
+ const tor_addr_t *target_ipv6_addr,
const char **msg_out,
- int *launch_out);
+ int *launch_out));
/* Ask which of two channels is better for circuit-extension purposes */
int channel_is_better(channel_t *a, channel_t *b);
@@ -723,7 +725,7 @@ const char * channel_get_actual_remote_descr(channel_t *chan);
const char * channel_get_actual_remote_address(channel_t *chan);
MOCK_DECL(int, channel_get_addr_if_possible, (channel_t *chan,
tor_addr_t *addr_out));
-const char * channel_get_canonical_remote_descr(channel_t *chan);
+MOCK_DECL(const char *, channel_get_canonical_remote_descr,(channel_t *chan));
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);
@@ -736,8 +738,6 @@ 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_matches_target_addr_for_extend(channel_t *chan,
- const tor_addr_t *target);
unsigned int channel_num_circuits(channel_t *chan);
MOCK_DECL(void,channel_set_circid_type,(channel_t *chan,
crypto_pk_t *identity_rcvd,
diff --git a/src/core/or/channeltls.c b/src/core/or/channeltls.c
index 2a35237d30..395fbf3455 100644
--- a/src/core/or/channeltls.c
+++ b/src/core/or/channeltls.c
@@ -45,6 +45,7 @@
#include "core/or/circuitmux_ewma.h"
#include "core/or/command.h"
#include "app/config/config.h"
+#include "app/config/resolve_addr.h"
#include "core/mainloop/connection.h"
#include "core/or/connection_or.h"
#include "feature/relay/relay_handshake.h"
@@ -564,9 +565,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)
{
-#define MAX_DESCR_LEN 32
-
- static char buf[MAX_DESCR_LEN + 1];
+ static char buf[TOR_ADDRPORT_BUF_LEN];
channel_tls_t *tlschan = BASE_CHAN_TO_TLS(chan);
connection_t *conn;
const char *answer = NULL;
@@ -579,15 +578,14 @@ channel_tls_get_remote_descr_method(channel_t *chan, int flags)
switch (flags) {
case 0:
/* Canonical address with port*/
- tor_snprintf(buf, MAX_DESCR_LEN + 1,
+ tor_snprintf(buf, TOR_ADDRPORT_BUF_LEN,
"%s:%u", conn->address, conn->port);
answer = buf;
break;
case GRD_FLAG_ORIGINAL:
/* Actual address with port */
addr_str = tor_addr_to_str_dup(&(tlschan->conn->real_addr));
- tor_snprintf(buf, MAX_DESCR_LEN + 1,
- "%s:%u", addr_str, conn->port);
+ tor_snprintf(buf, TOR_ADDRPORT_BUF_LEN, "%s:%u", addr_str, conn->port);
tor_free(addr_str);
answer = buf;
break;
@@ -738,10 +736,13 @@ channel_tls_matches_target_method(channel_t *chan,
* base_.addr is updated by connection_or_init_conn_from_address()
* to be the address in the descriptor. It may be tempting to
* allow either address to be allowed, but if we did so, it would
- * enable someone who steals a relay's keys to impersonate/MITM it
+ * enable someone who steals a relay's keys to covertly impersonate/MITM it
* from anywhere on the Internet! (Because they could make long-lived
* TLS connections from anywhere to all relays, and wait for them to
* be used for extends).
+ *
+ * An adversary who has stolen a relay's keys could also post a fake relay
+ * descriptor, but that attack is easier to detect.
*/
return tor_addr_eq(&(tlschan->conn->real_addr), target);
}
@@ -1238,7 +1239,7 @@ channel_tls_handle_var_cell(var_cell_t *var_cell, or_connection_t *conn)
/* But that should be happening any longer've disabled bufferevents. */
tor_assert_nonfatal_unreached_once();
- /* fall through */
+ FALLTHROUGH;
case OR_CONN_STATE_TLS_SERVER_RENEGOTIATING:
if (!(command_allowed_before_handshake(var_cell->command))) {
log_fn(LOG_PROTOCOL_WARN, LD_PROTOCOL,
@@ -1665,7 +1666,7 @@ tor_addr_from_netinfo_addr(tor_addr_t *tor_addr,
} else if (type == NETINFO_ADDR_TYPE_IPV6 && len == 16) {
const uint8_t *ipv6_bytes = netinfo_addr_getconstarray_addr_ipv6(
netinfo_addr);
- tor_addr_from_ipv6_bytes(tor_addr, (const char *)ipv6_bytes);
+ tor_addr_from_ipv6_bytes(tor_addr, ipv6_bytes);
} else {
log_fn(LOG_PROTOCOL_WARN, LD_OR, "Cannot read address from NETINFO "
"- wrong type/length.");
diff --git a/src/core/or/circuitbuild.c b/src/core/or/circuitbuild.c
index 003b91af8d..83ce9f882b 100644
--- a/src/core/or/circuitbuild.c
+++ b/src/core/or/circuitbuild.c
@@ -21,8 +21,7 @@
* cells arrive, the client will invoke circuit_send_next_onion_skin() to send
* CREATE or RELAY_EXTEND cells.
*
- * On the server side, this module also handles the logic of responding to
- * RELAY_EXTEND requests, using circuit_extend().
+ * The server side is handled in feature/relay/circuitbuild_relay.c.
**/
#define CIRCUITBUILD_PRIVATE
@@ -35,7 +34,6 @@
#include "core/crypto/onion_crypto.h"
#include "core/crypto/onion_fast.h"
#include "core/crypto/onion_tap.h"
-#include "core/crypto/relay_crypto.h"
#include "core/mainloop/connection.h"
#include "core/mainloop/mainloop.h"
#include "core/or/channel.h"
@@ -84,13 +82,6 @@
#include "feature/nodelist/routerinfo_st.h"
#include "feature/nodelist/routerstatus_st.h"
-static channel_t * channel_connect_for_circuit(const tor_addr_t *addr,
- uint16_t port,
- const char *id_digest,
- const ed25519_public_key_t *ed_id);
-static int circuit_deliver_create_cell(circuit_t *circ,
- const create_cell_t *create_cell,
- int relayed);
static int circuit_send_first_onion_skin(origin_circuit_t *circ);
static int circuit_build_no_more_hops(origin_circuit_t *circ);
static int circuit_send_intermediate_onion_skin(origin_circuit_t *circ,
@@ -104,10 +95,10 @@ static const node_t *choose_good_middle_server(uint8_t purpose,
* and then calls command_setup_channel() to give it the right
* callbacks.
*/
-static channel_t *
-channel_connect_for_circuit(const tor_addr_t *addr, uint16_t port,
- const char *id_digest,
- const ed25519_public_key_t *ed_id)
+MOCK_IMPL(channel_t *,
+channel_connect_for_circuit,(const tor_addr_t *addr, uint16_t port,
+ const char *id_digest,
+ const struct ed25519_public_key_t *ed_id))
{
channel_t *chan;
@@ -568,11 +559,17 @@ circuit_handle_first_hop(origin_circuit_t *circ)
fmt_addrport(&firsthop->extend_info->addr,
firsthop->extend_info->port));
- n_chan = channel_get_for_extend(firsthop->extend_info->identity_digest,
- &firsthop->extend_info->ed_identity,
- &firsthop->extend_info->addr,
- &msg,
- &should_launch);
+ /* We'll cleanup this code in #33220, when we add an IPv6 address to
+ * extend_info_t. */
+ const bool addr_is_ipv4 =
+ (tor_addr_family(&firsthop->extend_info->addr) == AF_INET);
+ n_chan = channel_get_for_extend(
+ firsthop->extend_info->identity_digest,
+ &firsthop->extend_info->ed_identity,
+ addr_is_ipv4 ? &firsthop->extend_info->addr : NULL,
+ addr_is_ipv4 ? NULL : &firsthop->extend_info->addr,
+ &msg,
+ &should_launch);
if (!n_chan) {
/* not currently connected in a useful way. */
@@ -707,9 +704,10 @@ circuit_n_chan_done(channel_t *chan, int status, int close_origin_circuits)
* gave us via an EXTEND cell, so we shouldn't worry if we don't understand
* it. Return -1 if we failed to find a suitable circid, else return 0.
*/
-static int
-circuit_deliver_create_cell(circuit_t *circ, const create_cell_t *create_cell,
- int relayed)
+MOCK_IMPL(int,
+circuit_deliver_create_cell,(circuit_t *circ,
+ const struct create_cell_t *create_cell,
+ int relayed))
{
cell_t cell;
circid_t id;
@@ -767,40 +765,6 @@ circuit_deliver_create_cell(circuit_t *circ, const create_cell_t *create_cell,
return -1;
}
-/** We've decided to start our reachability testing. If all
- * is set, log this to the user. Return 1 if we did, or 0 if
- * we chose not to log anything. */
-int
-inform_testing_reachability(void)
-{
- char dirbuf[128];
- char *address;
- const routerinfo_t *me = router_get_my_routerinfo();
- if (!me)
- return 0;
- address = tor_dup_ip(me->addr);
- control_event_server_status(LOG_NOTICE,
- "CHECKING_REACHABILITY ORADDRESS=%s:%d",
- address, me->or_port);
- if (me->dir_port) {
- tor_snprintf(dirbuf, sizeof(dirbuf), " and DirPort %s:%d",
- address, me->dir_port);
- control_event_server_status(LOG_NOTICE,
- "CHECKING_REACHABILITY DIRADDRESS=%s:%d",
- address, me->dir_port);
- }
- log_notice(LD_OR, "Now checking whether ORPort %s:%d%s %s reachable... "
- "(this may take up to %d minutes -- look for log "
- "messages indicating success)",
- address, me->or_port,
- me->dir_port ? dirbuf : "",
- me->dir_port ? "are" : "is",
- TIMEOUT_UNTIL_UNREACHABILITY_COMPLAINT/60);
-
- tor_free(address);
- return 1;
-}
-
/** Return true iff we should send a create_fast cell to start building a given
* circuit */
static inline int
@@ -1200,164 +1164,6 @@ circuit_note_clock_jumped(int64_t seconds_elapsed, bool was_idle)
}
}
-/** Take the 'extend' <b>cell</b>, pull out addr/port plus the onion
- * skin and identity digest for the next hop. If we're already connected,
- * pass the onion skin to the next hop using a create cell; otherwise
- * launch a new OR connection, and <b>circ</b> will notice when the
- * connection succeeds or fails.
- *
- * Return -1 if we want to warn and tear down the circuit, else return 0.
- */
-int
-circuit_extend(cell_t *cell, circuit_t *circ)
-{
- channel_t *n_chan;
- relay_header_t rh;
- extend_cell_t ec;
- const char *msg = NULL;
- int should_launch = 0;
-
- if (circ->n_chan) {
- log_fn(LOG_PROTOCOL_WARN, LD_PROTOCOL,
- "n_chan already set. Bug/attack. Closing.");
- return -1;
- }
- if (circ->n_hop) {
- log_fn(LOG_PROTOCOL_WARN, LD_PROTOCOL,
- "conn to next hop already launched. Bug/attack. Closing.");
- return -1;
- }
-
- if (!server_mode(get_options())) {
- log_fn(LOG_PROTOCOL_WARN, LD_PROTOCOL,
- "Got an extend cell, but running as a client. Closing.");
- return -1;
- }
-
- relay_header_unpack(&rh, cell->payload);
-
- if (extend_cell_parse(&ec, rh.command,
- cell->payload+RELAY_HEADER_SIZE,
- rh.length) < 0) {
- log_fn(LOG_PROTOCOL_WARN, LD_PROTOCOL,
- "Can't parse extend cell. Closing circuit.");
- return -1;
- }
-
- if (!ec.orport_ipv4.port || tor_addr_is_null(&ec.orport_ipv4.addr)) {
- log_fn(LOG_PROTOCOL_WARN, LD_PROTOCOL,
- "Client asked me to extend to zero destination port or addr.");
- return -1;
- }
-
- if (tor_addr_is_internal(&ec.orport_ipv4.addr, 0) &&
- !get_options()->ExtendAllowPrivateAddresses) {
- log_fn(LOG_PROTOCOL_WARN, LD_PROTOCOL,
- "Client asked me to extend to a private address");
- return -1;
- }
-
- /* Check if they asked us for 0000..0000. We support using
- * an empty fingerprint for the first hop (e.g. for a bridge relay),
- * but we don't want to let clients send us extend cells for empty
- * fingerprints -- a) because it opens the user up to a mitm attack,
- * and b) because it lets an attacker force the relay to hold open a
- * new TLS connection for each extend request. */
- if (tor_digest_is_zero((const char*)ec.node_id)) {
- log_fn(LOG_PROTOCOL_WARN, LD_PROTOCOL,
- "Client asked me to extend without specifying an id_digest.");
- return -1;
- }
-
- /* Fill in ed_pubkey if it was not provided and we can infer it from
- * our networkstatus */
- if (ed25519_public_key_is_zero(&ec.ed_pubkey)) {
- const node_t *node = node_get_by_id((const char*)ec.node_id);
- const ed25519_public_key_t *node_ed_id = NULL;
- if (node &&
- node_supports_ed25519_link_authentication(node, 1) &&
- (node_ed_id = node_get_ed25519_id(node))) {
- ed25519_pubkey_copy(&ec.ed_pubkey, node_ed_id);
- }
- }
-
- /* Next, check if we're being asked to connect to the hop that the
- * extend cell came from. There isn't any reason for that, and it can
- * assist circular-path attacks. */
- if (tor_memeq(ec.node_id,
- TO_OR_CIRCUIT(circ)->p_chan->identity_digest,
- DIGEST_LEN)) {
- log_fn(LOG_PROTOCOL_WARN, LD_PROTOCOL,
- "Client asked me to extend back to the previous hop.");
- return -1;
- }
-
- /* Check the previous hop Ed25519 ID too */
- if (! ed25519_public_key_is_zero(&ec.ed_pubkey) &&
- ed25519_pubkey_eq(&ec.ed_pubkey,
- &TO_OR_CIRCUIT(circ)->p_chan->ed25519_identity)) {
- log_fn(LOG_PROTOCOL_WARN, LD_PROTOCOL,
- "Client asked me to extend back to the previous hop "
- "(by Ed25519 ID).");
- return -1;
- }
-
- n_chan = channel_get_for_extend((const char*)ec.node_id,
- &ec.ed_pubkey,
- &ec.orport_ipv4.addr,
- &msg,
- &should_launch);
-
- if (!n_chan) {
- log_debug(LD_CIRC|LD_OR,"Next router (%s): %s",
- fmt_addrport(&ec.orport_ipv4.addr,ec.orport_ipv4.port),
- msg?msg:"????");
-
- circ->n_hop = extend_info_new(NULL /*nickname*/,
- (const char*)ec.node_id,
- &ec.ed_pubkey,
- NULL, /*onion_key*/
- NULL, /*curve25519_key*/
- &ec.orport_ipv4.addr,
- ec.orport_ipv4.port);
-
- circ->n_chan_create_cell = tor_memdup(&ec.create_cell,
- sizeof(ec.create_cell));
-
- circuit_set_state(circ, CIRCUIT_STATE_CHAN_WAIT);
-
- if (should_launch) {
- /* we should try to open a connection */
- n_chan = channel_connect_for_circuit(&ec.orport_ipv4.addr,
- ec.orport_ipv4.port,
- (const char*)ec.node_id,
- &ec.ed_pubkey);
- if (!n_chan) {
- log_info(LD_CIRC,"Launching n_chan failed. Closing circuit.");
- circuit_mark_for_close(circ, END_CIRC_REASON_CONNECTFAILED);
- return 0;
- }
- log_debug(LD_CIRC,"connecting in progress (or finished). Good.");
- }
- /* return success. The onion/circuit/etc will be taken care of
- * automatically (may already have been) whenever n_chan reaches
- * OR_CONN_STATE_OPEN.
- */
- return 0;
- }
-
- tor_assert(!circ->n_hop); /* Connection is already established. */
- circ->n_chan = n_chan;
- log_debug(LD_CIRC,
- "n_chan is %s",
- channel_get_canonical_remote_descr(n_chan));
-
- if (circuit_deliver_create_cell(circ, &ec.create_cell, 1) < 0)
- return -1;
-
- return 0;
-}
-
/** A "created" cell <b>reply</b> came back to us on circuit <b>circ</b>.
* (The body of <b>reply</b> varies depending on what sort of handshake
* this is.)
@@ -1467,61 +1273,6 @@ circuit_truncated(origin_circuit_t *circ, int reason)
#endif /* 0 */
}
-/** Given a response payload and keys, initialize, then send a created
- * cell back.
- */
-int
-onionskin_answer(or_circuit_t *circ,
- const created_cell_t *created_cell,
- const char *keys, size_t keys_len,
- const uint8_t *rend_circ_nonce)
-{
- cell_t cell;
-
- tor_assert(keys_len == CPATH_KEY_MATERIAL_LEN);
-
- if (created_cell_format(&cell, created_cell) < 0) {
- log_warn(LD_BUG,"couldn't format created cell (type=%d, len=%d)",
- (int)created_cell->cell_type, (int)created_cell->handshake_len);
- return -1;
- }
- cell.circ_id = circ->p_circ_id;
-
- 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 (relay_crypto_init(&circ->crypto, keys, keys_len, 0, 0)<0) {
- log_warn(LD_BUG,"Circuit initialization failed");
- return -1;
- }
-
- memcpy(circ->rend_circ_nonce, rend_circ_nonce, DIGEST_LEN);
-
- int used_create_fast = (created_cell->cell_type == CELL_CREATED_FAST);
-
- append_cell_to_circuit_queue(TO_CIRCUIT(circ),
- circ->p_chan, &cell, CELL_DIRECTION_IN, 0);
- log_debug(LD_CIRC,"Finished sending '%s' cell.",
- used_create_fast ? "created_fast" : "created");
-
- /* Ignore the local bit when ExtendAllowPrivateAddresses is set:
- * it violates the assumption that private addresses are local.
- * Also, many test networks run on local addresses, and
- * TestingTorNetwork sets ExtendAllowPrivateAddresses. */
- if ((!channel_is_local(circ->p_chan)
- || get_options()->ExtendAllowPrivateAddresses)
- && !channel_is_outgoing(circ->p_chan)) {
- /* record that we could process create cells from a non-local conn
- * that we didn't initiate; presumably this means that create cells
- * can reach us too. */
- router_orport_found_reachable();
- }
-
- return 0;
-}
-
/** Helper for new_route_len(). Choose a circuit length for purpose
* <b>purpose</b>: DEFAULT_ROUTE_LEN (+ 1 if someone else chose the
* exit). If someone else chose the exit, they could be colluding
@@ -2108,7 +1859,7 @@ choose_good_exit_server(origin_circuit_t *circ,
/* For these three, we want to pick the exit like a middle hop,
* since it should be random. */
tor_assert_nonfatal(is_internal);
- /* Falls through */
+ FALLTHROUGH;
case CIRCUIT_PURPOSE_C_GENERAL:
if (is_internal) /* pick it like a middle hop */
return router_choose_random_node(NULL, options->ExcludeNodes, flags);
diff --git a/src/core/or/circuitbuild.h b/src/core/or/circuitbuild.h
index 48592dd346..e62bb41de9 100644
--- a/src/core/or/circuitbuild.h
+++ b/src/core/or/circuitbuild.h
@@ -29,19 +29,13 @@ struct circuit_guard_state_t *origin_circuit_get_guard_state(
int circuit_handle_first_hop(origin_circuit_t *circ);
void circuit_n_chan_done(channel_t *chan, int status,
int close_origin_circuits);
-int inform_testing_reachability(void);
int circuit_timeout_want_to_count_circ(const origin_circuit_t *circ);
int circuit_send_next_onion_skin(origin_circuit_t *circ);
void circuit_note_clock_jumped(int64_t seconds_elapsed, bool was_idle);
-int circuit_extend(cell_t *cell, circuit_t *circ);
struct created_cell_t;
int circuit_finish_handshake(origin_circuit_t *circ,
const struct created_cell_t *created_cell);
int circuit_truncated(origin_circuit_t *circ, int reason);
-int onionskin_answer(or_circuit_t *circ,
- const struct created_cell_t *created_cell,
- const char *keys, size_t keys_len,
- const uint8_t *rend_circ_nonce);
MOCK_DECL(int, circuit_all_predicted_ports_handled, (time_t now,
int *need_uptime,
int *need_capacity));
@@ -77,6 +71,20 @@ const node_t *choose_good_entry_server(uint8_t purpose,
struct circuit_guard_state_t **guard_state_out);
void circuit_upgrade_circuits_from_guard_wait(void);
+struct ed25519_public_key_t;
+
+MOCK_DECL(channel_t *,
+channel_connect_for_circuit,(const tor_addr_t *addr,
+ uint16_t port,
+ const char *id_digest,
+ const struct ed25519_public_key_t *ed_id));
+
+struct create_cell_t;
+MOCK_DECL(int,
+circuit_deliver_create_cell,(circuit_t *circ,
+ const struct create_cell_t *create_cell,
+ int relayed));
+
#ifdef CIRCUITBUILD_PRIVATE
STATIC circid_t get_unique_circ_id_by_chan(channel_t *chan);
STATIC int new_route_len(uint8_t purpose, extend_info_t *exit_ei,
diff --git a/src/core/or/circuitlist.c b/src/core/or/circuitlist.c
index ca174c442c..4c37ef8b41 100644
--- a/src/core/or/circuitlist.c
+++ b/src/core/or/circuitlist.c
@@ -846,7 +846,7 @@ circuit_purpose_to_controller_hs_state_string(uint8_t purpose)
"Unrecognized circuit purpose: %d",
(int)purpose);
tor_fragile_assert();
- /* fall through */
+ FALLTHROUGH;
case CIRCUIT_PURPOSE_OR:
case CIRCUIT_PURPOSE_C_GENERAL:
diff --git a/src/core/or/circuituse.c b/src/core/or/circuituse.c
index 066d5d437a..e2c4df25d0 100644
--- a/src/core/or/circuituse.c
+++ b/src/core/or/circuituse.c
@@ -548,9 +548,10 @@ circuit_expire_building(void)
MAX(get_circuit_build_close_time_ms()*2 + 1000,
options->SocksTimeout * 1000));
+ bool fixed_time = circuit_build_times_disabled(get_options());
+
SMARTLIST_FOREACH_BEGIN(circuit_get_global_list(), circuit_t *,victim) {
struct timeval cutoff;
- bool fixed_time = circuit_build_times_disabled(get_options());
if (!CIRCUIT_IS_ORIGIN(victim) || /* didn't originate here */
victim->marked_for_close) /* don't mess with marked circs */
@@ -780,7 +781,7 @@ circuit_expire_building(void)
if (!hs_circ_is_rend_sent_in_intro1(CONST_TO_ORIGIN_CIRCUIT(victim))) {
break;
}
- /* fallthrough! */
+ FALLTHROUGH;
case CIRCUIT_PURPOSE_C_INTRODUCE_ACK_WAIT:
case CIRCUIT_PURPOSE_C_REND_READY_INTRO_ACKED:
/* If we have reached this line, we want to spare the circ for now. */
diff --git a/src/core/or/command.c b/src/core/or/command.c
index 9d946974bc..8a1d2066cc 100644
--- a/src/core/or/command.c
+++ b/src/core/or/command.c
@@ -54,6 +54,7 @@
#include "feature/nodelist/describe.h"
#include "feature/nodelist/nodelist.h"
#include "feature/nodelist/routerlist.h"
+#include "feature/relay/circuitbuild_relay.h"
#include "feature/relay/routermode.h"
#include "feature/stats/rephist.h"
#include "lib/crypt_ops/crypto_util.h"
diff --git a/src/core/or/connection_edge.c b/src/core/or/connection_edge.c
index 23c6e230cb..5c9bf64e8e 100644
--- a/src/core/or/connection_edge.c
+++ b/src/core/or/connection_edge.c
@@ -307,7 +307,7 @@ connection_edge_process_inbuf(edge_connection_t *conn, int package_partial)
note_user_activity(approx_time());
}
- /* falls through. */
+ FALLTHROUGH;
case EXIT_CONN_STATE_OPEN:
if (connection_edge_package_raw_inbuf(conn, package_partial, NULL) < 0) {
/* (We already sent an end cell if possible) */
@@ -332,7 +332,7 @@ connection_edge_process_inbuf(edge_connection_t *conn, int package_partial)
}
/* Fall through if the connection is on a circuit without optimistic
* data support. */
- /* Falls through. */
+ FALLTHROUGH;
case EXIT_CONN_STATE_CONNECTING:
case AP_CONN_STATE_RENDDESC_WAIT:
case AP_CONN_STATE_CIRCUIT_WAIT:
@@ -781,7 +781,7 @@ connection_edge_flushed_some(edge_connection_t *conn)
note_user_activity(approx_time());
}
- /* falls through. */
+ FALLTHROUGH;
case EXIT_CONN_STATE_OPEN:
sendme_connection_edge_consider_sending(conn);
break;
@@ -1658,9 +1658,11 @@ parse_extended_hostname(char *address, hostname_type_t *type_out)
failed:
/* otherwise, return to previous state and return 0 */
*s = '.';
+ const bool is_onion = (*type_out == ONION_V2_HOSTNAME) ||
+ (*type_out == ONION_V3_HOSTNAME);
log_warn(LD_APP, "Invalid %shostname %s; rejecting",
- (*type_out == (ONION_V2_HOSTNAME || ONION_V3_HOSTNAME) ? "onion " : ""),
- safe_str_client(address));
+ is_onion ? "onion " : "",
+ safe_str_client(address));
return false;
}
@@ -3531,7 +3533,7 @@ connection_ap_handshake_socks_resolved,(entry_connection_t *conn,
}
} else if (answer_type == RESOLVED_TYPE_IPV6 && answer_len == 16) {
tor_addr_t a;
- tor_addr_from_ipv6_bytes(&a, (char*)answer);
+ tor_addr_from_ipv6_bytes(&a, answer);
if (! tor_addr_is_null(&a)) {
client_dns_set_addressmap(conn,
conn->socks_request->address, &a,
diff --git a/src/core/or/connection_or.c b/src/core/or/connection_or.c
index 6b11f33232..5d71b363f8 100644
--- a/src/core/or/connection_or.c
+++ b/src/core/or/connection_or.c
@@ -18,7 +18,8 @@
* tortls.c) which it uses as its TLS stream. It is responsible for
* sending and receiving cells over that TLS.
*
- * This module also implements the client side of the v3 Tor link handshake,
+ * This module also implements the client side of the v3 (and greater) Tor
+ * link handshake.
**/
#include "core/or/or.h"
#include "feature/client/bridges.h"
@@ -660,6 +661,7 @@ connection_or_finished_flushing(or_connection_t *conn)
}
break;
}
+ break;
case OR_CONN_STATE_OPEN:
case OR_CONN_STATE_OR_HANDSHAKING_V2:
case OR_CONN_STATE_OR_HANDSHAKING_V3:
@@ -901,12 +903,21 @@ connection_or_check_canonicity(or_connection_t *conn, int started_here)
}
if (r) {
- tor_addr_port_t node_ap;
- node_get_pref_orport(r, &node_ap);
- /* XXXX proposal 186 is making this more complex. For now, a conn
- is canonical when it uses the _preferred_ address. */
- if (tor_addr_eq(&conn->base_.addr, &node_ap.addr))
+ tor_addr_port_t node_ipv4_ap;
+ tor_addr_port_t node_ipv6_ap;
+ node_get_prim_orport(r, &node_ipv4_ap);
+ node_get_pref_ipv6_orport(r, &node_ipv6_ap);
+ if (tor_addr_eq(&conn->base_.addr, &node_ipv4_ap.addr) ||
+ tor_addr_eq(&conn->base_.addr, &node_ipv6_ap.addr)) {
connection_or_set_canonical(conn, 1);
+ }
+ /* Choose the correct canonical address and port. */
+ tor_addr_port_t *node_ap;
+ if (tor_addr_family(&conn->base_.addr) == AF_INET) {
+ node_ap = &node_ipv4_ap;
+ } else {
+ node_ap = &node_ipv6_ap;
+ }
if (!started_here) {
/* Override the addr/port, so our log messages will make sense.
* This is dangerous, since if we ever try looking up a conn by
@@ -918,13 +929,14 @@ connection_or_check_canonicity(or_connection_t *conn, int started_here)
* right IP address and port 56244, that wouldn't be as helpful. now we
* log the "right" port too, so we know if it's moria1 or moria2.
*/
- tor_addr_copy(&conn->base_.addr, &node_ap.addr);
- conn->base_.port = node_ap.port;
+ /* See #33898 for a ticket that resolves this technical debt. */
+ tor_addr_copy(&conn->base_.addr, &node_ap->addr);
+ conn->base_.port = node_ap->port;
}
tor_free(conn->nickname);
conn->nickname = tor_strdup(node_get_nickname(r));
tor_free(conn->base_.address);
- conn->base_.address = tor_addr_to_str_dup(&node_ap.addr);
+ conn->base_.address = tor_addr_to_str_dup(&node_ap->addr);
} else {
tor_free(conn->nickname);
conn->nickname = tor_malloc(HEX_DIGEST_LEN+2);
diff --git a/src/core/or/connection_or.h b/src/core/or/connection_or.h
index 02bc87a864..e9ace56ab4 100644
--- a/src/core/or/connection_or.h
+++ b/src/core/or/connection_or.h
@@ -22,10 +22,6 @@ or_connection_t *TO_OR_CONN(connection_t *);
void connection_or_clear_identity(or_connection_t *conn);
void connection_or_clear_identity_map(void);
void clear_broken_connection_map(int disable);
-or_connection_t *connection_or_get_for_extend(const char *digest,
- const tor_addr_t *target_addr,
- const char **msg_out,
- int *launch_out);
void connection_or_block_renegotiation(or_connection_t *conn);
int connection_or_reached_eof(or_connection_t *conn);
diff --git a/src/core/or/crypt_path.c b/src/core/or/crypt_path.c
index 9296b00208..8f41540848 100644
--- a/src/core/or/crypt_path.c
+++ b/src/core/or/crypt_path.c
@@ -113,7 +113,7 @@ cpath_assert_layer_ok(const crypt_path_t *cp)
{
case CPATH_STATE_OPEN:
relay_crypto_assert_ok(&cp->pvt_crypto);
- /* fall through */
+ FALLTHROUGH;
case CPATH_STATE_CLOSED:
/*XXXX Assert that there's no handshake_state either. */
tor_assert(!cp->rend_dh_handshake_state);
diff --git a/src/core/or/onion.c b/src/core/or/onion.c
index 4a5b296b9e..a3b5c6922d 100644
--- a/src/core/or/onion.c
+++ b/src/core/or/onion.c
@@ -240,11 +240,21 @@ created_cell_parse(created_cell_t *cell_out, const cell_t *cell_in)
static int
check_extend_cell(const extend_cell_t *cell)
{
+ const bool is_extend2 = (cell->cell_type == RELAY_COMMAND_EXTEND2);
+
if (tor_digest_is_zero((const char*)cell->node_id))
return -1;
- /* We don't currently allow EXTEND2 cells without an IPv4 address */
- if (tor_addr_family(&cell->orport_ipv4.addr) == AF_UNSPEC)
- return -1;
+ if (!tor_addr_port_is_valid_ap(&cell->orport_ipv4, 0)) {
+ /* EXTEND cells must have an IPv4 address. */
+ if (!is_extend2) {
+ return -1;
+ }
+ /* EXTEND2 cells must have at least one IP address.
+ * It can be IPv4 or IPv6. */
+ if (!tor_addr_port_is_valid_ap(&cell->orport_ipv6, 0)) {
+ return -1;
+ }
+ }
if (cell->create_cell.cell_type == CELL_CREATE) {
if (cell->cell_type != RELAY_COMMAND_EXTEND)
return -1;
@@ -343,7 +353,7 @@ extend_cell_from_extend2_cell_body(extend_cell_t *cell_out,
continue;
found_ipv6 = 1;
tor_addr_from_ipv6_bytes(&cell_out->orport_ipv6.addr,
- (const char *)ls->un_ipv6_addr);
+ ls->un_ipv6_addr);
cell_out->orport_ipv6.port = ls->un_ipv6_port;
break;
case LS_LEGACY_ID:
@@ -364,7 +374,12 @@ extend_cell_from_extend2_cell_body(extend_cell_t *cell_out,
}
}
- if (!found_rsa_id || !found_ipv4) /* These are mandatory */
+ /* EXTEND2 cells must have an RSA ID */
+ if (!found_rsa_id)
+ return -1;
+
+ /* EXTEND2 cells must have at least one IP address */
+ if (!found_ipv4 && !found_ipv6)
return -1;
return create_cell_from_create2_cell_body(&cell_out->create_cell,
@@ -374,9 +389,11 @@ extend_cell_from_extend2_cell_body(extend_cell_t *cell_out,
/** Parse an EXTEND or EXTEND2 cell (according to <b>command</b>) from the
* <b>payload_length</b> bytes of <b>payload</b> into <b>cell_out</b>. Return
* 0 on success, -1 on failure. */
-int
-extend_cell_parse(extend_cell_t *cell_out, const uint8_t command,
- const uint8_t *payload, size_t payload_length)
+MOCK_IMPL(int,
+extend_cell_parse,(extend_cell_t *cell_out,
+ const uint8_t command,
+ const uint8_t *payload,
+ size_t payload_length))
{
tor_assert(cell_out);
@@ -509,7 +526,7 @@ create_cell_format_impl(cell_t *cell_out, const create_cell_t *cell_in,
p += 16;
space -= 16;
}
- /* Fall through */
+ FALLTHROUGH;
case CELL_CREATE_FAST:
tor_assert(cell_in->handshake_len <= space);
memcpy(p, cell_in->onionskin, cell_in->handshake_len);
@@ -618,12 +635,13 @@ extend_cell_format(uint8_t *command_out, uint16_t *len_out,
break;
case RELAY_COMMAND_EXTEND2:
{
- uint8_t n_specifiers = 2;
+ uint8_t n_specifiers = 1;
*command_out = RELAY_COMMAND_EXTEND2;
extend2_cell_body_t *cell = extend2_cell_body_new();
link_specifier_t *ls;
- {
- /* IPv4 specifier first. */
+ if (tor_addr_port_is_valid_ap(&cell_in->orport_ipv4, 0)) {
+ /* Maybe IPv4 specifier first. */
+ ++n_specifiers;
ls = link_specifier_new();
extend2_cell_body_add_ls(cell, ls);
ls->ls_type = LS_IPV4;
@@ -649,6 +667,17 @@ extend_cell_format(uint8_t *command_out, uint16_t *len_out,
ls->ls_len = 32;
memcpy(ls->un_ed25519_id, cell_in->ed_pubkey.pubkey, 32);
}
+ if (tor_addr_port_is_valid_ap(&cell_in->orport_ipv6, 0)) {
+ /* Then maybe IPv6 specifier. */
+ ++n_specifiers;
+ ls = link_specifier_new();
+ extend2_cell_body_add_ls(cell, ls);
+ ls->ls_type = LS_IPV6;
+ ls->ls_len = 18;
+ tor_addr_copy_ipv6_bytes(ls->un_ipv6_addr,
+ &cell_in->orport_ipv6.addr);
+ ls->un_ipv6_port = cell_in->orport_ipv6.port;
+ }
cell->n_spec = n_specifiers;
/* Now, the handshake */
diff --git a/src/core/or/onion.h b/src/core/or/onion.h
index ff3083f374..256f0a3f31 100644
--- a/src/core/or/onion.h
+++ b/src/core/or/onion.h
@@ -56,8 +56,8 @@ typedef struct extend_cell_t {
/** Ed25519 public identity key. Zero if not set. */
struct ed25519_public_key_t ed_pubkey;
/** The "create cell" embedded in this extend cell. Note that unlike the
- * create cells we generate ourself, this once can have a handshake type we
- * don't recognize. */
+ * create cells we generate ourselves, this create cell can have a handshake
+ * type we don't recognize. */
create_cell_t create_cell;
} extend_cell_t;
@@ -74,8 +74,10 @@ void create_cell_init(create_cell_t *cell_out, uint8_t cell_type,
const uint8_t *onionskin);
int create_cell_parse(create_cell_t *cell_out, const cell_t *cell_in);
int created_cell_parse(created_cell_t *cell_out, const cell_t *cell_in);
-int extend_cell_parse(extend_cell_t *cell_out, const uint8_t command,
- const uint8_t *payload_in, size_t payload_len);
+MOCK_DECL(int,extend_cell_parse,(extend_cell_t *cell_out,
+ const uint8_t command,
+ const uint8_t *payload_in,
+ size_t payload_len));
int extended_cell_parse(extended_cell_t *cell_out, const uint8_t command,
const uint8_t *payload_in, size_t payload_len);
diff --git a/src/core/or/or.h b/src/core/or/or.h
index 488a0fb09c..5b35cbe7f1 100644
--- a/src/core/or/or.h
+++ b/src/core/or/or.h
@@ -995,8 +995,6 @@ typedef struct routerset_t routerset_t;
typedef struct or_options_t or_options_t;
-#define LOG_PROTOCOL_WARN (get_protocol_warning_severity_level())
-
typedef struct or_state_t or_state_t;
#define MAX_SOCKS_ADDR_LEN 256
diff --git a/src/core/or/or_sys.c b/src/core/or/or_sys.c
index 126f5448cf..73c6087dce 100644
--- a/src/core/or/or_sys.c
+++ b/src/core/or/or_sys.c
@@ -47,6 +47,7 @@ subsys_or_add_pubsub(struct pubsub_connector_t *connector)
const struct subsys_fns_t sys_or = {
.name = "or",
+ SUBSYS_DECLARE_LOCATION(),
.supported = true,
.level = 20,
.initialize = subsys_or_initialize,
diff --git a/src/core/or/policies.c b/src/core/or/policies.c
index dd4feaadfc..2bf2dc7005 100644
--- a/src/core/or/policies.c
+++ b/src/core/or/policies.c
@@ -167,7 +167,7 @@ policy_expand_unspec(smartlist_t **policy)
}
tor_addr_from_ipv4h(&newpolicy_ipv4.addr, 0);
tor_addr_from_ipv6_bytes(&newpolicy_ipv6.addr,
- "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0");
+ (const uint8_t *)"\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0");
smartlist_add(tmp, addr_policy_get_canonical_entry(&newpolicy_ipv4));
smartlist_add(tmp, addr_policy_get_canonical_entry(&newpolicy_ipv6));
addr_policy_free(p);
@@ -1005,7 +1005,7 @@ fascist_firewall_choose_address_ls(const smartlist_t *lspecs,
* direct connection. */
if (have_v6) continue;
tor_addr_from_ipv6_bytes(&addr_v6,
- (const char *) link_specifier_getconstarray_un_ipv6_addr(ls));
+ link_specifier_getconstarray_un_ipv6_addr(ls));
port_v6 = link_specifier_get_un_ipv6_port(ls);
have_v6 = 1;
break;
@@ -2775,7 +2775,7 @@ parse_short_policy(const char *summary)
switch (*next) {
case ',':
++next;
- /* fall through */
+ FALLTHROUGH;
case '\0':
high = low;
break;
diff --git a/src/core/or/reasons.c b/src/core/or/reasons.c
index b60dfdf275..7da7843cab 100644
--- a/src/core/or/reasons.c
+++ b/src/core/or/reasons.c
@@ -489,7 +489,7 @@ end_reason_to_http_connect_response_line(int endreason)
return "HTTP/1.0 502 Bad Gateway (tor protocol violation)\r\n\r\n";
case END_STREAM_REASON_ENTRYPOLICY:
return "HTTP/1.0 403 Forbidden (entry policy violation)\r\n\r\n";
- case END_STREAM_REASON_NOTDIRECTORY: /* Fall Through */
+ case END_STREAM_REASON_NOTDIRECTORY: FALLTHROUGH;
default:
tor_assert_nonfatal_unreached();
return "HTTP/1.0 500 Internal Server Error (weird end reason)\r\n\r\n";
diff --git a/src/core/or/relay.c b/src/core/or/relay.c
index 5ddabf3474..75d2d479e7 100644
--- a/src/core/or/relay.c
+++ b/src/core/or/relay.c
@@ -66,6 +66,7 @@
#include "lib/crypt_ops/crypto_util.h"
#include "feature/dircommon/directory.h"
#include "feature/relay/dns.h"
+#include "feature/relay/circuitbuild_relay.h"
#include "feature/stats/geoip_stats.h"
#include "feature/hs/hs_cache.h"
#include "core/mainloop/mainloop.h"
@@ -866,7 +867,7 @@ connection_ap_process_end_not_open(
ttl = (int)ntohl(get_uint32(cell->payload+RELAY_HEADER_SIZE+5));
} else if (rh->length == 17 || rh->length == 21) {
tor_addr_from_ipv6_bytes(&addr,
- (char*)(cell->payload+RELAY_HEADER_SIZE+1));
+ (cell->payload+RELAY_HEADER_SIZE+1));
if (rh->length == 21)
ttl = (int)ntohl(get_uint32(cell->payload+RELAY_HEADER_SIZE+17));
}
@@ -940,7 +941,7 @@ connection_ap_process_end_not_open(
break; /* break means it'll close, below */
/* Else fall through: expire this circuit, clear the
* chosen_exit_name field, and try again. */
- /* Falls through. */
+ FALLTHROUGH;
case END_STREAM_REASON_RESOLVEFAILED:
case END_STREAM_REASON_TIMEOUT:
case END_STREAM_REASON_MISC:
@@ -1091,7 +1092,7 @@ connected_cell_parse(const relay_header_t *rh, const cell_t *cell,
return -1;
if (get_uint8(payload + 4) != 6)
return -1;
- tor_addr_from_ipv6_bytes(addr_out, (char*)(payload + 5));
+ tor_addr_from_ipv6_bytes(addr_out, (payload + 5));
bytes = ntohl(get_uint32(payload + 21));
if (bytes <= INT32_MAX)
*ttl_out = (int) bytes;
@@ -1164,7 +1165,7 @@ resolved_cell_parse(const cell_t *cell, const relay_header_t *rh,
if (answer_len != 16)
goto err;
addr = tor_malloc_zero(sizeof(*addr));
- tor_addr_from_ipv6_bytes(&addr->addr, (const char*) cp);
+ tor_addr_from_ipv6_bytes(&addr->addr, cp);
cp += 16;
addr->ttl = ntohl(get_uint32(cp));
cp += 4;
@@ -3216,7 +3217,7 @@ decode_address_from_payload(tor_addr_t *addr_out, const uint8_t *payload,
case RESOLVED_TYPE_IPV6:
if (payload[1] != 16)
return NULL;
- tor_addr_from_ipv6_bytes(addr_out, (char*)(payload+2));
+ tor_addr_from_ipv6_bytes(addr_out, (payload+2));
break;
default:
tor_addr_make_unspec(addr_out);
diff --git a/src/core/or/scheduler.c b/src/core/or/scheduler.c
index 6633ccfe1f..ff58f9ca5b 100644
--- a/src/core/or/scheduler.c
+++ b/src/core/or/scheduler.c
@@ -191,7 +191,7 @@ get_scheduler_type_string(scheduler_types_t type)
case SCHEDULER_KIST_LITE:
return "KISTLite";
case SCHEDULER_NONE:
- /* fallthrough */
+ FALLTHROUGH;
default:
tor_assert_unreached();
return "(N/A)";
@@ -287,7 +287,7 @@ select_scheduler(void)
scheduler_kist_set_lite_mode();
goto end;
case SCHEDULER_NONE:
- /* fallthrough */
+ FALLTHROUGH;
default:
/* Our option validation should have caught this. */
tor_assert_unreached();
diff --git a/src/core/or/sendme.c b/src/core/or/sendme.c
index db3e2e94fd..788f56088c 100644
--- a/src/core/or/sendme.c
+++ b/src/core/or/sendme.c
@@ -293,7 +293,7 @@ send_circuit_level_sendme(circuit_t *circ, crypt_path_t *layer_hint,
log_debug(LD_PROTOCOL, "Emitting SENDME version 1 cell.");
break;
case 0x00:
- /* Fallthrough because default is to use v0. */
+ FALLTHROUGH;
default:
/* Unknown version, fallback to version 0 meaning no payload. */
payload_len = 0;
diff --git a/src/core/or/versions.c b/src/core/or/versions.c
index a9a960d66e..31f1f5b997 100644
--- a/src/core/or/versions.c
+++ b/src/core/or/versions.c
@@ -296,7 +296,7 @@ tor_version_parse(const char *s, tor_version_t *out)
return -1;
hexlen = (int)(close_paren-cp);
memwipe(digest, 0, sizeof(digest));
- if ( hexlen == 0 || (hexlen % 2) == 1)
+ if (hexlen == 0 || (hexlen % 2) == 1)
return -1;
if (base16_decode(digest, hexlen/2, cp, hexlen) != hexlen/2)
return -1;
diff --git a/src/core/proto/proto_socks.c b/src/core/proto/proto_socks.c
index 6fd08b2273..198195c0ae 100644
--- a/src/core/proto/proto_socks.c
+++ b/src/core/proto/proto_socks.c
@@ -587,9 +587,8 @@ parse_socks5_client_request(const uint8_t *raw_data, socks_request_t *req,
strlcpy(req->address, hostname, sizeof(req->address));
} break;
case 4: {
- const char *ipv6 =
- (const char *)socks5_client_request_getarray_dest_addr_ipv6(
- trunnel_req);
+ const uint8_t *ipv6 =
+ socks5_client_request_getarray_dest_addr_ipv6(trunnel_req);
tor_addr_from_ipv6_bytes(&destaddr, ipv6);
tor_addr_to_str(req->address, &destaddr, sizeof(req->address), 1);
@@ -861,7 +860,7 @@ fetch_from_buf_socks(buf_t *buf, socks_request_t *req,
case SOCKS_RESULT_TRUNCATED:
if (datalen == n_pullup)
return 0;
- /* FALLTHRU */
+ FALLTHROUGH;
case SOCKS_RESULT_MORE_EXPECTED:
res = 0;
break;
@@ -967,7 +966,7 @@ parse_socks(const char *data, size_t datalen, socks_request_t *req,
strlcpy((char*)req->reply, SOCKS_PROXY_IS_NOT_AN_HTTP_PROXY_MSG,
MAX_SOCKS_REPLY_LEN);
req->replylen = strlen((char*)req->reply)+1;
- /* fall through */
+ FALLTHROUGH;
default: /* version is not socks4 or socks5 */
log_warn(LD_APP,
"Socks version %d not recognized. (This port is not an "
@@ -1072,7 +1071,10 @@ parse_socks_client(const uint8_t *data, size_t datalen,
log_info(LD_NET, "SOCKS 5 client: need authentication.");
*drain_out = -1;
return 2;
- /* fall through */
+ default:
+ /* This wasn't supposed to be exhaustive; there are other
+ * authentication methods too. */
+ ;
}
*reason = tor_strdup("server doesn't support any of our available "
diff --git a/src/core/stA1RajU b/src/core/stA1RajU
new file mode 100644
index 0000000000..e69de29bb2
--- /dev/null
+++ b/src/core/stA1RajU
diff --git a/src/core/stiysZND b/src/core/stiysZND
new file mode 100644
index 0000000000..faa365b769
--- /dev/null
+++ b/src/core/stiysZND
Binary files differ
diff --git a/src/ext/csiphash.c b/src/ext/csiphash.c
index faa52ae4e1..e0f5b2e5c9 100644
--- a/src/ext/csiphash.c
+++ b/src/ext/csiphash.c
@@ -95,13 +95,13 @@ uint64_t siphash24(const void *src, unsigned long src_sz, const struct sipkey *k
}
#else
switch (src_sz - blocks) {
- case 7: last7 |= (uint64_t)m[i + 6] << 48; /* Falls through. */
- case 6: last7 |= (uint64_t)m[i + 5] << 40; /* Falls through. */
- case 5: last7 |= (uint64_t)m[i + 4] << 32; /* Falls through. */
- case 4: last7 |= (uint64_t)m[i + 3] << 24; /* Falls through. */
- case 3: last7 |= (uint64_t)m[i + 2] << 16; /* Falls through. */
- case 2: last7 |= (uint64_t)m[i + 1] << 8; /* Falls through. */
- case 1: last7 |= (uint64_t)m[i + 0] ; /* Falls through. */
+ case 7: last7 |= (uint64_t)m[i + 6] << 48; FALLTHROUGH;
+ case 6: last7 |= (uint64_t)m[i + 5] << 40; FALLTHROUGH;
+ case 5: last7 |= (uint64_t)m[i + 4] << 32; FALLTHROUGH;
+ case 4: last7 |= (uint64_t)m[i + 3] << 24; FALLTHROUGH;
+ case 3: last7 |= (uint64_t)m[i + 2] << 16; FALLTHROUGH;
+ case 2: last7 |= (uint64_t)m[i + 1] << 8; FALLTHROUGH;
+ case 1: last7 |= (uint64_t)m[i + 0] ; FALLTHROUGH;
case 0:
default:;
}
diff --git a/src/ext/ed25519/donna/ed25519_tor.c b/src/ext/ed25519/donna/ed25519_tor.c
index 7f5ab398d8..a5bb6f4e21 100644
--- a/src/ext/ed25519/donna/ed25519_tor.c
+++ b/src/ext/ed25519/donna/ed25519_tor.c
@@ -35,6 +35,9 @@
#define ED25519_FN(fn) ED25519_FN2(fn,ED25519_SUFFIX)
#include "orconfig.h"
+
+#include "lib/cc/compat_compiler.h"
+
#include "ed25519-donna.h"
#include "ed25519_donna_tor.h"
#include "ed25519-randombytes.h"
@@ -366,4 +369,3 @@ ed25519_donna_scalarmult_with_group_order(unsigned char *out,
}
#include "test-internals.c"
-
diff --git a/src/ext/ed25519/donna/modm-donna-32bit.h b/src/ext/ed25519/donna/modm-donna-32bit.h
index 0ef9e58fa1..5934d9ca9d 100644
--- a/src/ext/ed25519/donna/modm-donna-32bit.h
+++ b/src/ext/ed25519/donna/modm-donna-32bit.h
@@ -385,14 +385,14 @@ sub256_modm_batch(bignum256modm out, const bignum256modm a, const bignum256modm
size_t i = 0;
bignum256modm_element_t carry = 0;
switch (limbsize) {
- case 8: out[i] = (a[i] - b[i]) - carry; carry = (out[i] >> 31); out[i] &= 0x3fffffff; i++; /* Falls through. */
- case 7: out[i] = (a[i] - b[i]) - carry; carry = (out[i] >> 31); out[i] &= 0x3fffffff; i++; /* Falls through. */
- case 6: out[i] = (a[i] - b[i]) - carry; carry = (out[i] >> 31); out[i] &= 0x3fffffff; i++; /* Falls through. */
- case 5: out[i] = (a[i] - b[i]) - carry; carry = (out[i] >> 31); out[i] &= 0x3fffffff; i++; /* Falls through. */
- case 4: out[i] = (a[i] - b[i]) - carry; carry = (out[i] >> 31); out[i] &= 0x3fffffff; i++; /* Falls through. */
- case 3: out[i] = (a[i] - b[i]) - carry; carry = (out[i] >> 31); out[i] &= 0x3fffffff; i++; /* Falls through. */
- case 2: out[i] = (a[i] - b[i]) - carry; carry = (out[i] >> 31); out[i] &= 0x3fffffff; i++; /* Falls through. */
- case 1: out[i] = (a[i] - b[i]) - carry; carry = (out[i] >> 31); out[i] &= 0x3fffffff; i++; /* Falls through. */
+ case 8: out[i] = (a[i] - b[i]) - carry; carry = (out[i] >> 31); out[i] &= 0x3fffffff; i++; FALLTHROUGH;
+ case 7: out[i] = (a[i] - b[i]) - carry; carry = (out[i] >> 31); out[i] &= 0x3fffffff; i++; FALLTHROUGH;
+ case 6: out[i] = (a[i] - b[i]) - carry; carry = (out[i] >> 31); out[i] &= 0x3fffffff; i++; FALLTHROUGH;
+ case 5: out[i] = (a[i] - b[i]) - carry; carry = (out[i] >> 31); out[i] &= 0x3fffffff; i++; FALLTHROUGH;
+ case 4: out[i] = (a[i] - b[i]) - carry; carry = (out[i] >> 31); out[i] &= 0x3fffffff; i++; FALLTHROUGH;
+ case 3: out[i] = (a[i] - b[i]) - carry; carry = (out[i] >> 31); out[i] &= 0x3fffffff; i++; FALLTHROUGH;
+ case 2: out[i] = (a[i] - b[i]) - carry; carry = (out[i] >> 31); out[i] &= 0x3fffffff; i++; FALLTHROUGH;
+ case 1: out[i] = (a[i] - b[i]) - carry; carry = (out[i] >> 31); out[i] &= 0x3fffffff; i++; FALLTHROUGH;
case 0:
default: out[i] = (a[i] - b[i]) - carry;
}
@@ -403,14 +403,14 @@ sub256_modm_batch(bignum256modm out, const bignum256modm a, const bignum256modm
static int
lt256_modm_batch(const bignum256modm a, const bignum256modm b, size_t limbsize) {
switch (limbsize) {
- case 8: if (a[8] > b[8]) return 0; if (a[8] < b[8]) return 1; /* Falls through. */
- case 7: if (a[7] > b[7]) return 0; if (a[7] < b[7]) return 1; /* Falls through. */
- case 6: if (a[6] > b[6]) return 0; if (a[6] < b[6]) return 1; /* Falls through. */
- case 5: if (a[5] > b[5]) return 0; if (a[5] < b[5]) return 1; /* Falls through. */
- case 4: if (a[4] > b[4]) return 0; if (a[4] < b[4]) return 1; /* Falls through. */
- case 3: if (a[3] > b[3]) return 0; if (a[3] < b[3]) return 1; /* Falls through. */
- case 2: if (a[2] > b[2]) return 0; if (a[2] < b[2]) return 1; /* Falls through. */
- case 1: if (a[1] > b[1]) return 0; if (a[1] < b[1]) return 1; /* Falls through. */
+ case 8: if (a[8] > b[8]) return 0; if (a[8] < b[8]) return 1; FALLTHROUGH;
+ case 7: if (a[7] > b[7]) return 0; if (a[7] < b[7]) return 1; FALLTHROUGH;
+ case 6: if (a[6] > b[6]) return 0; if (a[6] < b[6]) return 1; FALLTHROUGH;
+ case 5: if (a[5] > b[5]) return 0; if (a[5] < b[5]) return 1; FALLTHROUGH;
+ case 4: if (a[4] > b[4]) return 0; if (a[4] < b[4]) return 1; FALLTHROUGH;
+ case 3: if (a[3] > b[3]) return 0; if (a[3] < b[3]) return 1; FALLTHROUGH;
+ case 2: if (a[2] > b[2]) return 0; if (a[2] < b[2]) return 1; FALLTHROUGH;
+ case 1: if (a[1] > b[1]) return 0; if (a[1] < b[1]) return 1; FALLTHROUGH;
case 0: if (a[0] > b[0]) return 0; if (a[0] < b[0]) return 1;
}
return 0;
@@ -420,14 +420,14 @@ lt256_modm_batch(const bignum256modm a, const bignum256modm b, size_t limbsize)
static int
lte256_modm_batch(const bignum256modm a, const bignum256modm b, size_t limbsize) {
switch (limbsize) {
- case 8: if (a[8] > b[8]) return 0; if (a[8] < b[8]) return 1; /* Falls through. */
- case 7: if (a[7] > b[7]) return 0; if (a[7] < b[7]) return 1; /* Falls through. */
- case 6: if (a[6] > b[6]) return 0; if (a[6] < b[6]) return 1; /* Falls through. */
- case 5: if (a[5] > b[5]) return 0; if (a[5] < b[5]) return 1; /* Falls through. */
- case 4: if (a[4] > b[4]) return 0; if (a[4] < b[4]) return 1; /* Falls through. */
- case 3: if (a[3] > b[3]) return 0; if (a[3] < b[3]) return 1; /* Falls through. */
- case 2: if (a[2] > b[2]) return 0; if (a[2] < b[2]) return 1; /* Falls through. */
- case 1: if (a[1] > b[1]) return 0; if (a[1] < b[1]) return 1; /* Falls through. */
+ case 8: if (a[8] > b[8]) return 0; if (a[8] < b[8]) return 1; FALLTHROUGH;
+ case 7: if (a[7] > b[7]) return 0; if (a[7] < b[7]) return 1; FALLTHROUGH;
+ case 6: if (a[6] > b[6]) return 0; if (a[6] < b[6]) return 1; FALLTHROUGH;
+ case 5: if (a[5] > b[5]) return 0; if (a[5] < b[5]) return 1; FALLTHROUGH;
+ case 4: if (a[4] > b[4]) return 0; if (a[4] < b[4]) return 1; FALLTHROUGH;
+ case 3: if (a[3] > b[3]) return 0; if (a[3] < b[3]) return 1; FALLTHROUGH;
+ case 2: if (a[2] > b[2]) return 0; if (a[2] < b[2]) return 1; FALLTHROUGH;
+ case 1: if (a[1] > b[1]) return 0; if (a[1] < b[1]) return 1; FALLTHROUGH;
case 0: if (a[0] > b[0]) return 0; if (a[0] < b[0]) return 1;
}
return 1;
diff --git a/src/ext/ed25519/donna/modm-donna-64bit.h b/src/ext/ed25519/donna/modm-donna-64bit.h
index 06c98e3039..aa361afdbc 100644
--- a/src/ext/ed25519/donna/modm-donna-64bit.h
+++ b/src/ext/ed25519/donna/modm-donna-64bit.h
@@ -294,10 +294,10 @@ sub256_modm_batch(bignum256modm out, const bignum256modm a, const bignum256modm
size_t i = 0;
bignum256modm_element_t carry = 0;
switch (limbsize) {
- case 4: out[i] = (a[i] - b[i]) ; carry = (out[i] >> 63); out[i] &= 0xffffffffffffff; i++; /* Falls through. */
- case 3: out[i] = (a[i] - b[i]) - carry; carry = (out[i] >> 63); out[i] &= 0xffffffffffffff; i++; /* Falls through. */
- case 2: out[i] = (a[i] - b[i]) - carry; carry = (out[i] >> 63); out[i] &= 0xffffffffffffff; i++; /* Falls through. */
- case 1: out[i] = (a[i] - b[i]) - carry; carry = (out[i] >> 63); out[i] &= 0xffffffffffffff; i++; /* Falls through. */
+ case 4: out[i] = (a[i] - b[i]) ; carry = (out[i] >> 63); out[i] &= 0xffffffffffffff; i++; FALLTHROUGH;
+ case 3: out[i] = (a[i] - b[i]) - carry; carry = (out[i] >> 63); out[i] &= 0xffffffffffffff; i++; FALLTHROUGH;
+ case 2: out[i] = (a[i] - b[i]) - carry; carry = (out[i] >> 63); out[i] &= 0xffffffffffffff; i++; FALLTHROUGH;
+ case 1: out[i] = (a[i] - b[i]) - carry; carry = (out[i] >> 63); out[i] &= 0xffffffffffffff; i++; FALLTHROUGH;
case 0:
default: out[i] = (a[i] - b[i]) - carry;
}
@@ -310,10 +310,10 @@ lt256_modm_batch(const bignum256modm a, const bignum256modm b, size_t limbsize)
size_t i = 0;
bignum256modm_element_t t, carry = 0;
switch (limbsize) {
- case 4: t = (a[i] - b[i]) ; carry = (t >> 63); i++; /* Falls through. */
- case 3: t = (a[i] - b[i]) - carry; carry = (t >> 63); i++; /* Falls through. */
- case 2: t = (a[i] - b[i]) - carry; carry = (t >> 63); i++; /* Falls through. */
- case 1: t = (a[i] - b[i]) - carry; carry = (t >> 63); i++; /* Falls through. */
+ case 4: t = (a[i] - b[i]) ; carry = (t >> 63); i++; FALLTHROUGH;
+ case 3: t = (a[i] - b[i]) - carry; carry = (t >> 63); i++; FALLTHROUGH;
+ case 2: t = (a[i] - b[i]) - carry; carry = (t >> 63); i++; FALLTHROUGH;
+ case 1: t = (a[i] - b[i]) - carry; carry = (t >> 63); i++; FALLTHROUGH;
case 0: t = (a[i] - b[i]) - carry; carry = (t >> 63);
}
return (int)carry;
@@ -325,10 +325,10 @@ lte256_modm_batch(const bignum256modm a, const bignum256modm b, size_t limbsize)
size_t i = 0;
bignum256modm_element_t t, carry = 0;
switch (limbsize) {
- case 4: t = (b[i] - a[i]) ; carry = (t >> 63); i++; /* Falls through. */
- case 3: t = (b[i] - a[i]) - carry; carry = (t >> 63); i++; /* Falls through. */
- case 2: t = (b[i] - a[i]) - carry; carry = (t >> 63); i++; /* Falls through. */
- case 1: t = (b[i] - a[i]) - carry; carry = (t >> 63); i++; /* Falls through. */
+ case 4: t = (b[i] - a[i]) ; carry = (t >> 63); i++; FALLTHROUGH;
+ case 3: t = (b[i] - a[i]) - carry; carry = (t >> 63); i++; FALLTHROUGH;
+ case 2: t = (b[i] - a[i]) - carry; carry = (t >> 63); i++; FALLTHROUGH;
+ case 1: t = (b[i] - a[i]) - carry; carry = (t >> 63); i++; FALLTHROUGH;
case 0: t = (b[i] - a[i]) - carry; carry = (t >> 63);
}
return (int)!carry;
diff --git a/src/feature/client/addressmap.c b/src/feature/client/addressmap.c
index cc97166f36..9ad2d7f934 100644
--- a/src/feature/client/addressmap.c
+++ b/src/feature/client/addressmap.c
@@ -902,7 +902,7 @@ get_random_virtual_addr(const virtual_addr_conf_t *conf, tor_addr_t *addr_out)
}
if (ipv6)
- tor_addr_from_ipv6_bytes(addr_out, (char*) bytes);
+ tor_addr_from_ipv6_bytes(addr_out, bytes);
else
tor_addr_from_ipv4n(addr_out, get_uint32(bytes));
diff --git a/src/feature/client/entrynodes.c b/src/feature/client/entrynodes.c
index 2843558e93..55cc22cf0c 100644
--- a/src/feature/client/entrynodes.c
+++ b/src/feature/client/entrynodes.c
@@ -2265,7 +2265,7 @@ entry_guards_note_guard_success(guard_selection_t *gs,
break;
default:
tor_assert_nonfatal_unreached();
- /* Fall through. */
+ FALLTHROUGH;
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/client/transports.c b/src/feature/client/transports.c
index 55069bb60a..2bdc0ae151 100644
--- a/src/feature/client/transports.c
+++ b/src/feature/client/transports.c
@@ -97,6 +97,7 @@
#include "core/or/circuitbuild.h"
#include "feature/client/transports.h"
#include "feature/relay/router.h"
+#include "feature/relay/relay_find_addr.h"
/* 31851: split the server transport code out of the client module */
#include "feature/relay/transport_config.h"
#include "app/config/statefile.h"
diff --git a/src/feature/control/btrack.c b/src/feature/control/btrack.c
index 3595af0fcc..405630ecd4 100644
--- a/src/feature/control/btrack.c
+++ b/src/feature/control/btrack.c
@@ -56,6 +56,7 @@ btrack_add_pubsub(pubsub_connector_t *connector)
const subsys_fns_t sys_btrack = {
.name = "btrack",
+ SUBSYS_DECLARE_LOCATION(),
.supported = true,
.level = 55,
.initialize = btrack_init,
diff --git a/src/feature/control/btrack_orconn_cevent.c b/src/feature/control/btrack_orconn_cevent.c
index c5de473d0f..d11be59280 100644
--- a/src/feature/control/btrack_orconn_cevent.c
+++ b/src/feature/control/btrack_orconn_cevent.c
@@ -147,6 +147,7 @@ bto_cevent_apconn(const bt_orconn_t *bto)
break;
case OR_CONN_STATE_OPEN:
control_event_bootstrap(BOOTSTRAP_STATUS_AP_HANDSHAKE_DONE, 0);
+ break;
default:
break;
}
diff --git a/src/feature/control/control_cmd.c b/src/feature/control/control_cmd.c
index cdefef97e1..d9a38011de 100644
--- a/src/feature/control/control_cmd.c
+++ b/src/feature/control/control_cmd.c
@@ -1904,7 +1904,7 @@ handle_control_add_onion(control_connection_t *conn,
case RSAE_BADAUTH:
control_write_endreply(conn, 512, "Invalid client authorization");
break;
- case RSAE_INTERNAL: /* FALLSTHROUGH */
+ case RSAE_INTERNAL: FALLTHROUGH;
default:
control_write_endreply(conn, 551, "Failed to add Onion Service");
}
diff --git a/src/feature/control/control_getinfo.c b/src/feature/control/control_getinfo.c
index 5dcc4b170d..b2d0c9680d 100644
--- a/src/feature/control/control_getinfo.c
+++ b/src/feature/control/control_getinfo.c
@@ -44,6 +44,7 @@
#include "feature/nodelist/nodelist.h"
#include "feature/nodelist/routerinfo.h"
#include "feature/nodelist/routerlist.h"
+#include "feature/relay/relay_find_addr.h"
#include "feature/relay/router.h"
#include "feature/relay/routermode.h"
#include "feature/relay/selftest.h"
@@ -1331,8 +1332,22 @@ getinfo_helper_events(control_connection_t *control_conn,
}
routerinfo_t *r;
extrainfo_t *e;
- if (router_build_fresh_descriptor(&r, &e) < 0) {
- *errmsg = "Error generating descriptor";
+ int result;
+ if ((result = router_build_fresh_descriptor(&r, &e)) < 0) {
+ switch (result) {
+ case TOR_ROUTERINFO_ERROR_NO_EXT_ADDR:
+ *errmsg = "Cannot get relay address while generating descriptor";
+ break;
+ case TOR_ROUTERINFO_ERROR_DIGEST_FAILED:
+ *errmsg = "Key digest failed";
+ break;
+ case TOR_ROUTERINFO_ERROR_CANNOT_GENERATE:
+ *errmsg = "Cannot generate router descriptor";
+ break;
+ default:
+ *errmsg = "Error generating descriptor";
+ break;
+ }
return -1;
}
size_t size = r->cache_info.signed_descriptor_len + 1;
diff --git a/src/feature/control/control_hs.c b/src/feature/control/control_hs.c
index d3cd363f63..f5b331de9a 100644
--- a/src/feature/control/control_hs.c
+++ b/src/feature/control/control_hs.c
@@ -50,11 +50,18 @@ parse_private_key_from_control_port(const char *client_privkey_str,
if (base64_decode((char*)privkey->secret_key, sizeof(privkey->secret_key),
key_blob,
- strlen(key_blob)) != sizeof(privkey->secret_key)) {
+ strlen(key_blob)) != sizeof(privkey->secret_key)) {
control_printf_endreply(conn, 512, "Failed to decode x25519 private key");
goto err;
}
+ if (fast_mem_is_zero((const char*)privkey->secret_key,
+ sizeof(privkey->secret_key))) {
+ control_printf_endreply(conn, 553,
+ "Invalid private key \"%s\"", key_blob);
+ goto err;
+ }
+
retval = 0;
err:
diff --git a/src/feature/dirauth/dirauth_config.c b/src/feature/dirauth/dirauth_config.c
index 38d2a8bc5a..a0b6de7eca 100644
--- a/src/feature/dirauth/dirauth_config.c
+++ b/src/feature/dirauth/dirauth_config.c
@@ -20,6 +20,7 @@
/* Required for dirinfo_type_t in or_options_t */
#include "core/or/or.h"
#include "app/config/config.h"
+#include "app/config/resolve_addr.h"
#include "feature/dirauth/voting_schedule.h"
#include "feature/stats/rephist.h"
diff --git a/src/feature/dirauth/dirauth_stub.c b/src/feature/dirauth/dirauth_stub.c
index 15a195b0fb..9f48ce14fd 100644
--- a/src/feature/dirauth/dirauth_stub.c
+++ b/src/feature/dirauth/dirauth_stub.c
@@ -26,6 +26,7 @@ static const config_format_t dirauth_options_stub_fmt = {
const struct subsys_fns_t sys_dirauth = {
.name = "dirauth",
+ SUBSYS_DECLARE_LOCATION(),
.supported = false,
.level = DIRAUTH_SUBSYS_LEVEL,
diff --git a/src/feature/dirauth/dirauth_sys.c b/src/feature/dirauth/dirauth_sys.c
index 56ac501e16..07c5743877 100644
--- a/src/feature/dirauth/dirauth_sys.c
+++ b/src/feature/dirauth/dirauth_sys.c
@@ -60,6 +60,7 @@ dirauth_set_options(void *arg)
const struct subsys_fns_t sys_dirauth = {
.name = "dirauth",
+ SUBSYS_DECLARE_LOCATION(),
.supported = true,
.level = DIRAUTH_SUBSYS_LEVEL,
.initialize = subsys_dirauth_initialize,
diff --git a/src/feature/dirauth/dirvote.c b/src/feature/dirauth/dirvote.c
index 7eb2b720a6..6bf30d083b 100644
--- a/src/feature/dirauth/dirvote.c
+++ b/src/feature/dirauth/dirvote.c
@@ -6,6 +6,7 @@
#define DIRVOTE_PRIVATE
#include "core/or/or.h"
#include "app/config/config.h"
+#include "app/config/resolve_addr.h"
#include "core/or/policies.h"
#include "core/or/protover.h"
#include "core/or/tor_version_st.h"
diff --git a/src/feature/dirauth/keypin.c b/src/feature/dirauth/keypin.c
index 98584a7d42..5072a58573 100644
--- a/src/feature/dirauth/keypin.c
+++ b/src/feature/dirauth/keypin.c
@@ -265,7 +265,7 @@ keypin_add_or_replace_entry_in_map(keypin_ent_t *ent)
}
tor_free(ent2);
r = -1;
- /* Fall through */
+ /* Note lack of return here: we fall through to the next line. */
}
keypin_add_entry_to_map(ent);
diff --git a/src/feature/dirauth/shared_random_state.c b/src/feature/dirauth/shared_random_state.c
index 598d781557..07bc757506 100644
--- a/src/feature/dirauth/shared_random_state.c
+++ b/src/feature/dirauth/shared_random_state.c
@@ -1041,8 +1041,9 @@ sr_state_set_valid_after(time_t valid_after)
sr_phase_t
sr_state_get_phase(void)
{
- void *ptr;
+ void *ptr=NULL;
state_query(SR_STATE_ACTION_GET, SR_STATE_OBJ_PHASE, NULL, &ptr);
+ tor_assert(ptr);
return *(sr_phase_t *) ptr;
}
diff --git a/src/feature/dircache/conscache.c b/src/feature/dircache/conscache.c
index d9aaccddc1..2a831aa447 100644
--- a/src/feature/dircache/conscache.c
+++ b/src/feature/dircache/conscache.c
@@ -139,7 +139,7 @@ consensus_cache_may_overallocate(consensus_cache_t *cache)
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wsuggest-attribute=noreturn"
#endif
-#endif
+#endif /* defined(_WIN32) */
/**
* Tell the sandbox (if any) configured by <b>cfg</b> to allow the
diff --git a/src/feature/dircache/dircache.c b/src/feature/dircache/dircache.c
index 4f7f209207..ca127720f2 100644
--- a/src/feature/dircache/dircache.c
+++ b/src/feature/dircache/dircache.c
@@ -13,6 +13,7 @@
#include "core/or/or.h"
#include "app/config/config.h"
+#include "app/config/resolve_addr.h"
#include "core/mainloop/connection.h"
#include "core/or/relay.h"
#include "feature/dirauth/dirvote.h"
diff --git a/src/feature/dirclient/dirclient.c b/src/feature/dirclient/dirclient.c
index 2072dddadd..ae1e018df2 100644
--- a/src/feature/dirclient/dirclient.c
+++ b/src/feature/dirclient/dirclient.c
@@ -44,6 +44,7 @@
#include "feature/nodelist/routerinfo.h"
#include "feature/nodelist/routerlist.h"
#include "feature/nodelist/routerset.h"
+#include "feature/relay/relay_find_addr.h"
#include "feature/relay/routermode.h"
#include "feature/relay/selftest.h"
#include "feature/rend/rendcache.h"
@@ -1367,7 +1368,7 @@ directory_initiate_request,(directory_request_t *request))
case 1:
/* start flushing conn */
conn->base_.state = DIR_CONN_STATE_CLIENT_SENDING;
- /* fall through */
+ FALLTHROUGH;
case 0:
/* queue the command on the outbuf */
directory_send_command(conn, 1, request);
diff --git a/src/feature/dirclient/dirclient_modes.c b/src/feature/dirclient/dirclient_modes.c
index 23fd1a2f6e..31a3f8af58 100644
--- a/src/feature/dirclient/dirclient_modes.c
+++ b/src/feature/dirclient/dirclient_modes.c
@@ -16,6 +16,7 @@
#include "feature/dirclient/dirclient_modes.h"
#include "feature/dircache/dirserv.h"
+#include "feature/relay/relay_find_addr.h"
#include "feature/relay/router.h"
#include "feature/relay/routermode.h"
#include "feature/stats/predict_ports.h"
diff --git a/src/feature/dirparse/parsecommon.c b/src/feature/dirparse/parsecommon.c
index 0c63cd4846..ab465c4d7f 100644
--- a/src/feature/dirparse/parsecommon.c
+++ b/src/feature/dirparse/parsecommon.c
@@ -222,7 +222,7 @@ token_check_object(memarea_t *area, const char *kwd,
kwd, crypto_pk_num_bits(tok->key));
RET_ERR(ebuf);
}
- /* fall through */
+ FALLTHROUGH;
case NEED_KEY: /* There must be some kind of key. */
if (!tok->key) {
tor_snprintf(ebuf, sizeof(ebuf), "Missing public key for %s", kwd);
diff --git a/src/feature/hs/hs_circuit.c b/src/feature/hs/hs_circuit.c
index fdd226ba79..447f664f81 100644
--- a/src/feature/hs/hs_circuit.c
+++ b/src/feature/hs/hs_circuit.c
@@ -622,6 +622,20 @@ setup_introduce1_data(const hs_desc_intro_point_t *ip,
}
/** Helper: cleanup function for client circuit. This is for every HS version.
+ * It is called from hs_circ_cleanup_on_close() entry point. */
+static void
+cleanup_on_close_client_circ(circuit_t *circ)
+{
+ tor_assert(circ);
+
+ if (circuit_is_hs_v3(circ)) {
+ hs_client_circuit_cleanup_on_close(circ);
+ }
+ /* It is possible the circuit has an HS purpose but no identifier (rend_data
+ * or hs_ident). Thus possible that this passes through. */
+}
+
+/** Helper: cleanup function for client circuit. This is for every HS version.
* It is called from hs_circ_cleanup_on_free() entry point. */
static void
cleanup_on_free_client_circ(circuit_t *circ)
@@ -634,7 +648,7 @@ cleanup_on_free_client_circ(circuit_t *circ)
hs_client_circuit_cleanup_on_free(circ);
}
/* It is possible the circuit has an HS purpose but no identifier (rend_data
- * or hs_ident). Thus possible that this passess through. */
+ * or hs_ident). Thus possible that this passes through. */
}
/* ========== */
@@ -984,13 +998,13 @@ get_subcredential_for_handling_intro2_cell(const hs_service_t *service,
/* This should not happen since we should have made onionbalance
* subcredentials when we created our descriptors. */
- if (BUG(!service->ob_subcreds)) {
+ if (BUG(!service->state.ob_subcreds)) {
return -1;
}
/* We are an onionbalance instance: */
- data->n_subcredentials = service->n_ob_subcreds;
- data->subcredentials = service->ob_subcreds;
+ data->n_subcredentials = service->state.n_ob_subcreds;
+ data->subcredentials = service->state.ob_subcreds;
return 0;
}
@@ -1293,6 +1307,10 @@ hs_circ_cleanup_on_close(circuit_t *circ)
{
tor_assert(circ);
+ if (circuit_purpose_is_hs_client(circ->purpose)) {
+ cleanup_on_close_client_circ(circ);
+ }
+
/* On close, we simply remove it from the circuit map. It can not be used
* anymore. We keep this code path fast and lean. */
diff --git a/src/feature/hs/hs_client.c b/src/feature/hs/hs_client.c
index cc1b01d2ef..c3697d0c1d 100644
--- a/src/feature/hs/hs_client.c
+++ b/src/feature/hs/hs_client.c
@@ -961,6 +961,87 @@ client_get_random_intro(const ed25519_public_key_t *service_pk)
return ei;
}
+/** Return true iff all intro points for the given service have timed out. */
+static bool
+intro_points_all_timed_out(const ed25519_public_key_t *service_pk)
+{
+ bool ret = false;
+
+ tor_assert(service_pk);
+
+ const hs_descriptor_t *desc = hs_cache_lookup_as_client(service_pk);
+ if (BUG(!desc)) {
+ /* We can't introduce without a descriptor so ending up here means somehow
+ * between the introduction failure and this, the cache entry was removed
+ * which shouldn't be possible in theory. */
+ goto end;
+ }
+
+ SMARTLIST_FOREACH_BEGIN(desc->encrypted_data.intro_points,
+ const hs_desc_intro_point_t *, ip) {
+ const hs_cache_intro_state_t *state =
+ hs_cache_client_intro_state_find(service_pk,
+ &ip->auth_key_cert->signed_key);
+ if (!state || !state->timed_out) {
+ /* No state or if this intro point has not timed out, we are done since
+ * clearly not all of them have timed out. */
+ goto end;
+ }
+ } SMARTLIST_FOREACH_END(ip);
+
+ /* Exiting the loop here means that all intro points we've looked at have
+ * timed out. Note that we can _not_ have a descriptor without intro points
+ * in the client cache. */
+ ret = true;
+
+ end:
+ return ret;
+}
+
+/** Called when a rendezvous circuit has timed out. Every stream attached to
+ * the circuit will get set with the SOCKS5_HS_REND_FAILED (0xF3) extended
+ * error code so if the connection to the rendezvous point ends up not
+ * working, this code could be sent back as a reason. */
+static void
+socks_mark_rend_circuit_timed_out(const origin_circuit_t *rend_circ)
+{
+ tor_assert(rend_circ);
+
+ /* For each entry connection attached to this rendezvous circuit, report
+ * the error. */
+ for (edge_connection_t *edge = rend_circ->p_streams; edge;
+ edge = edge->next_stream) {
+ entry_connection_t *entry = EDGE_TO_ENTRY_CONN(edge);
+ if (entry->socks_request) {
+ entry->socks_request->socks_extended_error_code =
+ SOCKS5_HS_REND_FAILED;
+ }
+ }
+}
+
+/** Called when introduction has failed meaning there is no more usable
+ * introduction points to be used (either NACKed or failed) for the given
+ * entry connection.
+ *
+ * This function only reports back the SOCKS5_HS_INTRO_FAILED (0xF2) code or
+ * SOCKS5_HS_INTRO_TIMEDOUT (0xF7) if all intros have timed out. The caller
+ * has to make sure to close the entry connections. */
+static void
+socks_mark_introduction_failed(entry_connection_t *conn,
+ const ed25519_public_key_t *identity_pk)
+{
+ socks5_reply_status_t code = SOCKS5_HS_INTRO_FAILED;
+
+ tor_assert(conn);
+ tor_assert(conn->socks_request);
+ tor_assert(identity_pk);
+
+ if (intro_points_all_timed_out(identity_pk)) {
+ code = SOCKS5_HS_INTRO_TIMEDOUT;
+ }
+ conn->socks_request->socks_extended_error_code = code;
+}
+
/** For this introduction circuit, we'll look at if we have any usable
* introduction point left for this service. If so, we'll use the circuit to
* re-extend to a new intro point. Else, we'll close the circuit and its
@@ -1313,6 +1394,10 @@ client_desc_has_arrived(const smartlist_t *entry_conns)
if (!hs_client_any_intro_points_usable(identity_pk, desc)) {
log_info(LD_REND, "Hidden service descriptor is unusable. "
"Closing streams.");
+ /* Report the extended socks error code that we were unable to introduce
+ * to the service. */
+ socks_mark_introduction_failed(entry_conn, identity_pk);
+
connection_mark_unattached_ap(entry_conn,
END_STREAM_REASON_RESOLVEFAILED);
/* We are unable to use the descriptor so remove the directory request
@@ -1350,7 +1435,7 @@ client_desc_missing_bad_client_auth(const smartlist_t *entry_conns,
/* We should not be called with another type of status. Recover by
* sending a generic error. */
tor_assert_nonfatal_unreached();
- code = HS_DESC_DECODE_GENERIC_ERROR;
+ code = SOCKS5_GENERAL_ERROR;
}
entry_conn->socks_request->socks_extended_error_code = code;
connection_mark_unattached_ap(entry_conn, END_STREAM_REASON_MISC);
@@ -1762,6 +1847,37 @@ get_hs_client_auths_map(void)
/* ========== */
/** Called when a circuit was just cleaned up. This is done right before the
+ * circuit is marked for close. */
+void
+hs_client_circuit_cleanup_on_close(const circuit_t *circ)
+{
+ bool has_timed_out;
+
+ tor_assert(circ);
+ tor_assert(CIRCUIT_IS_ORIGIN(circ));
+
+ has_timed_out =
+ (circ->marked_for_close_orig_reason == END_CIRC_REASON_TIMEOUT);
+
+ switch (circ->purpose) {
+ case CIRCUIT_PURPOSE_C_ESTABLISH_REND:
+ case CIRCUIT_PURPOSE_C_REND_READY:
+ case CIRCUIT_PURPOSE_C_REND_READY_INTRO_ACKED:
+ case CIRCUIT_PURPOSE_C_REND_JOINED:
+ /* Report extended SOCKS error code when a rendezvous circuit times out.
+ * This MUST be done on_close() because it is possible the entry
+ * connection would get closed before the circuit is freed and thus
+ * would fail to report the error code. */
+ if (has_timed_out) {
+ socks_mark_rend_circuit_timed_out(CONST_TO_ORIGIN_CIRCUIT(circ));
+ }
+ break;
+ default:
+ break;
+ }
+}
+
+/** Called when a circuit was just cleaned up. This is done right before the
* circuit is freed. */
void
hs_client_circuit_cleanup_on_free(const circuit_t *circ)
@@ -2132,6 +2248,13 @@ parse_auth_file_content(const char *client_key_str)
"can't be decoded: %s", seckey_b32);
goto err;
}
+
+ if (fast_mem_is_zero((const char*)auth->enc_seckey.secret_key,
+ sizeof(auth->enc_seckey.secret_key))) {
+ log_warn(LD_REND, "Client authorization private key can't be all-zeroes");
+ goto err;
+ }
+
strncpy(auth->onion_address, onion_address, HS_SERVICE_ADDR_LEN_BASE32);
/* We are reading this from the disk, so set the permanent flag anyway. */
diff --git a/src/feature/hs/hs_client.h b/src/feature/hs/hs_client.h
index 3660bfa96c..a11caa309f 100644
--- a/src/feature/hs/hs_client.h
+++ b/src/feature/hs/hs_client.h
@@ -45,7 +45,7 @@ typedef enum {
REGISTER_SUCCESS_AND_DECRYPTED,
/* We failed to register these credentials, because of a bad HS address. */
REGISTER_FAIL_BAD_ADDRESS,
- /* We failed to register these credentials, because of a bad HS address. */
+ /* We failed to store these credentials in a persistent file on disk. */
REGISTER_FAIL_PERMANENT_STORAGE,
} hs_client_register_auth_status_t;
@@ -110,6 +110,7 @@ int hs_client_send_introduce1(origin_circuit_t *intro_circ,
origin_circuit_t *rend_circ);
void hs_client_circuit_has_opened(origin_circuit_t *circ);
+void hs_client_circuit_cleanup_on_close(const circuit_t *circ);
void hs_client_circuit_cleanup_on_free(const circuit_t *circ);
int hs_client_receive_rendezvous_acked(origin_circuit_t *circ,
diff --git a/src/feature/hs/hs_descriptor.c b/src/feature/hs/hs_descriptor.c
index a39a4a09c9..50a46fb40f 100644
--- a/src/feature/hs/hs_descriptor.c
+++ b/src/feature/hs/hs_descriptor.c
@@ -1429,11 +1429,15 @@ decrypt_descriptor_cookie(const hs_descriptor_t *desc,
tor_assert(!fast_mem_is_zero(
(char *) &desc->superencrypted_data.auth_ephemeral_pubkey,
sizeof(desc->superencrypted_data.auth_ephemeral_pubkey)));
- tor_assert(!fast_mem_is_zero((char *) client_auth_sk,
- sizeof(*client_auth_sk)));
tor_assert(!fast_mem_is_zero((char *) desc->subcredential.subcred,
DIGEST256_LEN));
+ /* Catch potential code-flow cases of an unitialized private key sneaking
+ * into this function. */
+ if (BUG(fast_mem_is_zero((char *)client_auth_sk, sizeof(*client_auth_sk)))) {
+ goto done;
+ }
+
/* Get the KEYS component to derive the CLIENT-ID and COOKIE-KEY. */
keystream_length =
build_descriptor_cookie_keys(&desc->subcredential,
diff --git a/src/feature/hs/hs_dos.c b/src/feature/hs/hs_dos.c
index b64ab0a1c3..1f7415a280 100644
--- a/src/feature/hs/hs_dos.c
+++ b/src/feature/hs/hs_dos.c
@@ -196,7 +196,9 @@ hs_dos_can_send_intro2(or_circuit_t *s_intro_circ)
goto allow;
}
- /* Fallthrough is to disallow since this means the bucket has reached 0. */
+ /* If we reach this point, then it means the bucket has reached zero, and
+ we're going to disallow. */
+
disallow:
/* Increment stats counter, we are rejecting the INTRO2 cell. */
intro2_rejected_count++;
diff --git a/src/feature/hs/hs_ob.c b/src/feature/hs/hs_ob.c
index f135ecd3f4..9499c28d20 100644
--- a/src/feature/hs/hs_ob.c
+++ b/src/feature/hs/hs_ob.c
@@ -159,8 +159,8 @@ ob_option_parse(hs_service_config_t *config, const ob_options_t *opts)
goto end;
}
smartlist_add(config->ob_master_pubkeys, pubkey);
- log_info(LD_REND, "OnionBalance: MasterOnionAddress %s registered",
- line->value);
+ log_notice(LD_REND, "OnionBalance: MasterOnionAddress %s registered",
+ line->value);
}
/* Success. */
ret = 1;
@@ -392,12 +392,12 @@ hs_ob_refresh_keys(hs_service_t *service)
}
/* Delete old subcredentials if any */
- if (service->ob_subcreds) {
- tor_free(service->ob_subcreds);
+ if (service->state.ob_subcreds) {
+ tor_free(service->state.ob_subcreds);
}
- service->ob_subcreds = ob_subcreds;
- service->n_ob_subcreds = num_subcreds;
+ service->state.ob_subcreds = ob_subcreds;
+ service->state.n_ob_subcreds = num_subcreds;
}
/** Free any memory allocated by the onionblance subsystem. */
diff --git a/src/feature/hs/hs_opts_st.h b/src/feature/hs/hs_opts_st.h
index f6ee0f3cfa..279f0d6da6 100644
--- a/src/feature/hs/hs_opts_st.h
+++ b/src/feature/hs/hs_opts_st.h
@@ -27,4 +27,4 @@
**/
typedef struct hs_opts_t hs_opts_t;
-#endif
+#endif /* !defined(TOR_FEATURE_HS_HS_OPTS_ST_H) */
diff --git a/src/feature/hs/hs_service.c b/src/feature/hs/hs_service.c
index 0a5cb4277c..5b8f661832 100644
--- a/src/feature/hs/hs_service.c
+++ b/src/feature/hs/hs_service.c
@@ -890,10 +890,18 @@ move_hs_state(hs_service_t *src_service, hs_service_t *dst_service)
if (dst->replay_cache_rend_cookie != NULL) {
replaycache_free(dst->replay_cache_rend_cookie);
}
+
dst->replay_cache_rend_cookie = src->replay_cache_rend_cookie;
+ src->replay_cache_rend_cookie = NULL; /* steal pointer reference */
+
dst->next_rotation_time = src->next_rotation_time;
- src->replay_cache_rend_cookie = NULL; /* steal pointer reference */
+ if (src->ob_subcreds) {
+ dst->ob_subcreds = src->ob_subcreds;
+ dst->n_ob_subcreds = src->n_ob_subcreds;
+
+ src->ob_subcreds = NULL; /* steal pointer reference */
+ }
}
/** Register services that are in the staging list. Once this function returns,
@@ -2838,7 +2846,7 @@ upload_descriptor_to_hsdir(const hs_service_t *service,
/* Let's avoid doing that if tor is configured to not publish. */
if (!get_options()->PublishHidServDescriptors) {
log_info(LD_REND, "Service %s not publishing descriptor. "
- "PublishHidServDescriptors is set to 1.",
+ "PublishHidServDescriptors is set to 0.",
safe_str_client(service->onion_address));
goto end;
}
@@ -4154,8 +4162,8 @@ hs_service_free_(hs_service_t *service)
}
/* Free onionbalance subcredentials (if any) */
- if (service->ob_subcreds) {
- tor_free(service->ob_subcreds);
+ if (service->state.ob_subcreds) {
+ tor_free(service->state.ob_subcreds);
}
/* Wipe service keys. */
diff --git a/src/feature/hs/hs_service.h b/src/feature/hs/hs_service.h
index 3fe14878ed..0f6a2c2358 100644
--- a/src/feature/hs/hs_service.h
+++ b/src/feature/hs/hs_service.h
@@ -279,6 +279,14 @@ typedef struct hs_service_state_t {
/** When is the next time we should rotate our descriptors. This is has to be
* done at the start time of the next SRV protocol run. */
time_t next_rotation_time;
+
+ /* If this is an onionbalance instance, this is an array of subcredentials
+ * that should be used when decrypting an INTRO2 cell. If this is not an
+ * onionbalance instance, this is NULL.
+ * See [ONIONBALANCE] section in rend-spec-v3.txt for more details . */
+ hs_subcredential_t *ob_subcreds;
+ /* Number of OB subcredentials */
+ size_t n_ob_subcreds;
} hs_service_state_t;
/** Representation of a service running on this tor instance. */
@@ -304,14 +312,6 @@ typedef struct hs_service_t {
hs_service_descriptor_t *desc_current;
/** Next descriptor. */
hs_service_descriptor_t *desc_next;
-
- /* If this is an onionbalance instance, this is an array of subcredentials
- * that should be used when decrypting an INTRO2 cell. If this is not an
- * onionbalance instance, this is NULL.
- * See [ONIONBALANCE] section in rend-spec-v3.txt for more details . */
- hs_subcredential_t *ob_subcreds;
- /* Number of OB subcredentials */
- size_t n_ob_subcreds;
} hs_service_t;
/** For the service global hash map, we define a specific type for it which
diff --git a/src/feature/nodelist/dirlist.c b/src/feature/nodelist/dirlist.c
index ad3af0a143..d7069bb0ec 100644
--- a/src/feature/nodelist/dirlist.c
+++ b/src/feature/nodelist/dirlist.c
@@ -27,6 +27,7 @@
#include "core/or/or.h"
#include "app/config/config.h"
+#include "app/config/resolve_addr.h"
#include "core/or/policies.h"
#include "feature/control/control_events.h"
#include "feature/dirauth/authmode.h"
diff --git a/src/feature/nodelist/nodelist.c b/src/feature/nodelist/nodelist.c
index fcf27b1a3a..7454f342f9 100644
--- a/src/feature/nodelist/nodelist.c
+++ b/src/feature/nodelist/nodelist.c
@@ -1074,8 +1074,8 @@ node_get_by_nickname,(const char *nickname, unsigned flags))
/** Return the Ed25519 identity key for the provided node, or NULL if it
* doesn't have one. */
-const ed25519_public_key_t *
-node_get_ed25519_id(const node_t *node)
+MOCK_IMPL(const ed25519_public_key_t *,
+node_get_ed25519_id,(const node_t *node))
{
const ed25519_public_key_t *ri_pk = NULL;
const ed25519_public_key_t *md_pk = NULL;
@@ -1158,9 +1158,9 @@ node_get_protover_summary_flags(const node_t *node)
* by ed25519 ID during the link handshake. If <b>compatible_with_us</b>,
* it needs to be using a link authentication method that we understand.
* If not, any plausible link authentication method will do. */
-int
-node_supports_ed25519_link_authentication(const node_t *node,
- int compatible_with_us)
+MOCK_IMPL(int,
+node_supports_ed25519_link_authentication,(const node_t *node,
+ int compatible_with_us))
{
if (! node_get_ed25519_id(node))
return 0;
diff --git a/src/feature/nodelist/nodelist.h b/src/feature/nodelist/nodelist.h
index 6e854ec879..57ab2d5913 100644
--- a/src/feature/nodelist/nodelist.h
+++ b/src/feature/nodelist/nodelist.h
@@ -70,11 +70,13 @@ const char *node_get_platform(const node_t *node);
uint32_t node_get_prim_addr_ipv4h(const node_t *node);
void node_get_address_string(const node_t *node, char *cp, size_t len);
long node_get_declared_uptime(const node_t *node);
-const struct ed25519_public_key_t *node_get_ed25519_id(const node_t *node);
+MOCK_DECL(const struct ed25519_public_key_t *,node_get_ed25519_id,
+ (const node_t *node));
int node_ed25519_id_matches(const node_t *node,
const struct ed25519_public_key_t *id);
-int node_supports_ed25519_link_authentication(const node_t *node,
- int compatible_with_us);
+MOCK_DECL(int,node_supports_ed25519_link_authentication,
+ (const node_t *node,
+ int compatible_with_us));
int node_supports_v3_hsdir(const node_t *node);
int node_supports_ed25519_hs_intro(const node_t *node);
int node_supports_v3_rendezvous_point(const node_t *node);
diff --git a/src/feature/nodelist/routerinfo_st.h b/src/feature/nodelist/routerinfo_st.h
index e54a444ec4..36ead50e33 100644
--- a/src/feature/nodelist/routerinfo_st.h
+++ b/src/feature/nodelist/routerinfo_st.h
@@ -26,9 +26,6 @@ struct routerinfo_t {
uint16_t dir_port; /**< Port for HTTP directory connections. */
/** A router's IPv6 address, if it has one. */
- /* XXXXX187 Actually these should probably be part of a list of addresses,
- * not just a special case. Use abstractions to access these; don't do it
- * directly. */
tor_addr_t ipv6_addr;
uint16_t ipv6_orport;
diff --git a/src/feature/relay/circuitbuild_relay.c b/src/feature/relay/circuitbuild_relay.c
new file mode 100644
index 0000000000..b89866b477
--- /dev/null
+++ b/src/feature/relay/circuitbuild_relay.c
@@ -0,0 +1,549 @@
+/* Copyright (c) 2001 Matej Pfajfar.
+ * Copyright (c) 2001-2004, Roger Dingledine.
+ * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
+ * Copyright (c) 2007-2020, The Tor Project, Inc. */
+/* See LICENSE for licensing information */
+
+/**
+ * @file circuitbuild_relay.c
+ * @brief Implements the details of exteding circuits (by relaying extend
+ * cells as create cells, and answering create cells).
+ *
+ * On the server side, this module handles the logic of responding to
+ * RELAY_EXTEND requests, using circuit_extend() and onionskin_answer().
+ *
+ * The shared client and server code is in core/or/circuitbuild.c.
+ **/
+
+#include "orconfig.h"
+#include "feature/relay/circuitbuild_relay.h"
+
+#include "lib/crypt_ops/crypto_rand.h"
+
+#include "core/or/or.h"
+#include "app/config/config.h"
+
+#include "core/crypto/relay_crypto.h"
+
+#include "core/or/cell_st.h"
+#include "core/or/circuit_st.h"
+#include "core/or/extend_info_st.h"
+#include "core/or/or_circuit_st.h"
+
+#include "core/or/channel.h"
+#include "core/or/circuitbuild.h"
+#include "core/or/circuitlist.h"
+#include "core/or/onion.h"
+#include "core/or/relay.h"
+
+#include "feature/nodelist/nodelist.h"
+
+#include "feature/relay/router.h"
+#include "feature/relay/routermode.h"
+#include "feature/relay/selftest.h"
+
+/* Before replying to an extend cell, check the state of the circuit
+ * <b>circ</b>, and the configured tor mode.
+ *
+ * <b>circ</b> must not be NULL.
+ *
+ * If the state and mode are valid, return 0.
+ * Otherwise, if they are invalid, log a protocol warning, and return -1.
+ */
+STATIC int
+circuit_extend_state_valid_helper(const struct circuit_t *circ)
+{
+ if (!server_mode(get_options())) {
+ circuitbuild_warn_client_extend();
+ return -1;
+ }
+
+ IF_BUG_ONCE(!circ) {
+ return -1;
+ }
+
+ if (circ->n_chan) {
+ log_fn(LOG_PROTOCOL_WARN, LD_PROTOCOL,
+ "n_chan already set. Bug/attack. Closing.");
+ return -1;
+ }
+
+ if (circ->n_hop) {
+ log_fn(LOG_PROTOCOL_WARN, LD_PROTOCOL,
+ "conn to next hop already launched. Bug/attack. Closing.");
+ return -1;
+ }
+
+ return 0;
+}
+
+/* Make sure the extend cell <b>ec</b> has an ed25519 link specifier.
+ *
+ * First, check that the RSA node id is valid.
+ * If the node id is valid, add the ed25519 link specifier (if required),
+ * and return 0.
+ *
+ * Otherwise, if the node id is invalid, log a protocol warning,
+ * and return -1.(And do not modify the extend cell.)
+ *
+ * Must be called before circuit_extend_lspec_valid_helper().
+ */
+STATIC int
+circuit_extend_add_ed25519_helper(struct extend_cell_t *ec)
+{
+ IF_BUG_ONCE(!ec) {
+ return -1;
+ }
+
+ /* Check if they asked us for 0000..0000. We support using
+ * an empty fingerprint for the first hop (e.g. for a bridge relay),
+ * but we don't want to let clients send us extend cells for empty
+ * fingerprints -- a) because it opens the user up to a mitm attack,
+ * and b) because it lets an attacker force the relay to hold open a
+ * new TLS connection for each extend request. */
+ if (tor_digest_is_zero((const char*)ec->node_id)) {
+ log_fn(LOG_PROTOCOL_WARN, LD_PROTOCOL,
+ "Client asked me to extend without specifying an id_digest.");
+ return -1;
+ }
+
+ /* Fill in ed_pubkey if it was not provided and we can infer it from
+ * our networkstatus */
+ if (ed25519_public_key_is_zero(&ec->ed_pubkey)) {
+ const node_t *node = node_get_by_id((const char*)ec->node_id);
+ const ed25519_public_key_t *node_ed_id = NULL;
+ if (node &&
+ node_supports_ed25519_link_authentication(node, 1) &&
+ (node_ed_id = node_get_ed25519_id(node))) {
+ ed25519_pubkey_copy(&ec->ed_pubkey, node_ed_id);
+ }
+ }
+
+ return 0;
+}
+
+/* Check if the address and port in the tor_addr_port_t <b>ap</b> are valid,
+ * and are allowed by the current ExtendAllowPrivateAddresses config.
+ *
+ * If they are valid, return true.
+ * Otherwise, if they are invalid, return false.
+ *
+ * If <b>log_zero_addrs</b> is true, log warnings about zero addresses at
+ * <b>log_level</b>. If <b>log_internal_addrs</b> is true, log warnings about
+ * internal addresses at <b>log_level</b>.
+ */
+static bool
+circuit_extend_addr_port_is_valid(const struct tor_addr_port_t *ap,
+ bool log_zero_addrs, bool log_internal_addrs,
+ int log_level)
+{
+ /* It's safe to print the family. But we don't want to print the address,
+ * unless specifically configured to do so. (Zero addresses aren't sensitive,
+ * But some internal addresses might be.)*/
+
+ if (!tor_addr_port_is_valid_ap(ap, 0)) {
+ if (log_zero_addrs) {
+ log_fn(log_level, LD_PROTOCOL,
+ "Client asked me to extend to a zero destination port or "
+ "%s address '%s'.",
+ fmt_addr_family(&ap->addr), safe_str(fmt_addrport_ap(ap)));
+ }
+ return false;
+ }
+
+ if (tor_addr_is_internal(&ap->addr, 0) &&
+ !get_options()->ExtendAllowPrivateAddresses) {
+ if (log_internal_addrs) {
+ log_fn(log_level, LD_PROTOCOL,
+ "Client asked me to extend to a private %s address '%s'.",
+ fmt_addr_family(&ap->addr),
+ safe_str(fmt_and_decorate_addr(&ap->addr)));
+ }
+ return false;
+ }
+
+ return true;
+}
+
+/* Before replying to an extend cell, check the link specifiers in the extend
+ * cell <b>ec</b>, which was received on the circuit <b>circ</b>.
+ *
+ * If they are valid, return 0.
+ * Otherwise, if they are invalid, log a protocol warning, and return -1.
+ *
+ * Must be called after circuit_extend_add_ed25519_helper().
+ */
+STATIC int
+circuit_extend_lspec_valid_helper(const struct extend_cell_t *ec,
+ const struct circuit_t *circ)
+{
+ IF_BUG_ONCE(!ec) {
+ return -1;
+ }
+
+ IF_BUG_ONCE(!circ) {
+ return -1;
+ }
+
+ /* Check the addresses, without logging */
+ const int ipv4_valid = circuit_extend_addr_port_is_valid(&ec->orport_ipv4,
+ false, false, 0);
+ const int ipv6_valid = circuit_extend_addr_port_is_valid(&ec->orport_ipv6,
+ false, false, 0);
+ /* We need at least one valid address */
+ if (!ipv4_valid && !ipv6_valid) {
+ /* Now, log the invalid addresses at protocol warning level */
+ circuit_extend_addr_port_is_valid(&ec->orport_ipv4,
+ true, true, LOG_PROTOCOL_WARN);
+ circuit_extend_addr_port_is_valid(&ec->orport_ipv6,
+ true, true, LOG_PROTOCOL_WARN);
+ /* And fail */
+ return -1;
+ } else if (!ipv4_valid) {
+ /* Always log unexpected internal addresses, but go on to use the other
+ * valid address */
+ circuit_extend_addr_port_is_valid(&ec->orport_ipv4,
+ false, true, LOG_PROTOCOL_WARN);
+ } else if (!ipv6_valid) {
+ circuit_extend_addr_port_is_valid(&ec->orport_ipv6,
+ false, true, LOG_PROTOCOL_WARN);
+ }
+
+ IF_BUG_ONCE(circ->magic != OR_CIRCUIT_MAGIC) {
+ return -1;
+ }
+
+ const channel_t *p_chan = CONST_TO_OR_CIRCUIT(circ)->p_chan;
+
+ IF_BUG_ONCE(!p_chan) {
+ return -1;
+ }
+
+ /* Next, check if we're being asked to connect to the hop that the
+ * extend cell came from. There isn't any reason for that, and it can
+ * assist circular-path attacks. */
+ if (tor_memeq(ec->node_id, p_chan->identity_digest, DIGEST_LEN)) {
+ log_fn(LOG_PROTOCOL_WARN, LD_PROTOCOL,
+ "Client asked me to extend back to the previous hop.");
+ return -1;
+ }
+
+ /* Check the previous hop Ed25519 ID too */
+ if (! ed25519_public_key_is_zero(&ec->ed_pubkey) &&
+ ed25519_pubkey_eq(&ec->ed_pubkey, &p_chan->ed25519_identity)) {
+ log_fn(LOG_PROTOCOL_WARN, LD_PROTOCOL,
+ "Client asked me to extend back to the previous hop "
+ "(by Ed25519 ID).");
+ return -1;
+ }
+
+ return 0;
+}
+
+/* If possible, return a supported, non-NULL IP address.
+ *
+ * If both addresses are supported and non-NULL, choose one uniformly at
+ * random.
+ *
+ * If we have an IPv6-only extend, but IPv6 is not supported, returns NULL.
+ * If both addresses are NULL, also returns NULL. */
+STATIC const tor_addr_port_t *
+circuit_choose_ip_ap_for_extend(const tor_addr_port_t *ipv4_ap,
+ const tor_addr_port_t *ipv6_ap)
+{
+ const bool ipv6_supported = router_can_extend_over_ipv6(get_options());
+
+ /* If IPv6 is not supported, we can't use the IPv6 address. */
+ if (!ipv6_supported) {
+ ipv6_ap = NULL;
+ }
+
+ /* If there is no IPv6 address, IPv4 is always supported.
+ * Until clients include IPv6 ORPorts, and most relays support IPv6,
+ * this is the most common case. */
+ if (!ipv6_ap) {
+ return ipv4_ap;
+ }
+
+ /* If there is no IPv4 address, return the (possibly NULL) IPv6 address. */
+ if (!ipv4_ap) {
+ return ipv6_ap;
+ }
+
+ /* Now we have an IPv4 and an IPv6 address, and IPv6 is supported.
+ * So make an IPv6 connection at random, with probability 1 in N.
+ * 1 means "always IPv6 (and no IPv4)"
+ * 2 means "equal probability of IPv4 or IPv6"
+ * ... (and so on) ...
+ * (UINT_MAX - 1) means "almost always IPv4 (and almost never IPv6)"
+ * To disable IPv6, set ipv6_supported to 0.
+ */
+#define IPV6_CONNECTION_ONE_IN_N 2
+
+ bool choose_ipv6 = crypto_fast_rng_one_in_n(get_thread_fast_rng(),
+ IPV6_CONNECTION_ONE_IN_N);
+ if (choose_ipv6) {
+ return ipv6_ap;
+ } else {
+ return ipv4_ap;
+ }
+}
+
+/* When there is no open channel for an extend cell <b>ec</b>, set up the
+ * circuit <b>circ</b> to wait for a new connection.
+ *
+ * If <b>should_launch</b> is true, open a new connection. (Otherwise, we are
+ * already waiting for a new connection to the same relay.)
+ *
+ * Check if IPv6 extends are supported by our current configuration. If they
+ * are, new connections may be made over IPv4 or IPv6. (IPv4 connections are
+ * always supported.)
+ */
+STATIC void
+circuit_open_connection_for_extend(const struct extend_cell_t *ec,
+ struct circuit_t *circ,
+ int should_launch)
+{
+ /* We have to check circ first, so we can close it on all other failures */
+ IF_BUG_ONCE(!circ) {
+ /* We can't mark a NULL circuit for close. */
+ return;
+ }
+
+ /* Now we know that circ is not NULL */
+ IF_BUG_ONCE(!ec) {
+ circuit_mark_for_close(circ, END_CIRC_REASON_CONNECTFAILED);
+ return;
+ }
+
+ /* Check the addresses, without logging */
+ const int ipv4_valid = circuit_extend_addr_port_is_valid(&ec->orport_ipv4,
+ false, false, 0);
+ const int ipv6_valid = circuit_extend_addr_port_is_valid(&ec->orport_ipv6,
+ false, false, 0);
+
+ IF_BUG_ONCE(!ipv4_valid && !ipv6_valid) {
+ /* circuit_extend_lspec_valid_helper() should have caught this */
+ circuit_mark_for_close(circ, END_CIRC_REASON_CONNECTFAILED);
+ return;
+ }
+
+ const tor_addr_port_t *chosen_ap = circuit_choose_ip_ap_for_extend(
+ ipv4_valid ? &ec->orport_ipv4 : NULL,
+ ipv6_valid ? &ec->orport_ipv6 : NULL);
+ if (!chosen_ap) {
+ /* An IPv6-only extend, but IPv6 is not supported */
+ log_fn(LOG_PROTOCOL_WARN, LD_PROTOCOL,
+ "Received IPv6-only extend, but we don't have an IPv6 ORPort.");
+ circuit_mark_for_close(circ, END_CIRC_REASON_CONNECTFAILED);
+ return;
+ }
+
+ circ->n_hop = extend_info_new(NULL /*nickname*/,
+ (const char*)ec->node_id,
+ &ec->ed_pubkey,
+ NULL, /*onion_key*/
+ NULL, /*curve25519_key*/
+ &chosen_ap->addr,
+ chosen_ap->port);
+
+ circ->n_chan_create_cell = tor_memdup(&ec->create_cell,
+ sizeof(ec->create_cell));
+
+ circuit_set_state(circ, CIRCUIT_STATE_CHAN_WAIT);
+
+ if (should_launch) {
+ /* we should try to open a connection */
+ channel_t *n_chan = channel_connect_for_circuit(
+ &circ->n_hop->addr,
+ circ->n_hop->port,
+ circ->n_hop->identity_digest,
+ &circ->n_hop->ed_identity);
+ if (!n_chan) {
+ log_info(LD_CIRC,"Launching n_chan failed. Closing circuit.");
+ circuit_mark_for_close(circ, END_CIRC_REASON_CONNECTFAILED);
+ return;
+ }
+ log_debug(LD_CIRC,"connecting in progress (or finished). Good.");
+ }
+}
+
+/** Take the 'extend' <b>cell</b>, pull out addr/port plus the onion
+ * skin and identity digest for the next hop. If we're already connected,
+ * pass the onion skin to the next hop using a create cell; otherwise
+ * launch a new OR connection, and <b>circ</b> will notice when the
+ * connection succeeds or fails.
+ *
+ * Return -1 if we want to warn and tear down the circuit, else return 0.
+ */
+int
+circuit_extend(struct cell_t *cell, struct circuit_t *circ)
+{
+ channel_t *n_chan;
+ relay_header_t rh;
+ extend_cell_t ec;
+ const char *msg = NULL;
+ int should_launch = 0;
+
+ IF_BUG_ONCE(!cell) {
+ return -1;
+ }
+
+ IF_BUG_ONCE(!circ) {
+ return -1;
+ }
+
+ if (circuit_extend_state_valid_helper(circ) < 0)
+ return -1;
+
+ relay_header_unpack(&rh, cell->payload);
+
+ if (extend_cell_parse(&ec, rh.command,
+ cell->payload+RELAY_HEADER_SIZE,
+ rh.length) < 0) {
+ log_fn(LOG_PROTOCOL_WARN, LD_PROTOCOL,
+ "Can't parse extend cell. Closing circuit.");
+ return -1;
+ }
+
+ if (circuit_extend_add_ed25519_helper(&ec) < 0)
+ return -1;
+
+ if (circuit_extend_lspec_valid_helper(&ec, circ) < 0)
+ return -1;
+
+ /* Check the addresses, without logging */
+ const int ipv4_valid = circuit_extend_addr_port_is_valid(&ec.orport_ipv4,
+ false, false, 0);
+ const int ipv6_valid = circuit_extend_addr_port_is_valid(&ec.orport_ipv6,
+ false, false, 0);
+ IF_BUG_ONCE(!ipv4_valid && !ipv6_valid) {
+ /* circuit_extend_lspec_valid_helper() should have caught this */
+ return -1;
+ }
+
+ n_chan = channel_get_for_extend((const char*)ec.node_id,
+ &ec.ed_pubkey,
+ ipv4_valid ? &ec.orport_ipv4.addr : NULL,
+ ipv6_valid ? &ec.orport_ipv6.addr : NULL,
+ &msg,
+ &should_launch);
+
+ if (!n_chan) {
+ /* We can't use fmt_addr*() twice in the same function call,
+ * because it uses a static buffer. */
+ log_debug(LD_CIRC|LD_OR, "Next router IPv4 (%s): %s.",
+ fmt_addrport_ap(&ec.orport_ipv4),
+ msg ? msg : "????");
+ log_debug(LD_CIRC|LD_OR, "Next router IPv6 (%s).",
+ fmt_addrport_ap(&ec.orport_ipv6));
+
+ circuit_open_connection_for_extend(&ec, circ, should_launch);
+
+ /* return success. The onion/circuit/etc will be taken care of
+ * automatically (may already have been) whenever n_chan reaches
+ * OR_CONN_STATE_OPEN.
+ */
+ return 0;
+ } else {
+ /* Connection is already established.
+ * So we need to extend the circuit to the next hop. */
+ tor_assert(!circ->n_hop);
+ circ->n_chan = n_chan;
+ log_debug(LD_CIRC,
+ "n_chan is %s.",
+ channel_get_canonical_remote_descr(n_chan));
+
+ if (circuit_deliver_create_cell(circ, &ec.create_cell, 1) < 0)
+ return -1;
+
+ return 0;
+ }
+}
+
+/** On a relay, accept a create cell, initialise a circuit, and send a
+ * created cell back.
+ *
+ * Given:
+ * - a response payload consisting of:
+ * - the <b>created_cell</b> and
+ * - an optional <b>rend_circ_nonce</b>, and
+ * - <b>keys</b> of length <b>keys_len</b>, which must be
+ * CPATH_KEY_MATERIAL_LEN;
+ * then:
+ * - initialize the circuit <b>circ</b>'s cryptographic material,
+ * - set the circuit's state to open, and
+ * - send a created cell back on that circuit.
+ *
+ * If we haven't found our ORPorts reachable yet, and the channel meets the
+ * necessary conditions, mark the relevant ORPorts as reachable.
+ *
+ * Returns -1 if cell or circuit initialisation fails.
+ */
+int
+onionskin_answer(struct or_circuit_t *circ,
+ const created_cell_t *created_cell,
+ const char *keys, size_t keys_len,
+ const uint8_t *rend_circ_nonce)
+{
+ cell_t cell;
+
+ IF_BUG_ONCE(!circ) {
+ return -1;
+ }
+
+ IF_BUG_ONCE(!created_cell) {
+ return -1;
+ }
+
+ IF_BUG_ONCE(!keys) {
+ return -1;
+ }
+
+ IF_BUG_ONCE(!rend_circ_nonce) {
+ return -1;
+ }
+
+ tor_assert(keys_len == CPATH_KEY_MATERIAL_LEN);
+
+ if (created_cell_format(&cell, created_cell) < 0) {
+ log_warn(LD_BUG,"couldn't format created cell (type=%d, len=%d).",
+ (int)created_cell->cell_type, (int)created_cell->handshake_len);
+ return -1;
+ }
+ cell.circ_id = circ->p_circ_id;
+
+ 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 (relay_crypto_init(&circ->crypto, keys, keys_len, 0, 0)<0) {
+ log_warn(LD_BUG,"Circuit initialization failed.");
+ return -1;
+ }
+
+ memcpy(circ->rend_circ_nonce, rend_circ_nonce, DIGEST_LEN);
+
+ int used_create_fast = (created_cell->cell_type == CELL_CREATED_FAST);
+
+ append_cell_to_circuit_queue(TO_CIRCUIT(circ),
+ circ->p_chan, &cell, CELL_DIRECTION_IN, 0);
+ log_debug(LD_CIRC,"Finished sending '%s' cell.",
+ used_create_fast ? "created_fast" : "created");
+
+ /* Ignore the local bit when ExtendAllowPrivateAddresses is set:
+ * it violates the assumption that private addresses are local.
+ * Also, many test networks run on local addresses, and
+ * TestingTorNetwork sets ExtendAllowPrivateAddresses. */
+ if ((!channel_is_local(circ->p_chan)
+ || get_options()->ExtendAllowPrivateAddresses)
+ && !channel_is_outgoing(circ->p_chan)) {
+ /* record that we could process create cells from a non-local conn
+ * that we didn't initiate; presumably this means that create cells
+ * can reach us too. */
+ router_orport_found_reachable();
+ }
+
+ return 0;
+}
diff --git a/src/feature/relay/circuitbuild_relay.h b/src/feature/relay/circuitbuild_relay.h
new file mode 100644
index 0000000000..0783161538
--- /dev/null
+++ b/src/feature/relay/circuitbuild_relay.h
@@ -0,0 +1,87 @@
+/* Copyright (c) 2001 Matej Pfajfar.
+ * Copyright (c) 2001-2004, Roger Dingledine.
+ * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
+ * Copyright (c) 2007-2020, The Tor Project, Inc. */
+/* See LICENSE for licensing information */
+
+/**
+ * @file circuitbuild_relay.h
+ * @brief Header for feature/relay/circuitbuild_relay.c
+ **/
+
+#ifndef TOR_FEATURE_RELAY_CIRCUITBUILD_RELAY_H
+#define TOR_FEATURE_RELAY_CIRCUITBUILD_RELAY_H
+
+#include "lib/cc/torint.h"
+#include "lib/log/log.h"
+
+#include "app/config/config.h"
+
+struct cell_t;
+struct created_cell_t;
+
+struct circuit_t;
+struct or_circuit_t;
+struct extend_cell_t;
+
+/* Log a protocol warning about getting an extend cell on a client. */
+static inline void
+circuitbuild_warn_client_extend(void)
+{
+ log_fn(LOG_PROTOCOL_WARN, LD_PROTOCOL,
+ "Got an extend cell, but running as a client. Closing.");
+}
+
+#ifdef HAVE_MODULE_RELAY
+
+int circuit_extend(struct cell_t *cell, struct circuit_t *circ);
+
+int onionskin_answer(struct or_circuit_t *circ,
+ const struct created_cell_t *created_cell,
+ const char *keys, size_t keys_len,
+ const uint8_t *rend_circ_nonce);
+
+#else /* !defined(HAVE_MODULE_RELAY) */
+
+static inline int
+circuit_extend(struct cell_t *cell, struct circuit_t *circ)
+{
+ (void)cell;
+ (void)circ;
+ circuitbuild_warn_client_extend();
+ return -1;
+}
+
+static inline int
+onionskin_answer(struct or_circuit_t *circ,
+ const struct created_cell_t *created_cell,
+ const char *keys, size_t keys_len,
+ const uint8_t *rend_circ_nonce)
+{
+ (void)circ;
+ (void)created_cell;
+ (void)keys;
+ (void)keys_len;
+ (void)rend_circ_nonce;
+ tor_assert_nonfatal_unreached();
+ return -1;
+}
+
+#endif /* defined(HAVE_MODULE_RELAY) */
+
+#ifdef TOR_UNIT_TESTS
+
+STATIC int circuit_extend_state_valid_helper(const struct circuit_t *circ);
+STATIC int circuit_extend_add_ed25519_helper(struct extend_cell_t *ec);
+STATIC int circuit_extend_lspec_valid_helper(const struct extend_cell_t *ec,
+ const struct circuit_t *circ);
+STATIC const tor_addr_port_t * circuit_choose_ip_ap_for_extend(
+ const tor_addr_port_t *ipv4_ap,
+ const tor_addr_port_t *ipv6_ap);
+STATIC void circuit_open_connection_for_extend(const struct extend_cell_t *ec,
+ struct circuit_t *circ,
+ int should_launch);
+
+#endif /* defined(TOR_UNIT_TESTS) */
+
+#endif /* !defined(TOR_FEATURE_RELAY_CIRCUITBUILD_RELAY_H) */
diff --git a/src/feature/relay/dns.c b/src/feature/relay/dns.c
index 5f868a9020..4dcf5b7031 100644
--- a/src/feature/relay/dns.c
+++ b/src/feature/relay/dns.c
@@ -530,9 +530,9 @@ send_resolved_cell,(edge_connection_t *conn, uint8_t answer_type,
break;
} else {
answer_type = RESOLVED_TYPE_ERROR;
- /* fall through. */
+ /* We let this fall through and treat it as an error. */
}
- /* Falls through. */
+ FALLTHROUGH;
case RESOLVED_TYPE_ERROR_TRANSIENT:
case RESOLVED_TYPE_ERROR:
{
diff --git a/src/feature/relay/include.am b/src/feature/relay/include.am
index 813ddb8fb1..84bb1ff35e 100644
--- a/src/feature/relay/include.am
+++ b/src/feature/relay/include.am
@@ -2,12 +2,14 @@
# Legacy shared relay code: migrate to the relay module over time
LIBTOR_APP_A_SOURCES += \
src/feature/relay/onion_queue.c \
+ src/feature/relay/relay_find_addr.c \
src/feature/relay/router.c
# The Relay module.
# ADD_C_FILE: INSERT SOURCES HERE.
MODULE_RELAY_SOURCES = \
+ src/feature/relay/circuitbuild_relay.c \
src/feature/relay/dns.c \
src/feature/relay/ext_orport.c \
src/feature/relay/routermode.c \
@@ -21,6 +23,7 @@ MODULE_RELAY_SOURCES = \
# ADD_C_FILE: INSERT HEADERS HERE.
noinst_HEADERS += \
+ src/feature/relay/circuitbuild_relay.h \
src/feature/relay/dns.h \
src/feature/relay/dns_structs.h \
src/feature/relay/ext_orport.h \
@@ -29,6 +32,7 @@ noinst_HEADERS += \
src/feature/relay/relay_handshake.h \
src/feature/relay/relay_periodic.h \
src/feature/relay/relay_sys.h \
+ src/feature/relay/relay_find_addr.h \
src/feature/relay/router.h \
src/feature/relay/routerkeys.h \
src/feature/relay/routermode.h \
diff --git a/src/feature/relay/relay_config.c b/src/feature/relay/relay_config.c
index 3e9961f47e..fac6a2f577 100644
--- a/src/feature/relay/relay_config.c
+++ b/src/feature/relay/relay_config.c
@@ -29,7 +29,6 @@
#include "core/mainloop/connection.h"
#include "core/mainloop/cpuworker.h"
#include "core/mainloop/mainloop.h"
-#include "core/or/circuitbuild.h"
#include "core/or/connection_or.h"
#include "core/or/port_cfg_st.h"
@@ -44,6 +43,7 @@
#include "feature/dircache/consdiffmgr.h"
#include "feature/relay/dns.h"
#include "feature/relay/routermode.h"
+#include "feature/relay/selftest.h"
/** Contents of most recently read DirPortFrontPage file. */
static char *global_dirfrontpagecontents = NULL;
diff --git a/src/feature/relay/relay_find_addr.c b/src/feature/relay/relay_find_addr.c
new file mode 100644
index 0000000000..86cd799d42
--- /dev/null
+++ b/src/feature/relay/relay_find_addr.c
@@ -0,0 +1,133 @@
+/* Copyright (c) 2001-2020, The Tor Project, Inc. */
+/* See LICENSE for licensing information */
+
+/**
+ * \file relay_find_addr.c
+ * \brief Implement mechanism for a relay to find its address.
+ **/
+
+#include "core/or/or.h"
+
+#include "app/config/config.h"
+#include "app/config/resolve_addr.h"
+
+#include "core/mainloop/mainloop.h"
+
+#include "feature/control/control_events.h"
+#include "feature/dircommon/dir_connection_st.h"
+#include "feature/relay/relay_find_addr.h"
+#include "feature/relay/router.h"
+#include "feature/relay/routermode.h"
+
+/** The most recently guessed value of our IP address, based on directory
+ * headers. */
+static tor_addr_t last_guessed_ip = TOR_ADDR_NULL;
+
+/** We failed to resolve our address locally, but we'd like to build
+ * a descriptor and publish / test reachability. If we have a guess
+ * about our address based on directory headers, answer it and return
+ * 0; else return -1. */
+static int
+router_guess_address_from_dir_headers(uint32_t *guess)
+{
+ if (!tor_addr_is_null(&last_guessed_ip)) {
+ *guess = tor_addr_to_ipv4h(&last_guessed_ip);
+ return 0;
+ }
+ return -1;
+}
+
+/** A directory server <b>d_conn</b> told us our IP address is
+ * <b>suggestion</b>.
+ * If this address is different from the one we think we are now, and
+ * if our computer doesn't actually know its IP address, then switch. */
+void
+router_new_address_suggestion(const char *suggestion,
+ const dir_connection_t *d_conn)
+{
+ tor_addr_t addr;
+ uint32_t cur = 0; /* Current IPv4 address. */
+ const or_options_t *options = get_options();
+
+ /* first, learn what the IP address actually is */
+ if (tor_addr_parse(&addr, suggestion) == -1) {
+ log_debug(LD_DIR, "Malformed X-Your-Address-Is header %s. Ignoring.",
+ escaped(suggestion));
+ return;
+ }
+
+ log_debug(LD_DIR, "Got X-Your-Address-Is: %s.", suggestion);
+
+ if (!server_mode(options)) {
+ tor_addr_copy(&last_guessed_ip, &addr);
+ return;
+ }
+
+ /* XXXX ipv6 */
+ cur = get_last_resolved_addr();
+ if (cur ||
+ resolve_my_address(LOG_INFO, options, &cur, NULL, NULL) >= 0) {
+ /* We're all set -- we already know our address. Great. */
+ tor_addr_from_ipv4h(&last_guessed_ip, cur); /* store it in case we
+ need it later */
+ return;
+ }
+ if (tor_addr_is_internal(&addr, 0)) {
+ /* Don't believe anybody who says our IP is, say, 127.0.0.1. */
+ return;
+ }
+ if (tor_addr_eq(&d_conn->base_.addr, &addr)) {
+ /* Don't believe anybody who says our IP is their IP. */
+ log_debug(LD_DIR, "A directory server told us our IP address is %s, "
+ "but they are just reporting their own IP address. Ignoring.",
+ suggestion);
+ return;
+ }
+
+ /* Okay. We can't resolve our own address, and X-Your-Address-Is is giving
+ * us an answer different from what we had the last time we managed to
+ * resolve it. */
+ if (!tor_addr_eq(&last_guessed_ip, &addr)) {
+ control_event_server_status(LOG_NOTICE,
+ "EXTERNAL_ADDRESS ADDRESS=%s METHOD=DIRSERV",
+ suggestion);
+ log_addr_has_changed(LOG_NOTICE, &last_guessed_ip, &addr,
+ d_conn->base_.address);
+ ip_address_changed(0);
+ tor_addr_copy(&last_guessed_ip, &addr); /* router_rebuild_descriptor()
+ will fetch it */
+ }
+}
+
+/** Make a current best guess at our address, either because
+ * it's configured in torrc, or because we've learned it from
+ * dirserver headers. Place the answer in *<b>addr</b> and return
+ * 0 on success, else return -1 if we have no guess.
+ *
+ * If <b>cache_only</b> is true, just return any cached answers, and
+ * don't try to get any new answers.
+ */
+MOCK_IMPL(int,
+router_pick_published_address, (const or_options_t *options, uint32_t *addr,
+ int cache_only))
+{
+ /* First, check the cached output from resolve_my_address(). */
+ *addr = get_last_resolved_addr();
+ if (*addr)
+ return 0;
+
+ /* Second, consider doing a resolve attempt right here. */
+ if (!cache_only) {
+ if (resolve_my_address(LOG_INFO, options, addr, NULL, NULL) >= 0) {
+ log_info(LD_CONFIG,"Success: chose address '%s'.", fmt_addr32(*addr));
+ return 0;
+ }
+ }
+
+ /* Third, check the cached output from router_new_address_suggestion(). */
+ if (router_guess_address_from_dir_headers(addr) >= 0)
+ return 0;
+
+ /* We have no useful cached answers. Return failure. */
+ return -1;
+}
diff --git a/src/feature/relay/relay_find_addr.h b/src/feature/relay/relay_find_addr.h
new file mode 100644
index 0000000000..ac51a977e6
--- /dev/null
+++ b/src/feature/relay/relay_find_addr.h
@@ -0,0 +1,23 @@
+/* Copyright (c) 2020, The Tor Project, Inc. */
+/* See LICENSE for licensing information */
+
+/**
+ * \file relay_find_addr.h
+ * \brief Header file for relay_find_addr.c.
+ **/
+
+#ifndef TOR_RELAY_FIND_ADDR_H
+#define TOR_RELAY_FIND_ADDR_H
+
+MOCK_DECL(int, router_pick_published_address,
+ (const or_options_t *options, uint32_t *addr, int cache_only));
+
+void router_new_address_suggestion(const char *suggestion,
+ const dir_connection_t *d_conn);
+
+#ifdef RELAY_FIND_ADDR_PRIVATE
+
+#endif /* RELAY_FIND_ADDR_PRIVATE */
+
+#endif /* TOR_RELAY_FIND_ADDR_H */
+
diff --git a/src/feature/relay/relay_stub.c b/src/feature/relay/relay_stub.c
index 42e08fcb6c..283aaf6e49 100644
--- a/src/feature/relay/relay_stub.c
+++ b/src/feature/relay/relay_stub.c
@@ -15,6 +15,7 @@
const struct subsys_fns_t sys_relay = {
.name = "relay",
+ SUBSYS_DECLARE_LOCATION(),
.supported = false,
.level = RELAY_SUBSYS_LEVEL,
};
diff --git a/src/feature/relay/relay_sys.c b/src/feature/relay/relay_sys.c
index 34489cf5aa..2e90740925 100644
--- a/src/feature/relay/relay_sys.c
+++ b/src/feature/relay/relay_sys.c
@@ -41,6 +41,7 @@ subsys_relay_shutdown(void)
const struct subsys_fns_t sys_relay = {
.name = "relay",
+ SUBSYS_DECLARE_LOCATION(),
.supported = true,
.level = RELAY_SUBSYS_LEVEL,
.initialize = subsys_relay_initialize,
diff --git a/src/feature/relay/router.c b/src/feature/relay/router.c
index 9b62bb385c..267dee8483 100644
--- a/src/feature/relay/router.c
+++ b/src/feature/relay/router.c
@@ -8,6 +8,7 @@
#include "core/or/or.h"
#include "app/config/config.h"
+#include "app/config/resolve_addr.h"
#include "app/config/statefile.h"
#include "app/main/main.h"
#include "core/mainloop/connection.h"
@@ -36,6 +37,7 @@
#include "feature/nodelist/torcert.h"
#include "feature/relay/dns.h"
#include "feature/relay/relay_config.h"
+#include "feature/relay/relay_find_addr.h"
#include "feature/relay/router.h"
#include "feature/relay/routerkeys.h"
#include "feature/relay/routermode.h"
@@ -1469,7 +1471,7 @@ router_get_advertised_ipv6_or_ap(const or_options_t *options,
AF_INET6);
if (!addr || port == 0) {
- log_info(LD_CONFIG, "There is no advertised IPv6 ORPort.");
+ log_debug(LD_CONFIG, "There is no advertised IPv6 ORPort.");
return;
}
@@ -1490,6 +1492,24 @@ router_get_advertised_ipv6_or_ap(const or_options_t *options,
ipv6_ap_out->port = port;
}
+/** Returns true if this router has an advertised IPv6 ORPort. */
+bool
+router_has_advertised_ipv6_orport(const or_options_t *options)
+{
+ tor_addr_port_t ipv6_ap;
+ router_get_advertised_ipv6_or_ap(options, &ipv6_ap);
+ return tor_addr_port_is_valid_ap(&ipv6_ap, 0);
+}
+
+/** Returns true if this router has an advertised IPv6 ORPort. */
+MOCK_IMPL(bool,
+router_can_extend_over_ipv6,(const or_options_t *options))
+{
+ /* We might add some extra checks here, such as ExtendAllowIPv6Addresses
+ * from ticket 33818. */
+ return router_has_advertised_ipv6_orport(options);
+}
+
/** 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
@@ -1745,41 +1765,6 @@ router_get_descriptor_gen_reason(void)
return desc_gen_reason;
}
-static int router_guess_address_from_dir_headers(uint32_t *guess);
-
-/** Make a current best guess at our address, either because
- * it's configured in torrc, or because we've learned it from
- * dirserver headers. Place the answer in *<b>addr</b> and return
- * 0 on success, else return -1 if we have no guess.
- *
- * If <b>cache_only</b> is true, just return any cached answers, and
- * don't try to get any new answers.
- */
-MOCK_IMPL(int,
-router_pick_published_address,(const or_options_t *options, uint32_t *addr,
- int cache_only))
-{
- /* First, check the cached output from resolve_my_address(). */
- *addr = get_last_resolved_addr();
- if (*addr)
- return 0;
-
- /* Second, consider doing a resolve attempt right here. */
- if (!cache_only) {
- if (resolve_my_address(LOG_INFO, options, addr, NULL, NULL) >= 0) {
- log_info(LD_CONFIG,"Success: chose address '%s'.", fmt_addr32(*addr));
- return 0;
- }
- }
-
- /* Third, check the cached output from router_new_address_suggestion(). */
- if (router_guess_address_from_dir_headers(addr) >= 0)
- return 0;
-
- /* We have no useful cached answers. Return failure. */
- return -1;
-}
-
/* Like router_check_descriptor_address_consistency, but specifically for the
* ORPort or DirPort.
* listener_type is either CONN_TYPE_OR_LISTENER or CONN_TYPE_DIR_LISTENER. */
@@ -2036,7 +2021,7 @@ router_build_fresh_unsigned_routerinfo,(routerinfo_t **ri_out))
/* For now, at most one IPv6 or-address is being advertised. */
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. */
+ /* If there is no valid IPv6 ORPort, the address and port are null. */
tor_addr_copy(&ri->ipv6_addr, &ipv6_orport.addr);
ri->ipv6_orport = ipv6_orport.port;
@@ -2505,7 +2490,7 @@ check_descriptor_bandwidth_changed(time_t now)
/** Note at log level severity that our best guess of address has changed from
* <b>prev</b> to <b>cur</b>. */
-static void
+void
log_addr_has_changed(int severity,
const tor_addr_t *prev,
const tor_addr_t *cur,
@@ -2577,86 +2562,6 @@ check_descriptor_ipaddress_changed(time_t now)
tor_free(hostname);
}
-/** The most recently guessed value of our IP address, based on directory
- * headers. */
-static tor_addr_t last_guessed_ip = TOR_ADDR_NULL;
-
-/** A directory server <b>d_conn</b> told us our IP address is
- * <b>suggestion</b>.
- * If this address is different from the one we think we are now, and
- * if our computer doesn't actually know its IP address, then switch. */
-void
-router_new_address_suggestion(const char *suggestion,
- const dir_connection_t *d_conn)
-{
- tor_addr_t addr;
- uint32_t cur = 0; /* Current IPv4 address. */
- const or_options_t *options = get_options();
-
- /* first, learn what the IP address actually is */
- if (tor_addr_parse(&addr, suggestion) == -1) {
- log_debug(LD_DIR, "Malformed X-Your-Address-Is header %s. Ignoring.",
- escaped(suggestion));
- return;
- }
-
- log_debug(LD_DIR, "Got X-Your-Address-Is: %s.", suggestion);
-
- if (!server_mode(options)) {
- tor_addr_copy(&last_guessed_ip, &addr);
- return;
- }
-
- /* XXXX ipv6 */
- cur = get_last_resolved_addr();
- if (cur ||
- resolve_my_address(LOG_INFO, options, &cur, NULL, NULL) >= 0) {
- /* We're all set -- we already know our address. Great. */
- tor_addr_from_ipv4h(&last_guessed_ip, cur); /* store it in case we
- need it later */
- return;
- }
- if (tor_addr_is_internal(&addr, 0)) {
- /* Don't believe anybody who says our IP is, say, 127.0.0.1. */
- return;
- }
- if (tor_addr_eq(&d_conn->base_.addr, &addr)) {
- /* Don't believe anybody who says our IP is their IP. */
- log_debug(LD_DIR, "A directory server told us our IP address is %s, "
- "but they are just reporting their own IP address. Ignoring.",
- suggestion);
- return;
- }
-
- /* Okay. We can't resolve our own address, and X-Your-Address-Is is giving
- * us an answer different from what we had the last time we managed to
- * resolve it. */
- if (!tor_addr_eq(&last_guessed_ip, &addr)) {
- control_event_server_status(LOG_NOTICE,
- "EXTERNAL_ADDRESS ADDRESS=%s METHOD=DIRSERV",
- suggestion);
- log_addr_has_changed(LOG_NOTICE, &last_guessed_ip, &addr,
- d_conn->base_.address);
- ip_address_changed(0);
- tor_addr_copy(&last_guessed_ip, &addr); /* router_rebuild_descriptor()
- will fetch it */
- }
-}
-
-/** We failed to resolve our address locally, but we'd like to build
- * a descriptor and publish / test reachability. If we have a guess
- * about our address based on directory headers, answer it and return
- * 0; else return -1. */
-static int
-router_guess_address_from_dir_headers(uint32_t *guess)
-{
- if (!tor_addr_is_null(&last_guessed_ip)) {
- *guess = tor_addr_to_ipv4h(&last_guessed_ip);
- return 0;
- }
- return -1;
-}
-
/** Set <b>platform</b> (max length <b>len</b>) to a NUL-terminated short
* string describing the version of Tor and the operating system we're
* currently running on.
diff --git a/src/feature/relay/router.h b/src/feature/relay/router.h
index d1b4ce5f8f..50790a73dd 100644
--- a/src/feature/relay/router.h
+++ b/src/feature/relay/router.h
@@ -68,6 +68,8 @@ uint16_t router_get_active_listener_port_by_type_af(int listener_type,
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);
+bool router_has_advertised_ipv6_orport(const or_options_t *options);
+MOCK_DECL(bool, router_can_extend_over_ipv6,(const or_options_t *options));
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,
@@ -85,8 +87,6 @@ void mark_my_descriptor_dirty(const char *reason);
void check_descriptor_bandwidth_changed(time_t now);
void check_descriptor_ipaddress_changed(time_t now);
int router_has_bandwidth_to_be_dirserver(const or_options_t *options);
-void router_new_address_suggestion(const char *suggestion,
- const dir_connection_t *d_conn);
int router_compare_to_my_exit_policy(const tor_addr_t *addr, uint16_t port);
MOCK_DECL(int, router_my_exit_policy_is_reject_star,(void));
MOCK_DECL(const routerinfo_t *, router_get_my_routerinfo, (void));
@@ -98,9 +98,6 @@ int router_digest_is_me(const char *digest);
const uint8_t *router_get_my_id_digest(void);
int router_extrainfo_digest_is_me(const char *digest);
int router_is_me(const routerinfo_t *router);
-MOCK_DECL(int,router_pick_published_address,(const or_options_t *options,
- uint32_t *addr,
- int cache_only));
int router_build_fresh_descriptor(routerinfo_t **r, extrainfo_t **e);
int router_rebuild_descriptor(int force);
char *router_dump_router_to_string(routerinfo_t *router,
@@ -118,6 +115,9 @@ int extrainfo_dump_to_string(char **s, extrainfo_t *extrainfo,
const char *routerinfo_err_to_string(int err);
int routerinfo_err_is_transient(int err);
+void log_addr_has_changed(int severity, const tor_addr_t *prev,
+ const tor_addr_t *cur, const char *source);
+
void router_reset_warnings(void);
void router_free_all(void);
diff --git a/src/feature/relay/selftest.c b/src/feature/relay/selftest.c
index 29febdee82..402ce0e3d3 100644
--- a/src/feature/relay/selftest.c
+++ b/src/feature/relay/selftest.c
@@ -8,7 +8,7 @@
* \file selftest.c
* \brief Relay self-testing
*
- * Relays need to make sure that their own ports are reasonable, and estimate
+ * Relays need to make sure that their own ports are reachable, and estimate
* their own bandwidth, before publishing.
*/
@@ -213,6 +213,40 @@ router_do_reachability_checks(int test_or, int test_dir)
}
}
+/** We've decided to start our reachability testing. If all
+ * is set, log this to the user. Return 1 if we did, or 0 if
+ * we chose not to log anything. */
+int
+inform_testing_reachability(void)
+{
+ char dirbuf[128];
+ char *address;
+ const routerinfo_t *me = router_get_my_routerinfo();
+ if (!me)
+ return 0;
+ address = tor_dup_ip(me->addr);
+ control_event_server_status(LOG_NOTICE,
+ "CHECKING_REACHABILITY ORADDRESS=%s:%d",
+ address, me->or_port);
+ if (me->dir_port) {
+ tor_snprintf(dirbuf, sizeof(dirbuf), " and DirPort %s:%d",
+ address, me->dir_port);
+ control_event_server_status(LOG_NOTICE,
+ "CHECKING_REACHABILITY DIRADDRESS=%s:%d",
+ address, me->dir_port);
+ }
+ log_notice(LD_OR, "Now checking whether ORPort %s:%d%s %s reachable... "
+ "(this may take up to %d minutes -- look for log "
+ "messages indicating success)",
+ address, me->or_port,
+ me->dir_port ? dirbuf : "",
+ me->dir_port ? "are" : "is",
+ TIMEOUT_UNTIL_UNREACHABILITY_COMPLAINT/60);
+
+ tor_free(address);
+ return 1;
+}
+
/** Annotate that we found our ORPort reachable. */
void
router_orport_found_reachable(void)
diff --git a/src/feature/relay/selftest.h b/src/feature/relay/selftest.h
index f3dd698bb7..f5babc95da 100644
--- a/src/feature/relay/selftest.h
+++ b/src/feature/relay/selftest.h
@@ -13,14 +13,18 @@
#define TOR_SELFTEST_H
#ifdef HAVE_MODULE_RELAY
+
struct or_options_t;
int check_whether_orport_reachable(const struct or_options_t *options);
int check_whether_dirport_reachable(const struct or_options_t *options);
void router_do_reachability_checks(int test_or, int test_dir);
+void router_perform_bandwidth_test(int num_circs, time_t now);
+int inform_testing_reachability(void);
+
void router_orport_found_reachable(void);
void router_dirport_found_reachable(void);
-void router_perform_bandwidth_test(int num_circs, time_t now);
+
void router_reset_reachability(void);
#else /* !defined(HAVE_MODULE_RELAY) */
@@ -30,13 +34,6 @@ void router_reset_reachability(void);
#define check_whether_dirport_reachable(opts) \
((void)(opts), 0)
-#define router_orport_found_reachable() \
- STMT_NIL
-#define router_dirport_found_reachable() \
- STMT_NIL
-#define router_reset_reachability() \
- STMT_NIL
-
static inline void
router_do_reachability_checks(int test_or, int test_dir)
{
@@ -51,6 +48,20 @@ router_perform_bandwidth_test(int num_circs, time_t now)
(void)now;
tor_assert_nonfatal_unreached();
}
+static inline int
+inform_testing_reachability(void)
+{
+ tor_assert_nonfatal_unreached();
+ return 0;
+}
+
+#define router_orport_found_reachable() \
+ STMT_NIL
+#define router_dirport_found_reachable() \
+ STMT_NIL
+
+#define router_reset_reachability() \
+ STMT_NIL
#endif /* defined(HAVE_MODULE_RELAY) */
diff --git a/src/feature/rend/rendclient.c b/src/feature/rend/rendclient.c
index cc55065fdd..09db7045fa 100644
--- a/src/feature/rend/rendclient.c
+++ b/src/feature/rend/rendclient.c
@@ -831,7 +831,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();
- /* fall through */
+ FALLTHROUGH;
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 10a3403166..9d7ff2d17f 100644
--- a/src/feature/rend/rendservice.c
+++ b/src/feature/rend/rendservice.c
@@ -4351,17 +4351,16 @@ rend_consider_descriptor_republication(void)
void
rend_service_dump_stats(int severity)
{
- int i,j;
rend_service_t *service;
rend_intro_point_t *intro;
const char *safe_name;
origin_circuit_t *circ;
- for (i=0; i < smartlist_len(rend_service_list); ++i) {
+ for (int i = 0; i < smartlist_len(rend_service_list); ++i) {
service = smartlist_get(rend_service_list, i);
tor_log(severity, LD_GENERAL, "Service configured in %s:",
rend_service_escaped_dir(service));
- for (j=0; j < smartlist_len(service->intro_nodes); ++j) {
+ for (int j = 0; j < smartlist_len(service->intro_nodes); ++j) {
intro = smartlist_get(service->intro_nodes, j);
safe_name = safe_str_client(intro->extend_info->nickname);
diff --git a/src/lib/buf/buffers.c b/src/lib/buf/buffers.c
index 09a074edcc..95b384bf06 100644
--- a/src/lib/buf/buffers.c
+++ b/src/lib/buf/buffers.c
@@ -285,7 +285,7 @@ buf_t *
buf_new_with_data(const char *cp, size_t sz)
{
/* Validate arguments */
- if (!cp || sz <= 0 || sz >= INT_MAX) {
+ if (!cp || sz <= 0 || sz > BUF_MAX_LEN) {
return NULL;
}
@@ -530,9 +530,9 @@ buf_add(buf_t *buf, const char *string, size_t string_len)
return (int)buf->datalen;
check();
- if (BUG(buf->datalen >= INT_MAX))
+ if (BUG(buf->datalen > BUF_MAX_LEN))
return -1;
- if (BUG(buf->datalen >= INT_MAX - string_len))
+ if (BUG(buf->datalen > BUF_MAX_LEN - string_len))
return -1;
while (string_len) {
@@ -551,7 +551,7 @@ buf_add(buf_t *buf, const char *string, size_t string_len)
}
check();
- tor_assert(buf->datalen < INT_MAX);
+ tor_assert(buf->datalen <= BUF_MAX_LEN);
return (int)buf->datalen;
}
@@ -645,7 +645,7 @@ buf_get_bytes(buf_t *buf, char *string, size_t string_len)
buf_peek(buf, string, string_len);
buf_drain(buf, string_len);
check();
- tor_assert(buf->datalen < INT_MAX);
+ tor_assert(buf->datalen <= BUF_MAX_LEN);
return (int)buf->datalen;
}
@@ -660,9 +660,9 @@ buf_move_to_buf(buf_t *buf_out, buf_t *buf_in, size_t *buf_flushlen)
char b[4096];
size_t cp, len;
- if (BUG(buf_out->datalen >= INT_MAX || *buf_flushlen >= INT_MAX))
+ if (BUG(buf_out->datalen > BUF_MAX_LEN || *buf_flushlen > BUF_MAX_LEN))
return -1;
- if (BUG(buf_out->datalen >= INT_MAX - *buf_flushlen))
+ if (BUG(buf_out->datalen > BUF_MAX_LEN - *buf_flushlen))
return -1;
len = *buf_flushlen;
@@ -670,7 +670,7 @@ buf_move_to_buf(buf_t *buf_out, buf_t *buf_in, size_t *buf_flushlen)
len = buf_in->datalen;
cp = len; /* Remember the number of bytes we intend to copy. */
- tor_assert(cp < INT_MAX);
+ tor_assert(cp <= BUF_MAX_LEN);
while (len) {
/* This isn't the most efficient implementation one could imagine, since
* it does two copies instead of 1, but I kinda doubt that this will be
@@ -692,9 +692,9 @@ buf_move_all(buf_t *buf_out, buf_t *buf_in)
tor_assert(buf_out);
if (!buf_in)
return;
- if (BUG(buf_out->datalen >= INT_MAX || buf_in->datalen >= INT_MAX))
+ if (BUG(buf_out->datalen > BUF_MAX_LEN || buf_in->datalen > BUF_MAX_LEN))
return;
- if (BUG(buf_out->datalen >= INT_MAX - buf_in->datalen))
+ if (BUG(buf_out->datalen > BUF_MAX_LEN - buf_in->datalen))
return;
if (buf_out->head == NULL) {
@@ -748,7 +748,7 @@ buf_find_pos_of_char(char ch, buf_pos_t *out)
char *cp = memchr(chunk->data+pos, ch, chunk->datalen - pos);
if (cp) {
out->chunk = chunk;
- tor_assert(cp - chunk->data < INT_MAX);
+ tor_assert(cp - chunk->data <= BUF_MAX_LEN);
out->pos = (int)(cp - chunk->data);
return out->chunk_pos + out->pos;
} else {
@@ -764,7 +764,7 @@ buf_find_pos_of_char(char ch, buf_pos_t *out)
static inline int
buf_pos_inc(buf_pos_t *pos)
{
- tor_assert(pos->pos < INT_MAX - 1);
+ tor_assert(pos->pos < BUF_MAX_LEN);
++pos->pos;
if (pos->pos == (ptrdiff_t)pos->chunk->datalen) {
if (!pos->chunk->next)
@@ -811,7 +811,7 @@ buf_find_string_offset(const buf_t *buf, const char *s, size_t n)
buf_pos_init(buf, &pos);
while (buf_find_pos_of_char(*s, &pos) >= 0) {
if (buf_matches_at_pos(&pos, s, n)) {
- tor_assert(pos.chunk_pos + pos.pos < INT_MAX);
+ tor_assert(pos.chunk_pos + pos.pos <= BUF_MAX_LEN);
return (int)(pos.chunk_pos + pos.pos);
} else {
if (buf_pos_inc(&pos)<0)
@@ -845,7 +845,7 @@ buf_find_offset_of_char(buf_t *buf, char ch)
{
chunk_t *chunk;
ptrdiff_t offset = 0;
- tor_assert(buf->datalen < INT_MAX);
+ tor_assert(buf->datalen <= BUF_MAX_LEN);
for (chunk = buf->head; chunk; chunk = chunk->next) {
char *cp = memchr(chunk->data, ch, chunk->datalen);
if (cp)
@@ -915,7 +915,7 @@ buf_assert_ok(buf_t *buf)
for (ch = buf->head; ch; ch = ch->next) {
total += ch->datalen;
tor_assert(ch->datalen <= ch->memlen);
- tor_assert(ch->datalen < INT_MAX);
+ tor_assert(ch->datalen <= BUF_MAX_LEN);
tor_assert(ch->data >= &ch->mem[0]);
tor_assert(ch->data <= &ch->mem[0]+ch->memlen);
if (ch->data == &ch->mem[0]+ch->memlen) {
diff --git a/src/lib/buf/buffers.h b/src/lib/buf/buffers.h
index fadd4174c0..d8a77feb72 100644
--- a/src/lib/buf/buffers.h
+++ b/src/lib/buf/buffers.h
@@ -29,6 +29,9 @@ void buf_free_(buf_t *buf);
void buf_clear(buf_t *buf);
buf_t *buf_copy(const buf_t *buf);
+/** Maximum bytes in a buffer, inclusive. */
+#define BUF_MAX_LEN (INT_MAX - 1)
+
MOCK_DECL(size_t, buf_datalen, (const buf_t *buf));
size_t buf_allocation(const buf_t *buf);
size_t buf_slack(const buf_t *buf);
diff --git a/src/lib/cc/compat_compiler.h b/src/lib/cc/compat_compiler.h
index e4b0ea61ca..96aa912652 100644
--- a/src/lib/cc/compat_compiler.h
+++ b/src/lib/cc/compat_compiler.h
@@ -50,6 +50,12 @@
#define CHECK_SCANF(formatIdx, firstArg)
#endif /* defined(__GNUC__) */
+#if defined(HAVE_ATTR_FALLTHROUGH)
+#define FALLTHROUGH __attribute__((fallthrough))
+#else
+#define FALLTHROUGH
+#endif
+
/* What GCC do we have? */
#ifdef __GNUC__
#define GCC_VERSION (__GNUC__ * 100 + __GNUC_MINOR__)
diff --git a/src/lib/compress/compress.c b/src/lib/compress/compress.c
index 84e9601920..7ce3910d84 100644
--- a/src/lib/compress/compress.c
+++ b/src/lib/compress/compress.c
@@ -694,6 +694,7 @@ subsys_compress_initialize(void)
const subsys_fns_t sys_compress = {
.name = "compress",
+ SUBSYS_DECLARE_LOCATION(),
.supported = true,
.level = -55,
.initialize = subsys_compress_initialize,
diff --git a/src/lib/conf/confdecl.h b/src/lib/conf/confdecl.h
index f7e79bb2b1..c2d3fb335d 100644
--- a/src/lib/conf/confdecl.h
+++ b/src/lib/conf/confdecl.h
@@ -136,11 +136,11 @@
},
/**@}*/
-/* @defgroup STUB_TABLE_MACROS Internal macros: stub table declarations,
+/** @defgroup STUB_TABLE_MACROS Internal macros: stub table declarations,
* for use when a module is disabled.
* Implementation helpers: the regular confdecl macros expand to these
* when CONF_CONTEXT is defined to LL_TABLE. Don't use them directly.
- * @{*/
+ * @{ */
#define BEGIN_CONF_STRUCT__STUB_TABLE(structname) \
static const config_var_t structname##_vars[] = {
#define END_CONF_STRUCT__STUB_TABLE(structname) \
@@ -166,7 +166,7 @@
* when the macro sees us declare a configuration option "foo" of type STRING,
* it can emit `config_decl_STRING foo;`, which is an alias for `char *foo`.
*/
-/**{*/
+/**@{*/
typedef char *config_decl_STRING;
typedef char *config_decl_FILENAME;
/* Yes, "POSINT" is really an int, and not an unsigned int. For
diff --git a/src/lib/container/smartlist.c b/src/lib/container/smartlist.c
index eeb3bce95c..7784f83957 100644
--- a/src/lib/container/smartlist.c
+++ b/src/lib/container/smartlist.c
@@ -652,7 +652,7 @@ smartlist_sort_pointers(smartlist_t *sl)
#define LEFT_CHILD(i) ( 2*(i) + 1 )
#define RIGHT_CHILD(i) ( 2*(i) + 2 )
#define PARENT(i) ( ((i)-1) / 2 )
-/** }@ */
+/** @} */
/** @{ */
/** Helper macros for heaps: Given a local variable <b>idx_field_offset</b>
diff --git a/src/lib/crypt_ops/crypto_digest_nss.c b/src/lib/crypt_ops/crypto_digest_nss.c
index 7e7464273e..92c20fe9e8 100644
--- a/src/lib/crypt_ops/crypto_digest_nss.c
+++ b/src/lib/crypt_ops/crypto_digest_nss.c
@@ -37,8 +37,8 @@ digest_alg_to_nss_oid(digest_algorithm_t alg)
case DIGEST_SHA1: return SEC_OID_SHA1;
case DIGEST_SHA256: return SEC_OID_SHA256;
case DIGEST_SHA512: return SEC_OID_SHA512;
- case DIGEST_SHA3_256: /* Fall through */
- case DIGEST_SHA3_512: /* Fall through */
+ case DIGEST_SHA3_256: FALLTHROUGH;
+ case DIGEST_SHA3_512: FALLTHROUGH;
default:
return SEC_OID_UNKNOWN;
}
@@ -89,12 +89,12 @@ static bool
library_supports_digest(digest_algorithm_t alg)
{
switch (alg) {
- case DIGEST_SHA1: /* Fall through */
- case DIGEST_SHA256: /* Fall through */
- case DIGEST_SHA512: /* Fall through */
+ case DIGEST_SHA1: FALLTHROUGH;
+ case DIGEST_SHA256: FALLTHROUGH;
+ case DIGEST_SHA512:
return true;
- case DIGEST_SHA3_256: /* Fall through */
- case DIGEST_SHA3_512: /* Fall through */
+ case DIGEST_SHA3_256: FALLTHROUGH;
+ case DIGEST_SHA3_512: FALLTHROUGH;
default:
return false;
}
@@ -201,8 +201,8 @@ crypto_digest_alloc_bytes(digest_algorithm_t alg)
#define END_OF_FIELD(f) (offsetof(crypto_digest_t, f) + \
STRUCT_FIELD_SIZE(crypto_digest_t, f))
switch (alg) {
- case DIGEST_SHA1: /* Fall through */
- case DIGEST_SHA256: /* Fall through */
+ case DIGEST_SHA1: FALLTHROUGH;
+ case DIGEST_SHA256: FALLTHROUGH;
case DIGEST_SHA512:
return END_OF_FIELD(d.ctx);
case DIGEST_SHA3_256:
@@ -228,8 +228,8 @@ crypto_digest_new_internal(digest_algorithm_t algorithm)
switch (algorithm)
{
- case DIGEST_SHA1: /* fall through */
- case DIGEST_SHA256: /* fall through */
+ case DIGEST_SHA1: FALLTHROUGH;
+ case DIGEST_SHA256: FALLTHROUGH;
case DIGEST_SHA512:
r->d.ctx = PK11_CreateDigestContext(digest_alg_to_nss_oid(algorithm));
if (BUG(!r->d.ctx)) {
@@ -316,8 +316,8 @@ crypto_digest_add_bytes(crypto_digest_t *digest, const char *data,
* just doing it ourselves. Hashes are fast.
*/
switch (digest->algorithm) {
- case DIGEST_SHA1: /* fall through */
- case DIGEST_SHA256: /* fall through */
+ case DIGEST_SHA1: FALLTHROUGH;
+ case DIGEST_SHA256: FALLTHROUGH;
case DIGEST_SHA512:
tor_assert(len <= UINT_MAX);
SECStatus s = PK11_DigestOp(digest->d.ctx,
@@ -325,7 +325,7 @@ crypto_digest_add_bytes(crypto_digest_t *digest, const char *data,
(unsigned int)len);
tor_assert(s == SECSuccess);
break;
- case DIGEST_SHA3_256: /* FALLSTHROUGH */
+ case DIGEST_SHA3_256: FALLTHROUGH;
case DIGEST_SHA3_512:
keccak_digest_update(&digest->d.sha3, (const uint8_t *)data, len);
break;
diff --git a/src/lib/crypt_ops/crypto_digest_openssl.c b/src/lib/crypt_ops/crypto_digest_openssl.c
index bc076df619..11189c7fb2 100644
--- a/src/lib/crypt_ops/crypto_digest_openssl.c
+++ b/src/lib/crypt_ops/crypto_digest_openssl.c
@@ -160,11 +160,11 @@ crypto_digest_alloc_bytes(digest_algorithm_t alg)
case DIGEST_SHA512:
return END_OF_FIELD(d.sha512);
#ifdef OPENSSL_HAS_SHA3
- case DIGEST_SHA3_256: /* Fall through */
+ case DIGEST_SHA3_256: FALLTHROUGH;
case DIGEST_SHA3_512:
return END_OF_FIELD(d.md);
#else
- case DIGEST_SHA3_256: /* Fall through */
+ case DIGEST_SHA3_256: FALLTHROUGH;
case DIGEST_SHA3_512:
return END_OF_FIELD(d.sha3);
#endif /* defined(OPENSSL_HAS_SHA3) */
@@ -304,14 +304,14 @@ crypto_digest_add_bytes(crypto_digest_t *digest, const char *data,
SHA512_Update(&digest->d.sha512, (void*)data, len);
break;
#ifdef OPENSSL_HAS_SHA3
- case DIGEST_SHA3_256: /* FALLSTHROUGH */
+ case DIGEST_SHA3_256: FALLTHROUGH;
case DIGEST_SHA3_512: {
int r = EVP_DigestUpdate(digest->d.md, data, len);
tor_assert(r);
}
break;
#else /* !defined(OPENSSL_HAS_SHA3) */
- case DIGEST_SHA3_256: /* FALLSTHROUGH */
+ case DIGEST_SHA3_256: FALLTHROUGH;
case DIGEST_SHA3_512:
keccak_digest_update(&digest->d.sha3, (const uint8_t *)data, len);
break;
@@ -377,7 +377,7 @@ crypto_digest_get_digest(crypto_digest_t *digest,
SHA512_Final(r, &tmpenv.d.sha512);
break;
//LCOV_EXCL_START
- case DIGEST_SHA3_256: /* FALLSTHROUGH */
+ case DIGEST_SHA3_256: FALLTHROUGH;
case DIGEST_SHA3_512:
default:
log_warn(LD_BUG, "Handling unexpected algorithm %d", digest->algorithm);
diff --git a/src/lib/crypt_ops/crypto_init.c b/src/lib/crypt_ops/crypto_init.c
index f09bf07c4d..a836bd8645 100644
--- a/src/lib/crypt_ops/crypto_init.c
+++ b/src/lib/crypt_ops/crypto_init.c
@@ -317,6 +317,7 @@ crypto_set_options(void *arg)
const struct subsys_fns_t sys_crypto = {
.name = "crypto",
+ SUBSYS_DECLARE_LOCATION(),
.supported = true,
.level = -60,
.initialize = subsys_crypto_initialize,
diff --git a/src/lib/crypt_ops/crypto_rand_numeric.c b/src/lib/crypt_ops/crypto_rand_numeric.c
index ffbfa2d56c..b2516c4bdc 100644
--- a/src/lib/crypt_ops/crypto_rand_numeric.c
+++ b/src/lib/crypt_ops/crypto_rand_numeric.c
@@ -33,8 +33,8 @@
/**
* Return a pseudorandom integer chosen uniformly from the values between 0
- * and <b>limit</b>-1 inclusive. limit must be strictly between 0 and
- * UINT_MAX. */
+ * and <b>limit</b>-1 inclusive. limit must be strictly greater than 0, and
+ * less than UINT_MAX. */
unsigned
crypto_rand_uint(unsigned limit)
{
diff --git a/src/lib/crypt_ops/crypto_rsa_openssl.c b/src/lib/crypt_ops/crypto_rsa_openssl.c
index d54db43b92..c96ee81fd3 100644
--- a/src/lib/crypt_ops/crypto_rsa_openssl.c
+++ b/src/lib/crypt_ops/crypto_rsa_openssl.c
@@ -583,15 +583,15 @@ rsa_private_key_too_long(RSA *rsa, int max_bits)
dmp1 = RSA_get0_dmp1(rsa);
dmq1 = RSA_get0_dmq1(rsa);
iqmp = RSA_get0_iqmp(rsa);
-#else
+#else /* !(OPENSSL_VERSION_NUMBER >= OPENSSL_V_SERIES(1,1,1)) */
/* The accessors above did not exist in openssl 1.1.0. */
p = q = dmp1 = dmq1 = iqmp = NULL;
RSA_get0_key(rsa, &n, &e, &d);
-#endif
+#endif /* OPENSSL_VERSION_NUMBER >= OPENSSL_V_SERIES(1,1,1) */
if (RSA_bits(rsa) > max_bits)
return true;
-#else
+#else /* !defined(OPENSSL_1_1_API) */
n = rsa->n;
e = rsa->e;
p = rsa->p;
@@ -600,7 +600,7 @@ rsa_private_key_too_long(RSA *rsa, int max_bits)
dmp1 = rsa->dmp1;
dmq1 = rsa->dmq1;
iqmp = rsa->iqmp;
-#endif
+#endif /* defined(OPENSSL_1_1_API) */
if (n && BN_num_bits(n) > max_bits)
return true;
diff --git a/src/lib/encoding/confline.c b/src/lib/encoding/confline.c
index eb1a4e30f0..613e4a00c6 100644
--- a/src/lib/encoding/confline.c
+++ b/src/lib/encoding/confline.c
@@ -151,6 +151,8 @@ config_get_lines_aux(const char *string, config_line_t **result, int extended,
if (allow_include && !strcmp(k, "%include") && handle_include) {
tor_free(k);
include_used = 1;
+ log_notice(LD_CONFIG, "Processing configuration path \"%s\" at "
+ "recursion level %d.", v, recursion_level);
config_line_t *include_list;
if (handle_include(v, recursion_level, extended, &include_list,
@@ -161,9 +163,6 @@ config_get_lines_aux(const char *string, config_line_t **result, int extended,
tor_free(v);
return -1;
}
- log_notice(LD_CONFIG, "Included configuration file or "
- "directory at recursion level %d: \"%s\".",
- recursion_level, v);
*next = include_list;
if (list_last)
next = &list_last->next;
diff --git a/src/lib/err/torerr_sys.c b/src/lib/err/torerr_sys.c
index 46fc853550..8ee1521f3b 100644
--- a/src/lib/err/torerr_sys.c
+++ b/src/lib/err/torerr_sys.c
@@ -34,6 +34,7 @@ subsys_torerr_shutdown(void)
const subsys_fns_t sys_torerr = {
.name = "err",
+ SUBSYS_DECLARE_LOCATION(),
/* Low-level error handling is a diagnostic feature, we want it to init
* right after windows process security, and shutdown last.
* (Security never shuts down.) */
diff --git a/src/lib/evloop/evloop_sys.c b/src/lib/evloop/evloop_sys.c
index fecec2f264..b639810c23 100644
--- a/src/lib/evloop/evloop_sys.c
+++ b/src/lib/evloop/evloop_sys.c
@@ -41,6 +41,7 @@ subsys_evloop_shutdown(void)
const struct subsys_fns_t sys_evloop = {
.name = "evloop",
+ SUBSYS_DECLARE_LOCATION(),
.supported = true,
.level = -20,
.initialize = subsys_evloop_initialize,
diff --git a/src/lib/fs/conffile.c b/src/lib/fs/conffile.c
index 392b2f4541..9583093c12 100644
--- a/src/lib/fs/conffile.c
+++ b/src/lib/fs/conffile.c
@@ -152,6 +152,7 @@ config_process_include(const char *path, int recursion_level, int extended,
int rv = -1;
SMARTLIST_FOREACH_BEGIN(config_files, const char *, config_file) {
+ log_notice(LD_CONFIG, "Including configuration file \"%s\".", config_file);
config_line_t *included_config = NULL;
config_line_t *included_config_last = NULL;
if (config_get_included_config(config_file, recursion_level, extended,
diff --git a/src/lib/llharden/winprocess_sys.c b/src/lib/llharden/winprocess_sys.c
index a5f22c182b..f2c88d8c75 100644
--- a/src/lib/llharden/winprocess_sys.c
+++ b/src/lib/llharden/winprocess_sys.c
@@ -58,6 +58,7 @@ subsys_winprocess_initialize(void)
const subsys_fns_t sys_winprocess = {
.name = "winprocess",
+ SUBSYS_DECLARE_LOCATION(),
/* HeapEnableTerminationOnCorruption and setdeppolicy() are security
* features, we want them to run first. */
.level = -100,
diff --git a/src/lib/log/log_sys.c b/src/lib/log/log_sys.c
index 1be4f5b7d8..021c05d3e6 100644
--- a/src/lib/log/log_sys.c
+++ b/src/lib/log/log_sys.c
@@ -28,6 +28,7 @@ subsys_logging_shutdown(void)
const subsys_fns_t sys_logging = {
.name = "log",
+ SUBSYS_DECLARE_LOCATION(),
.supported = true,
/* Logging depends on threads, approx time, raw logging, and security.
* Most other lib modules depend on logging. */
diff --git a/src/lib/log/util_bug.h b/src/lib/log/util_bug.h
index ae3d125a08..6b27b36f03 100644
--- a/src/lib/log/util_bug.h
+++ b/src/lib/log/util_bug.h
@@ -142,6 +142,8 @@
#define ALL_BUGS_ARE_FATAL
#endif
+/** Define ALL_BUGS_ARE_FATAL if you want Tor to crash when any problem comes
+ * up, so you can get a coredump and track things down. */
#ifdef ALL_BUGS_ARE_FATAL
#define tor_assert_nonfatal_unreached() tor_assert(0)
#define tor_assert_nonfatal(cond) tor_assert((cond))
@@ -154,6 +156,9 @@
(tor_assertion_failed_(SHORT_FILE__,__LINE__,__func__,"!("#cond")",NULL), \
tor_abort_(), 1) \
: 0)
+#ifndef COCCI
+#define IF_BUG_ONCE(cond) if (BUG(cond))
+#endif
#elif defined(TOR_UNIT_TESTS) && defined(DISABLE_ASSERTS_IN_UNIT_TESTS)
#define tor_assert_nonfatal_unreached() STMT_NIL
#define tor_assert_nonfatal(cond) ((void)(cond))
@@ -164,6 +169,9 @@
#define tor_assert_nonfatal_unreached_once() STMT_NIL
#define tor_assert_nonfatal_once(cond) ((void)(cond))
#define BUG(cond) (ASSERT_PREDICT_UNLIKELY_(cond) ? 1 : 0)
+#ifndef COCCI
+#define IF_BUG_ONCE(cond) if (BUG(cond))
+#endif
#else /* Normal case, !ALL_BUGS_ARE_FATAL, !DISABLE_ASSERTS_IN_UNIT_TESTS */
#define tor_assert_nonfatal_unreached() STMT_BEGIN \
tor_bug_occurred_(SHORT_FILE__, __LINE__, __func__, NULL, 0, NULL); \
@@ -200,7 +208,6 @@
(ASSERT_PREDICT_UNLIKELY_(cond) ? \
(tor_bug_occurred_(SHORT_FILE__,__LINE__,__func__,"!("#cond")",0,NULL),1) \
: 0)
-#endif /* defined(ALL_BUGS_ARE_FATAL) || ... */
#ifndef COCCI
#ifdef __GNUC__
@@ -232,7 +239,7 @@
#define IF_BUG_ONCE_VARNAME__(a) \
IF_BUG_ONCE_VARNAME_(a)
-/** This macro behaves as 'if (bug(x))', except that it only logs its
+/** This macro behaves as 'if (BUG(x))', except that it only logs its
* warning once, no matter how many times it triggers.
*/
@@ -240,9 +247,15 @@
IF_BUG_ONCE__(ASSERT_PREDICT_UNLIKELY_(cond), \
IF_BUG_ONCE_VARNAME__(__LINE__))
-/** 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)
+#endif /* defined(ALL_BUGS_ARE_FATAL) || ... */
+
+/** In older code, we used tor_fragile_assert() to mark optional failure
+ * points. At these points, we could make some debug builds fail.
+ * (But release builds would continue.)
+ *
+ * To get the same behaviour in recent tor versions, define
+ * ALL_BUGS_ARE_FATAL, and use any non-fatal assertion or *BUG() macro.
+ */
#define tor_fragile_assert() tor_assert_nonfatal_unreached_once()
void tor_assertion_failed_(const char *fname, unsigned int line,
diff --git a/src/lib/net/address.c b/src/lib/net/address.c
index e968d8a7f7..b8f5f37747 100644
--- a/src/lib/net/address.c
+++ b/src/lib/net/address.c
@@ -608,7 +608,8 @@ tor_addr_parse_mask_ports(const char *s,
family = AF_INET;
tor_addr_from_ipv4h(addr_out, 0);
} else if (flags & TAPMP_STAR_IPV6_ONLY) {
- static char nil_bytes[16] = { [0]=0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0 };
+ static uint8_t nil_bytes[16] =
+ { [0]=0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0 };
family = AF_INET6;
tor_addr_from_ipv6_bytes(addr_out, nil_bytes);
} else {
@@ -629,7 +630,7 @@ tor_addr_parse_mask_ports(const char *s,
tor_addr_from_ipv4h(addr_out, 0);
any_flag = 1;
} else if (!strcmp(address, "*6") && (flags & TAPMP_EXTENDED_STAR)) {
- static char nil_bytes[16] = { [0]=0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0 };
+ static uint8_t nil_bytes[16] = { [0]=0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0 };
family = AF_INET6;
tor_addr_from_ipv6_bytes(addr_out, nil_bytes);
any_flag = 1;
@@ -817,8 +818,12 @@ tor_addr_is_loopback(const tor_addr_t *addr)
/* Is addr valid?
* Checks that addr is non-NULL and not tor_addr_is_null().
- * If for_listening is true, IPv4 addr 0.0.0.0 is allowed.
- * It means "bind to all addresses on the local machine". */
+ * If for_listening is true, all IPv4 and IPv6 addresses are valid, including
+ * 0.0.0.0 (for IPv4) and :: (for IPv6). When listening, these addresses mean
+ * "bind to all addresses on the local machine".
+ * Otherwise, 0.0.0.0 and :: are invalid, because they are null addresses.
+ * All unspecified and unix addresses are invalid, regardless of for_listening.
+ */
int
tor_addr_is_valid(const tor_addr_t *addr, int for_listening)
{
@@ -827,10 +832,11 @@ tor_addr_is_valid(const tor_addr_t *addr, int for_listening)
return 0;
}
- /* Only allow IPv4 0.0.0.0 for_listening. */
- if (for_listening && addr->family == AF_INET
- && tor_addr_to_ipv4h(addr) == 0) {
- return 1;
+ /* Allow all IPv4 and IPv6 addresses, when for_listening is true */
+ if (for_listening) {
+ if (addr->family == AF_INET || addr->family == AF_INET6) {
+ return 1;
+ }
}
/* Otherwise, the address is valid if it's not tor_addr_is_null() */
@@ -882,7 +888,7 @@ tor_addr_from_ipv4n(tor_addr_t *dest, uint32_t v4addr)
/** Set <b>dest</b> to equal the IPv6 address in the 16 bytes at
* <b>ipv6_bytes</b>. */
void
-tor_addr_from_ipv6_bytes(tor_addr_t *dest, const char *ipv6_bytes)
+tor_addr_from_ipv6_bytes(tor_addr_t *dest, const uint8_t *ipv6_bytes)
{
tor_assert(dest);
tor_assert(ipv6_bytes);
@@ -895,7 +901,21 @@ tor_addr_from_ipv6_bytes(tor_addr_t *dest, const char *ipv6_bytes)
void
tor_addr_from_in6(tor_addr_t *dest, const struct in6_addr *in6)
{
- tor_addr_from_ipv6_bytes(dest, (const char*)in6->s6_addr);
+ tor_addr_from_ipv6_bytes(dest, in6->s6_addr);
+}
+
+/** Set the 16 bytes at <b>dest</b> to equal the IPv6 address <b>src</b>.
+ * <b>src</b> must be an IPv6 address, if it is not, log a warning, and clear
+ * <b>dest</b>. */
+void
+tor_addr_copy_ipv6_bytes(uint8_t *dest, const tor_addr_t *src)
+{
+ tor_assert(dest);
+ tor_assert(src);
+ memset(dest, 0, 16);
+ IF_BUG_ONCE(src->family != AF_INET6)
+ return;
+ memcpy(dest, src->addr.in6_addr.s6_addr, 16);
}
/** Copy a tor_addr_t from <b>src</b> to <b>dest</b>.
@@ -929,6 +949,7 @@ tor_addr_copy_tight(tor_addr_t *dest, const tor_addr_t *src)
break;
case AF_INET6:
memcpy(dest->addr.in6_addr.s6_addr, src->addr.in6_addr.s6_addr, 16);
+ break;
case AF_UNSPEC:
break;
// LCOV_EXCL_START
@@ -1168,8 +1189,7 @@ fmt_addr_impl(const tor_addr_t *addr, int decorate)
const char *
fmt_addrport(const tor_addr_t *addr, uint16_t port)
{
- /* Add space for a colon and up to 5 digits. */
- static char buf[TOR_ADDR_BUF_LEN + 6];
+ static char buf[TOR_ADDRPORT_BUF_LEN];
tor_snprintf(buf, sizeof(buf), "%s:%u", fmt_and_decorate_addr(addr), port);
return buf;
}
@@ -1187,6 +1207,39 @@ fmt_addr32(uint32_t addr)
return buf;
}
+/** Return a string representing the family of <b>addr</b>.
+ *
+ * This string is a string constant, and must not be freed.
+ * This function is thread-safe.
+ */
+const char *
+fmt_addr_family(const tor_addr_t *addr)
+{
+ static int default_bug_once = 0;
+
+ IF_BUG_ONCE(!addr)
+ return "NULL pointer";
+
+ switch (tor_addr_family(addr)) {
+ case AF_INET6:
+ return "IPv6";
+ case AF_INET:
+ return "IPv4";
+ case AF_UNIX:
+ return "UNIX socket";
+ case AF_UNSPEC:
+ return "unspecified";
+ default:
+ if (!default_bug_once) {
+ log_warn(LD_BUG, "Called with unknown address family %d",
+ (int)tor_addr_family(addr));
+ default_bug_once = 1;
+ }
+ return "unknown";
+ }
+ //return "(unreachable code)";
+}
+
/** Convert the string in <b>src</b> to a tor_addr_t <b>addr</b>. The string
* may be an IPv4 address, or an IPv6 address surrounded by square brackets.
*
@@ -1411,10 +1464,10 @@ ifconf_free_ifc_buf(struct ifconf *ifc)
* into smartlist of <b>tor_addr_t</b> structures.
*/
STATIC smartlist_t *
-ifreq_to_smartlist(char *buf, size_t buflen)
+ifreq_to_smartlist(const uint8_t *buf, size_t buflen)
{
smartlist_t *result = smartlist_new();
- char *end = buf + buflen;
+ const uint8_t *end = buf + buflen;
/* These acrobatics are due to alignment issues which trigger
* undefined behaviour traps on OSX. */
@@ -1488,7 +1541,7 @@ get_interface_addresses_ioctl(int severity, sa_family_t family)
/* Ensure we have least IFREQ_SIZE bytes unused at the end. Otherwise, we
* don't know if we got everything during ioctl. */
} while (mult * IFREQ_SIZE - ifc.ifc_len <= IFREQ_SIZE);
- result = ifreq_to_smartlist(ifc.ifc_buf, ifc.ifc_len);
+ result = ifreq_to_smartlist((const uint8_t *)ifc.ifc_buf, ifc.ifc_len);
done:
if (fd >= 0)
diff --git a/src/lib/net/address.h b/src/lib/net/address.h
index 4984494939..e5016ee4fe 100644
--- a/src/lib/net/address.h
+++ b/src/lib/net/address.h
@@ -104,6 +104,10 @@ int tor_addr_from_sockaddr(tor_addr_t *a, const struct sockaddr *sa,
uint16_t *port_out);
void tor_addr_make_unspec(tor_addr_t *a);
void tor_addr_make_null(tor_addr_t *a, sa_family_t family);
+#define tor_addr_port_make_null(addr, port, family) \
+ (void)(tor_addr_make_null(addr, family), (port) = 0)
+#define tor_addr_port_make_null_ap(ap, family) \
+ tor_addr_port_make_null(&(ap)->addr, (ap)->port, family)
char *tor_sockaddr_to_str(const struct sockaddr *sa);
/** Return an in6_addr* equivalent to <b>a</b>, or NULL if <b>a</b> is not
@@ -209,6 +213,15 @@ tor_addr_eq_ipv4h(const tor_addr_t *a, uint32_t u)
*/
#define TOR_ADDR_BUF_LEN 48
+/** Length of a buffer containing an IP address along with a port number and
+ * a seperating colon.
+ *
+ * This allows enough space for
+ * "[ffff:ffff:ffff:ffff:ffff:ffff:255.255.255.255]:12345",
+ * plus a terminating NUL.
+ */
+#define TOR_ADDRPORT_BUF_LEN (TOR_ADDR_BUF_LEN + 6)
+
char *tor_addr_to_str_dup(const tor_addr_t *addr) ATTR_MALLOC;
/** Wrapper function of fmt_addr_impl(). It does not decorate IPv6
@@ -221,7 +234,9 @@ char *tor_addr_to_str_dup(const tor_addr_t *addr) ATTR_MALLOC;
const char *fmt_addr_impl(const tor_addr_t *addr, int decorate);
const char *fmt_addrport(const tor_addr_t *addr, uint16_t port);
-const char * fmt_addr32(uint32_t addr);
+#define fmt_addrport_ap(ap) fmt_addrport(&(ap)->addr, (ap)->port)
+const char *fmt_addr32(uint32_t addr);
+const char *fmt_addr_family(const tor_addr_t *addr);
MOCK_DECL(int,get_interface_address6,(int severity, sa_family_t family,
tor_addr_t *addr));
@@ -298,11 +313,12 @@ void tor_addr_from_ipv4n(tor_addr_t *dest, uint32_t v4addr);
* order. */
#define tor_addr_from_ipv4h(dest, v4addr) \
tor_addr_from_ipv4n((dest), htonl(v4addr))
-void tor_addr_from_ipv6_bytes(tor_addr_t *dest, const char *bytes);
+void tor_addr_from_ipv6_bytes(tor_addr_t *dest, const uint8_t *bytes);
/** Set <b>dest</b> to the IPv4 address incoded in <b>in</b>. */
#define tor_addr_from_in(dest, in) \
tor_addr_from_ipv4n((dest), (in)->s_addr);
void tor_addr_from_in6(tor_addr_t *dest, const struct in6_addr *in6);
+void tor_addr_copy_ipv6_bytes(uint8_t *dest, const tor_addr_t *src);
int tor_addr_is_null(const tor_addr_t *addr);
int tor_addr_is_loopback(const tor_addr_t *addr);
@@ -393,8 +409,8 @@ STATIC struct smartlist_t *get_interface_addresses_win32(int severity,
#endif /* defined(HAVE_IP_ADAPTER_TO_SMARTLIST) */
#ifdef HAVE_IFCONF_TO_SMARTLIST
-STATIC struct smartlist_t *ifreq_to_smartlist(char *ifr,
- size_t buflen);
+STATIC struct smartlist_t *ifreq_to_smartlist(const uint8_t *ifr,
+ size_t buflen);
STATIC struct smartlist_t *get_interface_addresses_ioctl(int severity,
sa_family_t family);
#endif /* defined(HAVE_IFCONF_TO_SMARTLIST) */
diff --git a/src/lib/net/buffers_net.c b/src/lib/net/buffers_net.c
index aa84451074..4dbf491e1a 100644
--- a/src/lib/net/buffers_net.c
+++ b/src/lib/net/buffers_net.c
@@ -76,7 +76,7 @@ read_to_chunk(buf_t *buf, chunk_t *chunk, tor_socket_t fd, size_t at_most,
chunk->datalen += read_result;
log_debug(LD_NET,"Read %ld bytes. %d on inbuf.", (long)read_result,
(int)buf->datalen);
- tor_assert(read_result < INT_MAX);
+ tor_assert(read_result <= BUF_MAX_LEN);
return (int)read_result;
}
}
@@ -103,9 +103,9 @@ buf_read_from_fd(buf_t *buf, int fd, size_t at_most,
tor_assert(reached_eof);
tor_assert(SOCKET_OK(fd));
- if (BUG(buf->datalen >= INT_MAX))
+ if (BUG(buf->datalen > BUF_MAX_LEN))
return -1;
- if (BUG(buf->datalen >= INT_MAX - at_most))
+ if (BUG(buf->datalen > BUF_MAX_LEN - at_most))
return -1;
while (at_most > total_read) {
@@ -127,7 +127,7 @@ buf_read_from_fd(buf_t *buf, int fd, size_t at_most,
check();
if (r < 0)
return r; /* Error */
- tor_assert(total_read+r < INT_MAX);
+ tor_assert(total_read+r <= BUF_MAX_LEN);
total_read += r;
if ((size_t)r < readlen) { /* eof, block, or no more to read. */
break;
@@ -170,7 +170,7 @@ flush_chunk(tor_socket_t fd, buf_t *buf, chunk_t *chunk, size_t sz,
} else {
*buf_flushlen -= write_result;
buf_drain(buf, write_result);
- tor_assert(write_result < INT_MAX);
+ tor_assert(write_result <= BUF_MAX_LEN);
return (int)write_result;
}
}
@@ -217,7 +217,7 @@ buf_flush_to_fd(buf_t *buf, int fd, size_t sz,
if (r == 0 || (size_t)r < flushlen0) /* can't flush any more now. */
break;
}
- tor_assert(flushed < INT_MAX);
+ tor_assert(flushed <= BUF_MAX_LEN);
return (int)flushed;
}
diff --git a/src/lib/net/network_sys.c b/src/lib/net/network_sys.c
index f0421385b7..e95c3ba819 100644
--- a/src/lib/net/network_sys.c
+++ b/src/lib/net/network_sys.c
@@ -37,6 +37,7 @@ subsys_network_shutdown(void)
const subsys_fns_t sys_network = {
.name = "network",
+ SUBSYS_DECLARE_LOCATION(),
/* Network depends on logging, and a lot of other modules depend on network.
*/
.level = -55,
diff --git a/src/lib/net/socks5_status.h b/src/lib/net/socks5_status.h
index 2b663e00c4..90c4305d29 100644
--- a/src/lib/net/socks5_status.h
+++ b/src/lib/net/socks5_status.h
@@ -37,6 +37,7 @@ typedef enum {
SOCKS5_HS_MISSING_CLIENT_AUTH = 0xF4,
SOCKS5_HS_BAD_CLIENT_AUTH = 0xF5,
SOCKS5_HS_BAD_ADDRESS = 0xF6,
+ SOCKS5_HS_INTRO_TIMEDOUT = 0xF7,
} socks5_reply_status_t;
#endif /* !defined(TOR_SOCKS5_STATUS_H) */
diff --git a/src/lib/process/process_sys.c b/src/lib/process/process_sys.c
index 015ffadead..c8332ba91e 100644
--- a/src/lib/process/process_sys.c
+++ b/src/lib/process/process_sys.c
@@ -26,6 +26,7 @@ subsys_process_shutdown(void)
const subsys_fns_t sys_process = {
.name = "process",
+ SUBSYS_DECLARE_LOCATION(),
.level = -18,
.supported = true,
.initialize = subsys_process_initialize,
diff --git a/src/lib/sandbox/sandbox.c b/src/lib/sandbox/sandbox.c
index 1d2c40c753..b917912f4d 100644
--- a/src/lib/sandbox/sandbox.c
+++ b/src/lib/sandbox/sandbox.c
@@ -166,6 +166,7 @@ static int filter_nopar_gen[] = {
#ifdef __NR_fstat64
SCMP_SYS(fstat64),
#endif
+ SCMP_SYS(fsync),
SCMP_SYS(futex),
SCMP_SYS(getdents),
SCMP_SYS(getdents64),
@@ -265,6 +266,11 @@ static int filter_nopar_gen[] = {
SCMP_SYS(listen),
SCMP_SYS(connect),
SCMP_SYS(getsockname),
+#ifdef ENABLE_NSS
+#ifdef __NR_getpeername
+ SCMP_SYS(getpeername),
+#endif
+#endif
SCMP_SYS(recvmsg),
SCMP_SYS(recvfrom),
SCMP_SYS(sendto),
@@ -648,6 +654,15 @@ sb_socket(scmp_filter_ctx ctx, sandbox_cfg_t *filter)
}
}
+#ifdef ENABLE_NSS
+ rc = seccomp_rule_add_3(ctx, SCMP_ACT_ALLOW, SCMP_SYS(socket),
+ SCMP_CMP(0, SCMP_CMP_EQ, PF_INET),
+ SCMP_CMP(1, SCMP_CMP_EQ, SOCK_STREAM),
+ SCMP_CMP(2, SCMP_CMP_EQ, IPPROTO_IP));
+ if (rc)
+ return rc;
+#endif
+
rc = seccomp_rule_add_3(ctx, SCMP_ACT_ALLOW, SCMP_SYS(socket),
SCMP_CMP(0, SCMP_CMP_EQ, PF_UNIX),
SCMP_CMP_MASKED(1, SOCK_CLOEXEC|SOCK_NONBLOCK, SOCK_STREAM),
diff --git a/src/lib/string/compat_ctype.c b/src/lib/string/compat_ctype.c
index 2357605021..a7668bfbfb 100644
--- a/src/lib/string/compat_ctype.c
+++ b/src/lib/string/compat_ctype.c
@@ -29,6 +29,7 @@ const uint32_t TOR_ISPRINT_TABLE[8] =
{ 0, 0xffffffff, 0xffffffff, 0x7fffffff, 0, 0, 0, 0x0 };
const uint32_t TOR_ISUPPER_TABLE[8] = { 0, 0, 0x7fffffe, 0, 0, 0, 0, 0 };
const uint32_t TOR_ISLOWER_TABLE[8] = { 0, 0, 0, 0x7fffffe, 0, 0, 0, 0 };
+/**@}*/
/** Upper-casing and lowercasing tables to map characters to upper/lowercase
* equivalents. Used by tor_toupper() and tor_tolower(). */
diff --git a/src/lib/subsys/subsys.h b/src/lib/subsys/subsys.h
index c05b69af39..62c0de026d 100644
--- a/src/lib/subsys/subsys.h
+++ b/src/lib/subsys/subsys.h
@@ -42,6 +42,11 @@ typedef struct subsys_fns_t {
const char *name;
/**
+ * The file in which the subsystem object is declared. Used for debugging.
+ **/
+ const char *location;
+
+ /**
* Whether this subsystem is supported -- that is, whether it is compiled
* into Tor. For most subsystems, this should be true.
**/
@@ -187,6 +192,14 @@ typedef struct subsys_fns_t {
int (*flush_state)(void *);
} subsys_fns_t;
+#ifndef COCCI
+/**
+ * Macro to declare a subsystem's location.
+ **/
+#define SUBSYS_DECLARE_LOCATION() \
+ .location = __FILE__
+#endif /* !defined(COCCI) */
+
/**
* Lowest allowed subsystem level.
**/
diff --git a/src/lib/thread/compat_threads.c b/src/lib/thread/compat_threads.c
index 21125bddad..75ade9c9f2 100644
--- a/src/lib/thread/compat_threads.c
+++ b/src/lib/thread/compat_threads.c
@@ -129,6 +129,7 @@ subsys_threads_initialize(void)
const subsys_fns_t sys_threads = {
.name = "threads",
+ SUBSYS_DECLARE_LOCATION(),
.supported = true,
.level = -89,
.initialize = subsys_threads_initialize,
diff --git a/src/lib/time/time_sys.c b/src/lib/time/time_sys.c
index 044d328f81..1c1bc4cd18 100644
--- a/src/lib/time/time_sys.c
+++ b/src/lib/time/time_sys.c
@@ -20,6 +20,7 @@ subsys_time_initialize(void)
const subsys_fns_t sys_time = {
.name = "time",
+ SUBSYS_DECLARE_LOCATION(),
/* Monotonic time depends on logging, and a lot of other modules depend on
* monotonic time. */
.level = -80,
diff --git a/src/lib/tls/buffers_tls.c b/src/lib/tls/buffers_tls.c
index 87055744a7..b92a14d6a1 100644
--- a/src/lib/tls/buffers_tls.c
+++ b/src/lib/tls/buffers_tls.c
@@ -68,9 +68,9 @@ buf_read_from_tls(buf_t *buf, tor_tls_t *tls, size_t at_most)
check_no_tls_errors();
- IF_BUG_ONCE(buf->datalen >= INT_MAX)
+ IF_BUG_ONCE(buf->datalen > BUF_MAX_LEN)
return TOR_TLS_ERROR_MISC;
- IF_BUG_ONCE(buf->datalen >= INT_MAX - at_most)
+ IF_BUG_ONCE(buf->datalen > BUF_MAX_LEN - at_most)
return TOR_TLS_ERROR_MISC;
while (at_most > total_read) {
@@ -90,7 +90,7 @@ buf_read_from_tls(buf_t *buf, tor_tls_t *tls, size_t at_most)
r = read_to_chunk_tls(buf, chunk, tls, readlen);
if (r < 0)
return r; /* Error */
- tor_assert(total_read+r < INT_MAX);
+ tor_assert(total_read+r <= BUF_MAX_LEN);
total_read += r;
if ((size_t)r < readlen) /* eof, block, or no more to read. */
break;
@@ -177,6 +177,6 @@ buf_flush_to_tls(buf_t *buf, tor_tls_t *tls, size_t flushlen,
if (r == 0) /* Can't flush any more now. */
break;
} while (sz > 0);
- tor_assert(flushed < INT_MAX);
+ tor_assert(flushed <= BUF_MAX_LEN);
return (int)flushed;
}
diff --git a/src/lib/tls/tortls.c b/src/lib/tls/tortls.c
index fd41a84cfa..9e70e54725 100644
--- a/src/lib/tls/tortls.c
+++ b/src/lib/tls/tortls.c
@@ -456,6 +456,7 @@ subsys_tortls_shutdown(void)
const subsys_fns_t sys_tortls = {
.name = "tortls",
+ SUBSYS_DECLARE_LOCATION(),
.level = -50,
.shutdown = subsys_tortls_shutdown
};
diff --git a/src/lib/wallclock/approx_time.c b/src/lib/wallclock/approx_time.c
index d9f90ab2f7..c815f20e51 100644
--- a/src/lib/wallclock/approx_time.c
+++ b/src/lib/wallclock/approx_time.c
@@ -59,6 +59,7 @@ subsys_wallclock_initialize(void)
**/
const subsys_fns_t sys_wallclock = {
.name = "wallclock",
+ SUBSYS_DECLARE_LOCATION(),
.supported = true,
/* Approximate time is a diagnostic feature, we want it to init right after
* low-level error handling. */
diff --git a/src/lib/wallclock/time_to_tm.c b/src/lib/wallclock/time_to_tm.c
index dcd3c59c53..8c747b4c7b 100644
--- a/src/lib/wallclock/time_to_tm.c
+++ b/src/lib/wallclock/time_to_tm.c
@@ -198,3 +198,4 @@ tor_gmtime_r_msg(const time_t *timep, struct tm *result, char **err_out)
return correct_tm(0, timep, result, r, err_out);
}
#endif /* defined(HAVE_GMTIME_R) || ... */
+/**@}*/
diff --git a/src/mainpage.md b/src/mainpage.md
index 8a73578819..2c4c494354 100644
--- a/src/mainpage.md
+++ b/src/mainpage.md
@@ -4,6 +4,9 @@
@section welcome Welcome to Tor
+(For an up-to-date rendered copy of this documentation, see
+https://src-ref.docs.torproject.org/tor/index.html .)
+
This documentation describes the general structure of the Tor codebase, how
it fits together, what functionality is available for extending Tor, and
gives some notes on how Tor got that way. It also includes a reference for
diff --git a/src/test/conf_examples/empty_3/expected_log b/src/test/conf_examples/empty_3/expected_log
index a42514f37f..e3f2365893 100644
--- a/src/test/conf_examples/empty_3/expected_log
+++ b/src/test/conf_examples/empty_3/expected_log
@@ -1 +1 @@
-Included configuration .*directory at recursion level 1.*included
+Processing configuration path \".*included\" at recursion level 1\.
diff --git a/src/test/conf_examples/include_1/expected_log b/src/test/conf_examples/include_1/expected_log
index f95cad040d..0791a494d2 100644
--- a/src/test/conf_examples/include_1/expected_log
+++ b/src/test/conf_examples/include_1/expected_log
@@ -1 +1 @@
-Included configuration file .*at recursion level 2.*nested\.inc
+Processing configuration path \".*nested\.inc\" at recursion level 2\.
diff --git a/src/test/conf_examples/include_bug_31408/expected_log b/src/test/conf_examples/include_bug_31408/expected_log
index a42514f37f..e3f2365893 100644
--- a/src/test/conf_examples/include_bug_31408/expected_log
+++ b/src/test/conf_examples/include_bug_31408/expected_log
@@ -1 +1 @@
-Included configuration .*directory at recursion level 1.*included
+Processing configuration path \".*included\" at recursion level 1\.
diff --git a/src/test/include.am b/src/test/include.am
index de927836d6..e7647260c5 100644
--- a/src/test/include.am
+++ b/src/test/include.am
@@ -37,7 +37,8 @@ TESTSCRIPTS += \
src/test/test_ntor.sh \
src/test/test_hs_ntor.sh \
src/test/test_bt.sh \
- scripts/maint/practracker/test_practracker.sh
+ scripts/maint/practracker/test_practracker.sh \
+ scripts/maint/run_check_subsystem_order.sh
if COVERAGE_ENABLED
# ...
@@ -430,6 +431,7 @@ EXTRA_DIST += \
src/test/test_rebind.sh \
src/test/test_rebind.py \
src/test/zero_length_keys.sh \
+ scripts/maint/run_check_subsystem_order.sh \
src/test/rust_supp.txt \
src/test/test_keygen.sh \
src/test/test_key_expiration.sh \
diff --git a/src/test/test_addr.c b/src/test/test_addr.c
index 1a19e405ed..cf5aad7e71 100644
--- a/src/test/test_addr.c
+++ b/src/test/test_addr.c
@@ -110,7 +110,7 @@ test_addr_basic(void *arg)
tt_int_op(tor_inet_pton(AF_INET6, a, &t1.addr.in6_addr), OP_EQ, 1); \
t1.family = AF_INET6; \
if (tor_addr_is_internal(&t1, for_listening)) \
- TT_DIE(("%s was not internal", a)); \
+ TT_DIE(("%s was internal", a)); \
STMT_END
#ifndef COCCI
@@ -1671,6 +1671,136 @@ test_addr_octal(void *arg)
;
}
+#define get_ipv4(test_addr, str, iprv) STMT_BEGIN \
+ test_addr = tor_malloc(sizeof(tor_addr_t)); \
+ test_addr->family = AF_INET; \
+ iprv = tor_inet_aton(str, &test_addr->addr.in_addr); \
+ tor_assert(iprv); \
+ STMT_END;
+
+#define get_ipv6(test_addr, str, iprv) STMT_BEGIN \
+ test_addr = tor_malloc(sizeof(tor_addr_t)); \
+ test_addr->family = AF_INET6; \
+ iprv = tor_inet_pton(AF_INET6, str, &test_addr->addr.in6_addr); \
+ tor_assert(iprv); \
+ STMT_END;
+
+#define get_af_unix(test_addr) STMT_BEGIN \
+ test_addr = tor_malloc_zero(sizeof(tor_addr_t)); \
+ test_addr->family = AF_UNIX; \
+ STMT_END;
+
+#define get_af_unspec(test_addr) STMT_BEGIN \
+ test_addr = tor_malloc_zero(sizeof(tor_addr_t)); \
+ test_addr->family = AF_UNSPEC; \
+ STMT_END;
+
+#define TEST_ADDR_VALIDITY(a, lis, rv) STMT_BEGIN \
+ tor_assert(a); \
+ tt_int_op(tor_addr_is_valid(a, lis), OP_EQ, rv); \
+ STMT_END;
+
+/* Here we can change the addresses we are testing for. */
+#define IP4_TEST_ADDR "123.98.45.1"
+#define IP6_TEST_ADDR "2001:0DB8:AC10:FE01::"
+
+static void
+test_addr_is_valid(void *arg)
+{
+ (void)arg;
+ tor_addr_t *test_addr;
+ int iprv;
+
+ /* Tests for IPv4 addresses. */
+
+ /* Test for null IPv4 address. */
+ get_ipv4(test_addr, "0.0.0.0", iprv);
+ TEST_ADDR_VALIDITY(test_addr, 0, 0);
+ TEST_ADDR_VALIDITY(test_addr, 1, 1);
+ tor_free(test_addr);
+
+ /* Test for non-null IPv4 address. */
+ get_ipv4(test_addr, IP4_TEST_ADDR, iprv);
+ TEST_ADDR_VALIDITY(test_addr, 0, 1);
+ TEST_ADDR_VALIDITY(test_addr, 1, 1);
+ tor_free(test_addr);
+
+ /* Tests for IPv6 addresses. */
+
+ /* Test for null IPv6 address. */
+ get_ipv6(test_addr, "::", iprv);
+ TEST_ADDR_VALIDITY(test_addr, 0, 0);
+ TEST_ADDR_VALIDITY(test_addr, 1, 1);
+ tor_free(test_addr);
+
+ /* Test for non-null IPv6 address. */
+ get_ipv6(test_addr, IP6_TEST_ADDR, iprv);
+ TEST_ADDR_VALIDITY(test_addr, 0, 1);
+ TEST_ADDR_VALIDITY(test_addr, 1, 1);
+ tor_free(test_addr);
+
+ /* Test for address of type AF_UNIX. */
+
+ get_af_unix(test_addr);
+ TEST_ADDR_VALIDITY(test_addr, 0, 0);
+ TEST_ADDR_VALIDITY(test_addr, 1, 0);
+ tor_free(test_addr);
+
+ /* Test for address of type AF_UNSPEC. */
+
+ get_af_unspec(test_addr);
+ TEST_ADDR_VALIDITY(test_addr, 0, 0);
+ TEST_ADDR_VALIDITY(test_addr, 1, 0);
+
+ done:
+ tor_free(test_addr);
+}
+
+#define TEST_ADDR_IS_NULL(a, rv) STMT_BEGIN \
+ tor_assert(a); \
+ tt_int_op(tor_addr_is_null(a), OP_EQ, rv); \
+ STMT_END;
+
+static void
+test_addr_is_null(void *arg)
+{
+ (void)arg;
+ tor_addr_t *test_addr;
+ int iprv;
+
+ /* Test for null IPv4. */
+ get_ipv4(test_addr, "0.0.0.0", iprv);
+ TEST_ADDR_IS_NULL(test_addr, 1);
+ tor_free(test_addr);
+
+ /* Test for non-null IPv4. */
+ get_ipv4(test_addr, IP4_TEST_ADDR, iprv);
+ TEST_ADDR_IS_NULL(test_addr, 0);
+ tor_free(test_addr);
+
+ /* Test for null IPv6. */
+ get_ipv6(test_addr, "::", iprv);
+ TEST_ADDR_IS_NULL(test_addr, 1);
+ tor_free(test_addr);
+
+ /* Test for non-null IPv6. */
+ get_ipv6(test_addr, IP6_TEST_ADDR, iprv);
+ TEST_ADDR_IS_NULL(test_addr, 0);
+ tor_free(test_addr);
+
+ /* Test for address family AF_UNIX. */
+ get_af_unix(test_addr);
+ TEST_ADDR_IS_NULL(test_addr, 1);
+ tor_free(test_addr);
+
+ /* Test for address family AF_UNSPEC. */
+ get_af_unspec(test_addr);
+ TEST_ADDR_IS_NULL(test_addr, 1);
+
+ done:
+ tor_free(test_addr);
+}
+
#ifndef COCCI
#define ADDR_LEGACY(name) \
{ #name, test_addr_ ## name , 0, NULL, NULL }
@@ -1690,5 +1820,7 @@ struct testcase_t addr_tests[] = {
{ "make_null", test_addr_make_null, 0, NULL, NULL },
{ "rfc6598", test_addr_rfc6598, 0, NULL, NULL },
{ "octal", test_addr_octal, 0, NULL, NULL },
+ { "address_validity", test_addr_is_valid, 0, NULL, NULL },
+ { "address_is_null", test_addr_is_null, 0, NULL, NULL },
END_OF_TESTCASES
};
diff --git a/src/test/test_address.c b/src/test/test_address.c
index e068c99d97..4cedbda347 100644
--- a/src/test/test_address.c
+++ b/src/test/test_address.c
@@ -460,7 +460,7 @@ test_address_ifreq_to_smartlist(void *arg)
ifc->ifc_len = sizeof(struct ifreq);
ifc->ifc_ifcu.ifcu_req = ifr;
- results = ifreq_to_smartlist(ifc->ifc_buf,ifc->ifc_len);
+ results = ifreq_to_smartlist((const uint8_t *)ifc->ifc_buf,ifc->ifc_len);
tt_int_op(smartlist_len(results),OP_EQ,1);
tor_addr = smartlist_get(results, 0);
@@ -483,7 +483,7 @@ test_address_ifreq_to_smartlist(void *arg)
SMARTLIST_FOREACH(results, tor_addr_t *, t, tor_free(t));
smartlist_free(results);
- results = ifreq_to_smartlist(ifc->ifc_buf,ifc->ifc_len);
+ results = ifreq_to_smartlist((const uint8_t *)ifc->ifc_buf,ifc->ifc_len);
tt_int_op(smartlist_len(results),OP_EQ,2);
tor_addr = smartlist_get(results, 0);
diff --git a/src/test/test_cell_formats.c b/src/test/test_cell_formats.c
index 8d6d1940fd..f9ff101c98 100644
--- a/src/test/test_cell_formats.c
+++ b/src/test/test_cell_formats.c
@@ -713,16 +713,20 @@ test_cfmt_extend_cells(void *arg)
tt_mem_op(cc->onionskin,OP_EQ, b, 99+20);
tt_int_op(0, OP_EQ, extend_cell_format(&p2_cmd, &p2_len, p2, &ec));
tt_int_op(p2_cmd, OP_EQ, RELAY_COMMAND_EXTEND2);
- /* We'll generate it minus the IPv6 address and minus the konami code */
- tt_int_op(p2_len, OP_EQ, 89+99-34-20);
+ /* We'll generate it minus the konami code */
+ tt_int_op(p2_len, OP_EQ, 89+99-34);
test_memeq_hex(p2,
- /* Two items: one that same darn IP address. */
- "02000612F40001F0F1"
- /* The next is a digest : anthropomorphization */
- "0214616e7468726f706f6d6f727068697a6174696f6e"
+ /* Three items */
+ "03"
+ /* IPv4 address */
+ "0006" "12F40001" "F0F1"
+ /* The next is an RSA digest: anthropomorphization */
+ "0214" "616e7468726f706f6d6f727068697a6174696f6e"
+ /*IPv6 address */
+ "0112" "20020000000000000000000000f0c51e" "1112"
/* Now the handshake prologue */
"01050063");
- tt_mem_op(p2+1+8+22+4,OP_EQ, b, 99+20);
+ tt_mem_op(p2+1+8+22+20+4, OP_EQ, b, 99+20);
tt_int_op(0, OP_EQ, create_cell_format_relayed(&cell, cc));
/* Now let's add an ed25519 key to that extend2 cell. */
@@ -732,22 +736,31 @@ test_cfmt_extend_cells(void *arg)
/* As before, since we aren't extending by ed25519. */
get_options_mutable()->ExtendByEd25519ID = 0;
tt_int_op(0, OP_EQ, extend_cell_format(&p2_cmd, &p2_len, p2, &ec));
- tt_int_op(p2_len, OP_EQ, 89+99-34-20);
+ tt_int_op(p2_len, OP_EQ, 89+99-34);
test_memeq_hex(p2,
- "02000612F40001F0F1"
+ "03"
+ "000612F40001F0F1"
"0214616e7468726f706f6d6f727068697a6174696f6e"
+ "011220020000000000000000000000f0c51e1112"
"01050063");
/* Now try with the ed25519 ID. */
get_options_mutable()->ExtendByEd25519ID = 1;
tt_int_op(0, OP_EQ, extend_cell_format(&p2_cmd, &p2_len, p2, &ec));
- tt_int_op(p2_len, OP_EQ, 89+99-34-20 + 34);
+ tt_int_op(p2_len, OP_EQ, 89+99);
test_memeq_hex(p2,
- "03000612F40001F0F1"
+ /* Four items */
+ "04"
+ /* IPv4 address */
+ "0006" "12F40001" "F0F1"
+ /* The next is an RSA digest: anthropomorphization */
"0214616e7468726f706f6d6f727068697a6174696f6e"
- // ed digest follows:
+ /* Then an ed public key: brownshoesdontmakeit/brownshoesd */
"0320" "62726f776e73686f6573646f6e746d616b656"
"9742f62726f776e73686f657364"
+ /*IPv6 address */
+ "0112" "20020000000000000000000000f0c51e" "1112"
+ /* Now the handshake prologue */
"01050063");
/* Can we parse that? Did the key come through right? */
memset(&ec, 0, sizeof(ec));
@@ -756,6 +769,40 @@ test_cfmt_extend_cells(void *arg)
tt_mem_op("brownshoesdontmakeit/brownshoesd", OP_EQ,
ec.ed_pubkey.pubkey, 32);
+ /* Now try IPv6 without IPv4 */
+ memset(p, 0, sizeof(p));
+ memcpy(p, "\x02", 1);
+ memcpy(p+1, "\x02\x14" "anthropomorphization", 22);
+ memcpy(p+23, "\x01\x12" "xxxxxxxxxxxxxxxxYY", 20);
+ memcpy(p+43, "\xff\xff\x00\x20", 4);
+ tt_int_op(0, OP_EQ, extend_cell_parse(&ec, RELAY_COMMAND_EXTEND2,
+ p, sizeof(p)));
+ tt_int_op(RELAY_COMMAND_EXTEND2, OP_EQ, ec.cell_type);
+ tt_assert(fast_mem_is_zero((const char *)&ec.orport_ipv4.addr,
+ sizeof(tor_addr_t)));
+ tt_int_op(0, OP_EQ, ec.orport_ipv4.port);
+ tt_str_op("7878:7878:7878:7878:7878:7878:7878:7878",
+ OP_EQ, fmt_addr(&ec.orport_ipv6.addr));
+ tt_int_op(22873, OP_EQ, ec.orport_ipv6.port);
+ tt_assert(ed25519_public_key_is_zero(&ec.ed_pubkey));
+ tt_mem_op(ec.node_id,OP_EQ, "anthropomorphization", 20);
+ tt_int_op(cc->cell_type, OP_EQ, CELL_CREATE2);
+ tt_int_op(cc->handshake_type, OP_EQ, 0xffff);
+ tt_int_op(cc->handshake_len, OP_EQ, 32);
+ tt_int_op(0, OP_EQ, extend_cell_format(&p2_cmd, &p2_len, p2, &ec));
+ tt_int_op(p2_cmd, OP_EQ, RELAY_COMMAND_EXTEND2);
+ tt_int_op(p2_len, OP_EQ, 47+32);
+ test_memeq_hex(p2,
+ /* Two items */
+ "02"
+ /* The next is an RSA digest: anthropomorphization */
+ "0214" "616e7468726f706f6d6f727068697a6174696f6e"
+ /*IPv6 address */
+ "0112" "78787878787878787878787878787878" "5959"
+ /* Now the handshake prologue */
+ "ffff0020");
+ tt_int_op(0, OP_EQ, create_cell_format_relayed(&cell, cc));
+
/* == Now try parsing some junk */
/* Try a too-long handshake */
@@ -811,13 +858,6 @@ test_cfmt_extend_cells(void *arg)
memcpy(p+48, "\xff\xff\x00\x20", 4);
tt_int_op(-1, OP_EQ, extend_cell_parse(&ec, RELAY_COMMAND_EXTEND2,
p, sizeof(p)));
- memset(p, 0, sizeof(p));
- memcpy(p, "\x02", 1);
- memcpy(p+1, "\x02\x14" "anarchoindividualist", 22);
- memcpy(p+23, "\x01\x12" "xxxxxxxxxxxxxxxxYY", 18);
- memcpy(p+41, "\xff\xff\x00\x20", 4);
- tt_int_op(-1, OP_EQ, extend_cell_parse(&ec, RELAY_COMMAND_EXTEND2,
- p, sizeof(p)));
/* Running out of space in specifiers */
memset(p,0,sizeof(p));
diff --git a/src/test/test_channel.c b/src/test/test_channel.c
index 5b13f1f979..849cc497fc 100644
--- a/src/test/test_channel.c
+++ b/src/test/test_channel.c
@@ -1326,7 +1326,7 @@ test_channel_for_extend(void *arg)
channel_t *ret_chan = NULL;
char digest[DIGEST_LEN];
ed25519_public_key_t ed_id;
- tor_addr_t addr;
+ tor_addr_t ipv4_addr, ipv6_addr;
const char *msg;
int launch;
time_t now = time(NULL);
@@ -1336,6 +1336,9 @@ test_channel_for_extend(void *arg)
memset(digest, 'A', sizeof(digest));
memset(&ed_id, 'B', sizeof(ed_id));
+ tor_addr_make_null(&ipv4_addr, AF_INET);
+ tor_addr_make_null(&ipv6_addr, AF_INET6);
+
chan1 = new_fake_channel();
tt_assert(chan1);
/* Need to be registered to get added to the id map. */
@@ -1366,7 +1369,8 @@ test_channel_for_extend(void *arg)
tt_ptr_op(channel_find_by_remote_identity(digest, &ed_id), OP_EQ, chan1);
/* The expected result is chan2 because it is older than chan1. */
- ret_chan = channel_get_for_extend(digest, &ed_id, &addr, &msg, &launch);
+ ret_chan = channel_get_for_extend(digest, &ed_id, &ipv4_addr, &ipv6_addr,
+ &msg, &launch);
tt_assert(ret_chan);
tt_ptr_op(ret_chan, OP_EQ, chan2);
tt_int_op(launch, OP_EQ, 0);
@@ -1374,16 +1378,18 @@ test_channel_for_extend(void *arg)
/* Switch that around from previous test. */
chan2->timestamp_created = chan1->timestamp_created + 1;
- ret_chan = channel_get_for_extend(digest, &ed_id, &addr, &msg, &launch);
+ ret_chan = channel_get_for_extend(digest, &ed_id, &ipv4_addr, &ipv6_addr,
+ &msg, &launch);
tt_assert(ret_chan);
tt_ptr_op(ret_chan, OP_EQ, chan1);
tt_int_op(launch, OP_EQ, 0);
tt_str_op(msg, OP_EQ, "Connection is fine; using it.");
/* Same creation time, num circuits will be used and they both have 0 so the
- * channel 2 should be picked due to how channel_is_better() work. */
+ * channel 2 should be picked due to how channel_is_better() works. */
chan2->timestamp_created = chan1->timestamp_created;
- ret_chan = channel_get_for_extend(digest, &ed_id, &addr, &msg, &launch);
+ ret_chan = channel_get_for_extend(digest, &ed_id, &ipv4_addr, &ipv6_addr,
+ &msg, &launch);
tt_assert(ret_chan);
tt_ptr_op(ret_chan, OP_EQ, chan1);
tt_int_op(launch, OP_EQ, 0);
@@ -1394,7 +1400,8 @@ test_channel_for_extend(void *arg)
/* Condemned the older channel. */
chan1->state = CHANNEL_STATE_CLOSING;
- ret_chan = channel_get_for_extend(digest, &ed_id, &addr, &msg, &launch);
+ ret_chan = channel_get_for_extend(digest, &ed_id, &ipv4_addr, &ipv6_addr,
+ &msg, &launch);
tt_assert(ret_chan);
tt_ptr_op(ret_chan, OP_EQ, chan2);
tt_int_op(launch, OP_EQ, 0);
@@ -1403,7 +1410,8 @@ test_channel_for_extend(void *arg)
/* Make the older channel a client one. */
channel_mark_client(chan1);
- ret_chan = channel_get_for_extend(digest, &ed_id, &addr, &msg, &launch);
+ ret_chan = channel_get_for_extend(digest, &ed_id, &ipv4_addr, &ipv6_addr,
+ &msg, &launch);
tt_assert(ret_chan);
tt_ptr_op(ret_chan, OP_EQ, chan2);
tt_int_op(launch, OP_EQ, 0);
@@ -1413,8 +1421,9 @@ test_channel_for_extend(void *arg)
/* Non matching ed identity with valid digest. */
ed25519_public_key_t dumb_ed_id;
memset(&dumb_ed_id, 0, sizeof(dumb_ed_id));
- ret_chan = channel_get_for_extend(digest, &dumb_ed_id, &addr, &msg,
- &launch);
+ ret_chan = channel_get_for_extend(digest, &dumb_ed_id,
+ &ipv4_addr, &ipv6_addr,
+ &msg, &launch);
tt_assert(!ret_chan);
tt_str_op(msg, OP_EQ, "Not connected. Connecting.");
tt_int_op(launch, OP_EQ, 1);
@@ -1423,7 +1432,8 @@ test_channel_for_extend(void *arg)
test_chan_should_match_target = 1;
chan1->state = CHANNEL_STATE_OPENING;
chan2->state = CHANNEL_STATE_OPENING;
- ret_chan = channel_get_for_extend(digest, &ed_id, &addr, &msg, &launch);
+ ret_chan = channel_get_for_extend(digest, &ed_id, &ipv4_addr, &ipv6_addr,
+ &msg, &launch);
tt_assert(!ret_chan);
tt_str_op(msg, OP_EQ, "Connection in progress; waiting.");
tt_int_op(launch, OP_EQ, 0);
@@ -1432,7 +1442,8 @@ test_channel_for_extend(void *arg)
/* Mark channel 1 as bad for circuits. */
channel_mark_bad_for_new_circs(chan1);
- ret_chan = channel_get_for_extend(digest, &ed_id, &addr, &msg, &launch);
+ ret_chan = channel_get_for_extend(digest, &ed_id, &ipv4_addr, &ipv6_addr,
+ &msg, &launch);
tt_assert(ret_chan);
tt_ptr_op(ret_chan, OP_EQ, chan2);
tt_int_op(launch, OP_EQ, 0);
@@ -1442,7 +1453,8 @@ test_channel_for_extend(void *arg)
/* Mark both channels as unusable. */
channel_mark_bad_for_new_circs(chan1);
channel_mark_bad_for_new_circs(chan2);
- ret_chan = channel_get_for_extend(digest, &ed_id, &addr, &msg, &launch);
+ ret_chan = channel_get_for_extend(digest, &ed_id, &ipv4_addr, &ipv6_addr,
+ &msg, &launch);
tt_assert(!ret_chan);
tt_str_op(msg, OP_EQ, "Connections all too old, or too non-canonical. "
" Launching a new one.");
@@ -1453,7 +1465,8 @@ test_channel_for_extend(void *arg)
/* Non canonical channels. */
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);
+ ret_chan = channel_get_for_extend(digest, &ed_id, &ipv4_addr, &ipv6_addr,
+ &msg, &launch);
tt_assert(!ret_chan);
tt_str_op(msg, OP_EQ, "Connections all too old, or too non-canonical. "
" Launching a new one.");
diff --git a/src/test/test_channeltls.c b/src/test/test_channeltls.c
index 94ce56f2be..f4f5cb447e 100644
--- a/src/test/test_channeltls.c
+++ b/src/test/test_channeltls.c
@@ -14,6 +14,7 @@
#include "core/mainloop/connection.h"
#include "core/or/connection_or.h"
#include "app/config/config.h"
+#include "app/config/resolve_addr.h"
/* For init/free stuff */
#include "core/or/scheduler.h"
#include "lib/tls/tortls.h"
diff --git a/src/test/test_circuitbuild.c b/src/test/test_circuitbuild.c
index 10d78abc35..03fd176ead 100644
--- a/src/test/test_circuitbuild.c
+++ b/src/test/test_circuitbuild.c
@@ -8,18 +8,32 @@
#define ENTRYNODES_PRIVATE
#include "core/or/or.h"
+
#include "test/test.h"
#include "test/test_helpers.h"
#include "test/log_test_helpers.h"
+
+#define CONFIG_PRIVATE
#include "app/config/config.h"
+
+#include "core/or/channel.h"
#include "core/or/circuitbuild.h"
#include "core/or/circuitlist.h"
+#include "core/or/onion.h"
+#include "core/or/cell_st.h"
#include "core/or/cpath_build_state_st.h"
#include "core/or/extend_info_st.h"
#include "core/or/origin_circuit_st.h"
+#include "core/or/or_circuit_st.h"
#include "feature/client/entrynodes.h"
+#include "feature/nodelist/nodelist.h"
+#include "feature/relay/circuitbuild_relay.h"
+#include "feature/relay/router.h"
+#include "feature/relay/routermode.h"
+
+#include "feature/nodelist/node_st.h"
/* Dummy nodes smartlist for testing */
static smartlist_t dummy_nodes;
@@ -120,7 +134,7 @@ test_new_route_len_unhandled_exit(void *arg)
#if !defined(__COVERITY__) && !defined(__clang_analyzer__)
tt_skip();
#endif
-#endif
+#endif /* defined(ALL_BUGS_ARE_FATAL) */
MOCK(count_acceptable_nodes, mock_count_acceptable_nodes);
@@ -133,10 +147,10 @@ test_new_route_len_unhandled_exit(void *arg)
"!(exit_ei && !known_purpose)");
expect_single_log_msg_containing("Unhandled purpose");
expect_single_log_msg_containing("with a chosen exit; assuming routelen");
- teardown_capture_of_logs();
- tor_end_capture_bugs_();
done:
+ teardown_capture_of_logs();
+ tor_end_capture_bugs_();
UNMOCK(count_acceptable_nodes);
}
@@ -180,12 +194,1361 @@ test_upgrade_from_guard_wait(void *arg)
entry_guard_free_(guard);
}
+static int server = 0;
+static int
+mock_server_mode(const or_options_t *options)
+{
+ (void)options;
+ return server;
+}
+
+/* Test the different cases in circuit_extend_state_valid_helper(). */
+static void
+test_circuit_extend_state_valid(void *arg)
+{
+ (void)arg;
+ circuit_t *circ = tor_malloc_zero(sizeof(circuit_t));
+
+ server = 0;
+ MOCK(server_mode, mock_server_mode);
+
+ setup_full_capture_of_logs(LOG_INFO);
+
+ /* Clients can't extend */
+ server = 0;
+ tt_int_op(circuit_extend_state_valid_helper(NULL), OP_EQ, -1);
+ expect_log_msg("Got an extend cell, but running as a client. Closing.\n");
+ mock_clean_saved_logs();
+
+#ifndef ALL_BUGS_ARE_FATAL
+ /* Circuit must be non-NULL */
+ tor_capture_bugs_(1);
+ server = 1;
+ tt_int_op(circuit_extend_state_valid_helper(NULL), OP_EQ, -1);
+ tt_int_op(smartlist_len(tor_get_captured_bug_log_()), OP_EQ, 1);
+ tt_str_op(smartlist_get(tor_get_captured_bug_log_(), 0), OP_EQ,
+ "!(ASSERT_PREDICT_UNLIKELY_(!circ))");
+ tor_end_capture_bugs_();
+ mock_clean_saved_logs();
+#endif /* !defined(ALL_BUGS_ARE_FATAL) */
+
+ /* n_chan and n_hop are NULL, this should succeed */
+ server = 1;
+ tt_int_op(circuit_extend_state_valid_helper(circ), OP_EQ, 0);
+ mock_clean_saved_logs();
+
+ /* But clients still can't extend */
+ server = 0;
+ tt_int_op(circuit_extend_state_valid_helper(circ), OP_EQ, -1);
+ expect_log_msg("Got an extend cell, but running as a client. Closing.\n");
+ mock_clean_saved_logs();
+
+ /* n_chan must be NULL */
+ circ->n_chan = tor_malloc_zero(sizeof(channel_t));
+ server = 1;
+ tt_int_op(circuit_extend_state_valid_helper(circ), OP_EQ, -1);
+ expect_log_msg("n_chan already set. Bug/attack. Closing.\n");
+ mock_clean_saved_logs();
+ tor_free(circ->n_chan);
+
+ /* n_hop must be NULL */
+ circ->n_hop = tor_malloc_zero(sizeof(extend_info_t));
+ server = 1;
+ tt_int_op(circuit_extend_state_valid_helper(circ), OP_EQ, -1);
+ expect_log_msg("conn to next hop already launched. Bug/attack. Closing.\n");
+ mock_clean_saved_logs();
+ tor_free(circ->n_hop);
+
+ done:
+ tor_end_capture_bugs_();
+ teardown_capture_of_logs();
+
+ UNMOCK(server_mode);
+ server = 0;
+
+ tor_free(circ->n_chan);
+ tor_free(circ->n_hop);
+ tor_free(circ);
+}
+
+static node_t *mocked_node = NULL;
+static const node_t *
+mock_node_get_by_id(const char *identity_digest)
+{
+ (void)identity_digest;
+ return mocked_node;
+}
+
+static int mocked_supports_ed25519_link_authentication = 0;
+static int
+mock_node_supports_ed25519_link_authentication(const node_t *node,
+ int compatible_with_us)
+{
+ (void)node;
+ (void)compatible_with_us;
+ return mocked_supports_ed25519_link_authentication;
+}
+
+static ed25519_public_key_t * mocked_ed25519_id = NULL;
+static const ed25519_public_key_t *
+mock_node_get_ed25519_id(const node_t *node)
+{
+ (void)node;
+ return mocked_ed25519_id;
+}
+
+/* Test the different cases in circuit_extend_add_ed25519_helper(). */
+static void
+test_circuit_extend_add_ed25519(void *arg)
+{
+ (void)arg;
+ extend_cell_t *ec = tor_malloc_zero(sizeof(extend_cell_t));
+ extend_cell_t *old_ec = tor_malloc_zero(sizeof(extend_cell_t));
+ extend_cell_t *zero_ec = tor_malloc_zero(sizeof(extend_cell_t));
+
+ node_t *fake_node = tor_malloc_zero(sizeof(node_t));
+ ed25519_public_key_t *fake_ed25519_id = NULL;
+ fake_ed25519_id = tor_malloc_zero(sizeof(ed25519_public_key_t));
+
+ MOCK(node_get_by_id, mock_node_get_by_id);
+ MOCK(node_supports_ed25519_link_authentication,
+ mock_node_supports_ed25519_link_authentication);
+ MOCK(node_get_ed25519_id, mock_node_get_ed25519_id);
+
+ setup_full_capture_of_logs(LOG_INFO);
+
+#ifndef ALL_BUGS_ARE_FATAL
+ /* The extend cell must be non-NULL */
+ tor_capture_bugs_(1);
+ tt_int_op(circuit_extend_add_ed25519_helper(NULL), OP_EQ, -1);
+ tt_int_op(smartlist_len(tor_get_captured_bug_log_()), OP_EQ, 1);
+ tt_str_op(smartlist_get(tor_get_captured_bug_log_(), 0), OP_EQ,
+ "!(ASSERT_PREDICT_UNLIKELY_(!ec))");
+ tor_end_capture_bugs_();
+ mock_clean_saved_logs();
+#endif /* !defined(ALL_BUGS_ARE_FATAL) */
+
+ /* The node id must be non-zero */
+ memcpy(old_ec, ec, sizeof(extend_cell_t));
+ tt_int_op(circuit_extend_add_ed25519_helper(ec), OP_EQ, -1);
+ expect_log_msg(
+ "Client asked me to extend without specifying an id_digest.\n");
+ /* And nothing should have changed */
+ tt_mem_op(ec, OP_EQ, old_ec, sizeof(extend_cell_t));
+ mock_clean_saved_logs();
+
+ /* Fill in fake node_id, and try again */
+ memset(ec->node_id, 0xAA, sizeof(ec->node_id));
+ memcpy(old_ec, ec, sizeof(extend_cell_t));
+ tt_int_op(circuit_extend_add_ed25519_helper(ec), OP_EQ, 0);
+ /* There's no node with that id, so the ed pubkey should still be zeroed */
+ tt_mem_op(&ec->ed_pubkey, OP_EQ, &zero_ec->ed_pubkey, sizeof(ec->ed_pubkey));
+ /* In fact, nothing should have changed */
+ tt_mem_op(ec, OP_EQ, old_ec, sizeof(extend_cell_t));
+ mock_clean_saved_logs();
+
+ /* Provide 2 out of 3 of node, supports link auth, and ed_id.
+ * The ed_id should remain zeroed. */
+
+ /* Provide node and supports link auth */
+ memset(ec->node_id, 0xAA, sizeof(ec->node_id));
+ memcpy(old_ec, ec, sizeof(extend_cell_t));
+ /* Set up the fake variables */
+ mocked_node = fake_node;
+ mocked_supports_ed25519_link_authentication = 1;
+ /* Do the test */
+ tt_int_op(circuit_extend_add_ed25519_helper(ec), OP_EQ, 0);
+ /* The ed pubkey should still be zeroed */
+ tt_mem_op(&ec->ed_pubkey, OP_EQ, &zero_ec->ed_pubkey, sizeof(ec->ed_pubkey));
+ /* In fact, nothing should have changed */
+ tt_mem_op(ec, OP_EQ, old_ec, sizeof(extend_cell_t));
+ /* Cleanup */
+ mock_clean_saved_logs();
+ mocked_node = NULL;
+ mocked_supports_ed25519_link_authentication = 0;
+ mocked_ed25519_id = NULL;
+ memset(fake_ed25519_id, 0x00, sizeof(ed25519_public_key_t));
+
+ /* Provide supports link auth and ed id */
+ memset(ec->node_id, 0xAA, sizeof(ec->node_id));
+ memcpy(old_ec, ec, sizeof(extend_cell_t));
+ /* Set up the fake variables */
+ mocked_supports_ed25519_link_authentication = 1;
+ memset(fake_ed25519_id, 0xEE, sizeof(ed25519_public_key_t));
+ mocked_ed25519_id = fake_ed25519_id;
+ /* Do the test */
+ tt_int_op(circuit_extend_add_ed25519_helper(ec), OP_EQ, 0);
+ /* The ed pubkey should still be zeroed */
+ tt_mem_op(&ec->ed_pubkey, OP_EQ, &zero_ec->ed_pubkey, sizeof(ec->ed_pubkey));
+ /* In fact, nothing should have changed */
+ tt_mem_op(ec, OP_EQ, old_ec, sizeof(extend_cell_t));
+ /* Cleanup */
+ mock_clean_saved_logs();
+ mocked_node = NULL;
+ mocked_supports_ed25519_link_authentication = 0;
+ mocked_ed25519_id = NULL;
+ memset(fake_ed25519_id, 0x00, sizeof(ed25519_public_key_t));
+
+ /* Provide node and ed id */
+ memset(ec->node_id, 0xAA, sizeof(ec->node_id));
+ memcpy(old_ec, ec, sizeof(extend_cell_t));
+ /* Set up the fake variables */
+ mocked_node = fake_node;
+ memset(fake_ed25519_id, 0xEE, sizeof(ed25519_public_key_t));
+ mocked_ed25519_id = fake_ed25519_id;
+ /* Do the test */
+ tt_int_op(circuit_extend_add_ed25519_helper(ec), OP_EQ, 0);
+ /* The ed pubkey should still be zeroed */
+ tt_mem_op(&ec->ed_pubkey, OP_EQ, &zero_ec->ed_pubkey, sizeof(ec->ed_pubkey));
+ /* In fact, nothing should have changed */
+ tt_mem_op(ec, OP_EQ, old_ec, sizeof(extend_cell_t));
+ /* Cleanup */
+ mock_clean_saved_logs();
+ mocked_node = NULL;
+ mocked_supports_ed25519_link_authentication = 0;
+ mocked_ed25519_id = NULL;
+ memset(fake_ed25519_id, 0x00, sizeof(ed25519_public_key_t));
+
+ /* Now do the real lookup */
+ memset(ec->node_id, 0xAA, sizeof(ec->node_id));
+ memcpy(old_ec, ec, sizeof(extend_cell_t));
+ /* Set up the fake variables */
+ mocked_node = fake_node;
+ mocked_supports_ed25519_link_authentication = 1;
+ memset(fake_ed25519_id, 0xEE, sizeof(ed25519_public_key_t));
+ mocked_ed25519_id = fake_ed25519_id;
+ /* Do the test */
+ tt_int_op(circuit_extend_add_ed25519_helper(ec), OP_EQ, 0);
+ /* The ed pubkey should match */
+ tt_mem_op(&ec->ed_pubkey, OP_EQ, fake_ed25519_id, sizeof(ec->ed_pubkey));
+ /* Nothing else should have changed */
+ memcpy(&ec->ed_pubkey, &old_ec->ed_pubkey, sizeof(ec->ed_pubkey));
+ tt_mem_op(ec, OP_EQ, old_ec, sizeof(extend_cell_t));
+ /* Cleanup */
+ mock_clean_saved_logs();
+ mocked_node = NULL;
+ mocked_supports_ed25519_link_authentication = 0;
+ mocked_ed25519_id = NULL;
+ memset(fake_ed25519_id, 0x00, sizeof(ed25519_public_key_t));
+
+ /* Now do the real lookup, but with a zeroed ed id */
+ memset(ec->node_id, 0xAA, sizeof(ec->node_id));
+ memcpy(old_ec, ec, sizeof(extend_cell_t));
+ /* Set up the fake variables */
+ mocked_node = fake_node;
+ mocked_supports_ed25519_link_authentication = 1;
+ memset(fake_ed25519_id, 0x00, sizeof(ed25519_public_key_t));
+ mocked_ed25519_id = fake_ed25519_id;
+ /* Do the test */
+ tt_int_op(circuit_extend_add_ed25519_helper(ec), OP_EQ, 0);
+ /* The ed pubkey should match */
+ tt_mem_op(&ec->ed_pubkey, OP_EQ, fake_ed25519_id, sizeof(ec->ed_pubkey));
+ /* Nothing else should have changed */
+ memcpy(&ec->ed_pubkey, &old_ec->ed_pubkey, sizeof(ec->ed_pubkey));
+ tt_mem_op(ec, OP_EQ, old_ec, sizeof(extend_cell_t));
+ /* Cleanup */
+ mock_clean_saved_logs();
+ mocked_node = NULL;
+ mocked_supports_ed25519_link_authentication = 0;
+ mocked_ed25519_id = NULL;
+ memset(fake_ed25519_id, 0x00, sizeof(ed25519_public_key_t));
+
+ done:
+ UNMOCK(node_get_by_id);
+ UNMOCK(node_supports_ed25519_link_authentication);
+ UNMOCK(node_get_ed25519_id);
+
+ tor_end_capture_bugs_();
+ teardown_capture_of_logs();
+
+ tor_free(ec);
+ tor_free(old_ec);
+ tor_free(zero_ec);
+
+ tor_free(fake_ed25519_id);
+ tor_free(fake_node);
+}
+
+static or_options_t *mocked_options = NULL;
+static const or_options_t *
+mock_get_options(void)
+{
+ return mocked_options;
+}
+
+#define PUBLIC_IPV4 "1.2.3.4"
+#define INTERNAL_IPV4 "0.0.0.1"
+
+#define PUBLIC_IPV6 "1234::cdef"
+#define INTERNAL_IPV6 "::1"
+
+#define VALID_PORT 0x1234
+
+/* Test the different cases in circuit_extend_lspec_valid_helper(). */
+static void
+test_circuit_extend_lspec_valid(void *arg)
+{
+ (void)arg;
+ extend_cell_t *ec = tor_malloc_zero(sizeof(extend_cell_t));
+ channel_t *p_chan = tor_malloc_zero(sizeof(channel_t));
+ or_circuit_t *or_circ = tor_malloc_zero(sizeof(or_circuit_t));
+ circuit_t *circ = TO_CIRCUIT(or_circ);
+
+ or_options_t *fake_options = options_new();
+ MOCK(get_options, mock_get_options);
+ mocked_options = fake_options;
+
+ setup_full_capture_of_logs(LOG_INFO);
+
+#ifndef ALL_BUGS_ARE_FATAL
+ /* Extend cell must be non-NULL */
+ tor_capture_bugs_(1);
+ tt_int_op(circuit_extend_lspec_valid_helper(NULL, circ), OP_EQ, -1);
+ tt_int_op(smartlist_len(tor_get_captured_bug_log_()), OP_EQ, 1);
+ tt_str_op(smartlist_get(tor_get_captured_bug_log_(), 0), OP_EQ,
+ "!(ASSERT_PREDICT_UNLIKELY_(!ec))");
+ tor_end_capture_bugs_();
+ mock_clean_saved_logs();
+
+ /* Circuit must be non-NULL */
+ tor_capture_bugs_(1);
+ tt_int_op(circuit_extend_lspec_valid_helper(ec, NULL), OP_EQ, -1);
+ tt_int_op(smartlist_len(tor_get_captured_bug_log_()), OP_EQ, 1);
+ tt_str_op(smartlist_get(tor_get_captured_bug_log_(), 0), OP_EQ,
+ "!(ASSERT_PREDICT_UNLIKELY_(!circ))");
+ tor_end_capture_bugs_();
+ mock_clean_saved_logs();
+
+ /* Extend cell and circuit must be non-NULL */
+ tor_capture_bugs_(1);
+ tt_int_op(circuit_extend_lspec_valid_helper(NULL, NULL), OP_EQ, -1);
+ /* Since we're using IF_BUG_ONCE(), we might not log any bugs */
+ tt_int_op(smartlist_len(tor_get_captured_bug_log_()), OP_GE, 0);
+ tt_int_op(smartlist_len(tor_get_captured_bug_log_()), OP_LE, 2);
+ tor_end_capture_bugs_();
+ mock_clean_saved_logs();
+#endif /* !defined(ALL_BUGS_ARE_FATAL) */
+
+ /* IPv4 and IPv6 addr and port are all zero, this should fail */
+ tt_int_op(circuit_extend_lspec_valid_helper(ec, circ), OP_EQ, -1);
+ expect_log_msg("Client asked me to extend to a zero destination port "
+ "or unspecified address '[scrubbed]'.\n");
+ mock_clean_saved_logs();
+
+ /* Now ask for the actual address in the logs */
+ fake_options->SafeLogging_ = SAFELOG_SCRUB_NONE;
+
+ /* IPv4 port is 0, IPv6 addr and port are both zero, this should fail */
+ tor_addr_parse(&ec->orport_ipv4.addr, PUBLIC_IPV4);
+ tt_int_op(circuit_extend_lspec_valid_helper(ec, circ), OP_EQ, -1);
+ expect_log_msg("Client asked me to extend to a zero destination port "
+ "or IPv4 address '1.2.3.4:0'.\n");
+ mock_clean_saved_logs();
+ tor_addr_port_make_null_ap(&ec->orport_ipv4, AF_INET);
+ tor_addr_port_make_null_ap(&ec->orport_ipv6, AF_INET6);
+
+ /* IPv4 addr is 0, IPv6 addr and port are both zero, this should fail */
+ ec->orport_ipv4.port = VALID_PORT;
+ tt_int_op(circuit_extend_lspec_valid_helper(ec, circ), OP_EQ, -1);
+ expect_log_msg("Client asked me to extend to a zero destination port "
+ "or IPv4 address '0.0.0.0:4660'.\n");
+ mock_clean_saved_logs();
+ ec->orport_ipv4.port = 0;
+ tor_addr_port_make_null_ap(&ec->orport_ipv4, AF_INET);
+ tor_addr_port_make_null_ap(&ec->orport_ipv6, AF_INET6);
+
+ /* IPv4 addr is internal, and port is valid.
+ * (IPv6 addr and port are both zero.)
+ * Result depends on ExtendAllowPrivateAddresses. */
+ tor_addr_parse(&ec->orport_ipv4.addr, INTERNAL_IPV4);
+ ec->orport_ipv4.port = VALID_PORT;
+
+ fake_options->ExtendAllowPrivateAddresses = 0;
+ tt_int_op(circuit_extend_lspec_valid_helper(ec, circ), OP_EQ, -1);
+ expect_log_msg("Client asked me to extend "
+ "to a private IPv4 address '0.0.0.1'.\n");
+ mock_clean_saved_logs();
+ fake_options->ExtendAllowPrivateAddresses = 0;
+ tor_addr_port_make_null_ap(&ec->orport_ipv4, AF_INET);
+ tor_addr_port_make_null_ap(&ec->orport_ipv6, AF_INET6);
+
+ /* Now do the same tests, but for IPv6 */
+
+ /* IPv6 port is 0, IPv4 addr and port are both zero, this should fail */
+ tor_addr_parse(&ec->orport_ipv6.addr, PUBLIC_IPV6);
+ tt_int_op(circuit_extend_lspec_valid_helper(ec, circ), OP_EQ, -1);
+ expect_log_msg("Client asked me to extend to a zero destination port "
+ "or IPv6 address '[1234::cdef]:0'.\n");
+ mock_clean_saved_logs();
+ tor_addr_port_make_null_ap(&ec->orport_ipv4, AF_INET);
+ tor_addr_port_make_null_ap(&ec->orport_ipv6, AF_INET6);
+
+ /* IPv6 addr is 0, IPv4 addr and port are both zero, this should fail */
+ ec->orport_ipv6.port = VALID_PORT;
+ tt_int_op(circuit_extend_lspec_valid_helper(ec, circ), OP_EQ, -1);
+ expect_log_msg("Client asked me to extend to a zero destination port "
+ "or IPv6 address '[::]:4660'.\n");
+ mock_clean_saved_logs();
+ ec->orport_ipv4.port = 0;
+ tor_addr_port_make_null_ap(&ec->orport_ipv4, AF_INET);
+ tor_addr_port_make_null_ap(&ec->orport_ipv6, AF_INET6);
+
+ /* IPv6 addr is internal, and port is valid.
+ * (IPv4 addr and port are both zero.)
+ * Result depends on ExtendAllowPrivateAddresses. */
+ tor_addr_parse(&ec->orport_ipv6.addr, INTERNAL_IPV6);
+ ec->orport_ipv6.port = VALID_PORT;
+
+ fake_options->ExtendAllowPrivateAddresses = 0;
+ tt_int_op(circuit_extend_lspec_valid_helper(ec, circ), OP_EQ, -1);
+ expect_log_msg("Client asked me to extend "
+ "to a private IPv6 address '[::1]'.\n");
+ mock_clean_saved_logs();
+ fake_options->ExtendAllowPrivateAddresses = 0;
+ tor_addr_port_make_null_ap(&ec->orport_ipv4, AF_INET);
+ tor_addr_port_make_null_ap(&ec->orport_ipv6, AF_INET6);
+
+ /* Both addresses are internal.
+ * Result depends on ExtendAllowPrivateAddresses. */
+ tor_addr_parse(&ec->orport_ipv4.addr, INTERNAL_IPV4);
+ ec->orport_ipv4.port = VALID_PORT;
+ tor_addr_parse(&ec->orport_ipv6.addr, INTERNAL_IPV6);
+ ec->orport_ipv6.port = VALID_PORT;
+
+ fake_options->ExtendAllowPrivateAddresses = 0;
+ tt_int_op(circuit_extend_lspec_valid_helper(ec, circ), OP_EQ, -1);
+ expect_log_msg("Client asked me to extend "
+ "to a private IPv4 address '0.0.0.1'.\n");
+ expect_log_msg("Client asked me to extend "
+ "to a private IPv6 address '[::1]'.\n");
+ mock_clean_saved_logs();
+ fake_options->ExtendAllowPrivateAddresses = 0;
+ tor_addr_port_make_null_ap(&ec->orport_ipv4, AF_INET);
+ tor_addr_port_make_null_ap(&ec->orport_ipv6, AF_INET6);
+
+#ifndef ALL_BUGS_ARE_FATAL
+ /* If we pass the private address check, but don't have the right
+ * OR circuit magic number, we trigger another bug */
+ tor_addr_parse(&ec->orport_ipv4.addr, INTERNAL_IPV4);
+ ec->orport_ipv4.port = VALID_PORT;
+ tor_addr_parse(&ec->orport_ipv6.addr, INTERNAL_IPV6);
+ ec->orport_ipv6.port = VALID_PORT;
+ fake_options->ExtendAllowPrivateAddresses = 1;
+
+ tor_capture_bugs_(1);
+ tt_int_op(circuit_extend_lspec_valid_helper(ec, circ), OP_EQ, -1);
+ tt_int_op(smartlist_len(tor_get_captured_bug_log_()), OP_EQ, 1);
+ tt_str_op(smartlist_get(tor_get_captured_bug_log_(), 0), OP_EQ,
+ "!(ASSERT_PREDICT_UNLIKELY_(circ->magic != 0x98ABC04Fu))");
+ tor_end_capture_bugs_();
+ mock_clean_saved_logs();
+ fake_options->ExtendAllowPrivateAddresses = 0;
+ tor_addr_port_make_null_ap(&ec->orport_ipv4, AF_INET);
+ tor_addr_port_make_null_ap(&ec->orport_ipv6, AF_INET6);
+
+ /* Fail again, but this time only set an IPv4 address. */
+ tor_addr_parse(&ec->orport_ipv4.addr, INTERNAL_IPV4);
+ ec->orport_ipv4.port = VALID_PORT;
+ fake_options->ExtendAllowPrivateAddresses = 1;
+ tor_capture_bugs_(1);
+ tt_int_op(circuit_extend_lspec_valid_helper(ec, circ), OP_EQ, -1);
+ /* Since we're using IF_BUG_ONCE(), expect 0-1 bug logs */
+ tt_int_op(smartlist_len(tor_get_captured_bug_log_()), OP_GE, 0);
+ tt_int_op(smartlist_len(tor_get_captured_bug_log_()), OP_LE, 1);
+ tor_end_capture_bugs_();
+ mock_clean_saved_logs();
+ fake_options->ExtendAllowPrivateAddresses = 0;
+#endif /* !defined(ALL_BUGS_ARE_FATAL) */
+
+ /* Now set the right magic */
+ or_circ->base_.magic = OR_CIRCUIT_MAGIC;
+
+#ifndef ALL_BUGS_ARE_FATAL
+ /* If we pass the OR circuit magic check, but don't have p_chan,
+ * we trigger another bug */
+ fake_options->ExtendAllowPrivateAddresses = 1;
+ tor_capture_bugs_(1);
+ tt_int_op(circuit_extend_lspec_valid_helper(ec, circ), OP_EQ, -1);
+ tt_int_op(smartlist_len(tor_get_captured_bug_log_()), OP_EQ, 1);
+ tt_str_op(smartlist_get(tor_get_captured_bug_log_(), 0), OP_EQ,
+ "!(ASSERT_PREDICT_UNLIKELY_(!p_chan))");
+ tor_end_capture_bugs_();
+ mock_clean_saved_logs();
+ fake_options->ExtendAllowPrivateAddresses = 0;
+
+ /* We can also pass the OR circuit magic check with a public address */
+ tor_addr_parse(&ec->orport_ipv4.addr, PUBLIC_IPV4);
+ fake_options->ExtendAllowPrivateAddresses = 0;
+ tor_capture_bugs_(1);
+ tt_int_op(circuit_extend_lspec_valid_helper(ec, circ), OP_EQ, -1);
+ /* Since we're using IF_BUG_ONCE(), expect 0-1 bug logs */
+ tt_int_op(smartlist_len(tor_get_captured_bug_log_()), OP_GE, 0);
+ tt_int_op(smartlist_len(tor_get_captured_bug_log_()), OP_LE, 1);
+ tor_end_capture_bugs_();
+ mock_clean_saved_logs();
+ fake_options->ExtendAllowPrivateAddresses = 0;
+
+ tor_addr_make_null(&ec->orport_ipv4.addr, AF_INET);
+ ec->orport_ipv4.port = 0x0000;
+#endif /* !defined(ALL_BUGS_ARE_FATAL) */
+
+ /* Now let's fake a p_chan and the addresses */
+ tor_addr_parse(&ec->orport_ipv4.addr, PUBLIC_IPV4);
+ ec->orport_ipv4.port = VALID_PORT;
+ or_circ->p_chan = p_chan;
+
+ /* This is a trivial failure: node_id and p_chan->identity_digest are both
+ * zeroed */
+ tt_int_op(circuit_extend_lspec_valid_helper(ec, circ), OP_EQ, -1);
+ expect_log_msg("Client asked me to extend back to the previous hop.\n");
+ mock_clean_saved_logs();
+
+ /* Let's check with non-zero identities as well */
+ memset(ec->node_id, 0xAA, sizeof(ec->node_id));
+ memset(p_chan->identity_digest, 0xAA, sizeof(p_chan->identity_digest));
+
+ tt_int_op(circuit_extend_lspec_valid_helper(ec, circ), OP_EQ, -1);
+ expect_log_msg("Client asked me to extend back to the previous hop.\n");
+ mock_clean_saved_logs();
+
+ memset(ec->node_id, 0, sizeof(ec->node_id));
+ memset(p_chan->identity_digest, 0, sizeof(p_chan->identity_digest));
+
+ /* Let's pass the node_id test */
+ memset(ec->node_id, 0xAA, sizeof(ec->node_id));
+ memset(p_chan->identity_digest, 0xBB, sizeof(p_chan->identity_digest));
+
+ /* ed_pubkey is zero, and that's allowed, so we should succeed */
+ tt_int_op(circuit_extend_lspec_valid_helper(ec, circ), OP_EQ, 0);
+ mock_clean_saved_logs();
+
+ /* Now let's check that we warn, but succeed, when only one address is
+ * private */
+ tor_addr_parse(&ec->orport_ipv4.addr, INTERNAL_IPV4);
+ ec->orport_ipv4.port = VALID_PORT;
+ tor_addr_parse(&ec->orport_ipv6.addr, PUBLIC_IPV6);
+ ec->orport_ipv6.port = VALID_PORT;
+ fake_options->ExtendAllowPrivateAddresses = 0;
+
+ tt_int_op(circuit_extend_lspec_valid_helper(ec, circ), OP_EQ, 0);
+ expect_log_msg("Client asked me to extend "
+ "to a private IPv4 address '0.0.0.1'.\n");
+ mock_clean_saved_logs();
+ tor_addr_port_make_null_ap(&ec->orport_ipv4, AF_INET);
+ tor_addr_port_make_null_ap(&ec->orport_ipv6, AF_INET6);
+
+ /* Now with private IPv6 */
+ tor_addr_parse(&ec->orport_ipv4.addr, PUBLIC_IPV4);
+ ec->orport_ipv4.port = VALID_PORT;
+ tor_addr_parse(&ec->orport_ipv6.addr, INTERNAL_IPV6);
+ ec->orport_ipv6.port = VALID_PORT;
+ fake_options->ExtendAllowPrivateAddresses = 0;
+
+ tt_int_op(circuit_extend_lspec_valid_helper(ec, circ), OP_EQ, 0);
+ expect_log_msg("Client asked me to extend "
+ "to a private IPv6 address '[::1]'.\n");
+ mock_clean_saved_logs();
+ tor_addr_port_make_null_ap(&ec->orport_ipv4, AF_INET);
+ tor_addr_port_make_null_ap(&ec->orport_ipv6, AF_INET6);
+
+ /* Now reset to public IPv4 and IPv6 */
+ tor_addr_parse(&ec->orport_ipv4.addr, PUBLIC_IPV4);
+ ec->orport_ipv4.port = VALID_PORT;
+ tor_addr_parse(&ec->orport_ipv6.addr, PUBLIC_IPV6);
+ ec->orport_ipv6.port = VALID_PORT;
+
+ /* Fail on matching non-zero identities */
+ memset(&ec->ed_pubkey, 0xEE, sizeof(ec->ed_pubkey));
+ memset(&p_chan->ed25519_identity, 0xEE, sizeof(p_chan->ed25519_identity));
+
+ tt_int_op(circuit_extend_lspec_valid_helper(ec, circ), OP_EQ, -1);
+ expect_log_msg("Client asked me to extend back to the previous hop "
+ "(by Ed25519 ID).\n");
+ mock_clean_saved_logs();
+
+ memset(&ec->ed_pubkey, 0, sizeof(ec->ed_pubkey));
+ memset(&p_chan->ed25519_identity, 0, sizeof(p_chan->ed25519_identity));
+
+ /* Succeed on different, non-zero identities */
+ memset(&ec->ed_pubkey, 0xDD, sizeof(ec->ed_pubkey));
+ memset(&p_chan->ed25519_identity, 0xEE, sizeof(p_chan->ed25519_identity));
+
+ tt_int_op(circuit_extend_lspec_valid_helper(ec, circ), OP_EQ, 0);
+ mock_clean_saved_logs();
+
+ memset(&ec->ed_pubkey, 0, sizeof(ec->ed_pubkey));
+ memset(&p_chan->ed25519_identity, 0, sizeof(p_chan->ed25519_identity));
+
+ /* Succeed if the client knows the identity, but we don't */
+ memset(&ec->ed_pubkey, 0xDD, sizeof(ec->ed_pubkey));
+ memset(&p_chan->ed25519_identity, 0x00, sizeof(p_chan->ed25519_identity));
+
+ tt_int_op(circuit_extend_lspec_valid_helper(ec, circ), OP_EQ, 0);
+ mock_clean_saved_logs();
+
+ memset(&ec->ed_pubkey, 0, sizeof(ec->ed_pubkey));
+ memset(&p_chan->ed25519_identity, 0, sizeof(p_chan->ed25519_identity));
+
+ /* Succeed if we know the identity, but the client doesn't */
+ memset(&ec->ed_pubkey, 0x00, sizeof(ec->ed_pubkey));
+ memset(&p_chan->ed25519_identity, 0xEE, sizeof(p_chan->ed25519_identity));
+
+ tt_int_op(circuit_extend_lspec_valid_helper(ec, circ), OP_EQ, 0);
+ mock_clean_saved_logs();
+
+ memset(&ec->ed_pubkey, 0, sizeof(ec->ed_pubkey));
+ memset(&p_chan->ed25519_identity, 0, sizeof(p_chan->ed25519_identity));
+
+ /* Cleanup the node ids */
+ memset(ec->node_id, 0, sizeof(ec->node_id));
+ memset(p_chan->identity_digest, 0, sizeof(p_chan->identity_digest));
+
+ /* Cleanup the p_chan and the addresses */
+ tor_addr_make_null(&ec->orport_ipv4.addr, AF_UNSPEC);
+ ec->orport_ipv4.port = 0;
+ or_circ->p_chan = NULL;
+
+ done:
+ tor_end_capture_bugs_();
+ teardown_capture_of_logs();
+
+ UNMOCK(get_options);
+ or_options_free(fake_options);
+ mocked_options = NULL;
+
+ tor_free(ec);
+ tor_free(or_circ);
+ tor_free(p_chan);
+}
+
+static bool can_extend_over_ipv6_result = false;
+static int mock_router_can_extend_over_ipv6_calls = 0;
+static bool
+mock_router_can_extend_over_ipv6(const or_options_t *options)
+{
+ (void)options;
+ mock_router_can_extend_over_ipv6_calls++;
+ return can_extend_over_ipv6_result;
+}
+
+/* Test the different cases in circuit_choose_ip_ap_for_extend(). */
+static void
+test_circuit_choose_ip_ap_for_extend(void *arg)
+{
+ (void)arg;
+ tor_addr_port_t ipv4_ap;
+ tor_addr_port_t ipv6_ap;
+
+ /* Set up valid addresses */
+ tor_addr_parse(&ipv4_ap.addr, PUBLIC_IPV4);
+ ipv4_ap.port = VALID_PORT;
+ tor_addr_parse(&ipv6_ap.addr, PUBLIC_IPV6);
+ ipv6_ap.port = VALID_PORT;
+
+ or_options_t *fake_options = options_new();
+ MOCK(get_options, mock_get_options);
+ mocked_options = fake_options;
+
+ MOCK(router_can_extend_over_ipv6,
+ mock_router_can_extend_over_ipv6);
+ can_extend_over_ipv6_result = true;
+ mock_router_can_extend_over_ipv6_calls = 0;
+
+ /* No valid addresses */
+ can_extend_over_ipv6_result = true;
+ mock_router_can_extend_over_ipv6_calls = 0;
+ tt_ptr_op(circuit_choose_ip_ap_for_extend(NULL, NULL), OP_EQ, NULL);
+ tt_int_op(mock_router_can_extend_over_ipv6_calls, OP_EQ, 1);
+
+ can_extend_over_ipv6_result = false;
+ mock_router_can_extend_over_ipv6_calls = 0;
+ tt_ptr_op(circuit_choose_ip_ap_for_extend(NULL, NULL), OP_EQ, NULL);
+ tt_int_op(mock_router_can_extend_over_ipv6_calls, OP_EQ, 1);
+
+ /* One valid address: IPv4 */
+ can_extend_over_ipv6_result = true;
+ mock_router_can_extend_over_ipv6_calls = 0;
+ tt_ptr_op(circuit_choose_ip_ap_for_extend(&ipv4_ap, NULL), OP_EQ, &ipv4_ap);
+ tt_int_op(mock_router_can_extend_over_ipv6_calls, OP_EQ, 1);
+
+ can_extend_over_ipv6_result = false;
+ mock_router_can_extend_over_ipv6_calls = 0;
+ tt_ptr_op(circuit_choose_ip_ap_for_extend(&ipv4_ap, NULL), OP_EQ, &ipv4_ap);
+ tt_int_op(mock_router_can_extend_over_ipv6_calls, OP_EQ, 1);
+
+ /* One valid address: IPv6 */
+ can_extend_over_ipv6_result = true;
+ mock_router_can_extend_over_ipv6_calls = 0;
+ tt_ptr_op(circuit_choose_ip_ap_for_extend(NULL, &ipv6_ap), OP_EQ, &ipv6_ap);
+ tt_int_op(mock_router_can_extend_over_ipv6_calls, OP_EQ, 1);
+
+ can_extend_over_ipv6_result = false;
+ mock_router_can_extend_over_ipv6_calls = 0;
+ tt_ptr_op(circuit_choose_ip_ap_for_extend(NULL, &ipv6_ap), OP_EQ, NULL);
+ tt_int_op(mock_router_can_extend_over_ipv6_calls, OP_EQ, 1);
+
+ /* Two valid addresses */
+ const tor_addr_port_t *chosen_addr = NULL;
+
+ can_extend_over_ipv6_result = true;
+ mock_router_can_extend_over_ipv6_calls = 0;
+ chosen_addr = circuit_choose_ip_ap_for_extend(&ipv4_ap, &ipv6_ap);
+ tt_assert(chosen_addr == &ipv4_ap || chosen_addr == &ipv6_ap);
+ tt_int_op(mock_router_can_extend_over_ipv6_calls, OP_EQ, 1);
+
+ can_extend_over_ipv6_result = false;
+ mock_router_can_extend_over_ipv6_calls = 0;
+ tt_ptr_op(circuit_choose_ip_ap_for_extend(&ipv4_ap, &ipv6_ap),
+ OP_EQ, &ipv4_ap);
+ tt_int_op(mock_router_can_extend_over_ipv6_calls, OP_EQ, 1);
+
+ done:
+ UNMOCK(get_options);
+ or_options_free(fake_options);
+ mocked_options = NULL;
+
+ UNMOCK(router_can_extend_over_ipv6);
+
+ tor_free(fake_options);
+}
+
+static int mock_circuit_close_calls = 0;
+static void
+mock_circuit_mark_for_close_(circuit_t *circ, int reason,
+ int line, const char *cfile)
+{
+ (void)circ;
+ (void)reason;
+ (void)line;
+ (void)cfile;
+ mock_circuit_close_calls++;
+}
+
+static int mock_channel_connect_calls = 0;
+static channel_t *mock_channel_connect_nchan = NULL;
+static channel_t *
+mock_channel_connect_for_circuit(const tor_addr_t *addr,
+ uint16_t port,
+ const char *id_digest,
+ const struct ed25519_public_key_t *ed_id)
+{
+ (void)addr;
+ (void)port;
+ (void)id_digest;
+ (void)ed_id;
+ mock_channel_connect_calls++;
+ return mock_channel_connect_nchan;
+}
+
+/* Test the different cases in circuit_open_connection_for_extend().
+ * Chooses different IP addresses depending on the first character in arg:
+ * - 4: IPv4
+ * - 6: IPv6
+ * - d: IPv4 and IPv6 (dual-stack)
+ */
+static void
+test_circuit_open_connection_for_extend(void *arg)
+{
+ const char ip_version = ((const char *)arg)[0];
+ const bool use_ipv4 = (ip_version == '4' || ip_version == 'd');
+ const bool use_ipv6 = (ip_version == '6' || ip_version == 'd');
+ tor_assert(use_ipv4 || use_ipv6);
+
+ extend_cell_t *ec = tor_malloc_zero(sizeof(extend_cell_t));
+ circuit_t *circ = tor_malloc_zero(sizeof(circuit_t));
+ channel_t *fake_n_chan = tor_malloc_zero(sizeof(channel_t));
+
+ or_options_t *fake_options = options_new();
+ MOCK(get_options, mock_get_options);
+ mocked_options = fake_options;
+
+ MOCK(circuit_mark_for_close_, mock_circuit_mark_for_close_);
+ mock_circuit_close_calls = 0;
+ MOCK(channel_connect_for_circuit, mock_channel_connect_for_circuit);
+ mock_channel_connect_calls = 0;
+ mock_channel_connect_nchan = NULL;
+
+ MOCK(router_can_extend_over_ipv6,
+ mock_router_can_extend_over_ipv6);
+ can_extend_over_ipv6_result = true;
+
+ setup_full_capture_of_logs(LOG_INFO);
+
+#ifndef ALL_BUGS_ARE_FATAL
+ /* Circuit must be non-NULL */
+ mock_circuit_close_calls = 0;
+ mock_channel_connect_calls = 0;
+ tor_capture_bugs_(1);
+ circuit_open_connection_for_extend(ec, NULL, 0);
+ /* We can't close a NULL circuit */
+ tt_int_op(mock_circuit_close_calls, OP_EQ, 0);
+ tt_int_op(mock_channel_connect_calls, OP_EQ, 0);
+ tt_int_op(smartlist_len(tor_get_captured_bug_log_()), OP_EQ, 1);
+ tt_str_op(smartlist_get(tor_get_captured_bug_log_(), 0), OP_EQ,
+ "!(ASSERT_PREDICT_UNLIKELY_(!circ))");
+ tor_end_capture_bugs_();
+ mock_clean_saved_logs();
+
+ /* Extend cell must be non-NULL */
+ mock_circuit_close_calls = 0;
+ mock_channel_connect_calls = 0;
+ tor_capture_bugs_(1);
+ circuit_open_connection_for_extend(NULL, circ, 0);
+ tt_int_op(mock_circuit_close_calls, OP_EQ, 1);
+ tt_int_op(mock_channel_connect_calls, OP_EQ, 0);
+ tt_int_op(smartlist_len(tor_get_captured_bug_log_()), OP_EQ, 1);
+ tt_str_op(smartlist_get(tor_get_captured_bug_log_(), 0), OP_EQ,
+ "!(ASSERT_PREDICT_UNLIKELY_(!ec))");
+ tor_end_capture_bugs_();
+ mock_clean_saved_logs();
+
+ /* Extend cell and circuit must be non-NULL */
+ mock_circuit_close_calls = 0;
+ mock_channel_connect_calls = 0;
+ tor_capture_bugs_(1);
+ circuit_open_connection_for_extend(NULL, NULL, 0);
+ /* We can't close a NULL circuit */
+ tt_int_op(mock_circuit_close_calls, OP_EQ, 0);
+ tt_int_op(mock_channel_connect_calls, OP_EQ, 0);
+ /* Since we're using IF_BUG_ONCE(), we might not log any bugs */
+ tt_int_op(smartlist_len(tor_get_captured_bug_log_()), OP_GE, 0);
+ tt_int_op(smartlist_len(tor_get_captured_bug_log_()), OP_LE, 2);
+ tor_end_capture_bugs_();
+ mock_clean_saved_logs();
+
+ /* Fail, because neither address is valid */
+ mock_circuit_close_calls = 0;
+ mock_channel_connect_calls = 0;
+ tor_capture_bugs_(1);
+ circuit_open_connection_for_extend(ec, circ, 0);
+ /* Close the circuit, don't connect */
+ tt_int_op(mock_circuit_close_calls, OP_EQ, 1);
+ tt_int_op(mock_channel_connect_calls, OP_EQ, 0);
+ /* Check state */
+ tt_ptr_op(circ->n_hop, OP_EQ, NULL);
+ tt_ptr_op(circ->n_chan_create_cell, OP_EQ, NULL);
+ tt_int_op(circ->state, OP_EQ, 0);
+ /* Cleanup */
+ tor_end_capture_bugs_();
+ mock_clean_saved_logs();
+#endif /* !defined(ALL_BUGS_ARE_FATAL) */
+
+ /* Set up valid addresses */
+ if (use_ipv4) {
+ tor_addr_parse(&ec->orport_ipv4.addr, PUBLIC_IPV4);
+ ec->orport_ipv4.port = VALID_PORT;
+ }
+ if (use_ipv6) {
+ tor_addr_parse(&ec->orport_ipv6.addr, PUBLIC_IPV6);
+ ec->orport_ipv6.port = VALID_PORT;
+ }
+
+ /* Succeed, but don't try to open a connection */
+ mock_circuit_close_calls = 0;
+ mock_channel_connect_calls = 0;
+ circuit_open_connection_for_extend(ec, circ, 0);
+ /* If we haven't closed the circuit, that's success */
+ tt_int_op(mock_circuit_close_calls, OP_EQ, 0);
+ tt_int_op(mock_channel_connect_calls, OP_EQ, 0);
+ /* Check state */
+ tt_ptr_op(circ->n_hop, OP_NE, NULL);
+ tt_ptr_op(circ->n_chan_create_cell, OP_NE, NULL);
+ tt_int_op(circ->state, OP_EQ, CIRCUIT_STATE_CHAN_WAIT);
+ /* Cleanup */
+ mock_clean_saved_logs();
+ tor_free(circ->n_hop);
+ tor_free(circ->n_chan_create_cell);
+ circ->state = 0;
+
+ /* Try to open a connection, but fail with a NULL n_chan */
+ mock_circuit_close_calls = 0;
+ mock_channel_connect_calls = 0;
+ circuit_open_connection_for_extend(ec, circ, 1);
+ /* Try to connect, but fail, and close the circuit */
+ tt_int_op(mock_circuit_close_calls, OP_EQ, 1);
+ tt_int_op(mock_channel_connect_calls, OP_EQ, 1);
+ expect_log_msg("Launching n_chan failed. Closing circuit.\n");
+ /* Check state */
+ tt_ptr_op(circ->n_hop, OP_NE, NULL);
+ tt_ptr_op(circ->n_chan_create_cell, OP_NE, NULL);
+ tt_int_op(circ->state, OP_EQ, CIRCUIT_STATE_CHAN_WAIT);
+ /* Cleanup */
+ mock_clean_saved_logs();
+ tor_free(circ->n_hop);
+ tor_free(circ->n_chan_create_cell);
+ circ->state = 0;
+
+ /* Try to open a connection, and succeed, because n_chan is not NULL */
+ mock_channel_connect_nchan = fake_n_chan;
+ mock_circuit_close_calls = 0;
+ mock_channel_connect_calls = 0;
+ circuit_open_connection_for_extend(ec, circ, 1);
+ /* Connection attempt succeeded, leaving the circuit open */
+ tt_int_op(mock_circuit_close_calls, OP_EQ, 0);
+ tt_int_op(mock_channel_connect_calls, OP_EQ, 1);
+ /* Check state */
+ tt_ptr_op(circ->n_hop, OP_NE, NULL);
+ tt_ptr_op(circ->n_chan_create_cell, OP_NE, NULL);
+ tt_int_op(circ->state, OP_EQ, CIRCUIT_STATE_CHAN_WAIT);
+ /* Cleanup */
+ mock_clean_saved_logs();
+ tor_free(circ->n_hop);
+ tor_free(circ->n_chan_create_cell);
+ circ->state = 0;
+ mock_channel_connect_nchan = NULL;
+
+ done:
+ tor_end_capture_bugs_();
+ teardown_capture_of_logs();
+
+ UNMOCK(circuit_mark_for_close_);
+ mock_circuit_close_calls = 0;
+ UNMOCK(channel_connect_for_circuit);
+ mock_channel_connect_calls = 0;
+
+ UNMOCK(get_options);
+ or_options_free(fake_options);
+ mocked_options = NULL;
+
+ UNMOCK(router_can_extend_over_ipv6);
+
+ tor_free(ec);
+ tor_free(circ->n_hop);
+ tor_free(circ->n_chan_create_cell);
+ tor_free(circ);
+ tor_free(fake_n_chan);
+}
+
+/* Guaranteed to be initialised to zero. */
+static extend_cell_t mock_extend_cell_parse_cell_out;
+static int mock_extend_cell_parse_result = 0;
+static int mock_extend_cell_parse_calls = 0;
+
+static int
+mock_extend_cell_parse(extend_cell_t *cell_out,
+ const uint8_t command,
+ const uint8_t *payload_in,
+ size_t payload_len)
+{
+ (void)command;
+ (void)payload_in;
+ (void)payload_len;
+
+ mock_extend_cell_parse_calls++;
+ memcpy(cell_out, &mock_extend_cell_parse_cell_out,
+ sizeof(extend_cell_t));
+ return mock_extend_cell_parse_result;
+}
+
+static int mock_channel_get_for_extend_calls = 0;
+static int mock_channel_get_for_extend_launch_out = 0;
+static channel_t *mock_channel_get_for_extend_nchan = NULL;
+static channel_t *
+mock_channel_get_for_extend(const char *rsa_id_digest,
+ const ed25519_public_key_t *ed_id,
+ const tor_addr_t *target_ipv4_addr,
+ const tor_addr_t *target_ipv6_addr,
+ const char **msg_out,
+ int *launch_out)
+{
+ (void)rsa_id_digest;
+ (void)ed_id;
+ (void)target_ipv4_addr;
+ (void)target_ipv6_addr;
+
+ /* channel_get_for_extend() requires non-NULL arguments */
+ tt_ptr_op(msg_out, OP_NE, NULL);
+ tt_ptr_op(launch_out, OP_NE, NULL);
+
+ mock_channel_get_for_extend_calls++;
+ *msg_out = NULL;
+ *launch_out = mock_channel_get_for_extend_launch_out;
+ return mock_channel_get_for_extend_nchan;
+
+ done:
+ return NULL;
+}
+
+static const char *
+mock_channel_get_canonical_remote_descr(channel_t *chan)
+{
+ (void)chan;
+ return "mock_channel_get_canonical_remote_descr()";
+}
+
+static int mock_circuit_deliver_create_cell_calls = 0;
+static int mock_circuit_deliver_create_cell_result = 0;
+static int
+mock_circuit_deliver_create_cell(circuit_t *circ,
+ const struct create_cell_t *create_cell,
+ int relayed)
+{
+ (void)create_cell;
+
+ /* circuit_deliver_create_cell() requires non-NULL arguments,
+ * but we only check circ and circ->n_chan here. */
+ tt_ptr_op(circ, OP_NE, NULL);
+ tt_ptr_op(circ->n_chan, OP_NE, NULL);
+
+ /* We should only ever get relayed cells from extends */
+ tt_int_op(relayed, OP_EQ, 1);
+
+ mock_circuit_deliver_create_cell_calls++;
+ return mock_circuit_deliver_create_cell_result;
+
+ done:
+ return -1;
+}
+
+/* Test the different cases in circuit_extend(). */
+static void
+test_circuit_extend(void *arg)
+{
+ (void)arg;
+ cell_t *cell = tor_malloc_zero(sizeof(cell_t));
+ channel_t *p_chan = tor_malloc_zero(sizeof(channel_t));
+ or_circuit_t *or_circ = tor_malloc_zero(sizeof(or_circuit_t));
+ circuit_t *circ = TO_CIRCUIT(or_circ);
+ channel_t *fake_n_chan = tor_malloc_zero(sizeof(channel_t));
+
+ server = 0;
+ MOCK(server_mode, mock_server_mode);
+
+ /* Mock a debug function, but otherwise ignore it */
+ MOCK(channel_get_canonical_remote_descr,
+ mock_channel_get_canonical_remote_descr);
+
+ setup_full_capture_of_logs(LOG_INFO);
+
+#ifndef ALL_BUGS_ARE_FATAL
+ /* Circuit must be non-NULL */
+ tor_capture_bugs_(1);
+ tt_int_op(circuit_extend(cell, NULL), OP_EQ, -1);
+ tt_int_op(smartlist_len(tor_get_captured_bug_log_()), OP_EQ, 1);
+ tt_str_op(smartlist_get(tor_get_captured_bug_log_(), 0), OP_EQ,
+ "!(ASSERT_PREDICT_UNLIKELY_(!circ))");
+ tor_end_capture_bugs_();
+ mock_clean_saved_logs();
+
+ /* Cell must be non-NULL */
+ tor_capture_bugs_(1);
+ tt_int_op(circuit_extend(NULL, circ), OP_EQ, -1);
+ tt_int_op(smartlist_len(tor_get_captured_bug_log_()), OP_EQ, 1);
+ tt_str_op(smartlist_get(tor_get_captured_bug_log_(), 0), OP_EQ,
+ "!(ASSERT_PREDICT_UNLIKELY_(!cell))");
+ tor_end_capture_bugs_();
+ mock_clean_saved_logs();
+
+ /* Extend cell and circuit must be non-NULL */
+ tor_capture_bugs_(1);
+ tt_int_op(circuit_extend(NULL, NULL), OP_EQ, -1);
+ /* Since we're using IF_BUG_ONCE(), we might not log any bugs */
+ tt_int_op(smartlist_len(tor_get_captured_bug_log_()), OP_GE, 0);
+ tt_int_op(smartlist_len(tor_get_captured_bug_log_()), OP_LE, 2);
+ tor_end_capture_bugs_();
+ mock_clean_saved_logs();
+#endif /* !defined(ALL_BUGS_ARE_FATAL) */
+
+ /* Clients can't extend */
+ server = 0;
+ tt_int_op(circuit_extend(cell, circ), OP_EQ, -1);
+ expect_log_msg("Got an extend cell, but running as a client. Closing.\n");
+ mock_clean_saved_logs();
+
+ /* But servers can. Unpack the cell, but fail parsing. */
+ server = 1;
+ tt_int_op(circuit_extend(cell, circ), OP_EQ, -1);
+ expect_log_msg("Can't parse extend cell. Closing circuit.\n");
+ mock_clean_saved_logs();
+
+ /* Now mock parsing */
+ MOCK(extend_cell_parse, mock_extend_cell_parse);
+
+ /* And make parsing succeed, but fail on adding ed25519 */
+ memset(&mock_extend_cell_parse_cell_out, 0,
+ sizeof(mock_extend_cell_parse_cell_out));
+ mock_extend_cell_parse_result = 0;
+ mock_extend_cell_parse_calls = 0;
+
+ tt_int_op(circuit_extend(cell, circ), OP_EQ, -1);
+ tt_int_op(mock_extend_cell_parse_calls, OP_EQ, 1);
+ expect_log_msg(
+ "Client asked me to extend without specifying an id_digest.\n");
+ mock_clean_saved_logs();
+ mock_extend_cell_parse_calls = 0;
+
+ /* Now add a node_id. Fail the lspec check because IPv4 and port are zero. */
+ memset(&mock_extend_cell_parse_cell_out.node_id, 0xAA,
+ sizeof(mock_extend_cell_parse_cell_out.node_id));
+
+ tt_int_op(circuit_extend(cell, circ), OP_EQ, -1);
+ tt_int_op(mock_extend_cell_parse_calls, OP_EQ, 1);
+ expect_log_msg("Client asked me to extend to a zero destination port "
+ "or unspecified address '[scrubbed]'.\n");
+ mock_clean_saved_logs();
+ mock_extend_cell_parse_calls = 0;
+
+ /* Now add a valid IPv4 and port. Fail the OR circuit magic check. */
+ tor_addr_parse(&mock_extend_cell_parse_cell_out.orport_ipv4.addr,
+ PUBLIC_IPV4);
+ mock_extend_cell_parse_cell_out.orport_ipv4.port = VALID_PORT;
+
+#ifndef ALL_BUGS_ARE_FATAL
+ tor_capture_bugs_(1);
+ tt_int_op(circuit_extend(cell, circ), OP_EQ, -1);
+ tt_int_op(mock_extend_cell_parse_calls, OP_EQ, 1);
+ tt_int_op(smartlist_len(tor_get_captured_bug_log_()), OP_EQ, 1);
+ tt_str_op(smartlist_get(tor_get_captured_bug_log_(), 0), OP_EQ,
+ "!(ASSERT_PREDICT_UNLIKELY_(circ->magic != 0x98ABC04Fu))");
+ tor_end_capture_bugs_();
+ mock_clean_saved_logs();
+ mock_extend_cell_parse_calls = 0;
+#endif /* !defined(ALL_BUGS_ARE_FATAL) */
+
+ /* Now add the right magic and a p_chan. */
+ or_circ->base_.magic = OR_CIRCUIT_MAGIC;
+ or_circ->p_chan = p_chan;
+
+ /* Mock channel_get_for_extend(), so it doesn't crash. */
+ mock_channel_get_for_extend_calls = 0;
+ MOCK(channel_get_for_extend, mock_channel_get_for_extend);
+
+ /* Test circuit not established, but don't launch another one */
+ mock_channel_get_for_extend_launch_out = 0;
+ mock_channel_get_for_extend_nchan = NULL;
+ tt_int_op(circuit_extend(cell, circ), OP_EQ, 0);
+ tt_int_op(mock_extend_cell_parse_calls, OP_EQ, 1);
+ tt_int_op(mock_channel_get_for_extend_calls, OP_EQ, 1);
+
+ /* cleanup */
+ mock_clean_saved_logs();
+ mock_extend_cell_parse_calls = 0;
+ mock_channel_get_for_extend_calls = 0;
+ /* circ and or_circ are the same object */
+ tor_free(circ->n_hop);
+ tor_free(circ->n_chan_create_cell);
+
+ /* Mock channel_connect_for_circuit(), so we don't crash */
+ mock_channel_connect_calls = 0;
+ MOCK(channel_connect_for_circuit, mock_channel_connect_for_circuit);
+
+ /* Test circuit not established, and successful launch of a channel */
+ mock_channel_get_for_extend_launch_out = 1;
+ mock_channel_get_for_extend_nchan = NULL;
+ mock_channel_connect_nchan = fake_n_chan;
+ tt_int_op(circuit_extend(cell, circ), OP_EQ, 0);
+ tt_int_op(mock_extend_cell_parse_calls, OP_EQ, 1);
+ tt_int_op(mock_channel_get_for_extend_calls, OP_EQ, 1);
+ tt_int_op(mock_channel_connect_calls, OP_EQ, 1);
+
+ /* cleanup */
+ mock_clean_saved_logs();
+ mock_extend_cell_parse_calls = 0;
+ mock_channel_get_for_extend_calls = 0;
+ mock_channel_connect_calls = 0;
+ /* circ and or_circ are the same object */
+ tor_free(circ->n_hop);
+ tor_free(circ->n_chan_create_cell);
+
+ /* Mock circuit_deliver_create_cell(), so it doesn't crash */
+ mock_circuit_deliver_create_cell_calls = 0;
+ MOCK(circuit_deliver_create_cell, mock_circuit_deliver_create_cell);
+
+ /* Test circuit established, re-using channel, successful delivery */
+ mock_channel_get_for_extend_launch_out = 0;
+ mock_channel_get_for_extend_nchan = fake_n_chan;
+ mock_channel_connect_nchan = NULL;
+ mock_circuit_deliver_create_cell_result = 0;
+ tt_int_op(circuit_extend(cell, circ), OP_EQ, 0);
+ tt_int_op(mock_extend_cell_parse_calls, OP_EQ, 1);
+ tt_int_op(mock_channel_get_for_extend_calls, OP_EQ, 1);
+ tt_int_op(mock_channel_connect_calls, OP_EQ, 0);
+ tt_int_op(mock_circuit_deliver_create_cell_calls, OP_EQ, 1);
+ tt_ptr_op(circ->n_chan, OP_EQ, fake_n_chan);
+
+ /* cleanup */
+ circ->n_chan = NULL;
+ mock_clean_saved_logs();
+ mock_extend_cell_parse_calls = 0;
+ mock_channel_get_for_extend_calls = 0;
+ mock_channel_connect_calls = 0;
+ mock_circuit_deliver_create_cell_calls = 0;
+ /* circ and or_circ are the same object */
+ tor_free(circ->n_hop);
+ tor_free(circ->n_chan_create_cell);
+
+ /* Test circuit established, re-using channel, failed delivery */
+ mock_channel_get_for_extend_launch_out = 0;
+ mock_channel_get_for_extend_nchan = fake_n_chan;
+ mock_channel_connect_nchan = NULL;
+ mock_circuit_deliver_create_cell_result = -1;
+ tt_int_op(circuit_extend(cell, circ), OP_EQ, -1);
+ tt_int_op(mock_extend_cell_parse_calls, OP_EQ, 1);
+ tt_int_op(mock_channel_get_for_extend_calls, OP_EQ, 1);
+ tt_int_op(mock_channel_connect_calls, OP_EQ, 0);
+ tt_int_op(mock_circuit_deliver_create_cell_calls, OP_EQ, 1);
+ tt_ptr_op(circ->n_chan, OP_EQ, fake_n_chan);
+
+ /* cleanup */
+ circ->n_chan = NULL;
+ mock_clean_saved_logs();
+ mock_extend_cell_parse_calls = 0;
+ mock_channel_get_for_extend_calls = 0;
+ mock_channel_connect_calls = 0;
+ mock_circuit_deliver_create_cell_calls = 0;
+ /* circ and or_circ are the same object */
+ tor_free(circ->n_hop);
+ tor_free(circ->n_chan_create_cell);
+
+ done:
+ tor_end_capture_bugs_();
+ teardown_capture_of_logs();
+
+ UNMOCK(server_mode);
+ server = 0;
+
+ UNMOCK(channel_get_canonical_remote_descr);
+
+ UNMOCK(extend_cell_parse);
+ memset(&mock_extend_cell_parse_cell_out, 0,
+ sizeof(mock_extend_cell_parse_cell_out));
+ mock_extend_cell_parse_result = 0;
+ mock_extend_cell_parse_calls = 0;
+
+ UNMOCK(channel_get_for_extend);
+ mock_channel_get_for_extend_calls = 0;
+ mock_channel_get_for_extend_launch_out = 0;
+ mock_channel_get_for_extend_nchan = NULL;
+
+ UNMOCK(channel_connect_for_circuit);
+ mock_channel_connect_calls = 0;
+ mock_channel_connect_nchan = NULL;
+
+ UNMOCK(circuit_deliver_create_cell);
+ mock_circuit_deliver_create_cell_calls = 0;
+ mock_circuit_deliver_create_cell_result = 0;
+
+ tor_free(cell);
+ /* circ and or_circ are the same object */
+ tor_free(circ->n_hop);
+ tor_free(circ->n_chan_create_cell);
+ tor_free(or_circ);
+ tor_free(p_chan);
+ tor_free(fake_n_chan);
+}
+
+/* Test the different cases in onionskin_answer(). */
+static void
+test_onionskin_answer(void *arg)
+{
+ (void)arg;
+ created_cell_t *created_cell = tor_malloc_zero(sizeof(created_cell_t));
+ or_circuit_t *or_circ = tor_malloc_zero(sizeof(or_circuit_t));
+ char keys[CPATH_KEY_MATERIAL_LEN] = {0};
+ uint8_t rend_circ_nonce[DIGEST_LEN] = {0};
+
+ setup_full_capture_of_logs(LOG_INFO);
+
+#ifndef ALL_BUGS_ARE_FATAL
+ /* Circuit must be non-NULL */
+ tor_capture_bugs_(1);
+ tt_int_op(onionskin_answer(NULL, created_cell,
+ keys, CPATH_KEY_MATERIAL_LEN,
+ rend_circ_nonce), OP_EQ, -1);
+ tt_int_op(smartlist_len(tor_get_captured_bug_log_()), OP_EQ, 1);
+ tt_str_op(smartlist_get(tor_get_captured_bug_log_(), 0), OP_EQ,
+ "!(ASSERT_PREDICT_UNLIKELY_(!circ))");
+ tor_end_capture_bugs_();
+ mock_clean_saved_logs();
+
+ /* Created cell must be non-NULL */
+ tor_capture_bugs_(1);
+ tt_int_op(onionskin_answer(or_circ, NULL,
+ keys, CPATH_KEY_MATERIAL_LEN,
+ rend_circ_nonce), OP_EQ, -1);
+ tt_int_op(smartlist_len(tor_get_captured_bug_log_()), OP_EQ, 1);
+ tt_str_op(smartlist_get(tor_get_captured_bug_log_(), 0), OP_EQ,
+ "!(ASSERT_PREDICT_UNLIKELY_(!created_cell))");
+ tor_end_capture_bugs_();
+ mock_clean_saved_logs();
+
+ /* Keys must be non-NULL */
+ tor_capture_bugs_(1);
+ tt_int_op(onionskin_answer(or_circ, created_cell,
+ NULL, CPATH_KEY_MATERIAL_LEN,
+ rend_circ_nonce), OP_EQ, -1);
+ tt_int_op(smartlist_len(tor_get_captured_bug_log_()), OP_EQ, 1);
+ tt_str_op(smartlist_get(tor_get_captured_bug_log_(), 0), OP_EQ,
+ "!(ASSERT_PREDICT_UNLIKELY_(!keys))");
+ tor_end_capture_bugs_();
+ mock_clean_saved_logs();
+
+ /* The rend circuit nonce must be non-NULL */
+ tor_capture_bugs_(1);
+ tt_int_op(onionskin_answer(or_circ, created_cell,
+ keys, CPATH_KEY_MATERIAL_LEN,
+ NULL), OP_EQ, -1);
+ tt_int_op(smartlist_len(tor_get_captured_bug_log_()), OP_EQ, 1);
+ tt_str_op(smartlist_get(tor_get_captured_bug_log_(), 0), OP_EQ,
+ "!(ASSERT_PREDICT_UNLIKELY_(!rend_circ_nonce))");
+ tor_end_capture_bugs_();
+ mock_clean_saved_logs();
+#endif /* !defined(ALL_BUGS_ARE_FATAL) */
+
+ /* Also, the keys length must be CPATH_KEY_MATERIAL_LEN, but we can't catch
+ * asserts in unit tests. */
+
+ /* Fail when formatting the created cell */
+ tt_int_op(onionskin_answer(or_circ, created_cell,
+ keys, CPATH_KEY_MATERIAL_LEN,
+ rend_circ_nonce), OP_EQ, -1);
+ expect_log_msg("couldn't format created cell (type=0, len=0).\n");
+ mock_clean_saved_logs();
+
+ /* TODO: test the rest of onionskin_answer(), see #33860 */
+ /* TODO: mock created_cell_format for the next test */
+
+ done:
+ tor_end_capture_bugs_();
+ teardown_capture_of_logs();
+
+ tor_free(created_cell);
+ tor_free(or_circ);
+}
+
+#define TEST(name, flags, setup, cleanup) \
+ { #name, test_ ## name, flags, setup, cleanup }
+
+#define TEST_NEW_ROUTE_LEN(name, flags) \
+ { #name, test_new_route_len_ ## name, flags, NULL, NULL }
+
+#define TEST_CIRCUIT(name, flags) \
+ { #name, test_circuit_ ## name, flags, NULL, NULL }
+
+#ifndef COCCI
+#define TEST_CIRCUIT_PASSTHROUGH(name, flags, arg) \
+ { #name "/" arg, test_circuit_ ## name, flags, \
+ &passthrough_setup, (void *)(arg) }
+#endif
+
struct testcase_t circuitbuild_tests[] = {
- { "noexit", test_new_route_len_noexit, 0, NULL, NULL },
- { "safe_exit", test_new_route_len_safe_exit, 0, NULL, NULL },
- { "unsafe_exit", test_new_route_len_unsafe_exit, 0, NULL, NULL },
- { "unhandled_exit", test_new_route_len_unhandled_exit, 0, NULL, NULL },
- { "upgrade_from_guard_wait", test_upgrade_from_guard_wait, TT_FORK,
- &helper_pubsub_setup, NULL },
+ TEST_NEW_ROUTE_LEN(noexit, 0),
+ TEST_NEW_ROUTE_LEN(safe_exit, 0),
+ TEST_NEW_ROUTE_LEN(unsafe_exit, 0),
+ TEST_NEW_ROUTE_LEN(unhandled_exit, 0),
+
+ TEST(upgrade_from_guard_wait, TT_FORK, &helper_pubsub_setup, NULL),
+
+ TEST_CIRCUIT(extend_state_valid, TT_FORK),
+ TEST_CIRCUIT(extend_add_ed25519, TT_FORK),
+ TEST_CIRCUIT(extend_lspec_valid, TT_FORK),
+ TEST_CIRCUIT(choose_ip_ap_for_extend, 0),
+ TEST_CIRCUIT_PASSTHROUGH(open_connection_for_extend, TT_FORK, "4"),
+ TEST_CIRCUIT_PASSTHROUGH(open_connection_for_extend, TT_FORK, "6"),
+ TEST_CIRCUIT_PASSTHROUGH(open_connection_for_extend, TT_FORK, "dual-stack"),
+ TEST_CIRCUIT(extend, TT_FORK),
+
+ TEST(onionskin_answer, TT_FORK, NULL, NULL),
+
END_OF_TESTCASES
};
diff --git a/src/test/test_config.c b/src/test/test_config.c
index 9ccdbc72c0..095eb24c49 100644
--- a/src/test/test_config.c
+++ b/src/test/test_config.c
@@ -18,6 +18,7 @@
#include "core/or/circuitmux_ewma.h"
#include "core/or/circuitbuild.h"
#include "app/config/config.h"
+#include "app/config/resolve_addr.h"
#include "feature/relay/relay_config.h"
#include "feature/relay/transport_config.h"
#include "lib/confmgt/confmgt.h"
@@ -42,6 +43,7 @@
#include "core/or/policies.h"
#include "feature/rend/rendclient.h"
#include "feature/rend/rendservice.h"
+#include "feature/relay/relay_find_addr.h"
#include "feature/relay/router.h"
#include "feature/relay/routermode.h"
#include "feature/nodelist/dirlist.h"
diff --git a/src/test/test_connection.h b/src/test/test_connection.h
index 9cf9efb8a4..bf327c0a3d 100644
--- a/src/test/test_connection.h
+++ b/src/test/test_connection.h
@@ -10,7 +10,7 @@
#define TEST_CONN_ADDRESS_2 "127.0.0.2"
#define TEST_CONN_PORT (12345)
#define TEST_CONN_ADDRESS_PORT "127.0.0.1:12345"
-#define TEST_CONN_FD_INIT 50
+#define TEST_CONN_FD_INIT 0x10000
void test_conn_lookup_addr_helper(const char *address,
int family, tor_addr_t *addr);
diff --git a/src/test/test_dir.c b/src/test/test_dir.c
index bf9a04b079..3a0b8237cb 100644
--- a/src/test/test_dir.c
+++ b/src/test/test_dir.c
@@ -3041,7 +3041,7 @@ test_dir_param_voting_lookup(void *arg)
tt_str_op(smartlist_get(tor_get_captured_bug_log_(), 0), OP_EQ,
"!(!ok)");
tor_end_capture_bugs_();
-#endif
+#endif /* !defined(ALL_BUGS_ARE_FATAL) */
done:
SMARTLIST_FOREACH(lst, char *, cp, tor_free(cp));
@@ -4997,7 +4997,7 @@ test_dir_purpose_needs_anonymity_returns_true_by_default(void *arg)
#if !defined(__COVERITY__) && !defined(__clang_analyzer__)
tt_skip();
#endif
-#endif
+#endif /* defined(ALL_BUGS_ARE_FATAL) */
tor_capture_bugs_(1);
setup_full_capture_of_logs(LOG_WARN);
diff --git a/src/test/test_hs_client.c b/src/test/test_hs_client.c
index 3d6422a83c..ae5cc5ed84 100644
--- a/src/test/test_hs_client.c
+++ b/src/test/test_hs_client.c
@@ -733,6 +733,10 @@ test_parse_auth_file_content(void *arg)
/* Bigger key than it should be */
tt_assert(!parse_auth_file_content("xx:descriptor:x25519:"
"vjqea4jbhwwc4hto7ekyvqfbeodghbaq6nxi45hz4wr3qvhqv3yqa"));
+ /* All-zeroes key */
+ tt_assert(!parse_auth_file_content("xx:descriptor:x25519:"
+ "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"));
+
done:
tor_free(auth);
}
@@ -1189,7 +1193,11 @@ static void
test_socks_hs_errors(void *arg)
{
int ret;
+ char digest[DIGEST_LEN];
char *desc_encoded = NULL;
+ circuit_t *circ = NULL;
+ origin_circuit_t *ocirc = NULL;
+ tor_addr_t addr;
ed25519_keypair_t service_kp;
ed25519_keypair_t signing_kp;
entry_connection_t *socks_conn = NULL;
@@ -1236,6 +1244,73 @@ test_socks_hs_errors(void *arg)
desc = hs_helper_build_hs_desc_with_ip(&service_kp);
tt_assert(desc);
+ /* Before testing the client authentication error code, encode the
+ * descriptor with no client auth. */
+ ret = hs_desc_encode_descriptor(desc, &service_kp, NULL, &desc_encoded);
+ tt_int_op(ret, OP_EQ, 0);
+ tt_assert(desc_encoded);
+
+ /*
+ * Test the introduction failure codes (X'F2' and X'F7')
+ */
+
+ /* First, we have to put all the IPs in the failure cache. */
+ SMARTLIST_FOREACH_BEGIN(desc->encrypted_data.intro_points,
+ hs_desc_intro_point_t *, ip) {
+ hs_cache_client_intro_state_note(&service_kp.pubkey,
+ &ip->auth_key_cert->signed_key,
+ INTRO_POINT_FAILURE_GENERIC);
+ } SMARTLIST_FOREACH_END(ip);
+
+ hs_client_dir_fetch_done(dir_conn, "Reason", desc_encoded, 200);
+ tt_int_op(socks_conn->socks_request->socks_extended_error_code, OP_EQ,
+ SOCKS5_HS_INTRO_FAILED);
+
+ /* Purge client cache of the descriptor so we can go again. */
+ hs_cache_purge_as_client();
+
+ /* Second, set all failures to be time outs. */
+ SMARTLIST_FOREACH_BEGIN(desc->encrypted_data.intro_points,
+ hs_desc_intro_point_t *, ip) {
+ hs_cache_client_intro_state_note(&service_kp.pubkey,
+ &ip->auth_key_cert->signed_key,
+ INTRO_POINT_FAILURE_TIMEOUT);
+ } SMARTLIST_FOREACH_END(ip);
+
+ hs_client_dir_fetch_done(dir_conn, "Reason", desc_encoded, 200);
+ tt_int_op(socks_conn->socks_request->socks_extended_error_code, OP_EQ,
+ SOCKS5_HS_INTRO_TIMEDOUT);
+
+ /* Purge client cache of the descriptor so we can go again. */
+ hs_cache_purge_as_client();
+
+ /*
+ * Test the rendezvous failure codes (X'F3')
+ */
+
+ circ = dummy_origin_circuit_new(0);
+ tt_assert(circ);
+ circ->purpose = CIRCUIT_PURPOSE_C_REND_READY;
+ ocirc = TO_ORIGIN_CIRCUIT(circ);
+ ocirc->hs_ident = hs_ident_circuit_new(&service_kp.pubkey);
+ ocirc->build_state = tor_malloc_zero(sizeof(cpath_build_state_t));
+ /* Code path will log this exit so build it. */
+ ocirc->build_state->chosen_exit = extend_info_new("TestNickname", digest,
+ NULL, NULL, NULL, &addr,
+ 4242);
+ /* Attach socks connection to this rendezvous circuit. */
+ ocirc->p_streams = ENTRY_TO_EDGE_CONN(socks_conn);
+ /* Trigger the rendezvous failure. Timeout the circuit and free. */
+ circuit_mark_for_close(circ, END_CIRC_REASON_TIMEOUT);
+
+ tt_int_op(socks_conn->socks_request->socks_extended_error_code, OP_EQ,
+ SOCKS5_HS_REND_FAILED);
+
+ /*
+ * Test client authorization codes.
+ */
+
+ tor_free(desc_encoded);
crypto_rand((char *) descriptor_cookie, sizeof(descriptor_cookie));
ret = hs_desc_encode_descriptor(desc, &service_kp, descriptor_cookie,
&desc_encoded);
@@ -1277,6 +1352,7 @@ test_socks_hs_errors(void *arg)
connection_free_minimal(TO_CONN(dir_conn));
hs_descriptor_free(desc);
tor_free(desc_encoded);
+ circuit_free(circ);
hs_free_all();
diff --git a/src/test/test_hs_control.c b/src/test/test_hs_control.c
index 9277711d2a..8ba9f1173c 100644
--- a/src/test/test_hs_control.c
+++ b/src/test/test_hs_control.c
@@ -467,6 +467,20 @@ test_hs_control_bad_onion_client_auth_add(void *arg)
cp1 = buf_get_contents(TO_CONN(&conn)->outbuf, &sz);
tt_str_op(cp1, OP_EQ, "512 Failed to decode x25519 private key\r\n");
+ tor_free(cp1);
+ tor_free(args);
+
+ /* Register with an all zero client key */
+ args = tor_strdup("jt4grrjwzyz3pjkylwfau5xnjaj23vxmhskqaeyfhrfylelw4hvxcuyd "
+ "x25519:AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=");
+ retval = handle_control_command(&conn, (uint32_t) strlen(args), args);
+ tt_int_op(retval, OP_EQ, 0);
+
+ /* Check contents */
+ cp1 = buf_get_contents(TO_CONN(&conn)->outbuf, &sz);
+ tt_str_op(cp1, OP_EQ, "553 Invalid private key \"AAAAAAAAAAAAAAAAAAAA"
+ "AAAAAAAAAAAAAAAAAAAAAAA=\"\r\n");
+
client_auths = get_hs_client_auths_map();
tt_assert(!client_auths);
diff --git a/src/test/test_hs_intropoint.c b/src/test/test_hs_intropoint.c
index 3b6e3fd213..e6b27d7a50 100644
--- a/src/test/test_hs_intropoint.c
+++ b/src/test/test_hs_intropoint.c
@@ -764,7 +764,7 @@ test_introduce1_validation(void *arg)
ret = validate_introduce1_parsed_cell(cell);
tor_end_capture_bugs_();
tt_int_op(ret, OP_EQ, -1);
-#endif
+#endif /* !defined(ALL_BUGS_ARE_FATAL) */
/* Reset legacy ID and make sure it's correct. */
memset(cell->legacy_key_id, 0, sizeof(cell->legacy_key_id));
diff --git a/src/test/test_hs_service.c b/src/test/test_hs_service.c
index 9966bd108d..80383baff8 100644
--- a/src/test/test_hs_service.c
+++ b/src/test/test_hs_service.c
@@ -2520,7 +2520,7 @@ test_intro2_handling(void *arg)
/* Start cleaning up X */
replaycache_free(x_service.state.replay_cache_rend_cookie);
smartlist_free(x_service.config.ob_master_pubkeys);
- tor_free(x_service.ob_subcreds);
+ tor_free(x_service.state.ob_subcreds);
service_descriptor_free(x_service.desc_current);
service_descriptor_free(x_service.desc_next);
service_intro_point_free(x_ip);
diff --git a/src/test/test_socks.c b/src/test/test_socks.c
index 40fb0481c6..4a465c7361 100644
--- a/src/test/test_socks.c
+++ b/src/test/test_socks.c
@@ -815,7 +815,7 @@ test_socks_truncated(void *ptr)
for (i = 0; i < ARRAY_LENGTH(commands); ++i) {
for (j = 0; j < commands[i].len; ++j) {
switch (commands[i].setup) {
- default: /* Falls through */
+ default: FALLTHROUGH;
case NONE:
/* This test calls for no setup on the socks state. */
break;
diff --git a/src/tools/tor-resolve.c b/src/tools/tor-resolve.c
index d369445dfc..e6d6bddcdb 100644
--- a/src/tools/tor-resolve.c
+++ b/src/tools/tor-resolve.c
@@ -509,7 +509,7 @@ do_resolve(const char *hostname,
} else if (atype == SOCKS5_ATYPE_IPV6) {
/* IPv6 address */
tor_addr_from_ipv6_bytes(result_addr,
- (const char *)socks5_server_reply_getarray_bind_addr_ipv6(reply));
+ socks5_server_reply_getarray_bind_addr_ipv6(reply));
} else if (atype == SOCKS5_ATYPE_HOSTNAME) {
/* Domain name */
domainname_t *dn =