aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--ChangeLog691
-rw-r--r--Doxyfile.in3
-rw-r--r--Makefile.am1
-rw-r--r--README4
-rw-r--r--ReleaseNotes286
-rw-r--r--changes/bug309924
-rw-r--r--changes/bug320407
-rw-r--r--changes/bug325884
-rw-r--r--changes/bug327094
-rw-r--r--changes/bug331313
-rw-r--r--changes/bug332844
-rw-r--r--changes/bug332853
-rw-r--r--changes/bug335313
-rw-r--r--changes/bug338999
-rw-r--r--changes/bug339003
-rw-r--r--changes/bug339175
-rw-r--r--changes/bug339774
-rw-r--r--changes/bug340655
-rw-r--r--changes/bug341304
-rw-r--r--changes/bug342334
-rw-r--r--changes/bug342484
-rw-r--r--changes/bug342514
-rw-r--r--changes/bug342993
-rw-r--r--changes/bug343035
-rw-r--r--changes/bug343574
-rw-r--r--changes/bug344005
-rw-r--r--changes/bug46316
-rw-r--r--changes/doc334173
-rw-r--r--changes/doc341336
-rw-r--r--changes/feature340683
-rw-r--r--changes/ticket248444
-rw-r--r--changes/ticket282084
-rw-r--r--changes/ticket282795
-rw-r--r--changes/ticket289923
-rw-r--r--changes/ticket306424
-rw-r--r--changes/ticket315763
-rw-r--r--changes/ticket316344
-rw-r--r--changes/ticket316993
-rw-r--r--changes/ticket3208813
-rw-r--r--changes/ticket321434
-rw-r--r--changes/ticket325423
-rw-r--r--changes/ticket327204
-rw-r--r--changes/ticket327923
-rw-r--r--changes/ticket328225
-rw-r--r--changes/ticket328736
-rw-r--r--changes/ticket328884
-rw-r--r--changes/ticket329056
-rw-r--r--changes/ticket329943
-rw-r--r--changes/ticket330143
-rw-r--r--changes/ticket331925
-rw-r--r--changes/ticket331944
-rw-r--r--changes/ticket331954
-rw-r--r--changes/ticket332228
-rw-r--r--changes/ticket332243
-rw-r--r--changes/ticket332334
-rw-r--r--changes/ticket332364
-rw-r--r--changes/ticket332385
-rw-r--r--changes/ticket332755
-rw-r--r--changes/ticket332804
-rw-r--r--changes/ticket333003
-rw-r--r--changes/ticket333034
-rw-r--r--changes/ticket3331615
-rw-r--r--changes/ticket333345
-rw-r--r--changes/ticket333393
-rw-r--r--changes/ticket333494
-rw-r--r--changes/ticket333663
-rw-r--r--changes/ticket333683
-rw-r--r--changes/ticket333694
-rw-r--r--changes/ticket333703
-rw-r--r--changes/ticket333984
-rw-r--r--changes/ticket334003
-rw-r--r--changes/ticket334364
-rw-r--r--changes/ticket334513
-rw-r--r--changes/ticket334584
-rw-r--r--changes/ticket336336
-rw-r--r--changes/ticket336424
-rw-r--r--changes/ticket336794
-rw-r--r--changes/ticket337783
-rw-r--r--changes/ticket337793
-rw-r--r--changes/ticket337884
-rw-r--r--changes/ticket337894
-rw-r--r--changes/ticket338164
-rw-r--r--changes/ticket3381712
-rw-r--r--changes/ticket339014
-rw-r--r--changes/ticket339565
-rw-r--r--changes/ticket340645
-rw-r--r--changes/ticket340674
-rw-r--r--changes/ticket341375
-rw-r--r--changes/ticket342003
-rw-r--r--changes/ticket342113
-rw-r--r--changes/ticket342325
-rw-r--r--changes/ticket34255_0433
-rw-r--r--changes/ticket344455
-rw-r--r--changes/ticket344465
-rw-r--r--changes/ticket400023
-rw-r--r--changes/ticket400066
-rw-r--r--changes/ticket400195
-rw-r--r--configure.ac10
-rw-r--r--contrib/win32build/tor-mingw.nsi.in2
-rw-r--r--doc/HACKING/CodeStructure.md123
-rw-r--r--doc/include.am1
-rw-r--r--doc/tor.1.txt29
-rwxr-xr-xscripts/git/git-list-tor-branches.sh6
-rwxr-xr-xscripts/git/pre-commit.git-hook24
-rwxr-xr-xscripts/git/pre-push.git-hook1
-rwxr-xr-xscripts/maint/clang-format.sh41
-rwxr-xr-xscripts/maint/code-format.sh232
-rw-r--r--scripts/maint/practracker/.enable_practracker_in_hooks1
-rw-r--r--scripts/maint/practracker/exceptions.txt21
-rwxr-xr-xscripts/maint/rename_c_identifier.py2
-rw-r--r--src/app/app.md5
-rw-r--r--src/app/config/config.c13
-rw-r--r--src/app/config/config.h3
-rw-r--r--src/app/config/or_options_st.h14
-rw-r--r--src/app/config/resolve_addr.c870
-rw-r--r--src/app/config/resolve_addr.h18
-rw-r--r--src/app/config/testnet.inc1
-rw-r--r--src/app/main/main.c11
-rw-r--r--src/core/crypto/onion_crypto.c2
-rw-r--r--src/core/mainloop/connection.c2
-rw-r--r--src/core/or/channelpadding.c2
-rw-r--r--src/core/or/channelpadding.h3
-rw-r--r--src/core/or/channeltls.c14
-rw-r--r--src/core/or/circuit_st.h6
-rw-r--r--src/core/or/circuitbuild.c419
-rw-r--r--src/core/or/circuitbuild.h27
-rw-r--r--src/core/or/circuitlist.c3
-rw-r--r--src/core/or/circuitpadding.c152
-rw-r--r--src/core/or/circuitpadding.h27
-rw-r--r--src/core/or/circuitpadding_machines.c25
-rw-r--r--src/core/or/circuitstats.c67
-rw-r--r--src/core/or/circuitstats.h6
-rw-r--r--src/core/or/circuituse.c27
-rw-r--r--src/core/or/circuituse.h16
-rw-r--r--src/core/or/connection_edge.c5
-rw-r--r--src/core/or/cpath_build_state_st.h2
-rw-r--r--src/core/or/crypt_path.c2
-rw-r--r--src/core/or/extend_info_st.h16
-rw-r--r--src/core/or/extendinfo.c305
-rw-r--r--src/core/or/extendinfo.h40
-rw-r--r--src/core/or/include.am2
-rw-r--r--src/core/or/onion.h3
-rw-r--r--src/core/or/or.h21
-rw-r--r--src/core/or/protover.c11
-rw-r--r--src/core/or/protover.h24
-rw-r--r--src/core/or/relay.c1
-rw-r--r--src/core/or/scheduler_kist.c5
-rw-r--r--src/core/or/versions.c59
-rw-r--r--src/core/stA1RajU0
-rw-r--r--src/core/stiysZNDbin19083264 -> 0 bytes
-rw-r--r--src/ext/README79
-rw-r--r--src/ext/ext.md88
-rw-r--r--src/ext/include.am2
-rw-r--r--src/feature/client/bridges.c18
-rw-r--r--src/feature/client/entrynodes.c2
-rw-r--r--src/feature/control/control_cmd.c36
-rw-r--r--src/feature/control/control_events.c59
-rw-r--r--src/feature/control/control_events.h2
-rw-r--r--src/feature/control/control_getinfo.c61
-rw-r--r--src/feature/control/control_getinfo.h4
-rw-r--r--src/feature/dirauth/dirauth_config.c4
-rw-r--r--src/feature/dirauth/dirauth_options.inc7
-rw-r--r--src/feature/dirauth/dirvote.c8
-rw-r--r--src/feature/dirauth/process_descs.c8
-rw-r--r--src/feature/dirauth/reachability.c5
-rw-r--r--src/feature/dirauth/voteflags.c6
-rw-r--r--src/feature/dircache/dircache.c2
-rw-r--r--src/feature/feature.md23
-rw-r--r--src/feature/hs/hs_circuit.c1
-rw-r--r--src/feature/hs/hs_client.c1
-rw-r--r--src/feature/hs/hs_common.c1
-rw-r--r--src/feature/hs/hs_service.c4
-rw-r--r--src/feature/nodelist/describe.c10
-rw-r--r--src/feature/nodelist/dirlist.c12
-rw-r--r--src/feature/nodelist/networkstatus.c51
-rw-r--r--src/feature/nodelist/node_select.c152
-rw-r--r--src/feature/nodelist/node_select.h28
-rw-r--r--src/feature/nodelist/node_st.h5
-rw-r--r--src/feature/nodelist/nodelist.c90
-rw-r--r--src/feature/nodelist/nodelist.h22
-rw-r--r--src/feature/nodelist/routerinfo.c35
-rw-r--r--src/feature/nodelist/routerinfo.h5
-rw-r--r--src/feature/nodelist/routerlist.c150
-rw-r--r--src/feature/nodelist/routerlist.h14
-rw-r--r--src/feature/nodelist/routerset.c56
-rw-r--r--src/feature/relay/circuitbuild_relay.c65
-rw-r--r--src/feature/relay/circuitbuild_relay.h2
-rw-r--r--src/feature/relay/relay_config.c4
-rw-r--r--src/feature/relay/relay_find_addr.c37
-rw-r--r--src/feature/relay/relay_periodic.c48
-rw-r--r--src/feature/relay/router.c131
-rw-r--r--src/feature/relay/router.h3
-rw-r--r--src/feature/relay/selftest.c352
-rw-r--r--src/feature/relay/selftest.h18
-rw-r--r--src/feature/rend/rendclient.c11
-rw-r--r--src/feature/rend/rendcommon.c10
-rw-r--r--src/feature/rend/rendparse.c17
-rw-r--r--src/feature/rend/rendservice.c20
-rw-r--r--src/feature/stats/predict_ports.c4
-rw-r--r--src/feature/stats/rephist.c20
-rw-r--r--src/feature/stats/rephist.h3
-rw-r--r--src/lib/net/address.c36
-rw-r--r--src/lib/net/address.h12
-rw-r--r--src/lib/tls/buffers_tls.c5
-rw-r--r--src/mainpage.md5
-rw-r--r--src/rust/protover/ffi.rs10
-rw-r--r--src/rust/protover/protover.rs8
-rw-r--r--src/test/conf_examples/dirauth_3/error_no_dirauth1
-rw-r--r--src/test/conf_examples/dirauth_3/error_no_dirauth_relay1
-rw-r--r--src/test/conf_examples/dirauth_3/expected9
-rw-r--r--src/test/conf_examples/dirauth_3/expected_log1
-rw-r--r--src/test/conf_examples/dirauth_3/torrc13
-rw-r--r--src/test/rend_test_helpers.c13
-rw-r--r--src/test/test-memwipe.c23
-rw-r--r--src/test/test.c21
-rw-r--r--src/test/test_address.c10
-rw-r--r--src/test/test_channeltls.c32
-rw-r--r--src/test/test_circuitbuild.c460
-rw-r--r--src/test/test_circuitpadding.c21
-rw-r--r--src/test/test_circuitstats.c95
-rw-r--r--src/test/test_config.c869
-rw-r--r--src/test/test_controller.c87
-rw-r--r--src/test/test_helpers.c62
-rw-r--r--src/test/test_helpers.h5
-rw-r--r--src/test/test_hs_client.c6
-rw-r--r--src/test/test_hs_service.c2
-rw-r--r--src/test/test_nodelist.c4
-rw-r--r--src/test/test_policy.c5
-rw-r--r--src/test/test_process_descs.c2
-rw-r--r--src/test/test_protover.c327
-rw-r--r--src/test/test_routerkeys.c53
-rw-r--r--src/test/test_routerset.c56
-rw-r--r--src/trunnel/circpad_negotiation.c52
-rw-r--r--src/trunnel/circpad_negotiation.h27
-rw-r--r--src/trunnel/circpad_negotiation.trunnel17
-rw-r--r--src/win32/orconfig.h2
236 files changed, 6011 insertions, 2253 deletions
diff --git a/ChangeLog b/ChangeLog
index 9ddbfa95fd..866a1153e7 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,694 @@
+Changes in version 0.3.5.11 - 2020-07-09
+ Tor 0.3.5.11 backports fixes from later tor releases, including several
+ usability, portability, and reliability fixes.
+
+ This release also fixes TROVE-2020-001, a medium-severity denial of
+ service vulnerability affecting all versions of Tor when compiled with
+ the NSS encryption library. (This is not the default configuration.)
+ Using this vulnerability, an attacker could cause an affected Tor
+ instance to crash remotely. This issue is also tracked as CVE-2020-
+ 15572. Anybody running a version of Tor built with the NSS library
+ should upgrade to 0.3.5.11, 0.4.2.8, 0.4.3.6, or 0.4.4.2-alpha
+ or later.
+
+ o Major bugfixes (NSS, security, backport from 0.4.4.2-alpha):
+ - Fix a crash due to an out-of-bound memory access when Tor is
+ compiled with NSS support. Fixes bug 33119; bugfix on
+ 0.3.5.1-alpha. This issue is also tracked as TROVE-2020-001
+ and CVE-2020-15572.
+
+ o Major bugfixes (DoS defenses, bridges, pluggable transport, backport from 0.4.3.4-rc):
+ - 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 features (testing, backport from 0.4.3.4-rc):
+ - 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 bugfix (CI, Windows, backport from 0.4.4.2-alpha):
+ - Use the correct 64-bit printf format when compiling with MINGW on
+ Appveyor. Fixes bug 40026; bugfix on 0.3.5.5-alpha.
+
+ o Minor bugfix (relay, configuration, backport from 0.4.3.3-alpha):
+ - 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 (client performance, backport from 0.4.4.1-alpha):
+ - Resume use of preemptively-built circuits when UseEntryGuards is set
+ to 0. We accidentally disabled this feature with that config
+ setting, leading to slower load times. Fixes bug 34303; bugfix
+ on 0.3.3.2-alpha.
+
+ o Minor bugfixes (compiler compatibility, backport from 0.4.3.5):
+ - Avoid compiler warnings from Clang 10 related to the use of GCC-
+ style "/* falls through */" comments. Both Clang and GCC allow
+ __attribute__((fallthrough)) instead, so that's what we're using
+ now. Fixes bug 34078; bugfix on 0.3.1.3-alpha.
+
+ o Minor bugfixes (compiler warnings, backport from 0.4.4.2-alpha):
+ - Fix a compiler warning on platforms with 32-bit time_t values.
+ Fixes bug 40028; bugfix on 0.3.2.8-rc.
+
+ o Minor bugfixes (embedded Tor, backport from 0.4.3.1-alpha):
+ - When starting Tor any time after the first time in a process,
+ register the thread in which it is running as the main thread.
+ Previously, we only did this on Windows, which could lead to bugs
+ like 23081 on non-Windows platforms. Fixes bug 32884; bugfix
+ on 0.3.3.1-alpha.
+
+ o Minor bugfixes (key portability, backport from 0.4.3.4-rc):
+ - 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, backport from 0.4.4.2-alpha):
+ - Downgrade a noisy log message that could occur naturally when
+ receiving an extrainfo document that we no longer want. Fixes bug
+ 16016; bugfix on 0.2.6.3-alpha.
+
+ o Minor bugfixes (onion service v3, client, backport from 0.4.3.3-alpha):
+ - 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 Testing (CI, backport from 0.4.3.4-rc):
+ - 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.2.8 - 2020-07-09
+ Tor 0.4.2.8 backports various fixes from later releases, including
+ several that affect usability and portability.
+
+ This release also fixes TROVE-2020-001, a medium-severity denial of
+ service vulnerability affecting all versions of Tor when compiled with
+ the NSS encryption library. (This is not the default configuration.)
+ Using this vulnerability, an attacker could cause an affected Tor
+ instance to crash remotely. This issue is also tracked as CVE-2020-
+ 15572. Anybody running a version of Tor built with the NSS library
+ should upgrade to 0.3.5.11, 0.4.2.8, 0.4.3.6, or 0.4.4.2-alpha
+ or later.
+
+ o Major bugfixes (NSS, security, backport from 0.4.4.2-alpha):
+ - Fix a crash due to an out-of-bound memory access when Tor is
+ compiled with NSS support. Fixes bug 33119; bugfix on
+ 0.3.5.1-alpha. This issue is also tracked as TROVE-2020-001
+ and CVE-2020-15572.
+
+ o Major bugfixes (DoS defenses, bridges, pluggable transport, backport from 0.4.3.4-rc):
+ - 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, backport form 0.4.3.4-rc):
+ - 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 (diagnostic, backport from 0.4.3.3-alpha):
+ - 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 (testing, backport from 0.4.3.4-rc):
+ - 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 bugfix (CI, Windows, backport from 0.4.4.2-alpha):
+ - Use the correct 64-bit printf format when compiling with MINGW on
+ Appveyor. Fixes bug 40026; bugfix on 0.3.5.5-alpha.
+
+ o Minor bugfix (relay, configuration, backport from 0.4.3.3-alpha):
+ - 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 (client performance, backport from 0.4.4.1-alpha):
+ - Resume use of preemptively-built circuits when UseEntryGuards is set
+ to 0. We accidentally disabled this feature with that config
+ setting, leading to slower load times. Fixes bug 34303; bugfix
+ on 0.3.3.2-alpha.
+
+ o Minor bugfixes (compiler compatibility, backport from 0.4.3.5):
+ - Avoid compiler warnings from Clang 10 related to the use of GCC-
+ style "/* falls through */" comments. Both Clang and GCC allow
+ __attribute__((fallthrough)) instead, so that's what we're using
+ now. Fixes bug 34078; bugfix on 0.3.1.3-alpha.
+ - Fix compilation warnings with GCC 10.0.1. Fixes bug 34077; bugfix
+ on 0.4.0.3-alpha.
+
+ o Minor bugfixes (compiler warnings, backport from 0.4.4.2-alpha):
+ - Fix a compiler warning on platforms with 32-bit time_t values.
+ Fixes bug 40028; bugfix on 0.3.2.8-rc.
+
+ o Minor bugfixes (controller protocol, backport from 0.4.3.2-alpha):
+ - When receiving "ACTIVE" or "DORMANT" signals on the control port,
+ report them as SIGNAL events. Previously we would log a bug
+ warning. Fixes bug 33104; bugfix on 0.4.0.1-alpha.
+
+ o Minor bugfixes (embedded Tor, backport from 0.4.3.1-alpha):
+ - When starting Tor any time after the first time in a process,
+ register the thread in which it is running as the main thread.
+ Previously, we only did this on Windows, which could lead to bugs
+ like 23081 on non-Windows platforms. Fixes bug 32884; bugfix
+ on 0.3.3.1-alpha.
+
+ o Minor bugfixes (key portability, backport from 0.4.3.4-rc):
+ - 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, backport from 0.4.3.2-rc):
+ - When logging a bug, do not say "Future instances of this warning
+ will be silenced" unless we are actually going to silence them.
+ Previously we would say this whenever a BUG() check failed in the
+ code. Fixes bug 33095; bugfix on 0.4.1.1-alpha.
+
+ o Minor bugfixes (logging, backport from 0.4.3.4-rc):
+ - 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.
+
+ o Minor bugfixes (logging, backport from 0.4.4.2-alpha):
+ - Downgrade a noisy log message that could occur naturally when
+ receiving an extrainfo document that we no longer want. Fixes bug
+ 16016; bugfix on 0.2.6.3-alpha.
+
+ o Minor bugfixes (onion service v3, client, backport from 0.4.3.3-alpha):
+ - 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 Testing (CI, backport from 0.4.3.4-rc):
+ - 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.6 - 2020-07-09
+ Tor 0.4.3.6 backports several bugfixes from later releases, including
+ some affecting usability.
+
+ This release also fixes TROVE-2020-001, a medium-severity denial of
+ service vulnerability affecting all versions of Tor when compiled with
+ the NSS encryption library. (This is not the default configuration.)
+ Using this vulnerability, an attacker could cause an affected Tor
+ instance to crash remotely. This issue is also tracked as CVE-2020-
+ 15572. Anybody running a version of Tor built with the NSS library
+ should upgrade to 0.3.5.11, 0.4.2.8, 0.4.3.6, or 0.4.4.2-alpha
+ or later.
+
+ o Major bugfixes (NSS, security, backport from 0.4.4.2-alpha):
+ - Fix a crash due to an out-of-bound memory access when Tor is
+ compiled with NSS support. Fixes bug 33119; bugfix on
+ 0.3.5.1-alpha. This issue is also tracked as TROVE-2020-001
+ and CVE-2020-15572.
+
+ o Minor bugfix (CI, Windows, backport from 0.4.4.2-alpha):
+ - Use the correct 64-bit printf format when compiling with MINGW on
+ Appveyor. Fixes bug 40026; bugfix on 0.3.5.5-alpha.
+
+ o Minor bugfixes (client performance, backport from 0.4.4.1-alpha):
+ - Resume use of preemptively-built circuits when UseEntryGuards is set
+ to 0. We accidentally disabled this feature with that config
+ setting, leading to slower load times. Fixes bug 34303; bugfix
+ on 0.3.3.2-alpha.
+
+ o Minor bugfixes (compiler warnings, backport from 0.4.4.2-alpha):
+ - Fix a compiler warning on platforms with 32-bit time_t values.
+ Fixes bug 40028; bugfix on 0.3.2.8-rc.
+
+ o Minor bugfixes (linux seccomp sandbox, nss, backport from 0.4.4.1-alpha):
+ - Fix a 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.
+
+ o Minor bugfixes (logging, backport from 0.4.4.2-alpha):
+ - Downgrade a noisy log message that could occur naturally when
+ receiving an extrainfo document that we no longer want. Fixes bug
+ 16016; bugfix on 0.2.6.3-alpha.
+
+ o Minor bugfixes (manual page, backport from 0.4.4.1-alpha):
+ - Update the man page to reflect that MinUptimeHidServDirectoryV2
+ defaults to 96 hours. Fixes bug 34299; bugfix on 0.2.6.3-alpha.
+
+ o Minor bugfixes (onion service v3, backport from 0.4.4.1-alpha):
+ - Prevent an assert() that would occur when cleaning the client
+ descriptor cache, and attempting to close circuits for a non-
+ decrypted descriptor (lacking client authorization). Fixes bug
+ 33458; bugfix on 0.4.2.1-alpha.
+
+ o Minor bugfixes (portability, backport from 0.4.4.1-alpha):
+ - Fix a portability error in the configure script, where we were
+ using "==" instead of "=". Fixes bug 34233; bugfix on 0.4.3.5.
+
+ o Minor bugfixes (relays, backport from 0.4.4.1-alpha):
+ - Stop advertising incorrect IPv6 ORPorts in relay and bridge
+ descriptors, when the IPv6 port was configured as "auto". Fixes
+ bug 32588; bugfix on 0.2.3.9-alpha.
+
+ o Documentation (backport from 0.4.4.1-alpha):
+ - Fix several doxygen warnings related to imbalanced groups. Closes
+ ticket 34255.
+
+
+Changes in version 0.4.4.2-alpha - 2020-07-09
+ This is the second alpha release in the 0.4.4.x series. It fixes a few
+ bugs in the previous release, and solves a few usability,
+ compatibility, and portability issues.
+
+ This release also fixes TROVE-2020-001, a medium-severity denial of
+ service vulnerability affecting all versions of Tor when compiled with
+ the NSS encryption library. (This is not the default configuration.)
+ Using this vulnerability, an attacker could cause an affected Tor
+ instance to crash remotely. This issue is also tracked as CVE-2020-
+ 15572. Anybody running a version of Tor built with the NSS library
+ should upgrade to 0.3.5.11, 0.4.2.8, 0.4.3.6, or 0.4.4.2-alpha
+ or later.
+
+ o Major bugfixes (NSS, security):
+ - Fix a crash due to an out-of-bound memory access when Tor is
+ compiled with NSS support. Fixes bug 33119; bugfix on
+ 0.3.5.1-alpha. This issue is also tracked as TROVE-2020-001
+ and CVE-2020-15572.
+
+ o Minor features (bootstrap reporting):
+ - Report more detailed reasons for bootstrap failure when the
+ failure happens due to a TLS error. Previously we would just call
+ these errors "MISC" when they happened during read, and "DONE"
+ when they happened during any other TLS operation. Closes
+ ticket 32622.
+
+ o Minor features (directory authority):
+ - Authorities now recommend the protocol versions that are supported
+ by Tor 0.3.5 and later. (Earlier versions of Tor have been
+ deprecated since January of this year.) This recommendation will
+ cause older clients and relays to give a warning on startup, or
+ when they download a consensus directory. Closes ticket 32696.
+
+ o Minor features (entry guards):
+ - Reinstate support for GUARD NEW/UP/DOWN control port events.
+ Closes ticket 40001.
+
+ o Minor features (linux seccomp2 sandbox, portability):
+ - Allow Tor to build on platforms where it doesn't know how to
+ report which syscall caused the linux seccomp2 sandbox to fail.
+ This change should make the sandbox code more portable to less
+ common Linux architectures. Closes ticket 34382.
+ - Permit the unlinkat() syscall, which some Libc implementations use
+ to implement unlink(). Closes ticket 33346.
+
+ o Minor bugfix (CI, Windows):
+ - Use the correct 64-bit printf format when compiling with MINGW on
+ Appveyor. Fixes bug 40026; bugfix on 0.3.5.5-alpha.
+
+ o Minor bugfix (onion service v3 client):
+ - Remove a BUG() warning that could occur naturally. Fixes bug
+ 34087; bugfix on 0.3.2.1-alpha.
+
+ o Minor bugfix (SOCKS, onion service client):
+ - Detect v3 onion service addresses of the wrong length when
+ returning the F6 ExtendedErrors code. Fixes bug 33873; bugfix
+ on 0.4.3.1-alpha.
+
+ o Minor bugfixes (compiler warnings):
+ - Fix a compiler warning on platforms with 32-bit time_t values.
+ Fixes bug 40028; bugfix on 0.3.2.8-rc.
+
+ o Minor bugfixes (control port, onion service):
+ - Consistently use 'address' in "Invalid v3 address" response to
+ ONION_CLIENT_AUTH commands. Previously, we would sometimes say
+ 'addr'. Fixes bug 40005; bugfix on 0.4.3.1-alpha.
+
+ o Minor bugfixes (logging):
+ - Downgrade a noisy log message that could occur naturally when
+ receiving an extrainfo document that we no longer want. Fixes bug
+ 16016; bugfix on 0.2.6.3-alpha.
+
+ o Minor bugfixes (onion services v3):
+ - Avoid a non-fatal assertion failure in certain edge-cases when
+ opening an intro circuit as a client. Fixes bug 34084; bugfix
+ on 0.3.2.1-alpha.
+
+ o Deprecated features (onion service v2):
+ - Add a deprecation warning for version 2 onion services. Closes
+ ticket 40003.
+
+ o Removed features (IPv6, revert):
+ - Revert the change in the default value of ClientPreferIPv6OrPort:
+ it breaks the torsocks use case. The SOCKS resolve command has no
+ mechanism to ask for a specific address family (v4 or v6), and so
+ prioritizing IPv6 when an IPv4 address is requested on the SOCKS
+ interface resulted in a failure. Tor Browser explicitly sets
+ PreferIPv6, so this should not affect the majority of our users.
+ Closes ticket 33796; bugfix on 0.4.4.1-alpha.
+
+
+Changes in version 0.4.4.1-alpha - 2020-06-16
+ This is the first alpha release in the 0.4.4.x series. It improves
+ our guard selection algorithms, improves the amount of code that
+ can be disabled when running without relay support, and includes numerous
+ small bugfixes and enhancements. It also lays the ground for some IPv6
+ features that we'll be developing more in the next (0.4.5) series.
+
+ Here are the changes since 0.4.3.5.
+
+ o Major features (Proposal 310, performance + security):
+ - Implements Proposal 310, "Bandaid on guard selection". Proposal
+ 310 solves load-balancing issues with older versions of the guard
+ selection algorithm, and improves its security. Under this new
+ algorithm, a newly selected guard never becomes Primary unless all
+ previously sampled guards are unreachable. Implements
+ recommendation from 32088. (Proposal 310 is linked to the CLAPS
+ project researching optimal client location-aware path selections.
+ This project is a collaboration between the UCLouvain Crypto Group,
+ the U.S. Naval Research Laboratory, and Princeton University.)
+
+ o Major features (IPv6, relay):
+ - 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, and both addresses are
+ provided, it chooses between them uniformly at random. Closes
+ ticket 33817.
+ - Re-use existing IPv6 connections for circuit extends. Closes
+ ticket 33817.
+ - 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.
+
+ o Major features (v3 onion services):
+ - Allow v3 onion services to act as OnionBalance backend instances,
+ by using the HiddenServiceOnionBalanceInstance torrc option.
+ Closes ticket 32709.
+
+ o Minor feature (developer tools):
+ - Add a script to help check the alphabetical ordering of option
+ names in the manual page. Closes ticket 33339.
+
+ 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. The semantics of
+ these error codes are documented in proposal 309. Closes
+ ticket 32542.
+
+ o Minor feature (onion service v3):
+ - If a service cannot upload its descriptor(s), log why at INFO
+ level. Closes ticket 33400; bugfix on 0.3.2.1-alpha.
+
+ o Minor feature (python scripts):
+ - Stop assuming that /usr/bin/python exists. Instead of using a
+ hardcoded path in scripts that still use Python 2, use
+ /usr/bin/env, similarly to the scripts that use Python 3. Fixes
+ bug 33192; bugfix on 0.4.2.
+
+ o Minor features (client-only compilation):
+ - Disable more code related to the ext_orport protocol when
+ compiling without support for relay mode. Closes ticket 33368.
+ - Disable more of our self-testing code when support for relay mode
+ is disabled. Closes ticket 33370.
+
+ o Minor features (code safety):
+ - Check for failures of tor_inet_ntop() and tor_inet_ntoa()
+ functions in DNS and IP address processing code, and adjust
+ codepaths to make them less likely to crash entire Tor instances.
+ Resolves issue 33788.
+
+ o Minor features (compilation size):
+ - Most server-side DNS code is now disabled when building without
+ support for relay mode. Closes ticket 33366.
+
+ o Minor features (continuous integration):
+ - Run unit-test and integration test (Stem, Chutney) jobs with
+ ALL_BUGS_ARE_FATAL macro being enabled on Travis and Appveyor.
+ Resolves ticket 32143.
+
+ 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.
+
+ o Minor features (developer tooling):
+ - Refrain from listing all .a files that are generated by the Tor
+ build in .gitignore. Add a single wildcard *.a entry that covers
+ all of them for present and future. Closes ticket 33642.
+ - Add a script ("git-install-tools.sh") to install git hooks and
+ helper scripts. Closes ticket 33451.
+
+ o Minor features (directory authority, shared random):
+ - Refactor more authority-only parts of the shared-random scheduling
+ code to reside in the dirauth module, and to be disabled when
+ compiling with --disable-module-dirauth. Closes ticket 33436.
+
+ o Minor features (directory):
+ - Remember the number of bytes we have downloaded for each directory
+ purpose while bootstrapping, and while fully bootstrapped. Log
+ this information as part of the heartbeat message. Closes
+ ticket 32720.
+
+ o Minor features (IPv6 support):
+ - 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.
+ - 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.
+
+ o Minor features (logging):
+ - When trying to find our own address, add debug-level logging to
+ report the sources of candidate addresses. Closes ticket 32888.
+
+ o Minor features (testing, architecture):
+ - 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.
+ - Initialize all subsystems at the beginning of our unit test
+ harness, to avoid crashes due to uninitialized subsystems. Follow-
+ up from ticket 33316.
+
+ o Minor features (v3 onion services):
+ - Add v3 onion service status to the dumpstats() call which is
+ triggered by a SIGUSR1 signal. Previously, we only did v2 onion
+ services. Closes ticket 24844. Patch by Neel Chauhan.
+
+ o Minor features (windows):
+ - Add support for console control signals like Ctrl+C in Windows.
+ Closes ticket 34211. Patch from Damon Harris (TheDcoder).
+
+ o Minor bugfix (onion service v3):
+ - Prevent an assert() that would occur when cleaning the client
+ descriptor cache, and attempting to close circuits for a non-
+ decrypted descriptor (lacking client authorization). Fixes bug
+ 33458; bugfix on 0.4.2.1-alpha.
+
+ o Minor bugfix (refactoring):
+ - Lift circuit_build_times_disabled() out of the
+ circuit_expire_building() loop, to save CPU time when there are
+ many circuits open. Fixes bug 33977; bugfix on 0.3.5.9.
+
+ o Minor bugfixes (client performance):
+ - Resume use of preemptively-built circuits when UseEntryGuards is set
+ to 0. We accidentally disabled this feature with that config
+ setting, leading to slower load times. Fixes bug 34303; bugfix
+ on 0.3.3.2-alpha.
+
+ o Minor bugfixes (directory authorities):
+ - Directory authorities now reject votes that arrive too late. In
+ particular, once an authority has started fetching missing votes,
+ it no longer accepts new votes posted by other authorities. This
+ change helps prevent a consensus split, where only some authorities
+ have the late vote. Fixes bug 4631; bugfix on 0.2.0.5-alpha.
+
+ o Minor bugfixes (git scripts):
+ - Stop executing the checked-out pre-commit hook from the pre-push
+ hook. Instead, execute the copy in the user's git directory. Fixes
+ bug 33284; bugfix on 0.4.1.1-alpha.
+
+ o Minor bugfixes (initialization):
+ - Initialize the subsystems in our code in an order more closely
+ corresponding to their dependencies, so that every system is
+ initialized before the ones that (theoretically) depend on it.
+ Fixes bug 33316; bugfix on 0.4.0.1-alpha.
+
+ 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.
+
+ 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.
+
+ o Minor bugfixes (linux seccomp sandbox nss):
+ - Fix a 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.
+
+ 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. (IF_BUG_ONCE()
+ used to log a non-fatal warning, regardless of the debugging
+ mode.) Fixes bug 33917; bugfix on 0.2.9.1-alpha.
+
+ o Minor bugfixes (logs):
+ - Remove surprising empty line in the INFO-level log about circuit
+ build timeout. Fixes bug 33531; bugfix on 0.3.3.1-alpha.
+
+ 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.
+
+ o Minor bugfixes (manual page):
+ - Update the man page to reflect that MinUptimeHidServDirectoryV2
+ defaults to 96 hours. Fixes bug 34299; bugfix on 0.2.6.3-alpha.
+
+ o Minor bugfixes (onion service v3, client):
+ - Remove a BUG() that was causing a stacktrace when a descriptor
+ changed at an unexpected time. Fixes bug 28992; bugfix
+ on 0.3.2.1-alpha.
+
+ o Minor bugfixes (onion service, logging):
+ - Fix a typo in a log message PublishHidServDescriptors is set to 0.
+ Fixes bug 33779; bugfix on 0.3.2.1-alpha.
+
+ 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.
+
+ o Minor bugfixes (protocol versions):
+ - Sort tor's supported protocol version lists, as recommended by the
+ tor directory specification. Fixes bug 33285; bugfix
+ on 0.4.0.1-alpha.
+
+ o Minor bugfixes (relays):
+ - Stop advertising incorrect IPv6 ORPorts in relay and bridge
+ descriptors, when the IPv6 port was configured as "auto". Fixes
+ bug 32588; bugfix on 0.2.3.9-alpha.
+
+ 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, separating colon, and port number. Closes ticket 33956.
+ Patch by Neel Chauhan.
+ - Merge the orconn and ocirc events into the "core" subsystem, which
+ manages or connections and origin circuits. Previously they were
+ isolated in subsystems of their own.
+ - Move LOG_PROTOCOL_WARN to app/config. Resolves a dependency
+ inversion. Closes ticket 33633.
+ - Move the circuit extend code to the relay module. Split the
+ circuit extend function into smaller functions. Closes
+ ticket 33633.
+ - Rewrite port_parse_config() to use the default port flags from
+ port_cfg_new(). Closes ticket 32994. Patch by MrSquanchee.
+ - Updated comments in 'scheduler.c' to reflect old code changes, and
+ simplified the scheduler channel state change code. Closes
+ ticket 33349.
+
+ o Documentation:
+ - Document the limitations of using %include on config files with
+ seccomp sandbox enabled. Fixes documentation bug 34133; bugfix on
+ 0.3.1.1-alpha. Patch by Daniel Pinto.
+ - Fix several doxygen warnings related to imbalanced groups. Closes
+ ticket 34255.
+
+ o Removed features:
+ - Remove the ClientAutoIPv6ORPort option. This option attempted to
+ randomly choose between IPv4 and IPv6 for client connections, and
+ wasn't a true implementation of Happy Eyeballs. Often, this option
+ failed on IPv4-only or IPv6-only connections. Closes ticket 32905.
+ Patch by Neel Chauhan.
+ - Stop shipping contrib/dist/rc.subr file, as it is not being used
+ on FreeBSD anymore. Closes issue 31576.
+
+ o Testing:
+ - Add a basic IPv6 test to "make test-network". This test only runs
+ when the local machine has an IPv6 stack. Closes ticket 33300.
+ - Add test-network-ipv4 and test-network-ipv6 jobs to the Makefile.
+ These jobs run the IPv4-only and dual-stack chutney flavours from
+ test-network-all. Closes ticket 33280.
+ - Remove a redundant distcheck job. Closes ticket 33194.
+ - Run the test-network-ipv6 Makefile target in the Travis CI IPv6
+ chutney job. This job runs on macOS, so it's a bit slow. Closes
+ ticket 33303.
+ - 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.
+ - Test v3 onion services to tor's mixed IPv4 chutney network. And
+ add a mixed IPv6 chutney network. These networks are used in the
+ test-network-all, test-network-ipv4, and test-network-ipv6 make
+ targets. Closes ticket 33334.
+ - Use the "bridges+hs-v23" chutney network flavour in "make test-
+ network". This test requires a recent version of chutney (mid-
+ February 2020). Closes ticket 28208.
+ - When a Travis chutney job fails, use chutney's new "diagnostics.sh"
+ tool to produce detailed diagnostic output. Closes ticket 32792.
+
+ o Code simplification and refactoring (onion service):
+ - Refactor configuration parsing to use the new config subsystem
+ code. Closes ticket 33014.
+
+ o Code simplification and refactoring (relay address):
+ - Move a series of functions related to address resolving into their
+ own files. Closes ticket 33789.
+
+ o Documentation (manual page):
+ - Add cross reference links and a table of contents to the HTML tor
+ manual page. Closes ticket 33369. Work by Swati Thacker as part of
+ Google Season of Docs.
+ - Alphabetize the Denial of Service Mitigation Options, Directory
+ Authority Server Options, Hidden Service Options, and Testing
+ Network Options sections of the tor(1) manual page. Closes ticket
+ 33275. Work by Swati Thacker as part of Google Season of Docs.
+ - Refrain from mentioning nicknames in manpage section for MyFamily
+ torrc option. Resolves issue 33417.
+ - Updated the options set by TestingTorNetwork in the manual page.
+ Closes ticket 33778.
+
+
Changes in version 0.4.3.5 - 2020-05-15
Tor 0.4.3.5 is the first stable release in the 0.4.3.x series. This
series adds support for building without relay code enabled, and
diff --git a/Doxyfile.in b/Doxyfile.in
index 503c1302db..4374e54858 100644
--- a/Doxyfile.in
+++ b/Doxyfile.in
@@ -863,7 +863,8 @@ RECURSIVE = YES
# Note that relative paths are relative to the directory from which doxygen is
# run.
-EXCLUDE = ./src/ext \
+EXCLUDE = ./src/ext/ed25519 \
+ ./src/ext/rust \
./src/trunnel \
./src/test \
./src/rust/registry
diff --git a/Makefile.am b/Makefile.am
index 1a1fa9b658..711d2cc037 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -273,7 +273,6 @@ check-local: \
check-spaces \
check-changes \
check-includes \
- check-best-practices \
shellcheck \
check-cocci
diff --git a/README b/README
index 9bbf027d70..def546f252 100644
--- a/README
+++ b/README
@@ -19,13 +19,13 @@ Documentation, including links to installation and setup instructions:
https://www.torproject.org/docs/documentation.html
Making applications work with Tor:
- https://wiki.torproject.org/projects/tor/wiki/doc/TorifyHOWTO
+ https://gitlab.torproject.org/legacy/trac/-/wikis/doc/TorifyHOWTO
Frequently Asked Questions:
https://www.torproject.org/docs/faq.html
Release timeline:
- https://trac.torproject.org/projects/tor/wiki/org/teams/NetworkTeam/CoreTorReleases
+ https://gitlab.torproject.org/tpo/core/tor/-/wikis/NetworkTeam/CoreTorReleases
To get started working on Tor development:
See the doc/HACKING directory.
diff --git a/ReleaseNotes b/ReleaseNotes
index a572293c07..688dea935e 100644
--- a/ReleaseNotes
+++ b/ReleaseNotes
@@ -3,6 +3,292 @@ 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.3.5.11 - 2020-07-09
+ Tor 0.3.5.11 backports fixes from later tor releases, including several
+ usability, portability, and reliability fixes.
+
+ This release also fixes TROVE-2020-001, a medium-severity denial of
+ service vulnerability affecting all versions of Tor when compiled with
+ the NSS encryption library. (This is not the default configuration.)
+ Using this vulnerability, an attacker could cause an affected Tor
+ instance to crash remotely. This issue is also tracked as CVE-2020-
+ 15572. Anybody running a version of Tor built with the NSS library
+ should upgrade to 0.3.5.11, 0.4.2.8, 0.4.3.6, or 0.4.4.2-alpha
+ or later.
+
+ o Major bugfixes (NSS, security, backport from 0.4.4.2-alpha):
+ - Fix a crash due to an out-of-bound memory access when Tor is
+ compiled with NSS support. Fixes bug 33119; bugfix on
+ 0.3.5.1-alpha. This issue is also tracked as TROVE-2020-001
+ and CVE-2020-15572.
+
+ o Major bugfixes (DoS defenses, bridges, pluggable transport, backport from 0.4.3.4-rc):
+ - 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 features (testing, backport from 0.4.3.4-rc):
+ - 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 bugfix (CI, Windows, backport from 0.4.4.2-alpha):
+ - Use the correct 64-bit printf format when compiling with MINGW on
+ Appveyor. Fixes bug 40026; bugfix on 0.3.5.5-alpha.
+
+ o Minor bugfix (relay, configuration, backport from 0.4.3.3-alpha):
+ - 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 (client performance, backport from 0.4.4.1-alpha):
+ - Resume use of preemptively-built circuits when UseEntryGuards is set
+ to 0. We accidentally disabled this feature with that config
+ setting, leading to slower load times. Fixes bug 34303; bugfix
+ on 0.3.3.2-alpha.
+
+ o Minor bugfixes (compiler compatibility, backport from 0.4.3.5):
+ - Avoid compiler warnings from Clang 10 related to the use of GCC-
+ style "/* falls through */" comments. Both Clang and GCC allow
+ __attribute__((fallthrough)) instead, so that's what we're using
+ now. Fixes bug 34078; bugfix on 0.3.1.3-alpha.
+
+ o Minor bugfixes (compiler warnings, backport from 0.4.4.2-alpha):
+ - Fix a compiler warning on platforms with 32-bit time_t values.
+ Fixes bug 40028; bugfix on 0.3.2.8-rc.
+
+ o Minor bugfixes (embedded Tor, backport from 0.4.3.1-alpha):
+ - When starting Tor any time after the first time in a process,
+ register the thread in which it is running as the main thread.
+ Previously, we only did this on Windows, which could lead to bugs
+ like 23081 on non-Windows platforms. Fixes bug 32884; bugfix
+ on 0.3.3.1-alpha.
+
+ o Minor bugfixes (key portability, backport from 0.4.3.4-rc):
+ - 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, backport from 0.4.4.2-alpha):
+ - Downgrade a noisy log message that could occur naturally when
+ receiving an extrainfo document that we no longer want. Fixes bug
+ 16016; bugfix on 0.2.6.3-alpha.
+
+ o Minor bugfixes (onion service v3, client, backport from 0.4.3.3-alpha):
+ - 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 Testing (CI, backport from 0.4.3.4-rc):
+ - 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.2.8 - 2020-07-09
+ Tor 0.4.2.8 backports various fixes from later releases, including
+ several that affect usability and portability.
+
+ This release also fixes TROVE-2020-001, a medium-severity denial of
+ service vulnerability affecting all versions of Tor when compiled with
+ the NSS encryption library. (This is not the default configuration.)
+ Using this vulnerability, an attacker could cause an affected Tor
+ instance to crash remotely. This issue is also tracked as CVE-2020-
+ 15572. Anybody running a version of Tor built with the NSS library
+ should upgrade to 0.3.5.11, 0.4.2.8, 0.4.3.6, or 0.4.4.2-alpha
+ or later.
+
+ o Major bugfixes (NSS, security, backport from 0.4.4.2-alpha):
+ - Fix a crash due to an out-of-bound memory access when Tor is
+ compiled with NSS support. Fixes bug 33119; bugfix on
+ 0.3.5.1-alpha. This issue is also tracked as TROVE-2020-001
+ and CVE-2020-15572.
+
+ o Major bugfixes (DoS defenses, bridges, pluggable transport, backport from 0.4.3.4-rc):
+ - 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, backport form 0.4.3.4-rc):
+ - 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 (diagnostic, backport from 0.4.3.3-alpha):
+ - 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 (testing, backport from 0.4.3.4-rc):
+ - 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 bugfix (CI, Windows, backport from 0.4.4.2-alpha):
+ - Use the correct 64-bit printf format when compiling with MINGW on
+ Appveyor. Fixes bug 40026; bugfix on 0.3.5.5-alpha.
+
+ o Minor bugfix (relay, configuration, backport from 0.4.3.3-alpha):
+ - 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 (client performance, backport from 0.4.4.1-alpha):
+ - Resume use of preemptively-built circuits when UseEntryGuards is set
+ to 0. We accidentally disabled this feature with that config
+ setting, leading to slower load times. Fixes bug 34303; bugfix
+ on 0.3.3.2-alpha.
+
+ o Minor bugfixes (compiler compatibility, backport from 0.4.3.5):
+ - Avoid compiler warnings from Clang 10 related to the use of GCC-
+ style "/* falls through */" comments. Both Clang and GCC allow
+ __attribute__((fallthrough)) instead, so that's what we're using
+ now. Fixes bug 34078; bugfix on 0.3.1.3-alpha.
+ - Fix compilation warnings with GCC 10.0.1. Fixes bug 34077; bugfix
+ on 0.4.0.3-alpha.
+
+ o Minor bugfixes (compiler warnings, backport from 0.4.4.2-alpha):
+ - Fix a compiler warning on platforms with 32-bit time_t values.
+ Fixes bug 40028; bugfix on 0.3.2.8-rc.
+
+ o Minor bugfixes (controller protocol, backport from 0.4.3.2-alpha):
+ - When receiving "ACTIVE" or "DORMANT" signals on the control port,
+ report them as SIGNAL events. Previously we would log a bug
+ warning. Fixes bug 33104; bugfix on 0.4.0.1-alpha.
+
+ o Minor bugfixes (embedded Tor, backport from 0.4.3.1-alpha):
+ - When starting Tor any time after the first time in a process,
+ register the thread in which it is running as the main thread.
+ Previously, we only did this on Windows, which could lead to bugs
+ like 23081 on non-Windows platforms. Fixes bug 32884; bugfix
+ on 0.3.3.1-alpha.
+
+ o Minor bugfixes (key portability, backport from 0.4.3.4-rc):
+ - 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, backport from 0.4.3.2-rc):
+ - When logging a bug, do not say "Future instances of this warning
+ will be silenced" unless we are actually going to silence them.
+ Previously we would say this whenever a BUG() check failed in the
+ code. Fixes bug 33095; bugfix on 0.4.1.1-alpha.
+
+ o Minor bugfixes (logging, backport from 0.4.3.4-rc):
+ - 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.
+
+ o Minor bugfixes (logging, backport from 0.4.4.2-alpha):
+ - Downgrade a noisy log message that could occur naturally when
+ receiving an extrainfo document that we no longer want. Fixes bug
+ 16016; bugfix on 0.2.6.3-alpha.
+
+ o Minor bugfixes (onion service v3, client, backport from 0.4.3.3-alpha):
+ - 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 Testing (CI, backport from 0.4.3.4-rc):
+ - 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.6 - 2020-07-09
+ Tor 0.4.3.6 backports several bugfixes from later releases, including
+ some affecting usability.
+
+ This release also fixes TROVE-2020-001, a medium-severity denial of
+ service vulnerability affecting all versions of Tor when compiled with
+ the NSS encryption library. (This is not the default configuration.)
+ Using this vulnerability, an attacker could cause an affected Tor
+ instance to crash remotely. This issue is also tracked as CVE-2020-
+ 15572. Anybody running a version of Tor built with the NSS library
+ should upgrade to 0.3.5.11, 0.4.2.8, 0.4.3.6, or 0.4.4.2-alpha
+ or later.
+
+ o Major bugfixes (NSS, security, backport from 0.4.4.2-alpha):
+ - Fix a crash due to an out-of-bound memory access when Tor is
+ compiled with NSS support. Fixes bug 33119; bugfix on
+ 0.3.5.1-alpha. This issue is also tracked as TROVE-2020-001
+ and CVE-2020-15572.
+
+ o Minor bugfix (CI, Windows, backport from 0.4.4.2-alpha):
+ - Use the correct 64-bit printf format when compiling with MINGW on
+ Appveyor. Fixes bug 40026; bugfix on 0.3.5.5-alpha.
+
+ o Minor bugfixes (client performance, backport from 0.4.4.1-alpha):
+ - Resume use of preemptively-built circuits when UseEntryGuards is set
+ to 0. We accidentally disabled this feature with that config
+ setting, leading to slower load times. Fixes bug 34303; bugfix
+ on 0.3.3.2-alpha.
+
+ o Minor bugfixes (compiler warnings, backport from 0.4.4.2-alpha):
+ - Fix a compiler warning on platforms with 32-bit time_t values.
+ Fixes bug 40028; bugfix on 0.3.2.8-rc.
+
+ o Minor bugfixes (linux seccomp sandbox, nss, backport from 0.4.4.1-alpha):
+ - Fix a 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.
+
+ o Minor bugfixes (logging, backport from 0.4.4.2-alpha):
+ - Downgrade a noisy log message that could occur naturally when
+ receiving an extrainfo document that we no longer want. Fixes bug
+ 16016; bugfix on 0.2.6.3-alpha.
+
+ o Minor bugfixes (manual page, backport from 0.4.4.1-alpha):
+ - Update the man page to reflect that MinUptimeHidServDirectoryV2
+ defaults to 96 hours. Fixes bug 34299; bugfix on 0.2.6.3-alpha.
+
+ o Minor bugfixes (onion service v3, backport from 0.4.4.1-alpha):
+ - Prevent an assert() that would occur when cleaning the client
+ descriptor cache, and attempting to close circuits for a non-
+ decrypted descriptor (lacking client authorization). Fixes bug
+ 33458; bugfix on 0.4.2.1-alpha.
+
+ o Minor bugfixes (portability, backport from 0.4.4.1-alpha):
+ - Fix a portability error in the configure script, where we were
+ using "==" instead of "=". Fixes bug 34233; bugfix on 0.4.3.5.
+
+ o Minor bugfixes (relays, backport from 0.4.4.1-alpha):
+ - Stop advertising incorrect IPv6 ORPorts in relay and bridge
+ descriptors, when the IPv6 port was configured as "auto". Fixes
+ bug 32588; bugfix on 0.2.3.9-alpha.
+
+ o Documentation (backport from 0.4.4.1-alpha):
+ - Fix several doxygen warnings related to imbalanced groups. Closes
+ ticket 34255.
+
+
Changes in version 0.4.3.5 - 2020-05-15
Tor 0.4.3.5 is the first stable release in the 0.4.3.x series. This
series adds support for building without relay code enabled, and
diff --git a/changes/bug30992 b/changes/bug30992
new file mode 100644
index 0000000000..f318319016
--- /dev/null
+++ b/changes/bug30992
@@ -0,0 +1,4 @@
+ o Minor bugfixes (circuitpadding):
+ - Add a per-circuit padding machine instance counter, so we can
+ differentiate between shutdown requests for old machines on a circuit;
+ Fixes bug 30992; bugfix on 0.4.1.1-alpha.
diff --git a/changes/bug32040 b/changes/bug32040
new file mode 100644
index 0000000000..1cdc0bec9a
--- /dev/null
+++ b/changes/bug32040
@@ -0,0 +1,7 @@
+ o Minor bugfixes (circuitpadding):
+ - Add the abilility to keep circuit padding machines if they match a set
+ of circuit state or purposes. This allows us to have machines that start
+ up under some conditions but don't shut down under others. We now
+ use this mask to avoid starting up introduction circuit padding
+ again after the machines have already completed. Fixes bug 32040;
+ bugfix on 0.4.1.1-alpha.
diff --git a/changes/bug32588 b/changes/bug32588
deleted file mode 100644
index f31f2ce1ad..0000000000
--- a/changes/bug32588
+++ /dev/null
@@ -1,4 +0,0 @@
- o Minor bugfixes (relays):
- - Stop advertising incorrect IPv6 ORPorts in relay and bridge descriptors,
- when the IPv6 port was configured as "auto".
- Fixes bug 32588; bugfix on 0.2.3.9-alpha
diff --git a/changes/bug32709 b/changes/bug32709
deleted file mode 100644
index d00b112be6..0000000000
--- a/changes/bug32709
+++ /dev/null
@@ -1,4 +0,0 @@
- o Major features (v3 onion services):
- - Allow v3 onion services to act as OnionBalance backend instances using
- the HiddenServiceOnionBalanceInstance torrc option. Closes ticket 32709.
-
diff --git a/changes/bug33131 b/changes/bug33131
deleted file mode 100644
index bc5ef7bc2d..0000000000
--- a/changes/bug33131
+++ /dev/null
@@ -1,3 +0,0 @@
- 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/bug33284 b/changes/bug33284
deleted file mode 100644
index e6aed4d2d4..0000000000
--- a/changes/bug33284
+++ /dev/null
@@ -1,4 +0,0 @@
- o Minor bugfixes (git scripts):
- - Stop executing the checked-out pre-commit hook from the pre-push hook.
- Instead, execute the copy in the user's git dir. Fixes bug 33284; bugfix
- on 0.4.1.1-alpha.
diff --git a/changes/bug33285 b/changes/bug33285
deleted file mode 100644
index a4d06a7eb8..0000000000
--- a/changes/bug33285
+++ /dev/null
@@ -1,3 +0,0 @@
- o Minor bugfixes (protocol versions):
- - Sort tor's supported protocol version lists, as recommended by the
- tor directory specification. Fixes bug 33285; bugfix on 0.4.0.1-alpha.
diff --git a/changes/bug33531 b/changes/bug33531
deleted file mode 100644
index c4284c55c9..0000000000
--- a/changes/bug33531
+++ /dev/null
@@ -1,3 +0,0 @@
- o Minor bugfixes (logs):
- - Remove surprising empty line in info-level log about circuit build
- timeout. Fixes bug 33531; bugfix on 0.3.3.1-alpha.
diff --git a/changes/bug33899 b/changes/bug33899
deleted file mode 100644
index b9b7d7cf13..0000000000
--- a/changes/bug33899
+++ /dev/null
@@ -1,9 +0,0 @@
- 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
deleted file mode 100644
index c1649d2284..0000000000
--- a/changes/bug33900
+++ /dev/null
@@ -1,3 +0,0 @@
- 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
deleted file mode 100644
index 6a8daa9e26..0000000000
--- a/changes/bug33917
+++ /dev/null
@@ -1,5 +0,0 @@
- 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
deleted file mode 100644
index b424a811a2..0000000000
--- a/changes/bug33977
+++ /dev/null
@@ -1,4 +0,0 @@
- 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/bug34065 b/changes/bug34065
new file mode 100644
index 0000000000..f81cb77c21
--- /dev/null
+++ b/changes/bug34065
@@ -0,0 +1,5 @@
+ o Minor features (IPv6, ExcludeNodes):
+ - Make routerset_contains_router() capable of handling IPv6
+ addresses. This makes ExcludeNodes capable of excluding an
+ IPv6 adddress. Previously, ExcludeNodes ignored IPv6
+ addresses. Closes ticket 34065. Patch by Neel Chauhan.
diff --git a/changes/bug34130 b/changes/bug34130
deleted file mode 100644
index b1e5715fdf..0000000000
--- a/changes/bug34130
+++ /dev/null
@@ -1,4 +0,0 @@
- 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
deleted file mode 100644
index 24c7869783..0000000000
--- a/changes/bug34233
+++ /dev/null
@@ -1,4 +0,0 @@
- 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/bug34248 b/changes/bug34248
new file mode 100644
index 0000000000..b89df444ed
--- /dev/null
+++ b/changes/bug34248
@@ -0,0 +1,4 @@
+ o Minor bugfixes (rust, protocol versions):
+ - Declare support for the onion service introduction point denial of
+ service extensions, when building tor with Rust.
+ Fixes bug 34248; bugfix on 0.4.2.1-alpha.
diff --git a/changes/bug34251 b/changes/bug34251
new file mode 100644
index 0000000000..bbf0535256
--- /dev/null
+++ b/changes/bug34251
@@ -0,0 +1,4 @@
+ o Minor bugfixes (rust, protocol versions):
+ - Make Rust protocol version support checks consistent with the
+ undocumented error behaviour of the corresponding C code.
+ Fixes bug 34251; bugfix on 0.3.3.5-rc.
diff --git a/changes/bug34299 b/changes/bug34299
deleted file mode 100644
index 464cf0d18a..0000000000
--- a/changes/bug34299
+++ /dev/null
@@ -1,3 +0,0 @@
- o Minor bugfixes (man page):
- - Update the man page to reflect that MinUptimeHidServDirectoryV2
- defaults to 96 hours. Fixes bug 34299; bugfix on 0.2.6.3-alpha.
diff --git a/changes/bug34303 b/changes/bug34303
deleted file mode 100644
index dce57f4646..0000000000
--- a/changes/bug34303
+++ /dev/null
@@ -1,5 +0,0 @@
- o Minor bugfixes (client performance):
- - Resume being willing to use preemptively-built circuits when
- UseEntryGuards is set to 0. We accidentally disabled this feature
- with that config setting, leading to slower load times. Fixes bug
- 34303; bugfix on 0.3.3.2-alpha.
diff --git a/changes/bug34357 b/changes/bug34357
new file mode 100644
index 0000000000..69fada7cc0
--- /dev/null
+++ b/changes/bug34357
@@ -0,0 +1,4 @@
+ o Minor features (directory authorities):
+ - Directory authorities now reject descriptors from relays running
+ Tor versions from the 0.4.1 series, but still allow the 0.3.5
+ series. Resolves ticket 34357. Patch by Neel Chauhan.
diff --git a/changes/bug34400 b/changes/bug34400
new file mode 100644
index 0000000000..e2b56688b9
--- /dev/null
+++ b/changes/bug34400
@@ -0,0 +1,5 @@
+ o Minor bugfixes (v2 onion services):
+ - For HSFETCH commands on v2 onion services addresses, check the length of
+ bytes decoded, not the base32 length. This takes the behavior introduced
+ in commit a517daa56f5848d25ba79617a1a7b82ed2b0a7c0 into consideration.
+ Fixes bug 34400; bugfix on 0.4.1.1-alpha. Patch by Neel Chauhan.
diff --git a/changes/bug4631 b/changes/bug4631
deleted file mode 100644
index be3dd2b43e..0000000000
--- a/changes/bug4631
+++ /dev/null
@@ -1,6 +0,0 @@
- o Minor bugfixes (directory authorities):
- - Directory authorities reject votes that arrive too late. In particular,
- once an authority has started fetching missing votes, it no longer
- accepts new votes posted by other authorities. This change helps prevent
- a consensus split, where only some authorities have the late vote.
- Fixes bug 4631; bugfix on 0.2.0.5-alpha.
diff --git a/changes/doc33417 b/changes/doc33417
deleted file mode 100644
index 0fc868fc65..0000000000
--- a/changes/doc33417
+++ /dev/null
@@ -1,3 +0,0 @@
- o Documentation (manpage):
- - Refrain from mentioning nicknames in manpage section for MyFamily torrc
- option. Resolves issue 33417.
diff --git a/changes/doc34133 b/changes/doc34133
deleted file mode 100644
index abe9db6148..0000000000
--- a/changes/doc34133
+++ /dev/null
@@ -1,6 +0,0 @@
- 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/feature34068 b/changes/feature34068
new file mode 100644
index 0000000000..10812c8eca
--- /dev/null
+++ b/changes/feature34068
@@ -0,0 +1,3 @@
+ o Minor features (controller, IPv6):
+ - Tor relays now try to report to the controller when they are launching
+ an IPv6 self-test. Closes ticket 34068.
diff --git a/changes/ticket24844 b/changes/ticket24844
deleted file mode 100644
index da55b4cf67..0000000000
--- a/changes/ticket24844
+++ /dev/null
@@ -1,4 +0,0 @@
- o Minor features (v3 onion servies):
- - Add v3 onion service status to the dumpstats() call which is
- triggered by a SIGUSR1 signal. Previously, we only did v2
- onion services. Closes ticket 24844. Patch by Neel Chauhan.
diff --git a/changes/ticket28208 b/changes/ticket28208
deleted file mode 100644
index 8818aad1d5..0000000000
--- a/changes/ticket28208
+++ /dev/null
@@ -1,4 +0,0 @@
- o Testing:
- - Use the "bridges+hs-v23" chutney network flavor in "make test-network".
- This test requires a recent version of chutney (mid-February 2020).
- Closes ticket 28208.
diff --git a/changes/ticket28279 b/changes/ticket28279
new file mode 100644
index 0000000000..1c085c2a6e
--- /dev/null
+++ b/changes/ticket28279
@@ -0,0 +1,5 @@
+ o Minor features (control port, rephist):
+ - Introduce GETINFO "stats/ntor/{assigned/requested}" and
+ "stats/tap/{assigned/requested}" to get the NTorand TAP
+ circuit onion handshake rephist values respectively.
+ Closes ticket 28279. Patch by Neel Chauhan.
diff --git a/changes/ticket28992 b/changes/ticket28992
deleted file mode 100644
index 3e45d73e45..0000000000
--- a/changes/ticket28992
+++ /dev/null
@@ -1,3 +0,0 @@
- o Minor bugfixes (onion service v3, client):
- - Remove a BUG() that is causing a stacktrace for a situation that very
- rarely happens but still can. Fixes bug 28992; bugfix on 0.3.2.1-alpha.
diff --git a/changes/ticket30642 b/changes/ticket30642
new file mode 100644
index 0000000000..13941b2ac5
--- /dev/null
+++ b/changes/ticket30642
@@ -0,0 +1,4 @@
+ o Minor features (ed25519, relay):
+ - Save a relay's base64-encoded ed25519 identity key to the data
+ directory in a file named fingerprint-ed25519. Closes ticket 30642.
+ Patch by Neel Chauhan.
diff --git a/changes/ticket31576 b/changes/ticket31576
deleted file mode 100644
index ab984cf3d4..0000000000
--- a/changes/ticket31576
+++ /dev/null
@@ -1,3 +0,0 @@
- o Removed features:
- - Stop shipping contrib/dist/rc.subr file, as it is not being used on
- FreeBSD anymore. Closes issue 31576.
diff --git a/changes/ticket31634 b/changes/ticket31634
deleted file mode 100644
index 2777595036..0000000000
--- a/changes/ticket31634
+++ /dev/null
@@ -1,4 +0,0 @@
- 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/ticket31699 b/changes/ticket31699
new file mode 100644
index 0000000000..1998248d57
--- /dev/null
+++ b/changes/ticket31699
@@ -0,0 +1,3 @@
+ o Code simplification and refactoring (autoconf):
+ - Remove autoconf checks for unused funcs and headers. Closes ticket
+ 31699; Patch by @bduszel
diff --git a/changes/ticket32088 b/changes/ticket32088
deleted file mode 100644
index 0d4fc74754..0000000000
--- a/changes/ticket32088
+++ /dev/null
@@ -1,13 +0,0 @@
- o Major features (Proposal 310, performance + security):
- - Implements Proposal 310 - Bandaid on guard selection.
- Proposal 310 solves a load-balancing issue within Prop271 which strongly
- impact experimental research with Shadow.
- Security improvement: Proposal 310 prevents any newly Guard relay to
- have a chance to get into the primary list of older Tor clients,
- except if the N first sampled guards of these clients are unreachable.
- Implements recommendation from 32088.
-
- Proposal 310 is linked to the CLAPS project researching optimal
- client location-aware path selections. This project is a collaboration
- between the UCLouvain Crypto Group, the U.S. Naval Research Laboratory and
- Princeton University.
diff --git a/changes/ticket32143 b/changes/ticket32143
deleted file mode 100644
index 7f8a809ba5..0000000000
--- a/changes/ticket32143
+++ /dev/null
@@ -1,4 +0,0 @@
- o Minor features (continuous integration):
- - Run unit-test and integration test (Stem, Chutney) jobs with
- ALL_BUGS_ARE_FATAL macro being enabled on Travis and Appveyor.
- Resolves ticket 32143.
diff --git a/changes/ticket32542 b/changes/ticket32542
deleted file mode 100644
index c52335b059..0000000000
--- a/changes/ticket32542
+++ /dev/null
@@ -1,3 +0,0 @@
- 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/ticket32720 b/changes/ticket32720
deleted file mode 100644
index 87c540b7ff..0000000000
--- a/changes/ticket32720
+++ /dev/null
@@ -1,4 +0,0 @@
- o Minor features (directory):
- - Remember the number of bytes we have downloaded for each directory
- purpose while bootstrapping, and while fully bootstrapped. Log this
- information as part of the heartbeat message. Closes ticket 32720.
diff --git a/changes/ticket32792 b/changes/ticket32792
deleted file mode 100644
index 553cf0ca81..0000000000
--- a/changes/ticket32792
+++ /dev/null
@@ -1,3 +0,0 @@
- o Testing:
- - When a Travis chutney job fails, use chutney's new "diagnostics.sh" tool
- to produce detailed diagnostic output. Closes ticket 32792.
diff --git a/changes/ticket32822 b/changes/ticket32822
new file mode 100644
index 0000000000..ca62f0cc53
--- /dev/null
+++ b/changes/ticket32822
@@ -0,0 +1,5 @@
+ o Minor features (directory authorities, IPv6):
+ - Make authorities add their IPv6 ORPort (if any) to the trusted dir
+ servers list. Authorities currently add themselves to the trusted dir
+ servers list, but they only add their IPv4 address and ports to the list.
+ Closes ticket 32822.
diff --git a/changes/ticket32873 b/changes/ticket32873
deleted file mode 100644
index 65ea1f64ad..0000000000
--- a/changes/ticket32873
+++ /dev/null
@@ -1,6 +0,0 @@
- 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/ticket32888 b/changes/ticket32888
deleted file mode 100644
index ce7fb40b30..0000000000
--- a/changes/ticket32888
+++ /dev/null
@@ -1,4 +0,0 @@
- o Minor features (logging):
- - When trying to find our own address, add debug-level logging
- to report the sources of candidate addresses. Closes ticket
- 32888.
diff --git a/changes/ticket32905 b/changes/ticket32905
deleted file mode 100644
index 6f420ec693..0000000000
--- a/changes/ticket32905
+++ /dev/null
@@ -1,6 +0,0 @@
- o Removed features:
- - Remove the ClientAutoIPv6ORPort option. This option attempted
- to randomly choose between IPv4 and IPv6 for client connections,
- and isn't a true implementation of Happy Eyeballs. Often, this
- option failed on IPv4-only or IPv6-only connections. Closes
- ticket 32905. Patch by Neel Chauhan.
diff --git a/changes/ticket32994 b/changes/ticket32994
deleted file mode 100644
index 43a32afa78..0000000000
--- a/changes/ticket32994
+++ /dev/null
@@ -1,3 +0,0 @@
- o Code simplification and refactoring:
- - Rewrite port_parse_config() to use the default port flags from
- port_cfg_new(). Closes ticket 32994. Patch by MrSquanchee.
diff --git a/changes/ticket33014 b/changes/ticket33014
deleted file mode 100644
index 885051d9cf..0000000000
--- a/changes/ticket33014
+++ /dev/null
@@ -1,3 +0,0 @@
- o Code simplification and refactoring (onion service):
- - Refactor configuration parsing to use the new config subsystem code.
- Closes ticket 33014.
diff --git a/changes/ticket33192 b/changes/ticket33192
deleted file mode 100644
index 97f976226b..0000000000
--- a/changes/ticket33192
+++ /dev/null
@@ -1,5 +0,0 @@
- o Minor feature (python):
- - Stop assuming that /usr/bin/python exists. Instead of using a
- hardcoded path in scripts that still use Python 2, use /usr/bin/env,
- similarly to the scripts that use Python 3. Fixes bug 33192; bugfix
- on 0.4.2. \ No newline at end of file
diff --git a/changes/ticket33194 b/changes/ticket33194
deleted file mode 100644
index b87e55348e..0000000000
--- a/changes/ticket33194
+++ /dev/null
@@ -1,4 +0,0 @@
- o Testing:
- - 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.
diff --git a/changes/ticket33195 b/changes/ticket33195
deleted file mode 100644
index 11abd4816e..0000000000
--- a/changes/ticket33195
+++ /dev/null
@@ -1,4 +0,0 @@
- o Testing:
- - 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.
diff --git a/changes/ticket33222 b/changes/ticket33222
new file mode 100644
index 0000000000..f7b117d6ad
--- /dev/null
+++ b/changes/ticket33222
@@ -0,0 +1,8 @@
+ o Major features (IPv6, relay):
+ - Launch IPv4 and IPv6 ORPort self-test circuits on relays and bridges.
+ Closes ticket 33222.
+ o Minor features (IPv6, relay):
+ - Allow relays to send IPv6-only extend cells. Closes ticket 33222.
+ - Declare support for the Relay=3 subprotocol version. Closes ticket 33226.
+ - When launching IPv6 ORPort self-test circuits, make sure that the
+ second-last hop can initiate an IPv6 extend. Closes ticket 33222.
diff --git a/changes/ticket33224 b/changes/ticket33224
new file mode 100644
index 0000000000..3fdab7dc53
--- /dev/null
+++ b/changes/ticket33224
@@ -0,0 +1,3 @@
+ o Minor features (relay, IPv6):
+ - Add an AssumeReachableIPv6 option to disable self-checking IPv6
+ reachability. Closes part of ticket 33224.
diff --git a/changes/ticket33233 b/changes/ticket33233
new file mode 100644
index 0000000000..977286c323
--- /dev/null
+++ b/changes/ticket33233
@@ -0,0 +1,4 @@
+ o Major feature (IPv6, relay):
+ - The torrc option Address now supports IPv6. By doing so, we've also
+ unified the interface to find our address to support IPv4, IPv6 and
+ hostname. Closes ticket 33233;
diff --git a/changes/ticket33236 b/changes/ticket33236
new file mode 100644
index 0000000000..d2b1d7e4da
--- /dev/null
+++ b/changes/ticket33236
@@ -0,0 +1,4 @@
+ o Minor feature (relay, address discovery):
+ - If Address is not found in torrc, attempt to learn our address with the
+ configured ORPort address if any. Closes ticket 33236.
+
diff --git a/changes/ticket33238 b/changes/ticket33238
new file mode 100644
index 0000000000..2c4c3968cc
--- /dev/null
+++ b/changes/ticket33238
@@ -0,0 +1,5 @@
+ o Minor feature (address discovery):
+ - If no Address statements are found, relays now prioritize guessing their
+ address by looking at the local interface instead of the local hostname.
+ If the interface address can't be found, the local hostname is used.
+ Closes ticket 33238.
diff --git a/changes/ticket33275 b/changes/ticket33275
deleted file mode 100644
index bff3a7a3ad..0000000000
--- a/changes/ticket33275
+++ /dev/null
@@ -1,5 +0,0 @@
- o Documentation (manpage):
- - Alphabetize the Denial of Service Mitigation Options, Directory
- Authority Server Options, Hidden Service Options, and Testing
- Network Options sections of the tor(1) manpage. Closes ticket
- 33275. Work by Swati Thacker as part of Google Season of Docs.
diff --git a/changes/ticket33280 b/changes/ticket33280
deleted file mode 100644
index b90c3086ea..0000000000
--- a/changes/ticket33280
+++ /dev/null
@@ -1,4 +0,0 @@
- o Testing:
- - Add test-network-ipv4 and test-network-ipv6 jobs to the Makefile.
- These jobs run the IPv4-only and dual-stack chutney flavours from
- test-network-all. Closes ticket 33280.
diff --git a/changes/ticket33300 b/changes/ticket33300
deleted file mode 100644
index 9b0bdce372..0000000000
--- a/changes/ticket33300
+++ /dev/null
@@ -1,3 +0,0 @@
- o Testing:
- - Add a basic IPv6 test to "make test-network". This test only runs when
- the local machine has an IPv6 stack. Closes ticket 33300.
diff --git a/changes/ticket33303 b/changes/ticket33303
deleted file mode 100644
index b7ac7b5067..0000000000
--- a/changes/ticket33303
+++ /dev/null
@@ -1,4 +0,0 @@
- o Testing:
- - Run the test-network-ipv6 Makefile target in the Travis CI IPv6 chutney
- job. This job runs on macOS, so it's a bit slow.
- Closes ticket 33303.
diff --git a/changes/ticket33316 b/changes/ticket33316
deleted file mode 100644
index 25b0444078..0000000000
--- a/changes/ticket33316
+++ /dev/null
@@ -1,15 +0,0 @@
- o Minor bugfixes (initialization):
- - Initialize the subsystems in our code in an order more closely
- corresponding to their dependencies, so that every system is
- initialized before the ones that (theoretically) depend on it.
- Fixes bug 33316; bugfix on 0.4.0.1-alpha.
-
- o Minor features (tests):
- - Initialize all subsystems at the beginning of our unit test harness,
- to avoid crashes due to uninitialized subsystems.
- Follow-up from ticket 33316.
-
- o Code simplification and refactoring:
- - Merge the orconn and ocirc events into the "core" subsystem, which
- manages or connections and origin circuits. Previously they
- were isolated in subsystems of their own.
diff --git a/changes/ticket33334 b/changes/ticket33334
deleted file mode 100644
index ada3cb284c..0000000000
--- a/changes/ticket33334
+++ /dev/null
@@ -1,5 +0,0 @@
- o Testing:
- - Test v3 onion services to tor's mixed IPv4 chutney network. And add a
- mixed IPv6 chutney network. These networks are used in the
- test-network-all, test-network-ipv4, and test-network-ipv6 make targets.
- Closes ticket 33334.
diff --git a/changes/ticket33339 b/changes/ticket33339
deleted file mode 100644
index 75ccb3546f..0000000000
--- a/changes/ticket33339
+++ /dev/null
@@ -1,3 +0,0 @@
- o Minor feature (developer tools):
- - Add a script to help check the alphabetical ordering of option
- names in a manpage. Closes ticket 33339.
diff --git a/changes/ticket33349 b/changes/ticket33349
deleted file mode 100644
index 0458a72c8d..0000000000
--- a/changes/ticket33349
+++ /dev/null
@@ -1,4 +0,0 @@
- o Code simplification and refactoring:
- - Updated comments in 'scheduler.c' to reflect old code changes,
- and simplified the scheduler channel state change code. Closes
- ticket 33349.
diff --git a/changes/ticket33366 b/changes/ticket33366
deleted file mode 100644
index 1310c493c2..0000000000
--- a/changes/ticket33366
+++ /dev/null
@@ -1,3 +0,0 @@
- o Minor features (compilation size):
- - Most Server-side DNS code is now disabled when building without
- support for relay mode. Closes ticket 33366.
diff --git a/changes/ticket33368 b/changes/ticket33368
deleted file mode 100644
index ecc6f66f4e..0000000000
--- a/changes/ticket33368
+++ /dev/null
@@ -1,3 +0,0 @@
- o Minor features (client-only compilation):
- - Disable more code related to the ext_orport protocol when compiling
- without support for relay mode. Closes ticket 33368.
diff --git a/changes/ticket33369 b/changes/ticket33369
deleted file mode 100644
index c55335c5b7..0000000000
--- a/changes/ticket33369
+++ /dev/null
@@ -1,4 +0,0 @@
- o Documentation (manpage):
- - Add cross reference links and a table of contents to the HTML
- tor manpage. Closes ticket 33369. Work by Swati Thacker as
- part of Google Season of Docs.
diff --git a/changes/ticket33370 b/changes/ticket33370
deleted file mode 100644
index 41e03357f0..0000000000
--- a/changes/ticket33370
+++ /dev/null
@@ -1,3 +0,0 @@
- o Minor features (client-only compilation):
- - Disable more of our self-testing code when support for relay mode is
- disabled. Closes ticket 33370.
diff --git a/changes/ticket33398 b/changes/ticket33398
new file mode 100644
index 0000000000..bd175bad2f
--- /dev/null
+++ b/changes/ticket33398
@@ -0,0 +1,4 @@
+ o Deprecated features:
+ - The "non-builtin" argument to the "--dump-config" command is now
+ deprecated. When it works, it behaves the same as "short", which
+ you should use instead. Closes ticket 33398.
diff --git a/changes/ticket33400 b/changes/ticket33400
deleted file mode 100644
index 7603890765..0000000000
--- a/changes/ticket33400
+++ /dev/null
@@ -1,3 +0,0 @@
- o Minor feature (onion service v3):
- - Log at INFO level why the service can not upload its descriptor(s). Closes
- ticket 33400; bugfix on 0.3.2.1-alpha.
diff --git a/changes/ticket33436 b/changes/ticket33436
deleted file mode 100644
index 69b5545c6d..0000000000
--- a/changes/ticket33436
+++ /dev/null
@@ -1,4 +0,0 @@
- o Minor features (directory authority, shared random):
- - Refactor more authority-only parts of the shared-random scheduling code
- to reside in the dirauth module, and to be disabled when compiling with
- --disable-module-dirauth. Closes ticket 33436.
diff --git a/changes/ticket33451 b/changes/ticket33451
deleted file mode 100644
index 74dd6d1ad8..0000000000
--- a/changes/ticket33451
+++ /dev/null
@@ -1,3 +0,0 @@
- o Minor features (developer tools):
- - Add a script ("git-install-tools.sh") to install git hooks and helper
- scripts. Closes ticket 33451.
diff --git a/changes/ticket33458 b/changes/ticket33458
deleted file mode 100644
index 885c6dc505..0000000000
--- a/changes/ticket33458
+++ /dev/null
@@ -1,4 +0,0 @@
- o Minor bugfix (onion service v3):
- - When cleaning the client descriptor cache, an attempt at closing circuits
- for a non decrypted descriptor (lacking client authorization) lead to an
- assert(). Fixes bug 33458; bugfix on 0.4.2.1-alpha.
diff --git a/changes/ticket33633 b/changes/ticket33633
deleted file mode 100644
index de030a6000..0000000000
--- a/changes/ticket33633
+++ /dev/null
@@ -1,6 +0,0 @@
- 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/ticket33642 b/changes/ticket33642
deleted file mode 100644
index b81edf7613..0000000000
--- a/changes/ticket33642
+++ /dev/null
@@ -1,4 +0,0 @@
- o Minor features (developer tooling):
- - Refrain from listing all .a files that are generated by Tor build in
- .gitignore. Add a single wildcard *.a entry that covers all of them for
- present and future. Closes ticket 33642.
diff --git a/changes/ticket33679 b/changes/ticket33679
deleted file mode 100644
index d37842d065..0000000000
--- a/changes/ticket33679
+++ /dev/null
@@ -1,4 +0,0 @@
- 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/ticket33778 b/changes/ticket33778
deleted file mode 100644
index a33c647a6e..0000000000
--- a/changes/ticket33778
+++ /dev/null
@@ -1,3 +0,0 @@
- o Documentation (manpage):
- - Updated the options set by TestingTorNetwork in the man page.
- Closes ticket 33778.
diff --git a/changes/ticket33779 b/changes/ticket33779
deleted file mode 100644
index d4bc769ebb..0000000000
--- a/changes/ticket33779
+++ /dev/null
@@ -1,3 +0,0 @@
- 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/ticket33788 b/changes/ticket33788
deleted file mode 100644
index 236c056623..0000000000
--- a/changes/ticket33788
+++ /dev/null
@@ -1,4 +0,0 @@
- o Minor features (code safety):
- - Check for failures of tor_inet_ntop() and tor_inet_ntoa() functions in
- DNS and IP address processing code and adjust codepaths to make them
- less likely to crash entire Tor instance. Resolves issue 33788.
diff --git a/changes/ticket33789 b/changes/ticket33789
deleted file mode 100644
index a7e69793e6..0000000000
--- a/changes/ticket33789
+++ /dev/null
@@ -1,4 +0,0 @@
- 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/ticket33816 b/changes/ticket33816
new file mode 100644
index 0000000000..6412e78443
--- /dev/null
+++ b/changes/ticket33816
@@ -0,0 +1,4 @@
+ o Code simplification and refactoring:
+ - When an extend cell is missing an IPv4 or IPv6 address, fill in the address
+ from the extend info. This is similar to what was done in ticket 33633 for
+ ed25519 keys. Closes ticket 33816. Patch by Neel Chauhan.
diff --git a/changes/ticket33817 b/changes/ticket33817
deleted file mode 100644
index 9c22d084eb..0000000000
--- a/changes/ticket33817
+++ /dev/null
@@ -1,12 +0,0 @@
- 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
deleted file mode 100644
index b824cc5b07..0000000000
--- a/changes/ticket33901
+++ /dev/null
@@ -1,4 +0,0 @@
- 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
deleted file mode 100644
index 7ad802797d..0000000000
--- a/changes/ticket33956
+++ /dev/null
@@ -1,5 +0,0 @@
- 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/ticket34064 b/changes/ticket34064
new file mode 100644
index 0000000000..13ed70c8f6
--- /dev/null
+++ b/changes/ticket34064
@@ -0,0 +1,5 @@
+ o Minor features (relay, ipv6):
+ - Add new "assume-reachable" and "assume-reachable-ipv6" parameters
+ to be used in an emergency to tell relays that they should publish
+ even if they cannot complete their ORPort self-checks.
+ Closes ticket 34064 and part of 33224.
diff --git a/changes/ticket34067 b/changes/ticket34067
new file mode 100644
index 0000000000..b67ccf6082
--- /dev/null
+++ b/changes/ticket34067
@@ -0,0 +1,4 @@
+ o Major features (relay self-testing, IPv6):
+ - Relays now track their IPv6 ORPort separately from the reachability of
+ their IPv4 ORPort. They will not publish a descriptor unless _both_
+ ports appear to be externally reachable. Closes ticket 34067.
diff --git a/changes/ticket34137 b/changes/ticket34137
new file mode 100644
index 0000000000..0982d9dd3b
--- /dev/null
+++ b/changes/ticket34137
@@ -0,0 +1,5 @@
+ o Minor features (relay):
+ - Log immediately when launching a relay self-check. Previously
+ we would try to log before launching checks, or approximately
+ when we intended to launch checks, but this tended to be
+ error-prone. Closes ticket 34137.
diff --git a/changes/ticket34200 b/changes/ticket34200
new file mode 100644
index 0000000000..b984bd83bb
--- /dev/null
+++ b/changes/ticket34200
@@ -0,0 +1,3 @@
+ o Code simplification and refactoring:
+ - Refactor some common node selection code into a single function.
+ Closes ticket 34200.
diff --git a/changes/ticket34211 b/changes/ticket34211
deleted file mode 100644
index b454873abf..0000000000
--- a/changes/ticket34211
+++ /dev/null
@@ -1,3 +0,0 @@
- o Minor features (windows):
- - Add support for console control signals like Ctrl+C in Windows
- Closes ticket 34211. Patch from Damon Harris (TheDcoder).
diff --git a/changes/ticket34232 b/changes/ticket34232
new file mode 100644
index 0000000000..2e00465427
--- /dev/null
+++ b/changes/ticket34232
@@ -0,0 +1,5 @@
+ o Minor bugfixes (string handling):
+ - In summarize_protover_flags(), treat empty strings the same as NULL.
+ This prevents protocols_known from being set. Previously, we treated
+ empty strings as normal strings, which led to protocols_known being
+ set. Fixes bug 34232; bugfix on 0.3.3.2-alpha. Patch by Neel Chauhan.
diff --git a/changes/ticket34255_043 b/changes/ticket34255_043
deleted file mode 100644
index 5cfec1d48d..0000000000
--- a/changes/ticket34255_043
+++ /dev/null
@@ -1,3 +0,0 @@
- o Documentation:
- - Fix several doxygen warnings related to imbalanced groups.
- Closes ticket 34255.
diff --git a/changes/ticket34445 b/changes/ticket34445
new file mode 100644
index 0000000000..111c815dac
--- /dev/null
+++ b/changes/ticket34445
@@ -0,0 +1,5 @@
+ o Minor features (directory authority):
+ - The AssumeReachable option no longer stops directory authorities
+ from checking whether other relays are running. A new
+ AuthDirTestReachability option can be used to disable these checks.
+ Closes ticket 34445.
diff --git a/changes/ticket34446 b/changes/ticket34446
new file mode 100644
index 0000000000..2ec7723129
--- /dev/null
+++ b/changes/ticket34446
@@ -0,0 +1,5 @@
+ o Minor features (testing configuration):
+ - The TestingTorNetwork no longer implicitly sets AssumeReachable to 1.
+ This change will allow us to test relays' self-testing mechanisms,
+ and eventually to test authorities' relay-testing functionality.
+ Closes ticket 34446.
diff --git a/changes/ticket40002 b/changes/ticket40002
new file mode 100644
index 0000000000..bd40dd055a
--- /dev/null
+++ b/changes/ticket40002
@@ -0,0 +1,3 @@
+ o Minor feature (control port):
+ - Add a DROPTIMEOUTS control port command to drop circuit build timeout
+ history and reset the timeout. Closes ticket 40002.
diff --git a/changes/ticket40006 b/changes/ticket40006
new file mode 100644
index 0000000000..ad10e236c3
--- /dev/null
+++ b/changes/ticket40006
@@ -0,0 +1,6 @@
+ o Major bugfix (TLS, buffer):
+ - When attempting to read N bytes on a TLS connection, really try to read
+ those N bytes. Before that, Tor would stop reading after the first TLS
+ record which can be smaller than N bytes even though more data was waiting
+ on the TLS connection socket. The remaining data would have been read at
+ the next mainloop event. Fixes bug 40006; bugfix on 0.1.0.5-rc.
diff --git a/changes/ticket40019 b/changes/ticket40019
new file mode 100644
index 0000000000..61ba171786
--- /dev/null
+++ b/changes/ticket40019
@@ -0,0 +1,5 @@
+ o Code simplification and refactoring (maintainer scripts):
+ - Disable by default the pre-commit hook. Use the environment variable
+ TOR_EXTRA_PRE_COMMIT_CHECKS in order to run it. Furthermore, stop running
+ practracker in the pre-commit hook and make check-local. Closes ticket
+ 40019.
diff --git a/configure.ac b/configure.ac
index 1e76ddd14d..a6df7149a0 100644
--- a/configure.ac
+++ b/configure.ac
@@ -4,7 +4,7 @@ dnl Copyright (c) 2007-2019, The Tor Project, Inc.
dnl See LICENSE for licensing information
AC_PREREQ([2.63])
-AC_INIT([tor],[0.4.4.2-alpha])
+AC_INIT([tor],[0.4.5.0-alpha-dev])
AC_CONFIG_SRCDIR([src/app/main/tor_main.c])
AC_CONFIG_MACRO_DIR([m4])
@@ -16,7 +16,7 @@ configure_flags="$*"
# version number changes. Tor uses it to make sure that it
# only shuts down for missing "required protocols" when those protocols
# are listed as required by a consensus after this date.
-AC_DEFINE(APPROX_RELEASE_DATE, ["2020-07-09"], # for 0.4.4.2-alpha
+AC_DEFINE(APPROX_RELEASE_DATE, ["2020-06-09"], # for 0.4.5.0-alpha-dev
[Approximate date when this software was released. (Updated when the version changes.)])
# "foreign" means we don't follow GNU package layout standards
@@ -679,12 +679,10 @@ AC_CHECK_FUNCS(
getdelim \
getifaddrs \
getline \
- getpass \
getrlimit \
gettimeofday \
gmtime_r \
gnu_get_libc_version \
- htonll \
inet_aton \
ioctl \
issetugid \
@@ -1042,7 +1040,6 @@ dnl to them.
AC_CHECK_FUNCS([ \
ERR_load_KDF_strings \
EVP_PBE_scrypt \
- EVP_sha3_256 \
SSL_CIPHER_find \
SSL_CTX_set1_groups_list \
SSL_CTX_set_security_level \
@@ -1569,8 +1566,6 @@ AC_CHECK_HEADERS([errno.h \
mach/vm_inherit.h \
machine/limits.h \
malloc.h \
- malloc/malloc.h \
- malloc_np.h \
netdb.h \
netinet/in.h \
netinet/in6.h \
@@ -1591,7 +1586,6 @@ AC_CHECK_HEADERS([errno.h \
sys/statvfs.h \
sys/syscall.h \
sys/sysctl.h \
- sys/syslimits.h \
sys/time.h \
sys/types.h \
sys/un.h \
diff --git a/contrib/win32build/tor-mingw.nsi.in b/contrib/win32build/tor-mingw.nsi.in
index 67b318d1f3..8ca918b15b 100644
--- a/contrib/win32build/tor-mingw.nsi.in
+++ b/contrib/win32build/tor-mingw.nsi.in
@@ -8,7 +8,7 @@
!include "LogicLib.nsh"
!include "FileFunc.nsh"
!insertmacro GetParameters
-!define VERSION "0.4.4.2-alpha"
+!define VERSION "0.4.5.0-alpha-dev"
!define INSTALLER "tor-${VERSION}-win32.exe"
!define WEBSITE "https://www.torproject.org/"
!define LICENSE "LICENSE"
diff --git a/doc/HACKING/CodeStructure.md b/doc/HACKING/CodeStructure.md
deleted file mode 100644
index d387018f9b..0000000000
--- a/doc/HACKING/CodeStructure.md
+++ /dev/null
@@ -1,123 +0,0 @@
-# Code Structure
-
-TODO: revise this to talk about how things are, rather than how things
-have changed.
-
-For quite a while now, the program *tor* has been built from source
-code in just two directories: **src/common** and **src/or**.
-
-This has become more-or-less untenable, for a few reasons -- most
-notably of which is that it has led our code to become more
-spaghetti-ish than I can endorse with a clean conscience.
-
-So to fix that, we've gone and done a huge code movement in our git
-master branch, which will land in a release once Tor `0.3.5.1-alpha` is
-out.
-
-Here's what we did:
-
- * **src/common** has been turned into a set of static libraries. These
-all live in the **src/lib/*** directories. The dependencies between
-these libraries should have no cycles. The libraries are:
-
- - **arch** -- Headers to handle architectural differences
- - **cc** -- headers to handle differences among compilers
- - **compress** -- wraps zlib, zstd, lzma
- - **container** -- high-level container types
- - **crypt_ops** -- Cryptographic operations. Planning to split this into
-a higher and lower level library
- - **ctime** -- Operations that need to run in constant-time. (Properly,
-data-invariant time)
- - **defs** -- miscelaneous definitions needed throughout Tor.
- - **encoding** -- transforming one data type into another, and various
-data types into strings.
- - **err** -- lowest-level error handling, in cases where we can't use
-the logs because something that the logging system needs has broken.
- - **evloop** -- Generic event-loop handling logic
- - **fdio** -- Low-level IO wrapper functions for file descriptors.
- - **fs** -- Operations on the filesystem
- - **intmath** -- low-level integer math and misc bit-twiddling hacks
- - **lock** -- low-level locking code
- - **log** -- Tor's logging module. This library sits roughly halfway up
-the library dependency diagram, since everything it depends on has to
-be carefully crafted to *not* log.
- - **malloc** -- Low-level wrappers for the platform memory allocation functions.
- - **math** -- Higher-level mathematical functions, and floating-point math
- - **memarea** -- An arena allocator
- - **meminfo** -- Functions for querying the current process's memory
-status and resources
- - **net** -- Networking compatibility and convenience code
- - **osinfo** -- Querying information about the operating system
- - **process** -- Launching and querying the status of other processes
- - **sandbox** -- Backend for the linux seccomp2 sandbox
- - **smartlist_core** -- The lowest-level of the smartlist_t data type.
-Separated from the rest of the containers library because the logging
-subsystem depends on it.
- - **string** -- Compatibility and convenience functions for manipulating
-C strings.
- - **term** -- Terminal-related functions (currently limited to a getpass
-function).
- - **testsupport** -- Macros for mocking, unit tests, etc.
- - **thread** -- Higher-level thread compatibility code
- - **time** -- Higher-level time management code, including format
-conversions and monotonic time
- - **tls** -- Our wrapper around our TLS library
- - **trace** -- Formerly src/trace -- a generic event tracing API
- - **wallclock** -- Low-level time code, used by the log module.
-
- * To ensure that the dependency graph in **src/common** remains under
-control, there is a tool that you can run called `make
-check-includes`. It verifies that each module in Tor only includes
-the headers that it is permitted to include, using a per-directory
-*.may_include* file.
-
- * The **src/or/or.h** header has been split into numerous smaller
-headers. Notably, many important structures are now declared in a
-header called *foo_st.h*, where "foo" is the name of the structure.
-
- * The **src/or** directory, which had most of Tor's code, had been split
-up into several directories. This is still a work in progress: This
-code has not itself been refactored, and its dependency graph is still
-a tangled web. I hope we'll be working on that over the coming
-releases, but it will take a while to do.
-
- - The new top-level source directories are:
- - **src/core** -- Code necessary to actually perform or use onion routing.
- - **src/feature** -- Code used only by some onion routing
-configurations, or only for a special purpose.
- - **src/app** -- Top-level code to run, invoke, and configure the
-lower-level code
-
- - The new second-level source directories are:
- - **src/core/crypto** -- High-level cryptographic protocols used in Tor
- - **src/core/mainloop** -- Tor's event loop, connection-handling, and
-traffic-routing code.
- - **src/core/or** -- Parts related to handling onion routing itself
- - **src/core/proto** -- support for encoding and decoding different
-wire protocols
- - **src/feature/api** -- Support for making Tor embeddable
- - **src/feature/client** -- Functionality which only Tor clients need
- - **src/feature/control** -- Controller implementation
- - **src/feature/dirauth** -- Directory authority
- - **src/feature/dircache** -- Directory cache
- - **src/feature/dirclient** -- Directory client
- - **src/feature/dircommon** -- Shared code between the other directory modules
- - **src/feature/hibernate** -- Hibernating when Tor is out of bandwidth
-or shutting down
- - **src/feature/hs** -- v3 onion service implementation
- - **src/feature/hs_common** -- shared code between both onion service
-implementations
- - **src/feature/nodelist** -- storing and accessing the list of relays on
-the network.
- - **src/feature/relay** -- code that only relay servers and exit servers need.
- - **src/feature/rend** -- v2 onion service implementation
- - **src/feature/stats** -- statistics and history
- - **src/app/config** -- configuration and state for Tor
- - **src/app/main** -- Top-level functions to invoke the rest or Tor.
-
- * The `tor` executable is now built in **src/app/tor** rather than **src/or/tor**.
-
- * There are more static libraries than before that you need to build
-into your application if you want to embed Tor. Rather than
-maintaining this list yourself, I recommend that you run `make
-show-libs` to have Tor emit a list of what you need to link.
diff --git a/doc/include.am b/doc/include.am
index 8651f845eb..5e0c90b0cd 100644
--- a/doc/include.am
+++ b/doc/include.am
@@ -52,7 +52,6 @@ EXTRA_DIST+= doc/asciidoc-helper.sh \
doc/HACKING/README.1st.md \
doc/HACKING/CodingStandards.md \
doc/HACKING/CodingStandardsRust.md \
- doc/HACKING/CodeStructure.md \
doc/HACKING/Fuzzing.md \
doc/HACKING/GettingStarted.md \
doc/HACKING/GettingStartedRust.md \
diff --git a/doc/tor.1.txt b/doc/tor.1.txt
index 9d073635af..b852dc2a5f 100644
--- a/doc/tor.1.txt
+++ b/doc/tor.1.txt
@@ -97,11 +97,10 @@ The following options in this section are only recognized on the
[[opt-verify-config]] **`--verify-config`**::
Verify whether the configuration file is valid.
-[[opt-dump-config]] **`--dump-config`** **`short`**|**`full`**|**`non-builtin`**::
- Write a complete list of Tor's configured options to standard output.
+[[opt-dump-config]] **`--dump-config`** **`short`**|**`full`**::
+ Write a list of Tor's configured options to standard output.
When the `short` flag is selected, only write the options that
- are different from their default values. When `non-builtin` is selected,
- write options that are not zero or the empty string.
+ are different from their default values
When `full` is selected, write every option.
[[opt-serviceinstall]] **`--service install`** [**`--options`** __command-line options__]::
@@ -2036,12 +2035,12 @@ different from other Tor clients:
A list of identity fingerprints and country codes of nodes
to use for "middle" hops in your normal circuits.
Normal circuits include all circuits except for direct connections
- to directory servers. Middle hops are all hops other than exit and entry. +
+ to directory servers. Middle hops are all hops other than exit and entry.
+
This is an **experimental** feature that is meant to be used by researchers
and developers to test new features in the Tor network safely. Using it
- without care will strongly influence your anonymity. This feature might get
- removed in the future.
+ without care will strongly influence your anonymity. Other tor features may
+ not work with MiddleNodes. This feature might get removed in the future.
+
The HSLayer2Node and HSLayer3Node options override this option for onion
service circuits, if they are set. The vanguards addon will read this
@@ -2142,9 +2141,12 @@ is non-zero):
[[AssumeReachable]] **AssumeReachable** **0**|**1**::
This option is used when bootstrapping a new Tor network. If set to 1,
don't do self-reachability testing; just upload your server descriptor
- immediately. If **AuthoritativeDirectory** is also set, this option
- instructs the dirserver to bypass remote reachability testing too and list
- all connected servers as running.
+ immediately. (Default: 0)
+
+[[AssumeReachableIPv6]] **AssumeReachableIPv6** **0**|**1**|**auto**::
+ Like **AssumeReachable**, but affects only the relay's own IPv6 ORPort.
+ If this value is set to "auto", then Tor will look at **AssumeReachable**
+ instead. (Default: auto)
[[BridgeRelay]] **BridgeRelay** **0**|**1**::
Sets the relay to act as a "bridge" with respect to relaying connections
@@ -3004,6 +3006,12 @@ on the public Tor network.
if there is some major bug in Ed25519 link authentication that causes us
to label all the relays as not Running. (Default: 1)
+[[AuthDirTestReachability]] **AuthDirTestReachability** **0**|**1**::
+ Authoritative directories only. If set to 1, then we periodically
+ check every relay we know about to see whether it is running.
+ If set to 0, we vote Running for every relay, and don't perform
+ these tests. (Default: 1)
+
[[BridgePassword]] **BridgePassword** __Password__::
If set, contains an HTTP authenticator that tells a bridge authority to
serve all requested bridge information. Used by the (only partially
@@ -3357,7 +3365,6 @@ The following options are used for running a testing Tor network.
DirAllowPrivateAddresses 1
EnforceDistinctSubnets 0
- AssumeReachable 1
AuthDirMaxServersPerAddr 0
ClientBootstrapConsensusAuthorityDownloadInitialDelay 0
ClientBootstrapConsensusFallbackDownloadInitialDelay 0
diff --git a/scripts/git/git-list-tor-branches.sh b/scripts/git/git-list-tor-branches.sh
index d6b30f064f..b0c30d2e8b 100755
--- a/scripts/git/git-list-tor-branches.sh
+++ b/scripts/git/git-list-tor-branches.sh
@@ -139,15 +139,15 @@ finish() {
branch maint-0.3.5
branch release-0.3.5
-branch maint-0.4.1
-branch release-0.4.1
-
branch maint-0.4.2
branch release-0.4.2
branch maint-0.4.3
branch release-0.4.3
+branch maint-0.4.4
+branch release-0.4.4
+
branch master
finish
diff --git a/scripts/git/pre-commit.git-hook b/scripts/git/pre-commit.git-hook
index f630a242bd..5533ed0cdd 100755
--- a/scripts/git/pre-commit.git-hook
+++ b/scripts/git/pre-commit.git-hook
@@ -5,7 +5,12 @@
#
# This is pre-commit git hook script that prevents commiting your changeset if
# it fails our code formatting, changelog entry formatting, module include
-# rules, or best practices tracker.
+# rules, etc...
+
+# Run only if this environment variable is set.
+if [ -z "$TOR_EXTRA_PRE_COMMIT_CHECKS" ]; then
+ exit 0
+fi
workdir=$(git rev-parse --show-toplevel)
@@ -49,13 +54,6 @@ if [ -e scripts/maint/checkShellScripts.sh ]; then
scripts/maint/checkShellScripts.sh
fi
-# Always run the practracker unit tests
-PT_DIR=scripts/maint/practracker
-
-if [ -e "${PT_DIR}/test_practracker.sh" ]; then
- "${PT_DIR}/test_practracker.sh"
-fi
-
if [ -e scripts/maint/checkSpaceTest.sh ]; then
scripts/maint/checkSpaceTest.sh
fi
@@ -74,19 +72,11 @@ printf "Modified tor-owned source files:\\n%s\\n" "$CHECK_FILES"
perl scripts/maint/checkSpace.pl -C \
$CHECK_FILES
+# This makes sure that we are only including things we're allowed to include.
if test -e scripts/maint/practracker/includes.py; then
python scripts/maint/practracker/includes.py
fi
-# Only call practracker if ${PT_DIR}/.enable_practracker_in_hooks exists
-# We do this check so that we can enable practracker in hooks in master, and
-# disable it on maint branches
-if [ -e "${PT_DIR}/practracker.py" ]; then
- if [ -e "${PT_DIR}/.enable_practracker_in_hooks" ]; then
- python3 "${PT_DIR}/practracker.py" "$workdir"
- fi
-fi
-
if [ -e scripts/coccinelle/check_cocci_parse.sh ]; then
# Run a verbose cocci parse check on the changed files
diff --git a/scripts/git/pre-push.git-hook b/scripts/git/pre-push.git-hook
index efa45b9860..f0a3a250ec 100755
--- a/scripts/git/pre-push.git-hook
+++ b/scripts/git/pre-push.git-hook
@@ -83,6 +83,7 @@ do
src/tools/*.[ch] \
)"
+ export TOR_EXTRA_PRE_COMMIT_CHECKS=1
# We want word splitting here, because file names are space
# separated
# shellcheck disable=SC2086
diff --git a/scripts/maint/clang-format.sh b/scripts/maint/clang-format.sh
deleted file mode 100755
index 59832117b4..0000000000
--- a/scripts/maint/clang-format.sh
+++ /dev/null
@@ -1,41 +0,0 @@
-#!/bin/sh
-# Copyright 2020, The Tor Project, Inc.
-# See LICENSE for licensing information.
-
-#
-# DO NOT COMMIT OR MERGE CODE THAT IS RUN THROUGH THIS TOOL YET.
-#
-# WE ARE STILL DISCUSSING OUR DESIRED STYLE AND ITERATING ON IT.
-# (12 Feb 2020)
-#
-
-# This script runs "clang-format" and "codetool" in sequence over each of
-# our source files, and replaces the original file only if it has changed.
-#
-# We can't just use clang-format -i, since we also want to use codetool to
-# reformat a few things back to how we want them, and we want avoid changing
-# the mtime on files that didn't actually change.
-
-set -e
-
-cd "$(dirname "$0")/../../src/"
-
-# Shellcheck complains that a for loop over find's output is unreliable,
-# since there might be special characters in the output. But we happen
-# to know that none of our C files have special characters or spaces in
-# their names, so this is safe.
-#
-# shellcheck disable=SC2044
-for fname in $(find lib core feature app test tools -name '[^.]*.[ch]'); do
- tmpfname="${fname}.clang_fmt.tmp"
- rm -f "${tmpfname}"
- clang-format --style=file "${fname}" > "${tmpfname}"
- ../scripts/maint/codetool.py "${tmpfname}"
- if cmp "${fname}" "${tmpfname}" >/dev/null 2>&1; then
- echo "No change in ${fname}"
- rm -f "${tmpfname}"
- else
- echo "Change in ${fname}"
- mv "${tmpfname}" "${fname}"
- fi
-done
diff --git a/scripts/maint/code-format.sh b/scripts/maint/code-format.sh
new file mode 100755
index 0000000000..d8f597d70d
--- /dev/null
+++ b/scripts/maint/code-format.sh
@@ -0,0 +1,232 @@
+#!/usr/bin/env bash
+# Copyright 2020, The Tor Project, Inc.
+# See LICENSE for licensing information.
+
+#
+# DO NOT COMMIT OR MERGE CODE THAT IS RUN THROUGH THIS TOOL YET.
+#
+# WE ARE STILL DISCUSSING OUR DESIRED STYLE AND ITERATING ON IT.
+# (12 Feb 2020)
+#
+
+# This script runs "clang-format" and "codetool" in sequence over each of its
+# arguments. It either replaces the original, or says whether anything has
+# changed, depending on its arguments.
+#
+# We can't just use clang-format directly, since we also want to use codetool
+# to reformat a few things back to how we want them, and we want avoid changing
+# the mtime on files that didn't actually change.
+#
+# Use "-i" to edit the file in-place.
+# Use "-c" to exit with a nonzero exit status if any file needs to change.
+# Use "-d" to emit diffs.
+#
+# The "-a" option tells us to run over every Tor source file.
+# The "-v" option tells us to be verbose.
+
+set -e
+
+ALL=0
+GITDIFF=0
+GITIDX=0
+DIFFMODE=0
+CHECKMODE=0
+CHANGEMODE=0
+
+SCRIPT_NAME=$(basename "$0")
+SCRIPT_DIR=$(dirname "$0")
+SRC_DIR="${SCRIPT_DIR}/../../src"
+
+function usage() {
+ echo "$SCRIPT_NAME [-h] [-c|-d|-i] [-v] [-a|-G|files...]"
+ echo
+ echo " flags:"
+ echo " -h: show this help text"
+ echo " -c: check whether files are correctly formatted"
+ echo " -d: print a diff for the changes that would be applied"
+ echo " -i: change files in-place"
+ echo " -a: run over all the C files in Tor"
+ echo " -v: verbose mode"
+ echo " -g: look at the files that have changed in git."
+ echo " -G: look at the files that are staged for the git commit."
+ echo
+ echo "EXAMPLES"
+ echo
+ echo " $SCRIPT_NAME -a -i"
+ echo " rewrite every file in place, whether it has changed or not."
+ echo " $SCRIPT_NAME -a -d"
+ echo " as above, but only display the changes."
+ echo " $SCRIPT_NAME -g -i"
+ echo " update every file that you have changed in the git working tree."
+ echo " $SCRIPT_NAME -G -c"
+ echo " exit with an error if any staged changes are not well-formatted."
+}
+
+FILEARGS_OK=1
+
+while getopts "acdgGhiv" opt; do
+ case "$opt" in
+ h) usage
+ exit 0
+ ;;
+ a) ALL=1
+ FILEARGS_OK=0
+ ;;
+ g) GITDIFF=1
+ FILEARGS_OK=0
+ ;;
+ G) GITIDX=1
+ FILEARGS_OK=0
+ ;;
+ c) CHECKMODE=1
+ ;;
+ d) DIFFMODE=1
+ ;;
+ i) CHANGEMODE=1
+ ;;
+ v) VERBOSE=1
+ ;;
+ *) echo
+ usage
+ exit 1
+ ;;
+ esac
+done
+# get rid of the flags; keep the filenames.
+shift $((OPTIND - 1))
+
+# Define a verbose function.
+if [[ $VERBOSE = 1 ]]; then
+ function note()
+ {
+ echo "$@"
+ }
+else
+ function note()
+ {
+ true
+ }
+fi
+
+# We have to be in at least one mode, or we can't do anything
+if [[ $CHECKMODE = 0 && $DIFFMODE = 0 && $CHANGEMODE = 0 ]]; then
+ echo "Nothing to do. You need to specify -c, -d, or -i."
+ echo "Try $SCRIPT_NAME -h for more information."
+ exit 0
+fi
+
+# We don't want to "give an error if anything would change" if we're
+# actually trying to change things.
+if [[ $CHECKMODE = 1 && $CHANGEMODE = 1 ]]; then
+ echo "It doesn't make sense to use -c and -i together."
+ exit 0
+fi
+# It doesn't make sense to look at "all files" and "git files"
+if [[ $((ALL + GITIDX + GITDIFF)) -gt 1 ]]; then
+ echo "It doesn't make sense to use more than one of -a, -g, or -G together."
+ exit 0
+fi
+
+if [[ $FILEARGS_OK = 1 ]]; then
+ # The filenames are on the command-line.
+ INPUTS=("${@}")
+else
+ if [[ "$#" != 0 ]]; then
+ echo "Can't use -a, -g, or -G with additional command-line arguments."
+ exit 1
+ fi
+fi
+
+if [[ $ALL = 1 ]]; then
+ # We're in "all" mode -- use find(1) to find the filenames.
+ mapfile -d '' INPUTS < <(find "${SRC_DIR}"/{lib,core,feature,app,test,tools} -name '[^.]*.[ch]' -print0)
+elif [[ $GITIDX = 1 ]]; then
+ # We're in "git index" mode -- use git diff --cached to find the filenames
+ # that are changing in the index, then strip out the ones that
+ # aren't C.
+ mapfile INPUTS < <(git diff --name-only --cached --diff-filter=AMCR | grep '\.[ch]$')
+elif [[ $GITDIFF = 1 ]]; then
+ # We are in 'git diff' mode -- we want everything that changed, including
+ # the index and the working tree.
+ #
+ # TODO: There might be a better way to do this.
+ mapfile INPUTS < <(git diff --name-only --cached --diff-filter=AMCR | grep '\.[ch]$'; git diff --name-only --diff-filter=AMCR | grep '\.[ch]$' )
+fi
+
+if [[ $GITIDX = 1 ]]; then
+ # If we're running in git mode, we need to stash all the changes that
+ # we don't want to look at. This is necessary even though we're only
+ # looking at the changed files, since we might have the file only
+ # partially staged.
+ note "Stashing unstaged changes"
+ git stash -q --keep-index
+ function restoregit() {
+ note "Restoring git state"
+ git stash pop -q
+ }
+else
+ function restoregit() {
+ true
+ }
+fi
+
+ANY_CHANGED=0
+
+tmpfname=""
+
+#
+# Set up a trap handler to make sure that on exit, we remove our
+# tmpfile and un-stash the git environment (if appropriate)
+#
+trap 'if [ -n "${tmpfname}" ]; then rm -f "${tmpfname}"; fi; restoregit' 0
+
+for fname in "${INPUTS[@]}"; do
+ note "Inspecting $fname..."
+ tmpfname="${fname}.$$.clang_fmt.tmp"
+ rm -f "${tmpfname}"
+ clang-format --style=file "${fname}" > "${tmpfname}"
+ "${SCRIPT_DIR}/codetool.py" "${tmpfname}"
+
+ changed=not_set
+
+ if [[ $DIFFMODE = 1 ]]; then
+ # If we're running diff for its output, we can also use it
+ # to compare the files.
+ if diff -u "${fname}" "${tmpfname}"; then
+ changed=0
+ else
+ changed=1
+ fi
+ else
+ # We aren't running diff, so we have to compare the files with cmp.
+ if cmp "${fname}" "${tmpfname}" >/dev/null 2>&1; then
+ changed=0
+ else
+ changed=1
+ fi
+ fi
+
+ if [[ $changed = 1 ]]; then
+ note "Found a change in $fname"
+ ANY_CHANGED=1
+
+ if [[ $CHANGEMODE = 1 ]]; then
+ mv "${tmpfname}" "${fname}"
+ fi
+ fi
+
+ rm -f "${tmpfname}"
+done
+
+exitcode=0
+
+if [[ $CHECKMODE = 1 ]]; then
+ if [[ $ANY_CHANGED = 1 ]]; then
+ note "Found at least one misformatted file; check failed"
+ exitcode=1
+ else
+ note "No changes found."
+ fi
+fi
+
+exit $exitcode
diff --git a/scripts/maint/practracker/.enable_practracker_in_hooks b/scripts/maint/practracker/.enable_practracker_in_hooks
new file mode 100644
index 0000000000..a9e707f5da
--- /dev/null
+++ b/scripts/maint/practracker/.enable_practracker_in_hooks
@@ -0,0 +1 @@
+This file is present to tell our git hooks to run practracker on this branch.
diff --git a/scripts/maint/practracker/exceptions.txt b/scripts/maint/practracker/exceptions.txt
index 35e860d8b1..25568f03f0 100644
--- a/scripts/maint/practracker/exceptions.txt
+++ b/scripts/maint/practracker/exceptions.txt
@@ -46,7 +46,7 @@ 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() 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 function-size /src/app/config/resolve_addr.c:resolve_my_address_v4() 197
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
@@ -96,7 +96,7 @@ problem function-size /src/core/or/channeltls.c:channel_tls_process_authenticate
problem dependency-violation /src/core/or/channeltls.c 11
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:choose_good_exit_server_general() 206
+problem function-size /src/core/or/circuitbuild.c:choose_good_exit_server_general() 196
problem dependency-violation /src/core/or/circuitbuild.c 25
problem include-count /src/core/or/circuitlist.c 55
problem function-size /src/core/or/circuitlist.c:HT_PROTOTYPE() 109
@@ -108,16 +108,16 @@ problem dependency-violation /src/core/or/circuitlist.h 1
problem function-size /src/core/or/circuitmux.c:circuitmux_set_policy() 109
problem function-size /src/core/or/circuitmux.c:circuitmux_attach_circuit() 113
problem dependency-violation /src/core/or/circuitmux_ewma.c 2
-problem file-size /src/core/or/circuitpadding.c 3101
+problem file-size /src/core/or/circuitpadding.c 3183
problem function-size /src/core/or/circuitpadding.c:circpad_machine_schedule_padding() 113
problem dependency-violation /src/core/or/circuitpadding.c 6
-problem file-size /src/core/or/circuitpadding.h 813
+problem file-size /src/core/or/circuitpadding.h 832
problem function-size /src/core/or/circuitpadding_machines.c:circpad_machine_relay_hide_intro_circuits() 103
problem function-size /src/core/or/circuitpadding_machines.c:circpad_machine_client_hide_rend_circuits() 112
problem dependency-violation /src/core/or/circuitpadding_machines.c 1
problem function-size /src/core/or/circuitstats.c:circuit_build_times_parse_state() 123
problem dependency-violation /src/core/or/circuitstats.c 11
-problem file-size /src/core/or/circuituse.c 3195
+problem file-size /src/core/or/circuituse.c 3250
problem function-size /src/core/or/circuituse.c:circuit_is_acceptable() 128
problem function-size /src/core/or/circuituse.c:circuit_expire_building() 389
problem function-size /src/core/or/circuituse.c:circuit_log_ancient_one_hop_circuits() 126
@@ -145,8 +145,9 @@ problem function-size /src/core/or/connection_or.c:connection_or_group_set_badne
problem function-size /src/core/or/connection_or.c:connection_or_client_learned_peer_id() 142
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/extendinfo.c 6
problem dependency-violation /src/core/or/onion.c 2
-problem file-size /src/core/or/or.h 1105
+problem file-size /src/core/or/or.h 1150
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
@@ -198,7 +199,7 @@ problem function-size /src/feature/control/control_events.c:control_event_stream
problem include-count /src/feature/control/control_getinfo.c 56
problem function-size /src/feature/control/control_getinfo.c:getinfo_helper_misc() 108
problem function-size /src/feature/control/control_getinfo.c:getinfo_helper_dir() 297
-problem function-size /src/feature/control/control_getinfo.c:getinfo_helper_events() 234
+problem function-size /src/feature/control/control_getinfo.c:getinfo_helper_events() 237
problem function-size /src/feature/dirauth/bwauth.c:dirserv_read_measured_bandwidths() 121
problem file-size /src/feature/dirauth/dirvote.c 4734
problem include-count /src/feature/dirauth/dirvote.c 55
@@ -255,11 +256,11 @@ problem function-size /src/feature/nodelist/microdesc.c:microdesc_cache_rebuild(
problem include-count /src/feature/nodelist/networkstatus.c 65
problem function-size /src/feature/nodelist/networkstatus.c:networkstatus_check_consensus_signature() 175
problem function-size /src/feature/nodelist/networkstatus.c:networkstatus_set_current_consensus() 289
-problem function-size /src/feature/nodelist/node_select.c:router_pick_directory_server_impl() 122
+problem function-size /src/feature/nodelist/node_select.c:router_pick_directory_server_impl() 126
problem function-size /src/feature/nodelist/node_select.c:compute_weighted_bandwidths() 204
-problem function-size /src/feature/nodelist/node_select.c:router_pick_trusteddirserver_impl() 112
+problem function-size /src/feature/nodelist/node_select.c:router_pick_trusteddirserver_impl() 116
problem function-size /src/feature/nodelist/nodelist.c:compute_frac_paths_available() 190
-problem file-size /src/feature/nodelist/routerlist.c 3247
+problem file-size /src/feature/nodelist/routerlist.c 3350
problem function-size /src/feature/nodelist/routerlist.c:router_rebuild_store() 148
problem function-size /src/feature/nodelist/routerlist.c:router_add_to_routerlist() 168
problem function-size /src/feature/nodelist/routerlist.c:routerlist_remove_old_routers() 121
diff --git a/scripts/maint/rename_c_identifier.py b/scripts/maint/rename_c_identifier.py
index 77802e10f3..7794689303 100755
--- a/scripts/maint/rename_c_identifier.py
+++ b/scripts/maint/rename_c_identifier.py
@@ -239,7 +239,7 @@ def main(argv):
print("I require an even number of identifiers.", file=sys.stderr)
return 1
- if any_uncommitted_changes():
+ if args.commit and any_uncommitted_changes():
print("Uncommitted changes found. Not running.", file=sys.stderr)
return 1
diff --git a/src/app/app.md b/src/app/app.md
index 138e75b127..298bde75f5 100644
--- a/src/app/app.md
+++ b/src/app/app.md
@@ -4,3 +4,8 @@
The "app" directory has Tor's main entry point and configuration logic,
and is responsible for initializing and managing the other modules in
Tor.
+
+The modules in "app" are:
+
+ - \refdir{app/config} -- configuration and state for Tor
+ - \refdir{app/main} -- Top-level functions to invoke the rest or Tor.
diff --git a/src/app/config/config.c b/src/app/config/config.c
index ba2cecd9ab..fbba43a2b2 100644
--- a/src/app/config/config.c
+++ b/src/app/config/config.c
@@ -313,7 +313,7 @@ static const config_var_t option_vars_[] = {
V(AccountingMax, MEMUNIT, "0 bytes"),
VAR("AccountingRule", STRING, AccountingRule_option, "max"),
V(AccountingStart, STRING, NULL),
- V(Address, STRING, NULL),
+ V(Address, LINELIST, NULL),
OBSOLETE("AllowDotExit"),
OBSOLETE("AllowInvalidNodes"),
V(AllowNonRFC953Hostnames, BOOL, "0"),
@@ -323,6 +323,7 @@ static const config_var_t option_vars_[] = {
V(AlternateDirAuthority, LINELIST, NULL),
OBSOLETE("AlternateHSAuthority"),
V(AssumeReachable, BOOL, "0"),
+ V(AssumeReachableIPv6, AUTOBOOL, "auto"),
OBSOLETE("AuthDirBadDir"),
OBSOLETE("AuthDirBadDirCCs"),
V(AuthDirBadExit, LINELIST, NULL),
@@ -2771,10 +2772,6 @@ options_dump(const or_options_t *options, int how_to_dump)
use_defaults = global_default_options;
minimal = 1;
break;
- case OPTIONS_DUMP_DEFAULTS:
- use_defaults = NULL;
- minimal = 1;
- break;
case OPTIONS_DUMP_ALL:
use_defaults = NULL;
minimal = 0;
@@ -3229,6 +3226,10 @@ options_validate_cb(const void *old_options_, void *options_, char **msg)
REJECT("TokenBucketRefillInterval must be between 1 and 1000 inclusive.");
}
+ if (options->AssumeReachable && options->AssumeReachableIPv6 == 0) {
+ REJECT("Cannot set AssumeReachable 1 and AssumeReachableIPv6 0.");
+ }
+
if (options->ExcludeExitNodes || options->ExcludeNodes) {
options->ExcludeExitNodesUnion_ = routerset_new();
routerset_union(options->ExcludeExitNodesUnion_,options->ExcludeExitNodes);
@@ -4028,7 +4029,7 @@ options_check_transition_cb(const void *old_,
if (! CFG_EQ_INT(old, new_val, opt)) \
BAD_CHANGE_TO(opt," with Sandbox active")
- SB_NOCHANGE_STR(Address);
+ SB_NOCHANGE_LINELIST(Address);
SB_NOCHANGE_STR(ServerDNSResolvConfFile);
SB_NOCHANGE_STR(DirPortFrontPage);
SB_NOCHANGE_STR(CookieAuthFile);
diff --git a/src/app/config/config.h b/src/app/config/config.h
index 17caa0e3ff..f7d4e49f6f 100644
--- a/src/app/config/config.h
+++ b/src/app/config/config.h
@@ -58,8 +58,7 @@ setopt_err_t options_trial_assign(struct config_line_t *list, unsigned flags,
void options_init(or_options_t *options);
#define OPTIONS_DUMP_MINIMAL 1
-#define OPTIONS_DUMP_DEFAULTS 2
-#define OPTIONS_DUMP_ALL 3
+#define OPTIONS_DUMP_ALL 2
char *options_dump(const or_options_t *options, int how_to_dump);
int options_init_from_torrc(int argc, char **argv);
setopt_err_t options_init_from_string(const char *cf_defaults, const char *cf,
diff --git a/src/app/config/or_options_st.h b/src/app/config/or_options_st.h
index bf58205f89..07126cc6ce 100644
--- a/src/app/config/or_options_st.h
+++ b/src/app/config/or_options_st.h
@@ -71,7 +71,10 @@ struct or_options_t {
int CacheDirectoryGroupReadable; /**< Boolean: Is the CacheDirectory g+r? */
char *Nickname; /**< OR only: nickname of this onion router. */
- char *Address; /**< OR only: configured address for this onion router. */
+ /** OR only: configured address for this onion router. Up to two times this
+ * options is accepted as in IPv4 and IPv6. */
+ struct config_line_t *Address;
+
char *PidFile; /**< Where to store PID of Tor process. */
struct routerset_t *ExitNodes; /**< Structure containing nicknames, digests,
@@ -192,7 +195,14 @@ struct or_options_t {
unsigned int HTTPTunnelPort_set : 1;
/**@}*/
- int AssumeReachable; /**< Whether to publish our descriptor regardless. */
+ /** Whether to publish our descriptor regardless of all our self-tests
+ */
+ int AssumeReachable;
+ /** Whether to publish our descriptor regardless of IPv6 self-tests.
+ *
+ * This is an autobool; when set to AUTO, it uses AssumeReachable.
+ **/
+ int AssumeReachableIPv6;
int AuthoritativeDir; /**< Boolean: is this an authoritative directory? */
int V3AuthoritativeDir; /**< Boolean: is this an authoritative directory
* for version 3 directories? */
diff --git a/src/app/config/resolve_addr.c b/src/app/config/resolve_addr.c
index 9d1a8e0260..caca5a37d9 100644
--- a/src/app/config/resolve_addr.c
+++ b/src/app/config/resolve_addr.c
@@ -15,300 +15,682 @@
#include "feature/control/control_events.h"
+#include "lib/encoding/confline.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;
+/** Maximum "Address" statement allowed in our configuration. */
+#define MAX_CONFIG_ADDRESS 2
+
+/** Ease our life. Arrays containing state per address family. These are to
+ * add semantic to the code so we know what is accessed. */
+#define IDX_NULL 0 /* Index to zeroed address object. */
+#define IDX_IPV4 1 /* Index to AF_INET. */
+#define IDX_IPV6 2 /* Index to AF_INET6. */
+#define IDX_SIZE 3 /* How many indexes do we have. */
+
+/** Function in our address function table return one of these code. */
+typedef enum {
+ /* The address has been found. */
+ FN_RET_OK = 0,
+ /* The failure requirements were not met and thus it is recommended that the
+ * caller stops the search. */
+ FN_RET_BAIL = 1,
+ /* The address was not found or failure is transient so the caller should go
+ * to the next method. */
+ FN_RET_NEXT = 2,
+} fn_address_ret_t;
+
+/** Last resolved addresses. */
+static tor_addr_t last_resolved_addrs[IDX_SIZE];
+
+static inline int
+af_to_idx(const int family)
+{
+ switch (family) {
+ case AF_INET:
+ return IDX_IPV4;
+ case AF_INET6:
+ return IDX_IPV6;
+ default:
+ /* It wouldn't be safe to just die here with an assert but we can heavily
+ * scream with a bug. Return the index of the NULL address. */
+ tor_assert_nonfatal_unreached();
+ return IDX_NULL;
+ }
+}
-/** Accessor for last_resolved_addr from outside this file. */
-uint32_t
-get_last_resolved_addr(void)
+/** Copy the last resolved address of family into addr_out.
+ *
+ * If not last resolved address existed, the addr_out is a null address (use
+ * tor_addr_is_null()). */
+void
+resolved_addr_get_last(int family, tor_addr_t *addr_out)
{
- return last_resolved_addr;
+ tor_addr_copy(addr_out, &last_resolved_addrs[af_to_idx(family)]);
}
-/** Reset last_resolved_addr from outside this file. */
+/** Reset the last resolved address of family.
+ *
+ * This makes it null address. */
void
-reset_last_resolved_addr(void)
+resolved_addr_reset_last(int family)
{
- last_resolved_addr = 0;
+ tor_addr_make_null(&last_resolved_addrs[af_to_idx(family)], family);
}
-/**
- * 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
+/** Errors returned by address_can_be_used() in order for the caller to know
+ * why the address is denied or not. */
+#define ERR_DEFAULT_DIRAUTH -1 /* Using default authorities. */
+#define ERR_ADDRESS_IS_INTERNAL -2 /* IP is internal. */
+
+/** @brief Return true iff the given IP address can be used as a valid
+ * external resolved address.
+ *
+ * Two tests are done in this function:
+ * 1) If the address if NOT internal, it can be used.
+ * 2) If the address is internal and we have custom directory authorities
+ * configured then it can they be used. Important for testing networks.
+ *
+ * @param addr The IP address to validate.
+ * @param options Global configuration options.
+ * @param warn_severity Log level that should be used on error.
+ * @param explicit_ip Was the IP address explicitly given.
+ *
+ * @return Return 0 if it can be used. Return error code ERR_* found at the
+ * top of the file.
*/
-int
-resolve_my_address(int warn_severity, const or_options_t *options,
- uint32_t *addr_out,
- const char **method_out, char **hostname_out)
+static int
+address_can_be_used(const tor_addr_t *addr, const or_options_t *options,
+ int warn_severity, const bool explicit_ip)
{
- 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);
+
+ /* Public address, this is fine. */
+ if (!tor_addr_is_internal(addr, 0)) {
+ goto allow;
+ }
+
+ /* We have a private IP address. It is allowed only if we set custom
+ * directory authorities. */
+ if (using_default_dir_authorities(options)) {
+ log_fn(warn_severity, LD_CONFIG,
+ "Address '%s' is a private IP address. Tor relays that use "
+ "the default DirAuthorities must have public IP addresses.",
+ fmt_addr(addr));
+ return ERR_DEFAULT_DIRAUTH;
+ }
+
+ if (!explicit_ip) {
+ /* Even with custom directory authorities, only an explicit internal
+ * address is accepted. */
+ log_fn(warn_severity, LD_CONFIG,
+ "Address %s was resolved and thus not explicitly "
+ "set. Even if DirAuthorities are custom, this is "
+ "not allowed.", fmt_addr(addr));
+ return ERR_ADDRESS_IS_INTERNAL;
+ }
+
+ allow:
+ return 0;
+}
+
+/** @brief Get IP address from the given config line and for a specific address
+ * family.
+ *
+ * This can fail is more than two Address statement are found for the same
+ * address family. It also fails if no statement is found.
+ *
+ * @param options Global configuration options.
+ * @param warn_severity Log level that should be used on error.
+ * @param family IP address family. Only AF_INET and AF_INET6 are supported.
+ * @param method_out OUT: String denoting by which method the address was
+ * found. This is described in the control-spec.txt as
+ * actions for "STATUS_SERVER".
+ * @param hostname_out OUT: String containing the hostname gotten from the
+ * Address value if any.
+ * @param addr_out OUT: Tor address of the address found in the cline or
+ * resolved from the cline.
+ *
+ * @return Return 0 on success that is an address has been found or resolved
+ * successfully. Return error code ERR_* found at the top of the file.
+ */
+static fn_address_ret_t
+get_address_from_config(const or_options_t *options, int warn_severity,
+ int family, const char **method_out,
+ char **hostname_out, tor_addr_t *addr_out)
+{
+ int ret;
+ bool explicit_ip = false;
+ int num_valid_addr = 0;
+
+ tor_assert(options);
tor_assert(addr_out);
+ tor_assert(method_out);
+ tor_assert(hostname_out);
- /*
- * Step one: Fill in 'hostname' to be our best guess.
- */
+ /* Set them to NULL for safety reasons. */
+ *hostname_out = NULL;
+ *method_out = NULL;
- if (address && *address) {
- strlcpy(hostname, address, sizeof(hostname));
- log_debug(LD_CONFIG, "Trying configured Address '%s' as local hostname",
- 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);
+ log_debug(LD_CONFIG, "Attempting to get address from configuration");
+
+ if (!options->Address) {
+ log_info(LD_CONFIG, "No Address option found in configuration.");
+ /* No Address statement, inform caller to try next method. */
+ return FN_RET_NEXT;
}
- /*
- * 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.
- */
+ for (const config_line_t *cfg = options->Address; cfg != NULL;
+ cfg = cfg->next) {
+ int af;
+ tor_addr_t addr;
+
+ af = tor_addr_parse(&addr, cfg->value);
+ if (af == family) {
+ tor_addr_copy(addr_out, &addr);
+ *method_out = "CONFIGURED";
+ explicit_ip = true;
+ num_valid_addr++;
+ continue;
+ } else if (af != -1) {
+ /* Parsable address but just not the one from the family we want. Skip
+ * it so we don't attempt a resolve. */
+ continue;
+ }
- if (tor_inet_aton(hostname, &in) == 0) {
- /* then we have to resolve it */
- log_debug(LD_CONFIG, "Local hostname '%s' is DNS address. "
- "Trying to resolve to IP address.", hostname);
- 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));
- }
+ /* Not an IP address. Considering this value a hostname and attempting to
+ * do a DNS lookup. */
+ if (!tor_addr_lookup(cfg->value, family, &addr)) {
+ tor_addr_copy(addr_out, &addr);
+ *method_out = "RESOLVED";
+ if (*hostname_out) {
+ tor_free(*hostname_out);
}
+ *hostname_out = tor_strdup(cfg->value);
+ explicit_ip = false;
+ num_valid_addr++;
+ continue;
+ } else {
+ /* Hostname that can't be resolved, this is a fatal error. */
+ log_fn(warn_severity, LD_CONFIG,
+ "Could not resolve local Address '%s'. Failing.", cfg->value);
+ continue;
}
- } else {
- log_debug(LD_CONFIG, "Local hostname '%s' is already IP address, "
- "skipping DNS resolution", hostname);
- 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.
- */
+ if (!num_valid_addr) {
+ log_fn(warn_severity, LD_CONFIG,
+ "No Address option found for family %s in configuration.",
+ fmt_af_family(family));
+ /* No Address statement for family but one exists since Address is not
+ * NULL thus we have to stop now and not attempt to send back a guessed
+ * address. */
+ return FN_RET_BAIL;
+ }
- tor_addr_from_ipv4h(&myaddr,addr);
+ if (num_valid_addr >= MAX_CONFIG_ADDRESS) {
+ /* Too many Address for same family. This is a fatal error. */
+ log_fn(warn_severity, LD_CONFIG,
+ "Found %d Address statement of address family %s. "
+ "Only one is allowed.", num_valid_addr, fmt_af_family(family));
+ tor_free(*hostname_out);
+ return FN_RET_BAIL;
+ }
- addr_string = tor_dup_ip(addr);
- if (addr_string && 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;
- }
+ /* Great, we found an address. */
+ ret = address_can_be_used(addr_out, options, warn_severity, explicit_ip);
+ if (ret != 0) {
+ /* One of the requirement of this interface is if an internal Address is
+ * used, custom authorities must be defined else it is a fatal error.
+ * Furthermore, if the Address was resolved to an internal interface, we
+ * stop immediately. */
+ tor_free(*hostname_out);
+ return FN_RET_BAIL;
}
- /*
- * 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.
- */
+ /* Address can be used. We are done. */
+ log_fn(warn_severity, LD_CONFIG, "Address found in configuration: %s",
+ fmt_addr(addr_out));
+ return FN_RET_OK;
+}
- 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;
+/** @brief Get IP address from the local hostname by calling gethostbyname()
+ * and doing a DNS resolution on the hostname.
+ *
+ * @param options Global configuration options.
+ * @param warn_severity Log level that should be used on error.
+ * @param family IP address family. Only AF_INET and AF_INET6 are supported.
+ * @param method_out OUT: String denoting by which method the address was
+ * found. This is described in the control-spec.txt as
+ * actions for "STATUS_SERVER".
+ * @param hostname_out OUT: String containing the local hostname.
+ * @param addr_out OUT: Tor address resolved from the local hostname.
+ *
+ * @return Return 0 on success that is an address has been found and resolved
+ * successfully. Return error code ERR_* found at the top of the file.
+ */
+static fn_address_ret_t
+get_address_from_hostname(const or_options_t *options, int warn_severity,
+ int family, const char **method_out,
+ char **hostname_out, tor_addr_t *addr_out)
+{
+ int ret;
+ char hostname[256];
+
+ tor_assert(addr_out);
+ tor_assert(method_out);
+
+ /* Set them to NULL for safety reasons. */
+ *hostname_out = NULL;
+ *method_out = NULL;
+
+ log_debug(LD_CONFIG, "Attempting to get address from local hostname");
+
+ if (tor_gethostname(hostname, sizeof(hostname)) < 0) {
+ log_fn(warn_severity, LD_NET, "Error obtaining local hostname");
+ /* Unable to obtain the local hostname is a fatal error. */
+ return FN_RET_BAIL;
+ }
+ if (tor_addr_lookup(hostname, family, addr_out)) {
+ log_fn(warn_severity, LD_NET,
+ "Could not resolve local hostname '%s'. Failing.", hostname);
+ /* Unable to resolve, inform caller to try next method. */
+ return FN_RET_NEXT;
}
- *addr_out = addr;
- if (method_out)
- *method_out = method_used;
- if (hostname_out)
- *hostname_out = hostname_used ? tor_strdup(hostname_used) : NULL;
+ ret = address_can_be_used(addr_out, options, warn_severity, false);
+ if (ret == ERR_DEFAULT_DIRAUTH) {
+ /* Non custom authorities, inform caller to try next method. */
+ return FN_RET_NEXT;
+ } else if (ret == ERR_ADDRESS_IS_INTERNAL) {
+ /* Internal address is a fatal error. */
+ return FN_RET_BAIL;
+ }
- /*
- * 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.
- */
+ /* addr_out contains the address of the local hostname. */
+ *method_out = "GETHOSTNAME";
+ *hostname_out = tor_strdup(hostname);
+
+ /* Found it! */
+ log_fn(warn_severity, LD_CONFIG, "Address found from local hostname: %s",
+ fmt_addr(addr_out));
+ return FN_RET_OK;
+}
+
+/** @brief Get IP address from a network interface.
+ *
+ * @param options Global configuration options.
+ * @param warn_severity Log level that should be used on error.
+ * @param family IP address family. Only AF_INET and AF_INET6 are supported.
+ * @param method_out OUT: Always "INTERFACE" on success which is detailed in
+ * the control-spec.txt as actions for "STATUS_SERVER".
+ * @param hostname_out OUT: String containing the local hostname. For this
+ * function, it is always set to NULL.
+ * @param addr_out OUT: Tor address found attached to the interface.
+ *
+ * @return Return 0 on success that is an address has been found. Return
+ * error code ERR_* found at the top of the file.
+ */
+static fn_address_ret_t
+get_address_from_interface(const or_options_t *options, int warn_severity,
+ int family, const char **method_out,
+ char **hostname_out, tor_addr_t *addr_out)
+{
+ int ret;
+
+ tor_assert(method_out);
+ tor_assert(hostname_out);
+ tor_assert(addr_out);
+
+ /* Set them to NULL for safety reasons. */
+ *method_out = NULL;
+ *hostname_out = NULL;
+
+ log_debug(LD_CONFIG, "Attempting to get address from network interface");
+
+ if (get_interface_address6(warn_severity, family, addr_out) < 0) {
+ log_fn(warn_severity, LD_CONFIG,
+ "Could not get local interface IP address.");
+ /* Unable to get IP from interface. Inform caller to try next method. */
+ return FN_RET_NEXT;
+ }
+
+ ret = address_can_be_used(addr_out, options, warn_severity, false);
+ if (ret < 0) {
+ /* Unable to use address. Inform caller to try next method. */
+ return FN_RET_NEXT;
+ }
- if (last_resolved_addr && last_resolved_addr != *addr_out) {
+ *method_out = "INTERFACE";
+
+ /* Found it! */
+ log_fn(warn_severity, LD_CONFIG, "Address found from interface: %s",
+ fmt_addr(addr_out));
+ return FN_RET_OK;
+}
+
+/** @brief Get IP address from the ORPort (if any).
+ *
+ * @param options Global configuration options.
+ * @param warn_severity Log level that should be used on error.
+ * @param family IP address family. Only AF_INET and AF_INET6 are supported.
+ * @param method_out OUT: Always "CONFIGURED_ORPORT" on success which is
+ * detailed in the control-spec.txt as actions
+ * for "STATUS_SERVER".
+ * @param hostname_out OUT: String containing the ORPort hostname if any.
+ * @param addr_out OUT: Tor address found if any.
+ *
+ * @return Return 0 on success that is an address has been found. Return
+ * error code ERR_* found at the top of the file.
+ */
+static fn_address_ret_t
+get_address_from_orport(const or_options_t *options, int warn_severity,
+ int family, const char **method_out,
+ char **hostname_out, tor_addr_t *addr_out)
+{
+ int ret;
+ const tor_addr_t *addr;
+
+ tor_assert(method_out);
+ tor_assert(hostname_out);
+ tor_assert(addr_out);
+
+ log_debug(LD_CONFIG, "Attempting to get address from ORPort");
+
+ if (!options->ORPort_set) {
+ log_info(LD_CONFIG, "No ORPort found in configuration.");
+ /* No ORPort statement, inform caller to try next method. */
+ return FN_RET_NEXT;
+ }
+
+ /* Get ORPort for requested family. */
+ addr = get_orport_addr(family);
+ if (!addr) {
+ /* No address configured for the ORPort. Ignore. */
+ return FN_RET_NEXT;
+ }
+
+ /* We found the ORPort address. Just make sure it can be used. */
+ ret = address_can_be_used(addr, options, warn_severity, true);
+ if (ret < 0) {
+ /* Unable to use address. Inform caller to try next method. */
+ return FN_RET_NEXT;
+ }
+
+ /* Found it! */
+ *method_out = "CONFIGURED_ORPORT";
+ tor_addr_copy(addr_out, addr);
+
+ log_fn(warn_severity, LD_CONFIG, "Address found from ORPort: %s",
+ fmt_addr(addr_out));
+ return FN_RET_OK;
+}
+
+/** @brief Update the last resolved address cache using the given address.
+ *
+ * A log notice is emitted if the given address has changed from before. Not
+ * emitted on first resolve.
+ *
+ * Control port event "STATUS_SERVER" is emitted with the new information if
+ * it has changed.
+ *
+ * Finally, tor is notified that the IP address has changed.
+ *
+ * @param addr IP address to update the cache with.
+ * @param method_used By which method did we resolved it (for logging and
+ * control port).
+ * @param hostname_used Which hostname was used. If none were used, it is
+ * NULL. (for logging and control port).
+ */
+static void
+update_resolved_cache(const tor_addr_t *addr, const char *method_used,
+ const char *hostname_used)
+{
+ /** Have we done a first resolve. This is used to control logging. */
+ static bool have_resolved_once[IDX_SIZE] = { false, false, false };
+ bool *done_one_resolve;
+ bool have_hostname = false;
+ tor_addr_t *last_resolved;
+
+ tor_assert(addr);
+ tor_assert(method_used);
+
+ /* Do we have an hostname. */
+ have_hostname = (hostname_used != NULL);
+
+ int idx = af_to_idx(tor_addr_family(addr));
+ if (idx == IDX_NULL) {
+ /* Not suppose to happen and if it does, af_to_idx() screams loudly. */
+ return;
+ }
+
+ /* Get values from cache. */
+ done_one_resolve = &have_resolved_once[idx];
+ last_resolved = &last_resolved_addrs[idx];
+
+ /* Same address last resolved. Ignore. */
+ if (tor_addr_eq(last_resolved, addr)) {
+ return;
+ }
+
+ /* Don't log notice if this is the first resolve we do. */
+ if (*done_one_resolve) {
/* 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 : "");
+ fmt_addr(addr), method_used,
+ have_hostname ? " HOSTNAME=" : "",
+ have_hostname ? 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 : "");
+ /* Notify control port. */
+ control_event_server_status(LOG_NOTICE,
+ "EXTERNAL_ADDRESS ADDRESS=%s METHOD=%s%s%s",
+ fmt_addr(addr), method_used,
+ have_hostname ? " HOSTNAME=" : "",
+ have_hostname ? hostname_used : "");
+ /* Copy address to cache. */
+ tor_addr_copy(last_resolved, addr);
+ *done_one_resolve = true;
+}
+
+/** Address discovery function table. The order matters as in the first one is
+ * executed first and so on. */
+static fn_address_ret_t
+ (*fn_address_table[])(
+ const or_options_t *options, int warn_severity, int family,
+ const char **method_out, char **hostname_out, tor_addr_t *addr_out) =
+{
+ /* These functions are in order for our find address algorithm. */
+ get_address_from_config,
+ get_address_from_orport,
+ get_address_from_interface,
+ get_address_from_hostname,
+};
+/** Length of address table as in how many functions. */
+static const size_t fn_address_table_len = ARRAY_LENGTH(fn_address_table);
+
+/** @brief Attempt to find our IP address that can be used as our external
+ * reachable address.
+ *
+ * The following describe the algorithm to find an address. Each have
+ * specific conditions so read carefully.
+ *
+ * On success, true is returned and depending on how the address was found,
+ * the out parameters can have different values.
+ *
+ * On error, false is returned and out parameters are set to NULL.
+ *
+ * 1. Look at the configuration Address option.
+
+ * If Address is a public address, True is returned and addr_out is set
+ * with it, the method_out is set to "CONFIGURED" and hostname_out is set
+ * to NULL.
+ *
+ * If Address is an internal address but NO custom authorities are used,
+ * an error is returned.
+ *
+ * If Address is a hostname, that is it can't be converted to an address,
+ * it is resolved. On success, addr_out is set with the address,
+ * method_out is set to "RESOLVED" and hostname_out is set to the resolved
+ * hostname. On failure to resolve, an error is returned.
+ *
+ * If no given Address, fallback to the local hostname (see section 2).
+ *
+ * 2. Look at the network interface.
+ *
+ * Attempt to find the first public usable address from the list of
+ * network interface returned by the OS.
+ *
+ * On failure, we attempt to look at the local hostname (3).
+ *
+ * On success, addr_out is set with it, method_out is set to "INTERFACE"
+ * and hostname_out is set to NULL.
+ *
+ * 3. Look at the local hostname.
+ *
+ * If the local hostname resolves to a non internal address, addr_out is
+ * set with it, method_out is set to "GETHOSTNAME" and hostname_out is set
+ * to the resolved hostname.
+ *
+ * If a local hostname can NOT be found, an error is returned.
+ *
+ * If the local hostname resolves to an internal address, an error is
+ * returned.
+ *
+ * If the local hostname can NOT be resolved, an error is returned.
+ *
+ * @param options Global configuration options.
+ * @param family IP address family. Only AF_INET and AF_INET6 are supported.
+ * @param warn_severity Logging level.
+ * @param addr_out OUT: Set with the IP address found if any.
+ * @param method_out OUT: (optional) String denoting by which method the
+ * address was found. This is described in the
+ * control-spec.txt as actions for "STATUS_SERVER".
+ * @param hostname_out OUT: String containing the hostname if any was used.
+ * Only be set for "RESOLVED" and "GETHOSTNAME" methods.
+ * Else it is set to NULL.
+ *
+ * @return True if the address was found for the given family. False if not or
+ * on errors.
+ */
+bool
+find_my_address(const or_options_t *options, int family, int warn_severity,
+ tor_addr_t *addr_out, const char **method_out,
+ char **hostname_out)
+{
+ const char *method_used = NULL;
+ char *hostname_used = NULL;
+ tor_addr_t my_addr;
+
+ tor_assert(options);
+ tor_assert(addr_out);
+
+ /* Set them to NULL for safety reasons. */
+ if (method_out) *method_out = NULL;
+ if (hostname_out) *hostname_out = NULL;
+
+ /*
+ * Step 1: Discover address by attempting 3 different methods consecutively.
+ */
+
+ /* Go over the function table. They are in order. */
+ for (size_t idx = 0; idx < fn_address_table_len; idx++) {
+ fn_address_ret_t ret = fn_address_table[idx](options, warn_severity,
+ family, &method_used,
+ &hostname_used, &my_addr);
+ if (ret == FN_RET_BAIL) {
+ return false;
+ } else if (ret == FN_RET_OK) {
+ goto found;
+ }
+ tor_assert(ret == FN_RET_NEXT);
}
- last_resolved_addr = *addr_out;
+ /* We've exhausted our attempts. Failure. */
+ log_fn(warn_severity, LD_CONFIG, "Unable to find our IP address.");
+ return false;
+
+ found:
/*
- * And finally, clean up and return success.
+ * Step 2: Update last resolved address cache and inform the control port.
*/
+ update_resolved_cache(&my_addr, method_used, hostname_used);
- tor_free(addr_string);
- return 0;
+ if (method_out) {
+ *method_out = method_used;
+ }
+ if (hostname_out) {
+ *hostname_out = hostname_used;
+ } else {
+ tor_free(hostname_used);
+ }
+
+ tor_addr_copy(addr_out, &my_addr);
+ return true;
}
-/** Return true iff <b>addr</b> is judged to be on the same network as us, or
- * on a private network.
+/** @brief: Return true iff the given addr is judged to be local to our
+ * resolved address.
+ *
+ * This function is used to tell whether another address is 'remote' enough
+ * that we can trust it when it tells us that we are reachable, or that we
+ * have a certain address.
+ *
+ * The criterion to learn if the address is local are the following:
+ *
+ * 1. Internal address.
+ * 2. If EnforceDistinctSubnets is set then it is never local.
+ * 3. Network mask is compared. IPv4: /24 and IPv6 /48. This is different
+ * from the path selection that looks at /16 and /32 because we only
+ * want to learn here if the address is considered to come from the
+ * Internet basically.
+ *
+ * @param addr The address to test if local and also test against our resovled
+ * address.
+ *
+ * @return True iff address is considered local or else False.
*/
-MOCK_IMPL(int,
-is_local_addr, (const tor_addr_t *addr))
+MOCK_IMPL(bool,
+is_local_to_resolve_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);
+ const int family = tor_addr_family(addr);
+ const tor_addr_t *last_resolved_addr = &last_resolved_addrs[family];
+ /* Internal address is always local. */
+ if (tor_addr_is_internal(addr, 0)) {
+ return true;
+ }
+
+ /* Address is not local if we don't enforce subnet distinction. */
+ if (get_options()->EnforceDistinctSubnets == 0) {
+ return false;
+ }
+
+ switch (family) {
+ case AF_INET:
/* 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;
+ * find_my_address actually succeeds. For clients, it is likely that
+ * find_my_address will never be called at all. In those cases,
+ * last_resolved_addr_v4 will be 0, and so checking to see whether ip is
+ * on the same /24 as last_resolved_addrs[AF_INET] will be the same as
+ * checking whether it was on net 0, which is already done by
+ * tor_addr_is_internal. */
+ return tor_addr_compare_masked(addr, last_resolved_addr, 24,
+ CMP_SEMANTIC) == 0;
+ case AF_INET6:
+ /* Look at /48 because it is typically the smallest network in the global
+ * IPv6 routing tables, and it was previously the recommended per-customer
+ * network block. (See [RFC 6177: IPv6 End Site Address Assignment].) */
+ return tor_addr_compare_masked(addr, last_resolved_addr, 48,
+ CMP_SEMANTIC) == 0;
+ break;
+ default:
+ /* Unknown address type so not local. */
+ return false;
}
- return 0;
}
diff --git a/src/app/config/resolve_addr.h b/src/app/config/resolve_addr.h
index 3747546402..e6f8a72554 100644
--- a/src/app/config/resolve_addr.h
+++ b/src/app/config/resolve_addr.h
@@ -9,16 +9,22 @@
#ifndef TOR_CONFIG_RESOLVE_ADDR_H
#define TOR_CONFIG_RESOLVE_ADDR_H
+#include "app/config/config.h"
+#include "core/mainloop/connection.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);
+#define get_orport_addr(family) \
+ (get_first_advertised_addr_by_type_af(CONN_TYPE_OR_LISTENER, family))
+
+bool find_my_address(const or_options_t *options, int family,
+ int warn_severity, tor_addr_t *addr_out,
+ const char **method_out, char **hostname_out);
-uint32_t get_last_resolved_addr(void);
-void reset_last_resolved_addr(void);
+void resolved_addr_get_last(int family, tor_addr_t *addr_out);
+void resolved_addr_reset_last(int family);
-MOCK_DECL(int, is_local_addr, (const tor_addr_t *addr));
+MOCK_DECL(bool, is_local_to_resolve_addr, (const tor_addr_t *addr));
#ifdef RESOLVE_ADDR_PRIVATE
diff --git a/src/app/config/testnet.inc b/src/app/config/testnet.inc
index 907c35f97c..605943d80b 100644
--- a/src/app/config/testnet.inc
+++ b/src/app/config/testnet.inc
@@ -2,7 +2,6 @@
// for 'TestingTorNetwork' in 'doc/tor.1.txt'
{ "DirAllowPrivateAddresses", "1" },
{ "EnforceDistinctSubnets", "0" },
-{ "AssumeReachable", "1" },
{ "AuthDirMaxServersPerAddr", "0" },
{ "ClientBootstrapConsensusAuthorityDownloadInitialDelay", "0" },
{ "ClientBootstrapConsensusFallbackDownloadInitialDelay", "0" },
diff --git a/src/app/main/main.c b/src/app/main/main.c
index dc39611f98..89ba787422 100644
--- a/src/app/main/main.c
+++ b/src/app/main/main.c
@@ -775,12 +775,14 @@ do_dump_config(void)
if (!strcmp(arg, "short")) {
how = OPTIONS_DUMP_MINIMAL;
} else if (!strcmp(arg, "non-builtin")) {
- how = OPTIONS_DUMP_DEFAULTS;
+ // Deprecated since 0.4.5.1-alpha.
+ fprintf(stderr, "'non-builtin' is deprecated; use 'short' instead.\n");
+ how = OPTIONS_DUMP_MINIMAL;
} else if (!strcmp(arg, "full")) {
how = OPTIONS_DUMP_ALL;
} else {
fprintf(stderr, "No valid argument to --dump-config found!\n");
- fprintf(stderr, "Please select 'short', 'non-builtin', or 'full'.\n");
+ fprintf(stderr, "Please select 'short' or 'full'.\n");
return -1;
}
@@ -795,8 +797,7 @@ do_dump_config(void)
static void
init_addrinfo(void)
{
- if (! server_mode(get_options()) ||
- (get_options()->Address && strlen(get_options()->Address) > 0)) {
+ if (! server_mode(get_options()) || get_options()->Address) {
/* We don't need to seed our own hostname, because we won't be calling
* resolve_my_address on it.
*/
@@ -1054,12 +1055,14 @@ sandbox_init_filter(void)
OPEN_DATADIR("approved-routers");
OPEN_DATADIR_SUFFIX("fingerprint", ".tmp");
+ OPEN_DATADIR_SUFFIX("fingerprint-ed25519", ".tmp");
OPEN_DATADIR_SUFFIX("hashed-fingerprint", ".tmp");
OPEN_DATADIR_SUFFIX("router-stability", ".tmp");
OPEN("/etc/resolv.conf");
RENAME_SUFFIX("fingerprint", ".tmp");
+ RENAME_SUFFIX("fingerprint-ed25519", ".tmp");
RENAME_KEYDIR_SUFFIX("secret_onion_key_ntor", ".tmp");
RENAME_KEYDIR_SUFFIX("secret_id_key", ".tmp");
diff --git a/src/core/crypto/onion_crypto.c b/src/core/crypto/onion_crypto.c
index 69b4dc40aa..1f34be1cc1 100644
--- a/src/core/crypto/onion_crypto.c
+++ b/src/core/crypto/onion_crypto.c
@@ -31,7 +31,7 @@
**/
#include "core/or/or.h"
-#include "core/or/circuitbuild.h"
+#include "core/or/extendinfo.h"
#include "core/crypto/onion_crypto.h"
#include "core/crypto/onion_fast.h"
#include "core/crypto/onion_ntor.h"
diff --git a/src/core/mainloop/connection.c b/src/core/mainloop/connection.c
index 792cdbf686..af823335a8 100644
--- a/src/core/mainloop/connection.c
+++ b/src/core/mainloop/connection.c
@@ -4871,7 +4871,7 @@ client_check_address_changed(tor_socket_t sock)
smartlist_clear(outgoing_addrs);
smartlist_add(outgoing_addrs, tor_memdup(&out_addr, sizeof(tor_addr_t)));
/* We'll need to resolve ourselves again. */
- reset_last_resolved_addr();
+ resolved_addr_reset_last(AF_INET);
/* Okay, now change our keys. */
ip_address_changed(1);
}
diff --git a/src/core/or/channelpadding.c b/src/core/or/channelpadding.c
index be2ce78a17..c754a58c42 100644
--- a/src/core/or/channelpadding.c
+++ b/src/core/or/channelpadding.c
@@ -90,7 +90,7 @@ static int consensus_nf_pad_single_onion;
* for every single connection, every second.
*/
void
-channelpadding_new_consensus_params(networkstatus_t *ns)
+channelpadding_new_consensus_params(const networkstatus_t *ns)
{
#define DFLT_NETFLOW_INACTIVE_KEEPALIVE_LOW 1500
#define DFLT_NETFLOW_INACTIVE_KEEPALIVE_HIGH 9500
diff --git a/src/core/or/channelpadding.h b/src/core/or/channelpadding.h
index d1c7192ffd..9246988cdc 100644
--- a/src/core/or/channelpadding.h
+++ b/src/core/or/channelpadding.h
@@ -37,7 +37,6 @@ int channelpadding_send_enable_command(channel_t *chan, uint16_t low_timeout,
int channelpadding_get_circuits_available_timeout(void);
unsigned int channelpadding_get_channel_idle_timeout(const channel_t *, int);
-void channelpadding_new_consensus_params(networkstatus_t *ns);
+void channelpadding_new_consensus_params(const networkstatus_t *ns);
#endif /* !defined(TOR_CHANNELPADDING_H) */
-
diff --git a/src/core/or/channeltls.c b/src/core/or/channeltls.c
index 395fbf3455..a51fbf1dd6 100644
--- a/src/core/or/channeltls.c
+++ b/src/core/or/channeltls.c
@@ -63,10 +63,10 @@
#include "trunnel/channelpadding_negotiation.h"
#include "trunnel/netinfo.h"
#include "core/or/channelpadding.h"
+#include "core/or/extendinfo.h"
#include "core/or/cell_st.h"
#include "core/or/cell_queue_st.h"
-#include "core/or/extend_info_st.h"
#include "core/or/or_connection_st.h"
#include "core/or/or_handshake_certs_st.h"
#include "core/or/or_handshake_state_st.h"
@@ -203,7 +203,7 @@ channel_tls_connect(const tor_addr_t *addr, uint16_t port,
tlschan,
(chan->global_identifier));
- if (is_local_addr(addr)) {
+ if (is_local_to_resolve_addr(addr)) {
log_debug(LD_CHANNEL,
"Marking new outgoing channel %"PRIu64 " at %p as local",
(chan->global_identifier), chan);
@@ -340,7 +340,7 @@ channel_tls_handle_incoming(or_connection_t *orconn)
tlschan->conn = orconn;
orconn->chan = tlschan;
- if (is_local_addr(&(TO_CONN(orconn)->addr))) {
+ if (is_local_to_resolve_addr(&(TO_CONN(orconn)->addr))) {
log_debug(LD_CHANNEL,
"Marking new incoming channel %"PRIu64 " at %p as local",
(chan->global_identifier), chan);
@@ -702,9 +702,9 @@ channel_tls_matches_extend_info_method(channel_t *chan,
return 0;
}
- return (tor_addr_eq(&(extend_info->addr),
- &(TO_CONN(tlschan->conn)->addr)) &&
- (extend_info->port == TO_CONN(tlschan->conn)->port));
+ return extend_info_has_orport(extend_info,
+ &TO_CONN(tlschan->conn)->addr,
+ TO_CONN(tlschan->conn)->port);
}
/**
@@ -1353,7 +1353,7 @@ channel_tls_update_marks(or_connection_t *conn)
chan = TLS_CHAN_TO_BASE(conn->chan);
- if (is_local_addr(&(TO_CONN(conn)->addr))) {
+ if (is_local_to_resolve_addr(&(TO_CONN(conn)->addr))) {
if (!channel_is_local(chan)) {
log_debug(LD_CHANNEL,
"Marking channel %"PRIu64 " at %p as local",
diff --git a/src/core/or/circuit_st.h b/src/core/or/circuit_st.h
index 4baafb1848..35d214ce08 100644
--- a/src/core/or/circuit_st.h
+++ b/src/core/or/circuit_st.h
@@ -238,6 +238,12 @@ struct circuit_t {
* Each element of this array corresponds to a different padding machine,
* and we can have up to CIRCPAD_MAX_MACHINES such machines. */
struct circpad_machine_runtime_t *padding_info[CIRCPAD_MAX_MACHINES];
+
+ /** padding_machine_ctr increments each time a new padding machine
+ * is negotiated. It is used for shutdown conditions, to ensure
+ * that STOP commands actually correspond to the current machine,
+ * and not a previous one. */
+ uint32_t padding_machine_ctr;
};
#endif /* !defined(CIRCUIT_ST_H) */
diff --git a/src/core/or/circuitbuild.c b/src/core/or/circuitbuild.c
index 83ce9f882b..cef70e3e76 100644
--- a/src/core/or/circuitbuild.c
+++ b/src/core/or/circuitbuild.c
@@ -45,6 +45,7 @@
#include "core/or/command.h"
#include "core/or/connection_edge.h"
#include "core/or/connection_or.h"
+#include "core/or/extendinfo.h"
#include "core/or/onion.h"
#include "core/or/ocirc_event.h"
#include "core/or/policies.h"
@@ -78,9 +79,6 @@
#include "feature/nodelist/node_st.h"
#include "core/or/or_circuit_st.h"
#include "core/or/origin_circuit_st.h"
-#include "feature/nodelist/microdesc_st.h"
-#include "feature/nodelist/routerinfo_st.h"
-#include "feature/nodelist/routerstatus_st.h"
static int circuit_send_first_onion_skin(origin_circuit_t *circ);
static int circuit_build_no_more_hops(origin_circuit_t *circ);
@@ -96,13 +94,17 @@ static const node_t *choose_good_middle_server(uint8_t purpose,
* callbacks.
*/
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_connect_for_circuit,(const extend_info_t *ei))
{
channel_t *chan;
- chan = channel_connect(addr, port, id_digest, ed_id);
+ const tor_addr_port_t *orport = extend_info_pick_orport(ei);
+ if (!orport)
+ return NULL;
+ const char *id_digest = ei->identity_digest;
+ const ed25519_public_key_t *ed_id = &ei->ed_identity;
+
+ chan = channel_connect(&orport->addr, orport->port, id_digest, ed_id);
if (chan) command_setup_channel(chan);
return chan;
@@ -439,7 +441,8 @@ onion_populate_cpath(origin_circuit_t *circ)
/** Create and return a new origin circuit. Initialize its purpose and
* build-state based on our arguments. The <b>flags</b> argument is a
- * bitfield of CIRCLAUNCH_* flags. */
+ * bitfield of CIRCLAUNCH_* flags, see circuit_launch_by_extend_info() for
+ * more details. */
origin_circuit_t *
origin_circuit_init(uint8_t purpose, int flags)
{
@@ -455,13 +458,16 @@ origin_circuit_init(uint8_t purpose, int flags)
((flags & CIRCLAUNCH_NEED_CAPACITY) ? 1 : 0);
circ->build_state->is_internal =
((flags & CIRCLAUNCH_IS_INTERNAL) ? 1 : 0);
+ circ->build_state->is_ipv6_selftest =
+ ((flags & CIRCLAUNCH_IS_IPV6_SELFTEST) ? 1 : 0);
circ->base_.purpose = purpose;
return circ;
}
-/** Build a new circuit for <b>purpose</b>. If <b>exit</b>
- * is defined, then use that as your exit router, else choose a suitable
- * exit node.
+/** Build a new circuit for <b>purpose</b>. If <b>exit</b> is defined, then use
+ * that as your exit router, else choose a suitable exit node. The <b>flags</b>
+ * argument is a bitfield of CIRCLAUNCH_* flags, see
+ * circuit_launch_by_extend_info() for more details.
*
* Also launch a connection to the first OR in the chosen path, if
* it's not open already.
@@ -546,7 +552,7 @@ circuit_handle_first_hop(origin_circuit_t *circ)
* - the address is internal, and
* - we're not connecting to a configured bridge, and
* - we're not configured to allow extends to private addresses. */
- if (tor_addr_is_internal(&firsthop->extend_info->addr, 0) &&
+ if (extend_info_any_orport_addr_is_internal(firsthop->extend_info) &&
!extend_info_is_a_configured_bridge(firsthop->extend_info) &&
!options->ExtendAllowPrivateAddresses) {
log_fn(LOG_PROTOCOL_WARN, LD_PROTOCOL,
@@ -555,19 +561,15 @@ circuit_handle_first_hop(origin_circuit_t *circ)
}
/* now see if we're already connected to the first OR in 'route' */
- log_debug(LD_CIRC,"Looking for firsthop '%s'",
- fmt_addrport(&firsthop->extend_info->addr,
- firsthop->extend_info->port));
-
- /* 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);
+ const tor_addr_port_t *orport4 =
+ extend_info_get_orport(firsthop->extend_info, AF_INET);
+ const tor_addr_port_t *orport6 =
+ extend_info_get_orport(firsthop->extend_info, AF_INET6);
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,
+ orport4 ? &orport4->addr : NULL,
+ orport6 ? &orport6->addr : NULL,
&msg,
&should_launch);
@@ -579,11 +581,7 @@ circuit_handle_first_hop(origin_circuit_t *circ)
circ->base_.n_hop = extend_info_dup(firsthop->extend_info);
if (should_launch) {
- n_chan = channel_connect_for_circuit(
- &firsthop->extend_info->addr,
- firsthop->extend_info->port,
- firsthop->extend_info->identity_digest,
- &firsthop->extend_info->ed_identity);
+ n_chan = channel_connect_for_circuit(firsthop->extend_info);
if (!n_chan) { /* connect failed, forget the whole thing */
log_info(LD_CIRC,"connect to firsthop failed. Closing.");
return -END_CIRC_REASON_CONNECTFAILED;
@@ -601,7 +599,8 @@ circuit_handle_first_hop(origin_circuit_t *circ)
tor_assert(!circ->base_.n_hop);
circ->base_.n_chan = n_chan;
circuit_chan_publish(circ, n_chan);
- log_debug(LD_CIRC,"Conn open. Delivering first onion skin.");
+ log_debug(LD_CIRC,"Conn open for %s. Delivering first onion skin.",
+ safe_str_client(extend_info_describe(firsthop->extend_info)));
if ((err_reason = circuit_send_next_onion_skin(circ)) < 0) {
log_info(LD_CIRC,"circuit_send_next_onion_skin failed.");
circ->base_.n_chan = NULL;
@@ -1050,8 +1049,8 @@ circuit_build_no_more_hops(origin_circuit_t *circ)
control_event_bootstrap(BOOTSTRAP_STATUS_DONE, 0);
control_event_client_status(LOG_NOTICE, "CIRCUIT_ESTABLISHED");
clear_broken_connection_map(1);
- if (server_mode(options) && !check_whether_orport_reachable(options)) {
- inform_testing_reachability();
+ if (server_mode(options) &&
+ !router_all_orports_seem_reachable(options)) {
router_do_reachability_checks(1, 1);
}
}
@@ -1075,23 +1074,40 @@ circuit_send_intermediate_onion_skin(origin_circuit_t *circ,
{
int len;
extend_cell_t ec;
+ /* Relays and bridges can send IPv6 extends. But for clients, it's an
+ * obvious version distinguisher. */
+ const bool include_ipv6 = server_mode(get_options());
memset(&ec, 0, sizeof(ec));
+ tor_addr_make_unspec(&ec.orport_ipv4.addr);
+ tor_addr_make_unspec(&ec.orport_ipv6.addr);
log_debug(LD_CIRC,"starting to send subsequent skin.");
- if (tor_addr_family(&hop->extend_info->addr) != AF_INET) {
- log_warn(LD_BUG, "Trying to extend to a non-IPv4 address.");
- return - END_CIRC_REASON_INTERNAL;
- }
-
circuit_pick_extend_handshake(&ec.cell_type,
&ec.create_cell.cell_type,
&ec.create_cell.handshake_type,
hop->extend_info);
- tor_addr_copy(&ec.orport_ipv4.addr, &hop->extend_info->addr);
- ec.orport_ipv4.port = hop->extend_info->port;
- tor_addr_make_unspec(&ec.orport_ipv6.addr);
+ const tor_addr_port_t *orport4 =
+ extend_info_get_orport(hop->extend_info, AF_INET);
+ const tor_addr_port_t *orport6 =
+ extend_info_get_orport(hop->extend_info, AF_INET6);
+ int n_addrs_set = 0;
+ if (orport4) {
+ tor_addr_copy(&ec.orport_ipv4.addr, &orport4->addr);
+ ec.orport_ipv4.port = orport4->port;
+ ++n_addrs_set;
+ }
+ if (orport6 && include_ipv6) {
+ tor_addr_copy(&ec.orport_ipv6.addr, &orport6->addr);
+ ec.orport_ipv6.port = orport6->port;
+ ++n_addrs_set;
+ }
+
+ if (n_addrs_set == 0) {
+ log_warn(LD_BUG, "No supported address family found in extend_info.");
+ return - END_CIRC_REASON_INTERNAL;
+ }
memcpy(ec.node_id, hop->extend_info->identity_digest, DIGEST_LEN);
/* Set the ED25519 identity too -- it will only get included
* in the extend2 cell if we're configured to use it, though. */
@@ -1539,7 +1555,23 @@ choose_good_exit_server_general(router_crn_flags_t flags)
const node_t *selected_node=NULL;
const int need_uptime = (flags & CRN_NEED_UPTIME) != 0;
const int need_capacity = (flags & CRN_NEED_CAPACITY) != 0;
- const int direct_conn = (flags & CRN_DIRECT_CONN) != 0;
+
+ /* We should not require guard flags on exits. */
+ IF_BUG_ONCE(flags & CRN_NEED_GUARD)
+ return NULL;
+
+ /* We reject single-hop exits for all node positions. */
+ IF_BUG_ONCE(flags & CRN_DIRECT_CONN)
+ return NULL;
+
+ /* This isn't the function for picking rendezvous nodes. */
+ IF_BUG_ONCE(flags & CRN_RENDEZVOUS_V3)
+ return NULL;
+
+ /* We only want exits to extend if we cannibalize the circuit.
+ * But we don't require IPv6 extends yet. */
+ IF_BUG_ONCE(flags & CRN_INITIATE_IPV6_EXTEND)
+ return NULL;
connections = get_connection_array();
@@ -1572,19 +1604,14 @@ choose_good_exit_server_general(router_crn_flags_t flags)
*/
continue;
}
- if (!node_has_preferred_descriptor(node, direct_conn)) {
+ if (!router_can_choose_node(node, flags)) {
n_supported[i] = -1;
continue;
}
- if (!node->is_running || node->is_bad_exit) {
+ if (node->is_bad_exit) {
n_supported[i] = -1;
continue; /* skip routers that are known to be down or bad exits */
}
- if (node_get_purpose(node) != ROUTER_PURPOSE_GENERAL) {
- /* never pick a non-general node as a random exit. */
- n_supported[i] = -1;
- continue;
- }
if (routerset_contains_node(options->ExcludeExitNodesUnion_, node)) {
n_supported[i] = -1;
continue; /* user asked us not to use it, no matter what */
@@ -1594,27 +1621,6 @@ choose_good_exit_server_general(router_crn_flags_t flags)
n_supported[i] = -1;
continue; /* not one of our chosen exit nodes */
}
-
- if (node_is_unreliable(node, need_uptime, need_capacity, 0)) {
- n_supported[i] = -1;
- continue; /* skip routers that are not suitable. Don't worry if
- * this makes us reject all the possible routers: if so,
- * we'll retry later in this function with need_update and
- * need_capacity set to 0. */
- }
- if (!(node->is_valid)) {
- /* if it's invalid and we don't want it */
- n_supported[i] = -1;
-// log_fn(LOG_DEBUG,"Skipping node %s (index %d) -- invalid router.",
-// router->nickname, i);
- continue; /* skip invalid routers */
- }
- /* We do not allow relays that allow single hop exits by default. Option
- * was deprecated in 0.2.9.2-alpha and removed in 0.3.1.0-alpha. */
- if (node_allows_single_hop_exits(node)) {
- n_supported[i] = -1;
- continue;
- }
if (node_exit_policy_rejects_all(node)) {
n_supported[i] = -1;
// log_fn(LOG_DEBUG,"Skipping node %s (index %d) -- it rejects all.",
@@ -1771,13 +1777,7 @@ pick_restricted_middle_node(router_crn_flags_t flags,
tor_assert(pick_from);
/* Add all running nodes to all_live_nodes */
- router_add_running_nodes_to_smartlist(all_live_nodes,
- (flags & CRN_NEED_UPTIME) != 0,
- (flags & CRN_NEED_CAPACITY) != 0,
- (flags & CRN_NEED_GUARD) != 0,
- (flags & CRN_NEED_DESC) != 0,
- (flags & CRN_PREF_ADDR) != 0,
- (flags & CRN_DIRECT_CONN) != 0);
+ router_add_running_nodes_to_smartlist(all_live_nodes, flags);
/* Filter all_live_nodes to only add live *and* whitelisted middles
* to the list whitelisted_live_middles. */
@@ -1957,6 +1957,43 @@ warn_if_last_router_excluded(origin_circuit_t *circ,
return;
}
+/* Return a set of generic CRN_* flags based on <b>state</b>.
+ *
+ * Called for every position in the circuit. */
+STATIC int
+cpath_build_state_to_crn_flags(const cpath_build_state_t *state)
+{
+ router_crn_flags_t flags = 0;
+ /* These flags apply to entry, middle, and exit nodes.
+ * If a flag only applies to a specific position, it should be checked in
+ * that function. */
+ if (state->need_uptime)
+ flags |= CRN_NEED_UPTIME;
+ if (state->need_capacity)
+ flags |= CRN_NEED_CAPACITY;
+ return flags;
+}
+
+/* Return the CRN_INITIATE_IPV6_EXTEND flag, based on <b>state</b> and
+ * <b>cur_len</b>.
+ *
+ * Only called for middle nodes (for now). Must not be called on single-hop
+ * circuits. */
+STATIC int
+cpath_build_state_to_crn_ipv6_extend_flag(const cpath_build_state_t *state,
+ int cur_len)
+{
+ IF_BUG_ONCE(state->desired_path_len < 2)
+ return 0;
+
+ /* The last node is the relay doing the self-test. So we want to extend over
+ * IPv6 from the second-last node. */
+ if (state->is_ipv6_selftest && cur_len == state->desired_path_len - 2)
+ return CRN_INITIATE_IPV6_EXTEND;
+ else
+ return 0;
+}
+
/** Decide a suitable length for circ's cpath, and pick an exit
* router (or use <b>exit</b> if provided). Store these in the
* cpath.
@@ -1990,14 +2027,13 @@ onion_pick_cpath_exit(origin_circuit_t *circ, extend_info_t *exit_ei,
exit_ei = extend_info_dup(exit_ei);
} else { /* we have to decide one */
router_crn_flags_t flags = CRN_NEED_DESC;
- if (state->need_uptime)
- flags |= CRN_NEED_UPTIME;
- if (state->need_capacity)
- flags |= CRN_NEED_CAPACITY;
- if (is_hs_v3_rp_circuit)
- flags |= CRN_RENDEZVOUS_V3;
+ flags |= cpath_build_state_to_crn_flags(state);
+ /* Some internal exits are one hop, for example directory connections.
+ * (Guards are always direct, middles are never direct.) */
if (state->onehop_tunnel)
flags |= CRN_DIRECT_CONN;
+ if (is_hs_v3_rp_circuit)
+ flags |= CRN_RENDEZVOUS_V3;
const node_t *node =
choose_good_exit_server(circ, flags, state->is_internal);
if (!node) {
@@ -2059,32 +2095,27 @@ circuit_extend_to_new_exit(origin_circuit_t *circ, extend_info_t *exit_ei)
return 0;
}
-/** Return the number of routers in <b>routers</b> that are currently up
- * and available for building circuits through.
+/** Return the number of routers in <b>nodes</b> that are currently up and
+ * available for building circuits through.
*
- * (Note that this function may overcount or undercount, if we have
- * descriptors that are not the type we would prefer to use for some
- * particular router. See bug #25885.)
+ * If <b>direct</b> is true, only count nodes that are suitable for direct
+ * connections. Counts nodes regardless of whether their addresses are
+ * preferred.
*/
MOCK_IMPL(STATIC int,
count_acceptable_nodes, (const smartlist_t *nodes, int direct))
{
int num=0;
+ int flags = CRN_NEED_DESC;
+
+ if (direct)
+ flags |= CRN_DIRECT_CONN;
SMARTLIST_FOREACH_BEGIN(nodes, const node_t *, node) {
// log_debug(LD_CIRC,
-// "Contemplating whether router %d (%s) is a new option.",
-// i, r->nickname);
- if (! node->is_running)
-// log_debug(LD_CIRC,"Nope, the directory says %d is not running.",i);
- continue;
- if (! node->is_valid)
-// log_debug(LD_CIRC,"Nope, the directory says %d is not valid.",i);
- continue;
- if (! node_has_preferred_descriptor(node, direct))
- continue;
- /* The node has a descriptor, so we can just check the ntor key directly */
- if (!node_has_curve25519_onion_key(node))
+ // "Contemplating whether router %d (%s) is a new option.",
+ // i, r->nickname);
+ if (!router_can_choose_node(node, flags))
continue;
++num;
} SMARTLIST_FOREACH_END(node);
@@ -2278,10 +2309,8 @@ choose_good_middle_server(uint8_t purpose,
excluded = build_middle_exclude_list(purpose, state, head, cur_len);
- if (state->need_uptime)
- flags |= CRN_NEED_UPTIME;
- if (state->need_capacity)
- flags |= CRN_NEED_CAPACITY;
+ flags |= cpath_build_state_to_crn_flags(state);
+ flags |= cpath_build_state_to_crn_ipv6_extend_flag(state, cur_len);
/** If a hidden service circuit wants a specific middle node, pin it. */
if (middle_node_must_be_vanguard(options, purpose, cur_len)) {
@@ -2357,10 +2386,7 @@ choose_good_entry_server(uint8_t purpose, cpath_build_state_t *state,
}
if (state) {
- if (state->need_uptime)
- flags |= CRN_NEED_UPTIME;
- if (state->need_capacity)
- flags |= CRN_NEED_CAPACITY;
+ flags |= cpath_build_state_to_crn_flags(state);
}
choice = router_choose_random_node(excluded, options->ExcludeNodes, flags);
@@ -2429,143 +2455,6 @@ onion_extend_cpath(origin_circuit_t *circ)
return 0;
}
-/** Allocate a new extend_info object based on the various arguments. */
-extend_info_t *
-extend_info_new(const char *nickname,
- const char *rsa_id_digest,
- const ed25519_public_key_t *ed_id,
- crypto_pk_t *onion_key,
- const curve25519_public_key_t *ntor_key,
- const tor_addr_t *addr, uint16_t port)
-{
- extend_info_t *info = tor_malloc_zero(sizeof(extend_info_t));
- memcpy(info->identity_digest, rsa_id_digest, DIGEST_LEN);
- if (ed_id && !ed25519_public_key_is_zero(ed_id))
- memcpy(&info->ed_identity, ed_id, sizeof(ed25519_public_key_t));
- if (nickname)
- strlcpy(info->nickname, nickname, sizeof(info->nickname));
- if (onion_key)
- info->onion_key = crypto_pk_dup_key(onion_key);
- if (ntor_key)
- memcpy(&info->curve25519_onion_key, ntor_key,
- sizeof(curve25519_public_key_t));
- tor_addr_copy(&info->addr, addr);
- info->port = port;
- return info;
-}
-
-/** Allocate and return a new extend_info that can be used to build a
- * circuit to or through the node <b>node</b>. Use the primary address
- * of the node (i.e. its IPv4 address) unless
- * <b>for_direct_connect</b> is true, in which case the preferred
- * address is used instead. May return NULL if there is not enough
- * info about <b>node</b> to extend to it--for example, if the preferred
- * routerinfo_t or microdesc_t is missing, or if for_direct_connect is
- * true and none of the node's addresses is allowed by tor's firewall
- * and IP version config.
- **/
-extend_info_t *
-extend_info_from_node(const node_t *node, int for_direct_connect)
-{
- crypto_pk_t *rsa_pubkey = NULL;
- extend_info_t *info = NULL;
- tor_addr_port_t ap;
- int valid_addr = 0;
-
- if (!node_has_preferred_descriptor(node, for_direct_connect)) {
- return NULL;
- }
-
- /* Choose a preferred address first, but fall back to an allowed address. */
- if (for_direct_connect)
- fascist_firewall_choose_address_node(node, FIREWALL_OR_CONNECTION, 0, &ap);
- else {
- node_get_prim_orport(node, &ap);
- }
- valid_addr = tor_addr_port_is_valid_ap(&ap, 0);
-
- if (valid_addr)
- log_debug(LD_CIRC, "using %s for %s",
- fmt_addrport(&ap.addr, ap.port),
- node->ri ? node->ri->nickname : node->rs->nickname);
- else
- log_warn(LD_CIRC, "Could not choose valid address for %s",
- node->ri ? node->ri->nickname : node->rs->nickname);
-
- /* Every node we connect or extend to must support ntor */
- if (!node_has_curve25519_onion_key(node)) {
- log_fn(LOG_PROTOCOL_WARN, LD_CIRC,
- "Attempted to create extend_info for a node that does not support "
- "ntor: %s", node_describe(node));
- return NULL;
- }
-
- const ed25519_public_key_t *ed_pubkey = NULL;
-
- /* Don't send the ed25519 pubkey unless the target node actually supports
- * authenticating with it. */
- if (node_supports_ed25519_link_authentication(node, 0)) {
- log_info(LD_CIRC, "Including Ed25519 ID for %s", node_describe(node));
- ed_pubkey = node_get_ed25519_id(node);
- } else if (node_get_ed25519_id(node)) {
- log_info(LD_CIRC, "Not including the ed25519 ID for %s, since it won't "
- "be able to authenticate it.",
- node_describe(node));
- }
-
- /* Retrieve the curve25519 pubkey. */
- const curve25519_public_key_t *curve_pubkey =
- node_get_curve25519_onion_key(node);
- rsa_pubkey = node_get_rsa_onion_key(node);
-
- if (valid_addr && node->ri) {
- info = extend_info_new(node->ri->nickname,
- node->identity,
- ed_pubkey,
- rsa_pubkey,
- curve_pubkey,
- &ap.addr,
- ap.port);
- } else if (valid_addr && node->rs && node->md) {
- info = extend_info_new(node->rs->nickname,
- node->identity,
- ed_pubkey,
- rsa_pubkey,
- curve_pubkey,
- &ap.addr,
- ap.port);
- }
-
- crypto_pk_free(rsa_pubkey);
- return info;
-}
-
-/** Release storage held by an extend_info_t struct. */
-void
-extend_info_free_(extend_info_t *info)
-{
- if (!info)
- return;
- crypto_pk_free(info->onion_key);
- tor_free(info);
-}
-
-/** Allocate and return a new extend_info_t with the same contents as
- * <b>info</b>. */
-extend_info_t *
-extend_info_dup(extend_info_t *info)
-{
- extend_info_t *newinfo;
- tor_assert(info);
- newinfo = tor_malloc(sizeof(extend_info_t));
- memcpy(newinfo, info, sizeof(extend_info_t));
- if (info->onion_key)
- newinfo->onion_key = crypto_pk_dup_key(info->onion_key);
- else
- newinfo->onion_key = NULL;
- return newinfo;
-}
-
/** Return the node_t for the chosen exit router in <b>state</b>.
* If there is no chosen exit, or if we don't know the node_t for
* the chosen exit, return NULL.
@@ -2601,43 +2490,6 @@ build_state_get_exit_nickname(cpath_build_state_t *state)
return state->chosen_exit->nickname;
}
-/** Return true iff the given address can be used to extend to. */
-int
-extend_info_addr_is_allowed(const tor_addr_t *addr)
-{
- tor_assert(addr);
-
- /* Check if we have a private address and if we can extend to it. */
- if ((tor_addr_is_internal(addr, 0) || tor_addr_is_multicast(addr)) &&
- !get_options()->ExtendAllowPrivateAddresses) {
- goto disallow;
- }
- /* Allowed! */
- return 1;
- disallow:
- return 0;
-}
-
-/* Does ei have a valid TAP key? */
-int
-extend_info_supports_tap(const extend_info_t* ei)
-{
- tor_assert(ei);
- /* Valid TAP keys are not NULL */
- return ei->onion_key != NULL;
-}
-
-/* Does ei have a valid ntor key? */
-int
-extend_info_supports_ntor(const extend_info_t* ei)
-{
- tor_assert(ei);
- /* Valid ntor keys have at least one non-zero byte */
- return !fast_mem_is_zero(
- (const char*)ei->curve25519_onion_key.public_key,
- CURVE25519_PUBKEY_LEN);
-}
-
/* Is circuit purpose allowed to use the deprecated TAP encryption protocol?
* The hidden service protocol still uses TAP for some connections, because
* ntor onion keys aren't included in HS descriptors or INTRODUCE cells. */
@@ -2672,15 +2524,6 @@ circuit_has_usable_onion_key(const origin_circuit_t *circ)
circuit_can_use_tap(circ));
}
-/* Does ei have an onion key which it would prefer to use?
- * Currently, we prefer ntor keys*/
-int
-extend_info_has_preferred_onion_key(const extend_info_t* ei)
-{
- tor_assert(ei);
- return extend_info_supports_ntor(ei);
-}
-
/** Find the circuits that are waiting to find out whether their guards are
* usable, and if any are ready to become usable, mark them open and try
* attaching streams as appropriate. */
diff --git a/src/core/or/circuitbuild.h b/src/core/or/circuitbuild.h
index e62bb41de9..0cd1eb4f45 100644
--- a/src/core/or/circuitbuild.h
+++ b/src/core/or/circuitbuild.h
@@ -42,23 +42,8 @@ MOCK_DECL(int, circuit_all_predicted_ports_handled, (time_t now,
int circuit_append_new_exit(origin_circuit_t *circ, extend_info_t *info);
int circuit_extend_to_new_exit(origin_circuit_t *circ, extend_info_t *info);
-extend_info_t *extend_info_new(const char *nickname,
- const char *rsa_id_digest,
- const struct ed25519_public_key_t *ed_id,
- crypto_pk_t *onion_key,
- const struct curve25519_public_key_t *ntor_key,
- const tor_addr_t *addr, uint16_t port);
-extend_info_t *extend_info_from_node(const node_t *r, int for_direct_connect);
-extend_info_t *extend_info_dup(extend_info_t *info);
-void extend_info_free_(extend_info_t *info);
-#define extend_info_free(info) \
- FREE_AND_NULL(extend_info_t, extend_info_free_, (info))
-int extend_info_addr_is_allowed(const tor_addr_t *addr);
-int extend_info_supports_tap(const extend_info_t* ei);
-int extend_info_supports_ntor(const extend_info_t* ei);
int circuit_can_use_tap(const origin_circuit_t *circ);
int circuit_has_usable_onion_key(const origin_circuit_t *circ);
-int extend_info_has_preferred_onion_key(const extend_info_t* ei);
const uint8_t *build_state_get_exit_rsa_id(cpath_build_state_t *state);
MOCK_DECL(const node_t *,
build_state_get_exit_node,(cpath_build_state_t *state));
@@ -71,13 +56,7 @@ 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));
+MOCK_DECL(channel_t *, channel_connect_for_circuit,(const extend_info_t *ei));
struct create_cell_t;
MOCK_DECL(int,
@@ -97,6 +76,10 @@ STATIC int onion_extend_cpath(origin_circuit_t *circ);
STATIC int
onion_pick_cpath_exit(origin_circuit_t *circ, extend_info_t *exit_ei,
int is_hs_v3_rp_circuit);
+STATIC int cpath_build_state_to_crn_flags(const cpath_build_state_t *state);
+STATIC int cpath_build_state_to_crn_ipv6_extend_flag(
+ const cpath_build_state_t *state,
+ int cur_len);
#endif /* defined(CIRCUITBUILD_PRIVATE) */
diff --git a/src/core/or/circuitlist.c b/src/core/or/circuitlist.c
index 90cce47490..f4d6cd3c12 100644
--- a/src/core/or/circuitlist.c
+++ b/src/core/or/circuitlist.c
@@ -64,6 +64,7 @@
#include "core/or/circuitstats.h"
#include "core/or/circuitpadding.h"
#include "core/or/crypt_path.h"
+#include "core/or/extendinfo.h"
#include "core/mainloop/connection.h"
#include "app/config/config.h"
#include "core/or/connection_edge.h"
@@ -1944,7 +1945,7 @@ circuit_find_to_cannibalize(uint8_t purpose_to_produce, extend_info_t *info,
/* Ignore any circuits for which we can't use the Guard. It is possible
* that the Guard was removed from the sampled set after the circuit
- * was created so avoid using it. */
+ * was created, so avoid using it. */
if (!entry_guard_could_succeed(circ->guard_state)) {
goto next;
}
diff --git a/src/core/or/circuitpadding.c b/src/core/or/circuitpadding.c
index 43f4a31624..889ffb03f1 100644
--- a/src/core/or/circuitpadding.c
+++ b/src/core/or/circuitpadding.c
@@ -266,18 +266,31 @@ circpad_marked_circuit_for_padding(circuit_t *circ, int reason)
/**
* Free all the machineinfos in <b>circ</b> that match <b>machine_num</b>.
*
+ * If machine_ctr is non-zero, also make sure it matches the padding_info's
+ * machine counter before freeing.
+ *
* Returns true if any machineinfos with that number were freed.
* False otherwise. */
static int
-free_circ_machineinfos_with_machine_num(circuit_t *circ, int machine_num)
+free_circ_machineinfos_with_machine_num(circuit_t *circ, int machine_num,
+ uint32_t machine_ctr)
{
int found = 0;
FOR_EACH_CIRCUIT_MACHINE_BEGIN(i) {
if (circ->padding_machine[i] &&
circ->padding_machine[i]->machine_num == machine_num) {
- circpad_circuit_machineinfo_free_idx(circ, i);
- circ->padding_machine[i] = NULL;
- found = 1;
+ /* If machine_ctr is non-zero, make sure it matches too. This
+ * is to ensure that old STOP messages don't shutdown newer machines. */
+ if (machine_ctr && circ->padding_info[i] &&
+ circ->padding_info[i]->machine_ctr != machine_ctr) {
+ log_info(LD_CIRC,
+ "Padding shutdown for wrong (old?) machine ctr: %u vs %u",
+ machine_ctr, circ->padding_info[i]->machine_ctr);
+ } else {
+ circpad_circuit_machineinfo_free_idx(circ, i);
+ circ->padding_machine[i] = NULL;
+ found = 1;
+ }
}
} FOR_EACH_CIRCUIT_MACHINE_END;
@@ -306,6 +319,7 @@ circpad_circuit_machineinfo_new(circuit_t *on_circ, int machine_index)
mi->machine_index = machine_index;
mi->on_circ = on_circ;
mi->last_cell_time_sec = approx_time();
+ mi->machine_ctr = on_circ->padding_machine_ctr;
return mi;
}
@@ -1556,19 +1570,23 @@ circpad_machine_spec_transitioned_to_end(circpad_machine_runtime_t *mi)
/* We free the machine info here so that we can be replaced
* by a different machine. But we must leave the padding_machine
* in place to wait for the negotiated response */
+ uint32_t machine_ctr = mi->machine_ctr;
circpad_circuit_machineinfo_free_idx(on_circ,
machine->machine_index);
circpad_negotiate_padding(TO_ORIGIN_CIRCUIT(on_circ),
machine->machine_num,
machine->target_hopnum,
- CIRCPAD_COMMAND_STOP);
+ CIRCPAD_COMMAND_STOP,
+ machine_ctr);
} else {
+ uint32_t machine_ctr = mi->machine_ctr;
circpad_circuit_machineinfo_free_idx(on_circ,
machine->machine_index);
circpad_padding_negotiated(on_circ,
machine->machine_num,
CIRCPAD_COMMAND_STOP,
- CIRCPAD_RESPONSE_OK);
+ CIRCPAD_RESPONSE_OK,
+ machine_ctr);
on_circ->padding_machine[machine->machine_index] = NULL;
}
}
@@ -1990,7 +2008,7 @@ circpad_internal_event_state_length_up(circpad_machine_runtime_t *mi)
* Returns true if the circuit matches the conditions.
*/
static inline bool
-circpad_machine_conditions_met(origin_circuit_t *circ,
+circpad_machine_conditions_apply(origin_circuit_t *circ,
const circpad_machine_spec_t *machine)
{
/* If padding is disabled, no machines should match/apply. This has
@@ -2007,7 +2025,7 @@ circpad_machine_conditions_met(origin_circuit_t *circ,
}
if (!(circpad_circ_purpose_to_mask(TO_CIRCUIT(circ)->purpose)
- & machine->conditions.purpose_mask))
+ & machine->conditions.apply_purpose_mask))
return 0;
if (machine->conditions.requires_vanguards) {
@@ -2023,7 +2041,7 @@ circpad_machine_conditions_met(origin_circuit_t *circ,
* "I want to apply to circuits with either streams or no streams"; OR
* "I only want to apply to circuits with streams"; OR
* "I only want to apply to circuits without streams". */
- if (!(circpad_circuit_state(circ) & machine->conditions.state_mask))
+ if (!(circpad_circuit_state(circ) & machine->conditions.apply_state_mask))
return 0;
if (circuit_get_cpath_opened_len(circ) < machine->conditions.min_hops)
@@ -2033,6 +2051,26 @@ circpad_machine_conditions_met(origin_circuit_t *circ,
}
/**
+ * Check to see if any of the keep conditions still apply to this circuit.
+ *
+ * These conditions keep the machines active if they match, but do not
+ * cause new machines to start up.
+ */
+static inline bool
+circpad_machine_conditions_keep(origin_circuit_t *circ,
+ const circpad_machine_spec_t *machine)
+{
+ if ((circpad_circ_purpose_to_mask(TO_CIRCUIT(circ)->purpose)
+ & machine->conditions.keep_purpose_mask))
+ return 1;
+
+ if ((circpad_circuit_state(circ) & machine->conditions.keep_state_mask))
+ return 1;
+
+ return 0;
+}
+
+/**
* Returns a minimized representation of the circuit state.
*
* The padding code only cares if the circuit is building,
@@ -2097,15 +2135,22 @@ circpad_shutdown_old_machines(origin_circuit_t *on_circ)
circuit_t *circ = TO_CIRCUIT(on_circ);
FOR_EACH_ACTIVE_CIRCUIT_MACHINE_BEGIN(i, circ) {
- if (!circpad_machine_conditions_met(on_circ,
+ /* We shut down a machine if neither the apply conditions
+ * nor the keep conditions match. If either set of conditions match,
+ * keep it around. */
+ if (!circpad_machine_conditions_apply(on_circ,
+ circ->padding_machine[i]) &&
+ !circpad_machine_conditions_keep(on_circ,
circ->padding_machine[i])) {
+ uint32_t machine_ctr = circ->padding_info[i]->machine_ctr;
// Clear machineinfo (frees timers)
circpad_circuit_machineinfo_free_idx(circ, i);
// Send padding negotiate stop
circpad_negotiate_padding(on_circ,
circ->padding_machine[i]->machine_num,
circ->padding_machine[i]->target_hopnum,
- CIRCPAD_COMMAND_STOP);
+ CIRCPAD_COMMAND_STOP,
+ machine_ctr);
}
} FOR_EACH_ACTIVE_CIRCUIT_MACHINE_END;
}
@@ -2154,7 +2199,7 @@ circpad_add_matching_machines(origin_circuit_t *on_circ,
* machines installed on a circuit. Make sure we only
* add this machine if its target machine index is free. */
if (machine->machine_index == i &&
- circpad_machine_conditions_met(on_circ, machine)) {
+ circpad_machine_conditions_apply(on_circ, machine)) {
// We can only replace this machine if the target hopnum
// is the same, otherwise we'll get invalid data
@@ -2172,7 +2217,8 @@ circpad_add_matching_machines(origin_circuit_t *on_circ,
circpad_setup_machine_on_circ(circ, machine);
if (circpad_negotiate_padding(on_circ, machine->machine_num,
machine->target_hopnum,
- CIRCPAD_COMMAND_START) < 0) {
+ CIRCPAD_COMMAND_START,
+ circ->padding_machine_ctr) < 0) {
log_info(LD_CIRC,
"Padding not negotiated. Cleaning machine from circuit %u",
CIRCUIT_IS_ORIGIN(circ) ?
@@ -2463,6 +2509,17 @@ circpad_setup_machine_on_circ(circuit_t *on_circ,
machine->name, on_circ->purpose);
}
+ /* Padding machine ctr starts at 1, so we increment this ctr first.
+ * (machine ctr of 0 means "any machine").
+ *
+ * See https://bugs.tororject.org/30992. */
+ on_circ->padding_machine_ctr++;
+
+ /* uint32 wraparound check: 0 is special, just wrap to 1 */
+ if (on_circ->padding_machine_ctr == 0) {
+ on_circ->padding_machine_ctr = 1;
+ }
+
on_circ->padding_info[machine->machine_index] =
circpad_circuit_machineinfo_new(on_circ, machine->machine_index);
on_circ->padding_machine[machine->machine_index] = machine;
@@ -2555,9 +2612,9 @@ circpad_circ_client_machine_init(void)
= tor_malloc_zero(sizeof(circpad_machine_spec_t));
circ_client_machine->conditions.min_hops = 2;
- circ_client_machine->conditions.state_mask =
+ circ_client_machine->conditions.apply_state_mask =
CIRCPAD_CIRC_BUILDING|CIRCPAD_CIRC_OPENED|CIRCPAD_CIRC_HAS_RELAY_EARLY;
- circ_client_machine->conditions.purpose_mask = CIRCPAD_PURPOSE_ALL;
+ circ_client_machine->conditions.apply_purpose_mask = CIRCPAD_PURPOSE_ALL;
circ_client_machine->conditions.reduced_padding_ok = 1;
circ_client_machine->target_hopnum = 2;
@@ -2816,7 +2873,8 @@ signed_error_t
circpad_negotiate_padding(origin_circuit_t *circ,
circpad_machine_num_t machine,
uint8_t target_hopnum,
- uint8_t command)
+ uint8_t command,
+ uint32_t machine_ctr)
{
circpad_negotiate_t type;
cell_t cell;
@@ -2838,14 +2896,16 @@ circpad_negotiate_padding(origin_circuit_t *circ,
circpad_negotiate_set_command(&type, command);
circpad_negotiate_set_version(&type, 0);
circpad_negotiate_set_machine_type(&type, machine);
+ circpad_negotiate_set_machine_ctr(&type, machine_ctr);
if ((len = circpad_negotiate_encode(cell.payload, CELL_PAYLOAD_SIZE,
&type)) < 0)
return -1;
log_fn(LOG_INFO,LD_CIRC,
- "Negotiating padding on circuit %u (%d), command %d",
- circ->global_identifier, TO_CIRCUIT(circ)->purpose, command);
+ "Negotiating padding on circuit %u (%d), command %d, for ctr %u",
+ circ->global_identifier, TO_CIRCUIT(circ)->purpose, command,
+ machine_ctr);
return circpad_send_command_to_hop(circ, target_hopnum,
RELAY_COMMAND_PADDING_NEGOTIATE,
@@ -2861,7 +2921,8 @@ bool
circpad_padding_negotiated(circuit_t *circ,
circpad_machine_num_t machine,
uint8_t command,
- uint8_t response)
+ uint8_t response,
+ uint32_t machine_ctr)
{
circpad_negotiated_t type;
cell_t cell;
@@ -2878,6 +2939,7 @@ circpad_padding_negotiated(circuit_t *circ,
circpad_negotiated_set_response(&type, response);
circpad_negotiated_set_version(&type, 0);
circpad_negotiated_set_machine_type(&type, machine);
+ circpad_negotiated_set_machine_ctr(&type, machine_ctr);
if ((len = circpad_negotiated_encode(cell.payload, CELL_PAYLOAD_SIZE,
&type)) < 0)
@@ -2923,19 +2985,33 @@ circpad_handle_padding_negotiate(circuit_t *circ, cell_t *cell)
if (negotiate->command == CIRCPAD_COMMAND_STOP) {
/* Free the machine corresponding to this machine type */
if (free_circ_machineinfos_with_machine_num(circ,
- negotiate->machine_type)) {
- log_info(LD_CIRC, "Received STOP command for machine %u",
- negotiate->machine_type);
+ negotiate->machine_type,
+ negotiate->machine_ctr)) {
+ log_info(LD_CIRC, "Received STOP command for machine %u, ctr %u",
+ negotiate->machine_type, negotiate->machine_ctr);
goto done;
}
- log_fn(LOG_PROTOCOL_WARN, LD_CIRC,
- "Received circuit padding stop command for unknown machine.");
- goto err;
- } else if (negotiate->command == CIRCPAD_COMMAND_START) {
+ if (negotiate->machine_ctr <= circ->padding_machine_ctr) {
+ log_info(LD_CIRC, "Received STOP command for old machine %u, ctr %u",
+ negotiate->machine_type, negotiate->machine_ctr);
+ goto done;
+
+ } else {
+ log_fn(LOG_PROTOCOL_WARN, LD_CIRC,
+ "Received circuit padding stop command for unknown machine.");
+ goto err;
+ }
+ } else if (negotiate->command == CIRCPAD_COMMAND_START) {
SMARTLIST_FOREACH_BEGIN(relay_padding_machines,
const circpad_machine_spec_t *, m) {
if (m->machine_num == negotiate->machine_type) {
circpad_setup_machine_on_circ(circ, m);
+ if (negotiate->machine_ctr &&
+ circ->padding_machine_ctr != negotiate->machine_ctr) {
+ log_fn(LOG_PROTOCOL_WARN, LD_CIRC,
+ "Client and relay have different counts for padding machines: "
+ "%u vs %u", circ->padding_machine_ctr, negotiate->machine_ctr);
+ }
circpad_cell_event_nonpadding_received(circ);
goto done;
}
@@ -2948,7 +3024,8 @@ circpad_handle_padding_negotiate(circuit_t *circ, cell_t *cell)
done:
circpad_padding_negotiated(circ, negotiate->machine_type,
negotiate->command,
- (retval == 0) ? CIRCPAD_RESPONSE_OK : CIRCPAD_RESPONSE_ERR);
+ (retval == 0) ? CIRCPAD_RESPONSE_OK : CIRCPAD_RESPONSE_ERR,
+ negotiate->machine_ctr);
circpad_negotiate_free(negotiate);
return retval;
@@ -2999,17 +3076,22 @@ circpad_handle_padding_negotiated(circuit_t *circ, cell_t *cell,
* circpad_add_matching_matchines() added a new machine,
* there may be a padding_machine for a different machine num
* than this response. */
- free_circ_machineinfos_with_machine_num(circ, negotiated->machine_type);
+ free_circ_machineinfos_with_machine_num(circ, negotiated->machine_type,
+ negotiated->machine_ctr);
} else if (negotiated->command == CIRCPAD_COMMAND_START &&
negotiated->response == CIRCPAD_RESPONSE_ERR) {
- // This can happen due to consensus drift.. free the machines
+ // This can still happen due to consensus drift.. free the machines
// and be sad
- free_circ_machineinfos_with_machine_num(circ, negotiated->machine_type);
- TO_ORIGIN_CIRCUIT(circ)->padding_negotiation_failed = 1;
- log_fn(LOG_PROTOCOL_WARN, LD_CIRC,
- "Middle node did not accept our padding request on circuit %u (%d)",
- TO_ORIGIN_CIRCUIT(circ)->global_identifier,
- circ->purpose);
+ if (free_circ_machineinfos_with_machine_num(circ, negotiated->machine_type,
+ negotiated->machine_ctr)) {
+ // Only fail if a machine was there and matched the error cell
+ TO_ORIGIN_CIRCUIT(circ)->padding_negotiation_failed = 1;
+ log_fn(LOG_PROTOCOL_WARN, LD_CIRC,
+ "Middle node did not accept our padding request on circuit "
+ "%u (%d)",
+ TO_ORIGIN_CIRCUIT(circ)->global_identifier,
+ circ->purpose);
+ }
}
circpad_negotiated_free(negotiated);
diff --git a/src/core/or/circuitpadding.h b/src/core/or/circuitpadding.h
index 74b69a1c7a..3d2929cf74 100644
--- a/src/core/or/circuitpadding.h
+++ b/src/core/or/circuitpadding.h
@@ -173,11 +173,21 @@ typedef struct circpad_machine_conditions_t {
/** Only apply the machine *if* the circuit's state matches any of
* the bits set in this bitmask. */
- circpad_circuit_state_t state_mask;
+ circpad_circuit_state_t apply_state_mask;
/** Only apply a machine *if* the circuit's purpose matches one
* of the bits set in this bitmask */
- circpad_purpose_mask_t purpose_mask;
+ circpad_purpose_mask_t apply_purpose_mask;
+
+ /** Keep a machine if any of the circuits's state machine's match
+ * the bits set in this bitmask, but don't apply new machines if
+ * they match this mask. */
+ circpad_circuit_state_t keep_state_mask;
+
+ /** Keep a machine if any of the circuits's state machine's match
+ * the bits set in this bitmask, but don't apply new machines if
+ * they match this mask. */
+ circpad_purpose_mask_t keep_purpose_mask;
} circpad_machine_conditions_t;
@@ -565,6 +575,13 @@ typedef struct circpad_machine_runtime_t {
/** What state is this machine in? */
circpad_statenum_t current_state;
+ /** Machine counter, for shutdown sync.
+ *
+ * Set from circuit_t.padding_machine_ctr, which is incremented each
+ * padding machine instantiation.
+ */
+ uint32_t machine_ctr;
+
/**
* True if we have scheduled a timer for padding.
*
@@ -726,11 +743,13 @@ signed_error_t circpad_handle_padding_negotiated(struct circuit_t *circ,
signed_error_t circpad_negotiate_padding(struct origin_circuit_t *circ,
circpad_machine_num_t machine,
uint8_t target_hopnum,
- uint8_t command);
+ uint8_t command,
+ uint32_t machine_ctr);
bool circpad_padding_negotiated(struct circuit_t *circ,
circpad_machine_num_t machine,
uint8_t command,
- uint8_t response);
+ uint8_t response,
+ uint32_t machine_ctr);
circpad_purpose_mask_t circpad_circ_purpose_to_mask(uint8_t circ_purpose);
diff --git a/src/core/or/circuitpadding_machines.c b/src/core/or/circuitpadding_machines.c
index 98767f9e8f..1e6b580f5b 100644
--- a/src/core/or/circuitpadding_machines.c
+++ b/src/core/or/circuitpadding_machines.c
@@ -67,7 +67,7 @@ circpad_machine_client_hide_intro_circuits(smartlist_t *machines_sl)
client_machine->name = "client_ip_circ";
- client_machine->conditions.state_mask = CIRCPAD_CIRC_OPENED;
+ client_machine->conditions.apply_state_mask = CIRCPAD_CIRC_OPENED;
client_machine->target_hopnum = 2;
/* This is a client machine */
@@ -102,9 +102,18 @@ circpad_machine_client_hide_intro_circuits(smartlist_t *machines_sl)
* INTRO_MACHINE_MAXIMUM_PADDING cells, to match the "...(inbound data cells
* continue)" portion of the trace (aka the rest of an HTTPS response body).
*/
- client_machine->conditions.purpose_mask =
- circpad_circ_purpose_to_mask(CIRCUIT_PURPOSE_C_INTRODUCE_ACK_WAIT)|
- circpad_circ_purpose_to_mask(CIRCUIT_PURPOSE_C_INTRODUCE_ACKED)|
+
+ /* Start the machine on fresh intro circs. */
+ client_machine->conditions.apply_purpose_mask =
+ circpad_circ_purpose_to_mask(CIRCUIT_PURPOSE_C_INTRODUCE_ACK_WAIT);
+
+ /* If the client purpose changes back to CIRCUIT_PURPOSE_C_INTRODUCING,
+ * or transitions to CIRCUIT_PURPOSE_C_INTRODUCE_ACKED, keep the machine
+ * alive, but do not launch new machines for these purposes. Also
+ * keep the machine around if it is in the CIRCUIT_PADDING purpose
+ * (but do not try to take over other machines in that purpose). */
+ client_machine->conditions.keep_purpose_mask =
+ circpad_circ_purpose_to_mask(CIRCUIT_PURPOSE_C_INTRODUCE_ACKED) |
circpad_circ_purpose_to_mask(CIRCUIT_PURPOSE_C_CIRCUIT_PADDING);
/* Keep the circuit alive even after the introduction has been finished,
@@ -152,7 +161,7 @@ circpad_machine_relay_hide_intro_circuits(smartlist_t *machines_sl)
relay_machine->name = "relay_ip_circ";
- relay_machine->conditions.state_mask = CIRCPAD_CIRC_OPENED;
+ relay_machine->conditions.apply_state_mask = CIRCPAD_CIRC_OPENED;
/* This is a relay-side machine */
relay_machine->is_origin_side = 0;
@@ -263,7 +272,7 @@ circpad_machine_client_hide_rend_circuits(smartlist_t *machines_sl)
client_machine->name = "client_rp_circ";
/* Only pad after the circuit has been built and pad to the middle */
- client_machine->conditions.state_mask = CIRCPAD_CIRC_OPENED;
+ client_machine->conditions.apply_state_mask = CIRCPAD_CIRC_OPENED;
client_machine->target_hopnum = 2;
/* This is a client machine */
@@ -299,7 +308,7 @@ circpad_machine_client_hide_rend_circuits(smartlist_t *machines_sl)
*
* Hence this way we make rendezvous circuits look like general circuits up
* till the end of the circuit setup. */
- client_machine->conditions.purpose_mask =
+ client_machine->conditions.apply_purpose_mask =
circpad_circ_purpose_to_mask(CIRCUIT_PURPOSE_C_REND_JOINED)|
circpad_circ_purpose_to_mask(CIRCUIT_PURPOSE_C_REND_READY)|
circpad_circ_purpose_to_mask(CIRCUIT_PURPOSE_C_REND_READY_INTRO_ACKED);
@@ -383,7 +392,7 @@ circpad_machine_relay_hide_rend_circuits(smartlist_t *machines_sl)
/* Only pad after the circuit has been built and pad to the middle */
relay_machine->conditions.min_hops = 2;
- relay_machine->conditions.state_mask = CIRCPAD_CIRC_OPENED;
+ relay_machine->conditions.apply_state_mask = CIRCPAD_CIRC_OPENED;
/* This is a relay-side machine */
relay_machine->is_origin_side = 0;
diff --git a/src/core/or/circuitstats.c b/src/core/or/circuitstats.c
index 822e5bd308..bc6c263798 100644
--- a/src/core/or/circuitstats.c
+++ b/src/core/or/circuitstats.c
@@ -53,9 +53,6 @@
#undef log
#include <math.h>
-static void cbt_control_event_buildtimeout_set(
- const circuit_build_times_t *cbt,
- buildtimeout_set_event_t type);
static void circuit_build_times_scale_circ_counts(circuit_build_times_t *cbt);
#define CBT_BIN_TO_MS(bin) ((bin)*CBT_BIN_WIDTH + (CBT_BIN_WIDTH/2))
@@ -402,7 +399,7 @@ circuit_build_times_initial_timeout(void)
* and learn a new timeout.
*/
static int32_t
-circuit_build_times_recent_circuit_count(networkstatus_t *ns)
+circuit_build_times_recent_circuit_count(const networkstatus_t *ns)
{
int32_t num;
num = networkstatus_get_param(ns, "cbtrecentcount",
@@ -428,7 +425,7 @@ circuit_build_times_recent_circuit_count(networkstatus_t *ns)
*/
void
circuit_build_times_new_consensus_params(circuit_build_times_t *cbt,
- networkstatus_t *ns)
+ const networkstatus_t *ns)
{
int32_t num;
@@ -545,7 +542,7 @@ circuit_build_times_get_initial_timeout(void)
* Leave estimated parameters, timeout and network liveness intact
* for future use.
*/
-STATIC void
+void
circuit_build_times_reset(circuit_build_times_t *cbt)
{
memset(cbt->circuit_build_times, 0, sizeof(cbt->circuit_build_times));
@@ -1893,61 +1890,3 @@ circuit_build_times_update_last_circ(circuit_build_times_t *cbt)
{
cbt->last_circ_at = approx_time();
}
-
-static void
-cbt_control_event_buildtimeout_set(const circuit_build_times_t *cbt,
- buildtimeout_set_event_t type)
-{
- char *args = NULL;
- double qnt;
- double timeout_rate = 0.0;
- double close_rate = 0.0;
-
- switch (type) {
- case BUILDTIMEOUT_SET_EVENT_RESET:
- case BUILDTIMEOUT_SET_EVENT_SUSPENDED:
- case BUILDTIMEOUT_SET_EVENT_DISCARD:
- qnt = 1.0;
- break;
- case BUILDTIMEOUT_SET_EVENT_COMPUTED:
- case BUILDTIMEOUT_SET_EVENT_RESUME:
- default:
- qnt = circuit_build_times_quantile_cutoff();
- break;
- }
-
- /* The timeout rate is the ratio of the timeout count over
- * the total number of circuits attempted. The total number of
- * circuits is (timeouts+succeeded), since every circuit
- * either succeeds, or times out. "Closed" circuits are
- * MEASURE_TIMEOUT circuits whose measurement period expired.
- * All MEASURE_TIMEOUT circuits are counted in the timeouts stat
- * before transitioning to MEASURE_TIMEOUT (in
- * circuit_build_times_mark_circ_as_measurement_only()).
- * MEASURE_TIMEOUT circuits that succeed are *not* counted as
- * "succeeded". See circuit_build_times_handle_completed_hop().
- *
- * We cast the denominator
- * to promote it to double before the addition, to avoid int32
- * overflow. */
- const double total_circuits =
- ((double)cbt->num_circ_timeouts) + cbt->num_circ_succeeded;
- if (total_circuits >= 1.0) {
- timeout_rate = cbt->num_circ_timeouts / total_circuits;
- close_rate = cbt->num_circ_closed / total_circuits;
- }
-
- tor_asprintf(&args, "TOTAL_TIMES=%lu "
- "TIMEOUT_MS=%lu XM=%lu ALPHA=%f CUTOFF_QUANTILE=%f "
- "TIMEOUT_RATE=%f CLOSE_MS=%lu CLOSE_RATE=%f",
- (unsigned long)cbt->total_build_times,
- (unsigned long)cbt->timeout_ms,
- (unsigned long)cbt->Xm, cbt->alpha, qnt,
- timeout_rate,
- (unsigned long)cbt->close_ms,
- close_rate);
-
- control_event_buildtimeout_set(type, args);
-
- tor_free(args);
-}
diff --git a/src/core/or/circuitstats.h b/src/core/or/circuitstats.h
index 52c9100f53..930e0a9ba3 100644
--- a/src/core/or/circuitstats.h
+++ b/src/core/or/circuitstats.h
@@ -43,12 +43,13 @@ int circuit_build_times_needs_circuits_now(const circuit_build_times_t *cbt);
void circuit_build_times_init(circuit_build_times_t *cbt);
void circuit_build_times_free_timeouts(circuit_build_times_t *cbt);
void circuit_build_times_new_consensus_params(circuit_build_times_t *cbt,
- networkstatus_t *ns);
+ const networkstatus_t *ns);
double circuit_build_times_timeout_rate(const circuit_build_times_t *cbt);
double circuit_build_times_close_rate(const circuit_build_times_t *cbt);
void circuit_build_times_update_last_circ(circuit_build_times_t *cbt);
void circuit_build_times_mark_circ_as_measurement_only(origin_circuit_t *circ);
+void circuit_build_times_reset(circuit_build_times_t *cbt);
/** Total size of the circuit timeout history to accumulate.
* 1000 is approx 2.5 days worth of continual-use circuits. */
@@ -137,7 +138,6 @@ int32_t circuit_build_times_initial_timeout(void);
STATIC double circuit_build_times_calculate_timeout(circuit_build_times_t *cbt,
double quantile);
STATIC int circuit_build_times_update_alpha(circuit_build_times_t *cbt);
-STATIC void circuit_build_times_reset(circuit_build_times_t *cbt);
/* Network liveness functions */
STATIC int circuit_build_times_network_check_changed(
@@ -158,7 +158,6 @@ void circuit_build_times_network_is_live(circuit_build_times_t *cbt);
int circuit_build_times_network_check_live(const circuit_build_times_t *cbt);
void circuit_build_times_network_circ_success(circuit_build_times_t *cbt);
-#ifdef CIRCUITSTATS_PRIVATE
/** Information about the state of our local network connection */
typedef struct {
/** The timestamp we last completed a TLS handshake or received a cell */
@@ -208,6 +207,5 @@ struct circuit_build_times_t {
uint32_t num_circ_closed;
};
-#endif /* defined(CIRCUITSTATS_PRIVATE) */
#endif /* !defined(TOR_CIRCUITSTATS_H) */
diff --git a/src/core/or/circuituse.c b/src/core/or/circuituse.c
index e2c4df25d0..6ff308dae2 100644
--- a/src/core/or/circuituse.c
+++ b/src/core/or/circuituse.c
@@ -37,6 +37,7 @@
#include "core/or/circuituse.h"
#include "core/or/circuitpadding.h"
#include "core/or/connection_edge.h"
+#include "core/or/extendinfo.h"
#include "core/or/policies.h"
#include "feature/client/addressmap.h"
#include "feature/client/bridges.h"
@@ -202,8 +203,8 @@ circuit_is_acceptable(const origin_circuit_t *origin_circ,
const int family = tor_addr_parse(&addr,
conn->socks_request->address);
if (family < 0 ||
- !tor_addr_eq(&build_state->chosen_exit->addr, &addr) ||
- build_state->chosen_exit->port != conn->socks_request->port)
+ !extend_info_has_orport(build_state->chosen_exit, &addr,
+ conn->socks_request->port))
return 0;
}
}
@@ -1642,7 +1643,7 @@ static void
circuit_testing_opened(origin_circuit_t *circ)
{
if (have_performed_bandwidth_test ||
- !check_whether_orport_reachable(get_options())) {
+ !router_all_orports_seem_reachable(get_options())) {
/* either we've already done everything we want with testing circuits,
* or this testing circuit became open due to a fluke, e.g. we picked
* a last hop where we already had the connection open due to an
@@ -1660,7 +1661,8 @@ static void
circuit_testing_failed(origin_circuit_t *circ, int at_last_hop)
{
const or_options_t *options = get_options();
- if (server_mode(options) && check_whether_orport_reachable(options))
+ if (server_mode(options) &&
+ router_all_orports_seem_reachable(options))
return;
log_info(LD_GENERAL,
@@ -2092,11 +2094,18 @@ circuit_should_cannibalize_to_build(uint8_t purpose_to_build,
}
/** Launch a new circuit with purpose <b>purpose</b> and exit node
- * <b>extend_info</b> (or NULL to select a random exit node). If flags
- * contains CIRCLAUNCH_NEED_UPTIME, choose among routers with high uptime. If
- * CIRCLAUNCH_NEED_CAPACITY is set, choose among routers with high bandwidth.
- * If CIRCLAUNCH_IS_INTERNAL is true, the last hop need not be an exit node.
- * If CIRCLAUNCH_ONEHOP_TUNNEL is set, the circuit will have only one hop.
+ * <b>extend_info</b> (or NULL to select a random exit node).
+ *
+ * If flags contains:
+ * - CIRCLAUNCH_ONEHOP_TUNNEL: the circuit will have only one hop;
+ * - CIRCLAUNCH_NEED_UPTIME: choose routers with high uptime;
+ * - CIRCLAUNCH_NEED_CAPACITY: choose routers with high bandwidth;
+ * - CIRCLAUNCH_IS_IPV6_SELFTEST: the second-last hop must support IPv6
+ * extends;
+ * - CIRCLAUNCH_IS_INTERNAL: the last hop need not be an exit node;
+ * - CIRCLAUNCH_IS_V3_RP: the last hop must support v3 onion service
+ * rendezvous.
+ *
* Return the newly allocated circuit on success, or NULL on failure. */
origin_circuit_t *
circuit_launch_by_extend_info(uint8_t purpose,
diff --git a/src/core/or/circuituse.h b/src/core/or/circuituse.h
index 95d36d6474..028fe4aa48 100644
--- a/src/core/or/circuituse.h
+++ b/src/core/or/circuituse.h
@@ -36,17 +36,23 @@ void circuit_try_attaching_streams(origin_circuit_t *circ);
void circuit_build_failed(origin_circuit_t *circ);
/** Flag to set when a circuit should have only a single hop. */
-#define CIRCLAUNCH_ONEHOP_TUNNEL (1<<0)
+#define CIRCLAUNCH_ONEHOP_TUNNEL (1<<0)
/** Flag to set when a circuit needs to be built of high-uptime nodes */
-#define CIRCLAUNCH_NEED_UPTIME (1<<1)
+#define CIRCLAUNCH_NEED_UPTIME (1<<1)
/** Flag to set when a circuit needs to be built of high-capacity nodes */
-#define CIRCLAUNCH_NEED_CAPACITY (1<<2)
+#define CIRCLAUNCH_NEED_CAPACITY (1<<2)
/** Flag to set when the last hop of a circuit doesn't need to be an
* exit node. */
-#define CIRCLAUNCH_IS_INTERNAL (1<<3)
+#define CIRCLAUNCH_IS_INTERNAL (1<<3)
/** Flag to set when we are trying to launch a v3 rendezvous circuit. We need
* to apply some additional filters on the node picked. */
-#define CIRCLAUNCH_IS_V3_RP (1<<4)
+#define CIRCLAUNCH_IS_V3_RP (1<<4)
+/** Flag to set when we are trying to launch a self-testing circuit to our
+ * IPv6 ORPort. We need to apply some additional filters on the second-last
+ * node in the circuit. (We are both the client and the last node in the
+ * circuit.) */
+#define CIRCLAUNCH_IS_IPV6_SELFTEST (1<<5)
+
origin_circuit_t *circuit_launch_by_extend_info(uint8_t purpose,
extend_info_t *info,
int flags);
diff --git a/src/core/or/connection_edge.c b/src/core/or/connection_edge.c
index 26595003c1..45d2a9664a 100644
--- a/src/core/or/connection_edge.c
+++ b/src/core/or/connection_edge.c
@@ -70,6 +70,7 @@
#include "core/or/circuitpadding.h"
#include "core/or/connection_edge.h"
#include "core/or/connection_or.h"
+#include "core/or/extendinfo.h"
#include "core/or/policies.h"
#include "core/or/reasons.h"
#include "core/or/relay.h"
@@ -1444,8 +1445,8 @@ connection_ap_fail_onehop(const char *failed_digest,
continue;
}
if (tor_addr_parse(&addr, entry_conn->socks_request->address)<0 ||
- !tor_addr_eq(&build_state->chosen_exit->addr, &addr) ||
- build_state->chosen_exit->port != entry_conn->socks_request->port)
+ !extend_info_has_orport(build_state->chosen_exit, &addr,
+ entry_conn->socks_request->port))
continue;
}
log_info(LD_APP, "Closing one-hop stream to '%s/%s' because the OR conn "
diff --git a/src/core/or/cpath_build_state_st.h b/src/core/or/cpath_build_state_st.h
index ee9a0d972c..eb8e97edc5 100644
--- a/src/core/or/cpath_build_state_st.h
+++ b/src/core/or/cpath_build_state_st.h
@@ -24,6 +24,8 @@ struct cpath_build_state_t {
unsigned int need_capacity : 1;
/** Whether the last hop was picked with exiting in mind. */
unsigned int is_internal : 1;
+ /** Is this an IPv6 ORPort self-testing circuit? */
+ unsigned int is_ipv6_selftest : 1;
/** Did we pick this as a one-hop tunnel (not safe for other streams)?
* These are for encrypted dir conns that exit to this router, not
* for arbitrary exits from the circuit. */
diff --git a/src/core/or/crypt_path.c b/src/core/or/crypt_path.c
index 8f41540848..e1bbd81251 100644
--- a/src/core/or/crypt_path.c
+++ b/src/core/or/crypt_path.c
@@ -30,6 +30,7 @@
#include "core/crypto/onion_crypto.h"
#include "core/or/circuitbuild.h"
#include "core/or/circuitlist.h"
+#include "core/or/extendinfo.h"
#include "lib/crypt_ops/crypto_dh.h"
#include "lib/crypt_ops/crypto_util.h"
@@ -259,4 +260,3 @@ cpath_get_n_hops(crypt_path_t **head_ptr)
}
#endif /* defined(TOR_UNIT_TESTS) */
-
diff --git a/src/core/or/extend_info_st.h b/src/core/or/extend_info_st.h
index a66ce24cfa..757c6a1771 100644
--- a/src/core/or/extend_info_st.h
+++ b/src/core/or/extend_info_st.h
@@ -15,9 +15,14 @@
#include "lib/crypt_ops/crypto_curve25519.h"
#include "lib/crypt_ops/crypto_ed25519.h"
+/** Largest number of addresses we handle in an extend_info.
+ *
+ * More are permitted in an EXTEND cell, but we won't handle them. */
+#define EXTEND_INFO_MAX_ADDRS 2
+
/** Information on router used when extending a circuit. We don't need a
* full routerinfo_t to extend: we only need addr:port:keyid to build an OR
- * connection, and onion_key to create the onionskin. Note that for onehop
+ * connection, and onion_key to create the onionskin. Note that for one-hop
* general-purpose tunnels, the onion_key is NULL. */
struct extend_info_t {
char nickname[MAX_HEX_NICKNAME_LEN+1]; /**< This router's nickname for
@@ -26,9 +31,12 @@ struct extend_info_t {
char identity_digest[DIGEST_LEN];
/** Ed25519 identity for this router, if any. */
ed25519_public_key_t ed_identity;
- uint16_t port; /**< OR port. */
- tor_addr_t addr; /**< IP address. */
- crypto_pk_t *onion_key; /**< Current onionskin key. */
+ /** IP/Port values for this hop's ORPort(s). Any unused values are set
+ * to a null address. */
+ tor_addr_port_t orports[EXTEND_INFO_MAX_ADDRS];
+ /** TAP onion key for this hop. */
+ crypto_pk_t *onion_key;
+ /** Ntor onion key for this hop. */
curve25519_public_key_t curve25519_onion_key;
};
diff --git a/src/core/or/extendinfo.c b/src/core/or/extendinfo.c
new file mode 100644
index 0000000000..bcdb57d5a0
--- /dev/null
+++ b/src/core/or/extendinfo.c
@@ -0,0 +1,305 @@
+/* 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 extendinfo.c
+ * @brief Functions for creating and using extend_info_t objects.
+ *
+ * An extend_info_t is the information we hold about a relay in order to
+ * extend a circuit to it.
+ **/
+
+#include "core/or/or.h"
+#include "core/or/extendinfo.h"
+
+#include "app/config/config.h"
+#include "core/or/policies.h"
+#include "feature/nodelist/describe.h"
+#include "feature/nodelist/nodelist.h"
+
+#include "core/or/extend_info_st.h"
+#include "feature/nodelist/node_st.h"
+#include "feature/nodelist/routerinfo_st.h"
+#include "feature/nodelist/routerstatus_st.h"
+
+/** Allocate a new extend_info object based on the various arguments. */
+extend_info_t *
+extend_info_new(const char *nickname,
+ const char *rsa_id_digest,
+ const ed25519_public_key_t *ed_id,
+ crypto_pk_t *onion_key,
+ const curve25519_public_key_t *ntor_key,
+ const tor_addr_t *addr, uint16_t port)
+{
+ extend_info_t *info = tor_malloc_zero(sizeof(extend_info_t));
+ if (rsa_id_digest)
+ memcpy(info->identity_digest, rsa_id_digest, DIGEST_LEN);
+ if (ed_id && !ed25519_public_key_is_zero(ed_id))
+ memcpy(&info->ed_identity, ed_id, sizeof(ed25519_public_key_t));
+ if (nickname)
+ strlcpy(info->nickname, nickname, sizeof(info->nickname));
+ if (onion_key)
+ info->onion_key = crypto_pk_dup_key(onion_key);
+ if (ntor_key)
+ memcpy(&info->curve25519_onion_key, ntor_key,
+ sizeof(curve25519_public_key_t));
+ for (int i = 0; i < EXTEND_INFO_MAX_ADDRS; ++i) {
+ tor_addr_make_unspec(&info->orports[i].addr);
+ }
+
+ if (addr) {
+ extend_info_add_orport(info, addr, port);
+ }
+ return info;
+}
+
+/**
+ * Add another address:port pair to a given extend_info_t, if there is
+ * room. Return 0 on success, -1 on failure.
+ **/
+int
+extend_info_add_orport(extend_info_t *ei,
+ const tor_addr_t *addr,
+ uint16_t port)
+{
+ for (int i = 0; i < EXTEND_INFO_MAX_ADDRS; ++i) {
+ if (tor_addr_is_unspec(&ei->orports[i].addr)) {
+ tor_addr_copy(&ei->orports[i].addr, addr);
+ ei->orports[i].port = port;
+ return 0;
+ }
+ }
+ return -1;
+}
+
+/** Allocate and return a new extend_info that can be used to build a
+ * circuit to or through the node <b>node</b>. Use the primary address
+ * of the node (i.e. its IPv4 address) unless
+ * <b>for_direct_connect</b> is true, in which case the preferred
+ * address is used instead. May return NULL if there is not enough
+ * info about <b>node</b> to extend to it--for example, if the preferred
+ * routerinfo_t or microdesc_t is missing, or if for_direct_connect is
+ * true and none of the node's addresses is allowed by tor's firewall
+ * and IP version config.
+ **/
+extend_info_t *
+extend_info_from_node(const node_t *node, int for_direct_connect)
+{
+ crypto_pk_t *rsa_pubkey = NULL;
+ extend_info_t *info = NULL;
+ tor_addr_port_t ap;
+ int valid_addr = 0;
+
+ if (!node_has_preferred_descriptor(node, for_direct_connect)) {
+ return NULL;
+ }
+
+ /* Choose a preferred address first, but fall back to an allowed address. */
+ if (for_direct_connect)
+ fascist_firewall_choose_address_node(node, FIREWALL_OR_CONNECTION, 0, &ap);
+ else {
+ node_get_prim_orport(node, &ap);
+ }
+ valid_addr = tor_addr_port_is_valid_ap(&ap, 0);
+
+ if (valid_addr)
+ log_debug(LD_CIRC, "using %s for %s",
+ fmt_addrport(&ap.addr, ap.port),
+ node->ri ? node->ri->nickname : node->rs->nickname);
+ else
+ log_warn(LD_CIRC, "Could not choose valid address for %s",
+ node->ri ? node->ri->nickname : node->rs->nickname);
+
+ /* Every node we connect or extend to must support ntor */
+ if (!node_has_curve25519_onion_key(node)) {
+ log_fn(LOG_PROTOCOL_WARN, LD_CIRC,
+ "Attempted to create extend_info for a node that does not support "
+ "ntor: %s", node_describe(node));
+ return NULL;
+ }
+
+ const ed25519_public_key_t *ed_pubkey = NULL;
+
+ /* Don't send the ed25519 pubkey unless the target node actually supports
+ * authenticating with it. */
+ if (node_supports_ed25519_link_authentication(node, 0)) {
+ log_info(LD_CIRC, "Including Ed25519 ID for %s", node_describe(node));
+ ed_pubkey = node_get_ed25519_id(node);
+ } else if (node_get_ed25519_id(node)) {
+ log_info(LD_CIRC, "Not including the ed25519 ID for %s, since it won't "
+ "be able to authenticate it.",
+ node_describe(node));
+ }
+
+ /* Retrieve the curve25519 pubkey. */
+ const curve25519_public_key_t *curve_pubkey =
+ node_get_curve25519_onion_key(node);
+ rsa_pubkey = node_get_rsa_onion_key(node);
+
+ if (valid_addr && node->ri) {
+ info = extend_info_new(node->ri->nickname,
+ node->identity,
+ ed_pubkey,
+ rsa_pubkey,
+ curve_pubkey,
+ &ap.addr,
+ ap.port);
+ } else if (valid_addr && node->rs && node->md) {
+ info = extend_info_new(node->rs->nickname,
+ node->identity,
+ ed_pubkey,
+ rsa_pubkey,
+ curve_pubkey,
+ &ap.addr,
+ ap.port);
+ }
+
+ crypto_pk_free(rsa_pubkey);
+ return info;
+}
+
+/** Release storage held by an extend_info_t struct. */
+void
+extend_info_free_(extend_info_t *info)
+{
+ if (!info)
+ return;
+ crypto_pk_free(info->onion_key);
+ tor_free(info);
+}
+
+/** Allocate and return a new extend_info_t with the same contents as
+ * <b>info</b>. */
+extend_info_t *
+extend_info_dup(extend_info_t *info)
+{
+ extend_info_t *newinfo;
+ tor_assert(info);
+ newinfo = tor_malloc(sizeof(extend_info_t));
+ memcpy(newinfo, info, sizeof(extend_info_t));
+ if (info->onion_key)
+ newinfo->onion_key = crypto_pk_dup_key(info->onion_key);
+ else
+ newinfo->onion_key = NULL;
+ return newinfo;
+}
+
+/* Does ei have a valid TAP key? */
+int
+extend_info_supports_tap(const extend_info_t* ei)
+{
+ tor_assert(ei);
+ /* Valid TAP keys are not NULL */
+ return ei->onion_key != NULL;
+}
+
+/* Does ei have a valid ntor key? */
+int
+extend_info_supports_ntor(const extend_info_t* ei)
+{
+ tor_assert(ei);
+ /* Valid ntor keys have at least one non-zero byte */
+ return !fast_mem_is_zero(
+ (const char*)ei->curve25519_onion_key.public_key,
+ CURVE25519_PUBKEY_LEN);
+}
+
+/* Does ei have an onion key which it would prefer to use?
+ * Currently, we prefer ntor keys*/
+int
+extend_info_has_preferred_onion_key(const extend_info_t* ei)
+{
+ tor_assert(ei);
+ return extend_info_supports_ntor(ei);
+}
+
+/** Return true iff the given address can be used to extend to. */
+int
+extend_info_addr_is_allowed(const tor_addr_t *addr)
+{
+ tor_assert(addr);
+
+ /* Check if we have a private address and if we can extend to it. */
+ if ((tor_addr_is_internal(addr, 0) || tor_addr_is_multicast(addr)) &&
+ !get_options()->ExtendAllowPrivateAddresses) {
+ goto disallow;
+ }
+ /* Allowed! */
+ return 1;
+ disallow:
+ return 0;
+}
+
+/**
+ * Return true if @a addr : @a port is a listed ORPort in @a ei.
+ **/
+bool
+extend_info_has_orport(const extend_info_t *ei,
+ const tor_addr_t *addr, uint16_t port)
+{
+ IF_BUG_ONCE(ei == NULL) {
+ return false;
+ }
+
+ for (int i = 0; i < EXTEND_INFO_MAX_ADDRS; ++i) {
+ const tor_addr_port_t *ei_ap = &ei->orports[i];
+ if (tor_addr_eq(&ei_ap->addr, addr) && ei_ap->port == port)
+ return true;
+ }
+ return false;
+}
+
+/**
+ * If the extend_info @a ei has an orport of the chosen family, then return
+ * that orport. Otherwise, return NULL.
+ **/
+const tor_addr_port_t *
+extend_info_get_orport(const extend_info_t *ei, int family)
+{
+ for (int i = 0; i < EXTEND_INFO_MAX_ADDRS; ++i) {
+ if (tor_addr_is_unspec(&ei->orports[i].addr))
+ continue;
+ if (tor_addr_family(&ei->orports[i].addr) == family)
+ return &ei->orports[i];
+ }
+ return NULL;
+}
+
+/**
+ * Chose an addr_port_t within @a ei to connect to.
+ **/
+const tor_addr_port_t *
+extend_info_pick_orport(const extend_info_t *ei)
+{
+ // XXXX S55 -- for now, we just pick the first. We'll work on
+ // XXXX more choices as we move forward.
+ IF_BUG_ONCE(!ei) {
+ return NULL;
+ }
+
+ if (tor_addr_is_unspec(&ei->orports[0].addr)) {
+ return NULL;
+ }
+ return &ei->orports[0];
+}
+
+/**
+ * Return true if any orport address in @a ei is an internal address.
+ **/
+bool
+extend_info_any_orport_addr_is_internal(const extend_info_t *ei)
+{
+ IF_BUG_ONCE(ei == NULL) {
+ return false;
+ }
+
+ for (int i = 0; i < EXTEND_INFO_MAX_ADDRS; ++i) {
+ if (! tor_addr_is_unspec(&ei->orports[i].addr) &&
+ tor_addr_is_internal(&ei->orports[i].addr, 0))
+ return true;
+ }
+ return false;
+}
diff --git a/src/core/or/extendinfo.h b/src/core/or/extendinfo.h
new file mode 100644
index 0000000000..0049dd0189
--- /dev/null
+++ b/src/core/or/extendinfo.h
@@ -0,0 +1,40 @@
+/* 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 extendinfo.h
+ * @brief Header for core/or/extendinfo.c
+ **/
+
+#ifndef TOR_CORE_OR_EXTENDINFO_H
+#define TOR_CORE_OR_EXTENDINFO_H
+
+extend_info_t *extend_info_new(const char *nickname,
+ const char *rsa_id_digest,
+ const struct ed25519_public_key_t *ed_id,
+ crypto_pk_t *onion_key,
+ const struct curve25519_public_key_t *ntor_key,
+ const tor_addr_t *addr, uint16_t port);
+extend_info_t *extend_info_from_node(const node_t *r, int for_direct_connect);
+extend_info_t *extend_info_dup(extend_info_t *info);
+void extend_info_free_(extend_info_t *info);
+#define extend_info_free(info) \
+ FREE_AND_NULL(extend_info_t, extend_info_free_, (info))
+int extend_info_addr_is_allowed(const tor_addr_t *addr);
+int extend_info_supports_tap(const extend_info_t* ei);
+int extend_info_supports_ntor(const extend_info_t* ei);
+int extend_info_has_preferred_onion_key(const extend_info_t* ei);
+bool extend_info_has_orport(const extend_info_t *ei,
+ const tor_addr_t *addr, uint16_t port);
+int extend_info_add_orport(extend_info_t *ei,
+ const tor_addr_t *addr,
+ uint16_t port);
+const tor_addr_port_t *extend_info_get_orport(const extend_info_t *ei,
+ int family);
+const tor_addr_port_t *extend_info_pick_orport(const extend_info_t *ei);
+bool extend_info_any_orport_addr_is_internal(const extend_info_t *ei);
+
+#endif /* !defined(TOR_CORE_OR_EXTENDINFO_H) */
diff --git a/src/core/or/include.am b/src/core/or/include.am
index 3626e76bed..af7c5a6f51 100644
--- a/src/core/or/include.am
+++ b/src/core/or/include.am
@@ -18,6 +18,7 @@ LIBTOR_APP_A_SOURCES += \
src/core/or/connection_edge.c \
src/core/or/connection_or.c \
src/core/or/dos.c \
+ src/core/or/extendinfo.c \
src/core/or/onion.c \
src/core/or/ocirc_event.c \
src/core/or/or_periodic.c \
@@ -64,6 +65,7 @@ noinst_HEADERS += \
src/core/or/destroy_cell_queue_st.h \
src/core/or/dos.h \
src/core/or/edge_connection_st.h \
+ src/core/or/extendinfo.h \
src/core/or/half_edge_st.h \
src/core/or/entry_connection_st.h \
src/core/or/entry_port_cfg_st.h \
diff --git a/src/core/or/onion.h b/src/core/or/onion.h
index 256f0a3f31..600e67c3cd 100644
--- a/src/core/or/onion.h
+++ b/src/core/or/onion.h
@@ -48,8 +48,7 @@ typedef struct extend_cell_t {
uint8_t cell_type;
/** An IPv4 address and port for the node we're connecting to. */
tor_addr_port_t orport_ipv4;
- /** An IPv6 address and port for the node we're connecting to. Not currently
- * used. */
+ /** An IPv6 address and port for the node we're connecting to. */
tor_addr_port_t orport_ipv6;
/** Identity fingerprint of the node we're conecting to.*/
uint8_t node_id[DIGEST_LEN];
diff --git a/src/core/or/or.h b/src/core/or/or.h
index 8758a2ec6f..d80c41371e 100644
--- a/src/core/or/or.h
+++ b/src/core/or/or.h
@@ -816,6 +816,18 @@ typedef struct protover_summary_flags_t {
* accept EXTEND2 cells. This requires Relay=2. */
unsigned int supports_extend2_cells:1;
+ /** True iff this router has a version or protocol list that allows it to
+ * accept IPv6 connections. This requires Relay=2 or Relay=3. */
+ unsigned int supports_accepting_ipv6_extends:1;
+
+ /** True iff this router has a version or protocol list that allows it to
+ * initiate IPv6 connections. This requires Relay=3. */
+ unsigned int supports_initiating_ipv6_extends:1;
+
+ /** True iff this router has a version or protocol list that allows it to
+ * consider IPv6 connections canonical. This requires Relay=3. */
+ unsigned int supports_canonical_ipv6_conns:1;
+
/** True iff this router has a protocol list that allows it to negotiate
* ed25519 identity keys on a link handshake with us. This
* requires LinkAuth=3. */
@@ -831,6 +843,10 @@ typedef struct protover_summary_flags_t {
* the v3 protocol detailed in proposal 224. This requires HSIntro=4. */
unsigned int supports_ed25519_hs_intro : 1;
+ /** True iff this router has a protocol list that allows it to support the
+ * ESTABLISH_INTRO DoS cell extension. Requires HSIntro=5. */
+ unsigned int supports_establish_intro_dos_extension : 1;
+
/** True iff this router has a protocol list that allows it to be an hidden
* service directory supporting version 3 as seen in proposal 224. This
* requires HSDir=2. */
@@ -842,12 +858,9 @@ typedef struct protover_summary_flags_t {
unsigned int supports_v3_rendezvous_point: 1;
/** True iff this router has a protocol list that allows clients to
- * negotiate hs circuit setup padding. Requires Padding>=2. */
+ * negotiate hs circuit setup padding. Requires Padding=2. */
unsigned int supports_hs_setup_padding : 1;
- /** True iff this router has a protocol list that allows it to support the
- * ESTABLISH_INTRO DoS cell extension. Requires HSIntro>=5. */
- unsigned int supports_establish_intro_dos_extension : 1;
} protover_summary_flags_t;
typedef struct routerinfo_t routerinfo_t;
diff --git a/src/core/or/protover.c b/src/core/or/protover.c
index c3f443631b..c6b0243693 100644
--- a/src/core/or/protover.c
+++ b/src/core/or/protover.c
@@ -326,6 +326,9 @@ protover_is_supported_here(protocol_type_t pr, uint32_t ver)
/**
* Return true iff "list" encodes a protocol list that includes support for
* the indicated protocol and version.
+ *
+ * If the protocol list is unparseable, treat it as if it defines no
+ * protocols, and return 0.
*/
int
protocol_list_supports_protocol(const char *list, protocol_type_t tp,
@@ -348,6 +351,9 @@ protocol_list_supports_protocol(const char *list, protocol_type_t tp,
/**
* Return true iff "list" encodes a protocol list that includes support for
* the indicated protocol and version, or some later version.
+ *
+ * If the protocol list is unparseable, treat it as if it defines no
+ * protocols, and return 0.
*/
int
protocol_list_supports_protocol_or_later(const char *list,
@@ -403,7 +409,7 @@ protover_get_supported_protocols(void)
#endif
"Microdesc=1-2 "
"Padding=2 "
- "Relay=1-2";
+ "Relay=1-3";
}
/** The protocols from protover_get_supported_protocols(), as parsed into a
@@ -740,6 +746,9 @@ protover_compute_vote(const smartlist_t *list_of_proto_strings,
* one that we support, and false otherwise. If <b>missing_out</b> is
* provided, set it to the list of protocols we do not support.
*
+ * If the protocol version string is unparseable, treat it as if it defines no
+ * protocols, and return 1.
+ *
* NOTE: This is quadratic, but we don't do it much: only a few times per
* consensus. Checking signatures should be way more expensive than this
* ever would be.
diff --git a/src/core/or/protover.h b/src/core/or/protover.h
index 9509f3e8a3..2950147d1b 100644
--- a/src/core/or/protover.h
+++ b/src/core/or/protover.h
@@ -22,12 +22,32 @@ struct smartlist_t;
/// `FIRST_TOR_VERSION_TO_ADVERTISE_PROTOCOLS`
#define FIRST_TOR_VERSION_TO_ADVERTISE_PROTOCOLS "0.2.9.3-alpha"
-/** The protover version number that signifies HSDir support for HSv3 */
-#define PROTOVER_HSDIR_V3 2
+/** The protover version number that signifies ed25519 link handshake support
+ */
+#define PROTOVER_LINKAUTH_ED25519_HANDSHAKE 3
+
+/** The protover version number that signifies extend2 cell support */
+#define PROTOVER_RELAY_EXTEND2 2
+/** The protover version number where relays can accept IPv6 connections */
+#define PROTOVER_RELAY_ACCEPT_IPV6 2
+/** The protover version number where relays can initiate IPv6 extends */
+#define PROTOVER_RELAY_EXTEND_IPV6 3
+/** The protover version number where relays can consider IPv6 connections
+ * canonical */
+#define PROTOVER_RELAY_CANONICAL_IPV6 3
+
/** The protover version number that signifies HSv3 intro point support */
#define PROTOVER_HS_INTRO_V3 4
+/** The protover version number where intro points support denial of service
+ * resistance */
+#define PROTOVER_HS_INTRO_DOS 5
+
/** The protover version number that signifies HSv3 rendezvous point support */
#define PROTOVER_HS_RENDEZVOUS_POINT_V3 2
+
+/** The protover version number that signifies HSDir support for HSv3 */
+#define PROTOVER_HSDIR_V3 2
+
/** The protover that signals support for HS circuit setup padding machines */
#define PROTOVER_HS_SETUP_PADDING 2
diff --git a/src/core/or/relay.c b/src/core/or/relay.c
index 75d2d479e7..6895591064 100644
--- a/src/core/or/relay.c
+++ b/src/core/or/relay.c
@@ -56,6 +56,7 @@
#include "core/or/circuitlist.h"
#include "core/or/circuituse.h"
#include "core/or/circuitpadding.h"
+#include "core/or/extendinfo.h"
#include "lib/compress/compress.h"
#include "app/config/config.h"
#include "core/mainloop/connection.h"
diff --git a/src/core/or/scheduler_kist.c b/src/core/or/scheduler_kist.c
index c73d768f88..5c1922847e 100644
--- a/src/core/or/scheduler_kist.c
+++ b/src/core/or/scheduler_kist.c
@@ -445,6 +445,11 @@ update_socket_written(socket_table_t *table, channel_t *chan, size_t bytes)
* one cell for each and bouncing back and forth. This KIST impl avoids that
* by only writing a channel's outbuf to the kernel if it has 8 cells or more
* in it.
+ *
+ * Note: The number 8 has been picked for no particular reasons except that it
+ * is 4096 bytes which is a common number for buffering. A TLS record can hold
+ * up to 16KiB thus using 8 cells means that a relay will at most send a TLS
+ * record of 4KiB or 1/4 of the maximum capacity of a TLS record.
*/
MOCK_IMPL(int, channel_should_write_to_kernel,
(outbuf_table_t *table, channel_t *chan))
diff --git a/src/core/or/versions.c b/src/core/or/versions.c
index 31f1f5b997..5dfe0c2cc9 100644
--- a/src/core/or/versions.c
+++ b/src/core/or/versions.c
@@ -408,6 +408,10 @@ static strmap_t *protover_summary_map = NULL;
/**
* Helper. Given a non-NULL protover string <b>protocols</b>, set <b>out</b>
* to its summary, and memoize the result in <b>protover_summary_map</b>.
+ *
+ * If the protover string does not contain any recognised protocols, sets
+ * protocols_known, but does not set any other flags. (Empty strings are also
+ * treated this way.)
*/
static void
memoize_protover_summary(protover_summary_flags_t *out,
@@ -434,25 +438,49 @@ memoize_protover_summary(protover_summary_flags_t *out,
memset(out, 0, sizeof(*out));
out->protocols_known = 1;
- out->supports_extend2_cells =
- protocol_list_supports_protocol(protocols, PRT_RELAY, 2);
+
out->supports_ed25519_link_handshake_compat =
- protocol_list_supports_protocol(protocols, PRT_LINKAUTH, 3);
+ protocol_list_supports_protocol(protocols, PRT_LINKAUTH,
+ PROTOVER_LINKAUTH_ED25519_HANDSHAKE);
out->supports_ed25519_link_handshake_any =
- protocol_list_supports_protocol_or_later(protocols, PRT_LINKAUTH, 3);
+ protocol_list_supports_protocol_or_later(
+ protocols,
+ PRT_LINKAUTH,
+ PROTOVER_LINKAUTH_ED25519_HANDSHAKE);
+
+ out->supports_extend2_cells =
+ protocol_list_supports_protocol(protocols, PRT_RELAY,
+ PROTOVER_RELAY_EXTEND2);
+ out->supports_accepting_ipv6_extends = (
+ protocol_list_supports_protocol(protocols, PRT_RELAY,
+ PROTOVER_RELAY_ACCEPT_IPV6) ||
+ protocol_list_supports_protocol(protocols, PRT_RELAY,
+ PROTOVER_RELAY_EXTEND_IPV6));
+ out->supports_initiating_ipv6_extends =
+ protocol_list_supports_protocol(protocols, PRT_RELAY,
+ PROTOVER_RELAY_EXTEND_IPV6);
+ out->supports_canonical_ipv6_conns =
+ protocol_list_supports_protocol(protocols, PRT_RELAY,
+ PROTOVER_RELAY_CANONICAL_IPV6);
+
out->supports_ed25519_hs_intro =
- protocol_list_supports_protocol(protocols, PRT_HSINTRO, 4);
- out->supports_v3_hsdir =
- protocol_list_supports_protocol(protocols, PRT_HSDIR,
- PROTOVER_HSDIR_V3);
+ protocol_list_supports_protocol(protocols, PRT_HSINTRO,
+ PROTOVER_HS_INTRO_V3);
+ out->supports_establish_intro_dos_extension =
+ protocol_list_supports_protocol(protocols, PRT_HSINTRO,
+ PROTOVER_HS_INTRO_DOS);
+
out->supports_v3_rendezvous_point =
protocol_list_supports_protocol(protocols, PRT_HSREND,
PROTOVER_HS_RENDEZVOUS_POINT_V3);
+
+ out->supports_v3_hsdir =
+ protocol_list_supports_protocol(protocols, PRT_HSDIR,
+ PROTOVER_HSDIR_V3);
+
out->supports_hs_setup_padding =
protocol_list_supports_protocol(protocols, PRT_PADDING,
PROTOVER_HS_SETUP_PADDING);
- out->supports_establish_intro_dos_extension =
- protocol_list_supports_protocol(protocols, PRT_HSINTRO, 5);
protover_summary_flags_t *new_cached = tor_memdup(out, sizeof(*out));
cached = strmap_set(protover_summary_map, protocols, new_cached);
@@ -461,6 +489,13 @@ memoize_protover_summary(protover_summary_flags_t *out,
/** Summarize the protocols listed in <b>protocols</b> into <b>out</b>,
* falling back or correcting them based on <b>version</b> as appropriate.
+ *
+ * If protocols and version are both NULL or "", returns a summary with no
+ * flags set.
+ *
+ * If the protover string does not contain any recognised protocols, and the
+ * version is not recognised, sets protocols_known, but does not set any other
+ * flags. (Empty strings are also treated this way.)
*/
void
summarize_protover_flags(protover_summary_flags_t *out,
@@ -469,10 +504,10 @@ summarize_protover_flags(protover_summary_flags_t *out,
{
tor_assert(out);
memset(out, 0, sizeof(*out));
- if (protocols) {
+ if (protocols && strcmp(protocols, "")) {
memoize_protover_summary(out, protocols);
}
- if (version && !strcmpstart(version, "Tor ")) {
+ if (version && strcmp(version, "") && !strcmpstart(version, "Tor ")) {
if (!out->protocols_known) {
/* The version is a "Tor" version, and where there is no
* list of protocol versions that we should be looking at instead. */
diff --git a/src/core/stA1RajU b/src/core/stA1RajU
deleted file mode 100644
index e69de29bb2..0000000000
--- a/src/core/stA1RajU
+++ /dev/null
diff --git a/src/core/stiysZND b/src/core/stiysZND
deleted file mode 100644
index faa365b769..0000000000
--- a/src/core/stiysZND
+++ /dev/null
Binary files differ
diff --git a/src/ext/README b/src/ext/README
deleted file mode 100644
index d7e5439c71..0000000000
--- a/src/ext/README
+++ /dev/null
@@ -1,79 +0,0 @@
-
-OpenBSD_malloc_Linux.c:
-
- The OpenBSD malloc implementation, ported to Linux. Used only when
- --enable-openbsd-malloc is passed to the configure script.
-
-strlcat.c
-strlcpy.c
-
- Implementations of strlcat and strlcpy, the more sane replacements
- for strcat and strcpy. These are nonstandard, and some libc
- implementations refuse to add them for religious reasons.
-
-ht.h
-
- An implementation of a hash table in the style of Niels Provos's
- tree.h. Shared with Libevent.
-
-tinytest.[ch]
-tinytest_demos.c
-tinytest_macros.h
-
- A unit testing framework. https://github.com/nmathewson/tinytest
-
-tor_queue.h
-
- A copy of sys/queue.h from OpenBSD. We keep our own copy rather
- than using sys/queue.h, since some platforms don't have a
- sys/queue.h, and the ones that do have diverged in incompatible
- ways. (CIRCLEQ or no CIRCLEQ? SIMPLQ or STAILQ?) We also rename
- the identifiers with a TOR_ prefix to avoid conflicts with
- the system headers.
-
-curve25519_donna/*.c
-
- A copy of Adam Langley's curve25519-donna mostly-portable
- implementations of curve25519.
-
-csiphash.c
-siphash.h
-
- Marek Majkowski's implementation of siphash 2-4, a secure keyed
- hash algorithm to avoid collision-based DoS attacks against hash
- tables.
-
-trunnel/*.[ch]
-
- Headers and runtime code for Trunnel, a system for generating
- code to encode and decode binary formats.
-
-ed25519/ref10/*
-
- Daniel Bernsten's portable ref10 implementation of ed25519.
- Public domain.
-
-ed25519/donna/*
-
- Andrew Moon's semi-portable ed25519-donna implementation of
- ed25519. Public domain.
-
-keccak-tiny/
-
- David Leon Gil's portable Keccak implementation. CC0.
-
-readpassphrase.[ch]
-
- Portable readpassphrase implementation from OpenSSH portable, version
- 6.8p1.
-
-timeouts/
-
- William Ahern's hierarchical timer-wheel implementation. MIT license.
-
-mulodi/
-
- Contains an overflow-checking 64-bit signed integer multiply
- from LLVM's compiler_rt. For some reason, this is missing from
- 32-bit libclang in many places. Dual licensed MIT-license and
- BSD-like license; see mulodi/LICENSE.TXT.
diff --git a/src/ext/ext.md b/src/ext/ext.md
new file mode 100644
index 0000000000..1eaaab605b
--- /dev/null
+++ b/src/ext/ext.md
@@ -0,0 +1,88 @@
+@dir /ext
+@brief Externally maintained code
+
+The "ext" directory holds code that was written elsewhere, and is not
+reliably packaged as a library where we want to build, so we ship
+it along with Tor.
+
+In general, you should not edit this code: we are not the maintainers.
+Instead, you should submit patches upstream.
+
+OpenBSD_malloc_Linux.c:
+
+> The OpenBSD malloc implementation, ported to Linux. Used only when
+> --enable-openbsd-malloc is passed to the configure script.
+
+strlcat.c
+strlcpy.c
+
+> Implementations of strlcat and strlcpy, the more sane replacements
+> for strcat and strcpy. These are nonstandard, and some libc
+> implementations refuse to add them for religious reasons.
+
+ht.h
+
+> An implementation of a hash table in the style of Niels Provos's
+> tree.h. Shared with Libevent.
+
+tinytest.c tinytest.h
+tinytest_demos.c
+tinytest_macros.h
+
+> A unit testing framework. https://github.com/nmathewson/tinytest
+
+tor_queue.h
+
+> A copy of sys/queue.h from OpenBSD. We keep our own copy rather
+> than using sys/queue.h, since some platforms don't have a
+> sys/queue.h, and the ones that do have diverged in incompatible
+> ways. (CIRCLEQ or no CIRCLEQ? SIMPLQ or STAILQ?) We also rename
+> the identifiers with a TOR_ prefix to avoid conflicts with
+> the system headers.
+
+curve25519_donna/*.c
+
+> A copy of Adam Langley's curve25519-donna mostly-portable
+> implementations of curve25519.
+
+csiphash.c
+siphash.h
+
+> Marek Majkowski's implementation of siphash 2-4, a secure keyed
+> hash algorithm to avoid collision-based DoS attacks against hash
+> tables.
+
+trunnel/*.[ch]
+
+> Headers and runtime code for Trunnel, a system for generating
+> code to encode and decode binary formats.
+
+ed25519/ref10/*
+
+> Daniel Bernsten's portable ref10 implementation of ed25519.
+> Public domain.
+
+ed25519/donna/*
+
+> Andrew Moon's semi-portable ed25519-donna implementation of
+> ed25519. Public domain.
+
+keccak-tiny/
+
+> David Leon Gil's portable Keccak implementation. CC0.
+
+readpassphrase.[ch]
+
+> Portable readpassphrase implementation from OpenSSH portable, version
+> 6.8p1.
+
+timeouts/
+
+> William Ahern's hierarchical timer-wheel implementation. MIT license.
+
+mulodi/
+
+> Contains an overflow-checking 64-bit signed integer multiply
+> from LLVM's compiler_rt. For some reason, this is missing from
+> 32-bit libclang in many places. Dual licensed MIT-license and
+> BSD-like license; see mulodi/LICENSE.TXT.
diff --git a/src/ext/include.am b/src/ext/include.am
index 317e25d78e..8b646b1b4e 100644
--- a/src/ext/include.am
+++ b/src/ext/include.am
@@ -1,7 +1,7 @@
AM_CPPFLAGS += -I$(srcdir)/src/ext -Isrc/ext
-EXTRA_DIST += src/ext/README
+EXTRA_DIST += src/ext/ext.md
EXTHEADERS = \
src/ext/ht.h \
diff --git a/src/feature/client/bridges.c b/src/feature/client/bridges.c
index 66b04f3bc2..caa4776493 100644
--- a/src/feature/client/bridges.c
+++ b/src/feature/client/bridges.c
@@ -259,12 +259,26 @@ addr_is_a_configured_bridge(const tor_addr_t *addr,
/** If we have a bridge configured whose digest matches
* <b>ei->identity_digest</b>, or a bridge with no known digest whose address
* matches <b>ei->addr</b>:<b>ei->port</b>, return 1. Else return 0.
- * If <b>ei->onion_key</b> is NULL, check for address/port matches only. */
+ * If <b>ei->onion_key</b> is NULL, check for address/port matches only.
+ *
+ * Note that if the extend_info_t contains multiple addresses, we return true
+ * only if _every_ address is a bridge.
+ */
int
extend_info_is_a_configured_bridge(const extend_info_t *ei)
{
const char *digest = ei->onion_key ? ei->identity_digest : NULL;
- return addr_is_a_configured_bridge(&ei->addr, ei->port, digest);
+ const tor_addr_port_t *ap1 = NULL, *ap2 = NULL;
+ if (! tor_addr_is_null(&ei->orports[0].addr))
+ ap1 = &ei->orports[0];
+ if (! tor_addr_is_null(&ei->orports[1].addr))
+ ap2 = &ei->orports[1];
+ IF_BUG_ONCE(ap1 == NULL) {
+ return 0;
+ }
+ return addr_is_a_configured_bridge(&ap1->addr, ap1->port, digest) &&
+ (ap2 == NULL ||
+ addr_is_a_configured_bridge(&ap2->addr, ap2->port, digest));
}
/** Wrapper around get_configured_bridge_by_addr_port_digest() to look
diff --git a/src/feature/client/entrynodes.c b/src/feature/client/entrynodes.c
index 223815e7b2..6e8259142d 100644
--- a/src/feature/client/entrynodes.c
+++ b/src/feature/client/entrynodes.c
@@ -1554,7 +1554,7 @@ guard_in_node_family(const entry_guard_t *guard, const node_t *node)
if (get_options()->EnforceDistinctSubnets && guard->bridge_addr) {
tor_addr_t node_addr;
node_get_addr(node, &node_addr);
- if (addrs_in_same_network_family(&node_addr,
+ if (router_addrs_in_same_network(&node_addr,
&guard->bridge_addr->addr)) {
return 1;
}
diff --git a/src/feature/control/control_cmd.c b/src/feature/control/control_cmd.c
index d9a38011de..a8926c0b79 100644
--- a/src/feature/control/control_cmd.c
+++ b/src/feature/control/control_cmd.c
@@ -20,9 +20,12 @@
#include "core/or/circuitlist.h"
#include "core/or/circuituse.h"
#include "core/or/connection_edge.h"
+#include "core/or/circuitstats.h"
+#include "core/or/extendinfo.h"
#include "feature/client/addressmap.h"
#include "feature/client/dnsserv.h"
#include "feature/client/entrynodes.h"
+#include "feature/control/control_events.h"
#include "feature/control/control.h"
#include "feature/control/control_auth.h"
#include "feature/control/control_cmd.h"
@@ -55,6 +58,8 @@
#include "feature/rend/rend_encoded_v2_service_descriptor_st.h"
#include "feature/rend/rend_service_descriptor_st.h"
+#include "src/app/config/statefile.h"
+
static int control_setconf_helper(control_connection_t *conn,
const control_cmd_args_t *args,
int use_defaults);
@@ -1396,6 +1401,34 @@ handle_control_dropguards(control_connection_t *conn,
return 0;
}
+static const control_cmd_syntax_t droptimeouts_syntax = {
+ .max_args = 0,
+};
+
+/** Implementation for the DROPTIMEOUTS command. */
+static int
+handle_control_droptimeouts(control_connection_t *conn,
+ const control_cmd_args_t *args)
+{
+ (void) args; /* We don't take arguments. */
+
+ static int have_warned = 0;
+ if (! have_warned) {
+ log_warn(LD_CONTROL, "DROPTIMEOUTS is dangerous; make sure you understand "
+ "the risks before using it. It may be removed in a future "
+ "version of Tor.");
+ have_warned = 1;
+ }
+
+ circuit_build_times_reset(get_circuit_build_times_mutable());
+ send_control_done(conn);
+ or_state_mark_dirty(get_or_state(), 0);
+ cbt_control_event_buildtimeout_set(get_circuit_build_times(),
+ BUILDTIMEOUT_SET_EVENT_RESET);
+
+ return 0;
+}
+
static const char *hsfetch_keywords[] = {
"SERVER", NULL,
};
@@ -1430,7 +1463,7 @@ handle_control_hsfetch(control_connection_t *conn,
rend_valid_descriptor_id(arg1 + v2_str_len) &&
base32_decode(digest, sizeof(digest), arg1 + v2_str_len,
REND_DESC_ID_V2_LEN_BASE32) ==
- REND_DESC_ID_V2_LEN_BASE32) {
+ sizeof(digest)) {
/* We have a well formed version 2 descriptor ID. Keep the decoded value
* of the id. */
desc_id = digest;
@@ -2331,6 +2364,7 @@ static const control_cmd_def_t CONTROL_COMMANDS[] =
ONE_LINE(protocolinfo, 0),
ONE_LINE(authchallenge, CMD_FL_WIPE),
ONE_LINE(dropguards, 0),
+ ONE_LINE(droptimeouts, 0),
ONE_LINE(hsfetch, 0),
MULTLINE(hspost, 0),
ONE_LINE(add_onion, CMD_FL_WIPE),
diff --git a/src/feature/control/control_events.c b/src/feature/control/control_events.c
index 916ccea875..8e69c772f6 100644
--- a/src/feature/control/control_events.c
+++ b/src/feature/control/control_events.c
@@ -17,6 +17,7 @@
#include "core/mainloop/mainloop.h"
#include "core/or/channeltls.h"
#include "core/or/circuitlist.h"
+#include "core/or/circuitstats.h"
#include "core/or/command.h"
#include "core/or/connection_edge.h"
#include "core/or/connection_or.h"
@@ -141,6 +142,64 @@ clear_circ_bw_fields(void)
SMARTLIST_FOREACH_END(circ);
}
+/* Helper to emit the BUILDTIMEOUT_SET circuit build time event */
+void
+cbt_control_event_buildtimeout_set(const circuit_build_times_t *cbt,
+ buildtimeout_set_event_t type)
+{
+ char *args = NULL;
+ double qnt;
+ double timeout_rate = 0.0;
+ double close_rate = 0.0;
+
+ switch (type) {
+ case BUILDTIMEOUT_SET_EVENT_RESET:
+ case BUILDTIMEOUT_SET_EVENT_SUSPENDED:
+ case BUILDTIMEOUT_SET_EVENT_DISCARD:
+ qnt = 1.0;
+ break;
+ case BUILDTIMEOUT_SET_EVENT_COMPUTED:
+ case BUILDTIMEOUT_SET_EVENT_RESUME:
+ default:
+ qnt = circuit_build_times_quantile_cutoff();
+ break;
+ }
+
+ /* The timeout rate is the ratio of the timeout count over
+ * the total number of circuits attempted. The total number of
+ * circuits is (timeouts+succeeded), since every circuit
+ * either succeeds, or times out. "Closed" circuits are
+ * MEASURE_TIMEOUT circuits whose measurement period expired.
+ * All MEASURE_TIMEOUT circuits are counted in the timeouts stat
+ * before transitioning to MEASURE_TIMEOUT (in
+ * circuit_build_times_mark_circ_as_measurement_only()).
+ * MEASURE_TIMEOUT circuits that succeed are *not* counted as
+ * "succeeded". See circuit_build_times_handle_completed_hop().
+ *
+ * We cast the denominator
+ * to promote it to double before the addition, to avoid int32
+ * overflow. */
+ const double total_circuits =
+ ((double)cbt->num_circ_timeouts) + cbt->num_circ_succeeded;
+ if (total_circuits >= 1.0) {
+ timeout_rate = cbt->num_circ_timeouts / total_circuits;
+ close_rate = cbt->num_circ_closed / total_circuits;
+ }
+
+ tor_asprintf(&args, "TOTAL_TIMES=%lu "
+ "TIMEOUT_MS=%lu XM=%lu ALPHA=%f CUTOFF_QUANTILE=%f "
+ "TIMEOUT_RATE=%f CLOSE_MS=%lu CLOSE_RATE=%f",
+ (unsigned long)cbt->total_build_times,
+ (unsigned long)cbt->timeout_ms,
+ (unsigned long)cbt->Xm, cbt->alpha, qnt,
+ timeout_rate,
+ (unsigned long)cbt->close_ms,
+ close_rate);
+
+ control_event_buildtimeout_set(type, args);
+
+ tor_free(args);
+}
/** Set <b>global_event_mask*</b> to the bitwise OR of each live control
* connection's event_mask field. */
void
diff --git a/src/feature/control/control_events.h b/src/feature/control/control_events.h
index 4a5492b510..0c8448e0f8 100644
--- a/src/feature/control/control_events.h
+++ b/src/feature/control/control_events.h
@@ -223,6 +223,8 @@ void control_event_hs_descriptor_content(const char *onion_address,
const char *desc_id,
const char *hsdir_fp,
const char *content);
+void cbt_control_event_buildtimeout_set(const circuit_build_times_t *cbt,
+ buildtimeout_set_event_t type);
void control_events_free_all(void);
diff --git a/src/feature/control/control_getinfo.c b/src/feature/control/control_getinfo.c
index 0823acbe07..daf71f04c9 100644
--- a/src/feature/control/control_getinfo.c
+++ b/src/feature/control/control_getinfo.c
@@ -51,6 +51,7 @@
#include "feature/rend/rendcache.h"
#include "feature/stats/geoip_stats.h"
#include "feature/stats/predict_ports.h"
+#include "feature/stats/rephist.h"
#include "lib/version/torversion.h"
#include "lib/encoding/kvline.h"
@@ -1278,15 +1279,18 @@ getinfo_helper_events(control_connection_t *control_conn,
*answer = tor_strdup(directories_have_accepted_server_descriptor()
? "1" : "0");
} else if (!strcmp(question, "status/reachability-succeeded/or")) {
- *answer = tor_strdup(check_whether_orport_reachable(options) ?
- "1" : "0");
+ *answer = tor_strdup(
+ router_all_orports_seem_reachable(options) ?
+ "1" : "0");
} else if (!strcmp(question, "status/reachability-succeeded/dir")) {
- *answer = tor_strdup(check_whether_dirport_reachable(options) ?
- "1" : "0");
+ *answer = tor_strdup(
+ router_dirport_seems_reachable(options) ?
+ "1" : "0");
} else if (!strcmp(question, "status/reachability-succeeded")) {
- tor_asprintf(answer, "OR=%d DIR=%d",
- check_whether_orport_reachable(options) ? 1 : 0,
- check_whether_dirport_reachable(options) ? 1 : 0);
+ tor_asprintf(
+ answer, "OR=%d DIR=%d",
+ router_all_orports_seem_reachable(options) ? 1 : 0,
+ router_dirport_seems_reachable(options) ? 1 : 0);
} else if (!strcmp(question, "status/bootstrap-phase")) {
*answer = control_event_boot_last_msg();
} else if (!strcmpstart(question, "status/version/")) {
@@ -1437,6 +1441,39 @@ getinfo_helper_liveness(control_connection_t *control_conn,
return 0;
}
+/** Implementation helper for GETINFO: answers queries about circuit onion
+ * handshake rephist values */
+STATIC int
+getinfo_helper_rephist(control_connection_t *control_conn,
+ const char *question, char **answer,
+ const char **errmsg)
+{
+ (void) control_conn;
+ (void) errmsg;
+ int result;
+
+ if (!strcmp(question, "stats/ntor/assigned")) {
+ result =
+ rep_hist_get_circuit_handshake_assigned(ONION_HANDSHAKE_TYPE_NTOR);
+ } else if (!strcmp(question, "stats/ntor/requested")) {
+ result =
+ rep_hist_get_circuit_handshake_requested(ONION_HANDSHAKE_TYPE_NTOR);
+ } else if (!strcmp(question, "stats/tap/assigned")) {
+ result =
+ rep_hist_get_circuit_handshake_assigned(ONION_HANDSHAKE_TYPE_TAP);
+ } else if (!strcmp(question, "stats/tap/requested")) {
+ result =
+ rep_hist_get_circuit_handshake_requested(ONION_HANDSHAKE_TYPE_TAP);
+ } else {
+ *errmsg = "Unrecognized handshake type";
+ return -1;
+ }
+
+ tor_asprintf(answer, "%d", result);
+
+ return 0;
+}
+
/** Implementation helper for GETINFO: answers queries about shared random
* value. */
static int
@@ -1661,6 +1698,16 @@ static const getinfo_item_t getinfo_items[] = {
"Onion services detached from the control connection."),
ITEM("sr/current", sr, "Get current shared random value."),
ITEM("sr/previous", sr, "Get previous shared random value."),
+ PREFIX("stats/ntor/", rephist, "NTor circuit handshake stats."),
+ ITEM("stats/ntor/assigned", rephist,
+ "Assigned NTor circuit handshake stats."),
+ ITEM("stats/ntor/requested", rephist,
+ "Requested NTor circuit handshake stats."),
+ PREFIX("stats/tap/", rephist, "TAP circuit handshake stats."),
+ ITEM("stats/tap/assigned", rephist,
+ "Assigned TAP circuit handshake stats."),
+ ITEM("stats/tap/requested", rephist,
+ "Requested TAP circuit handshake stats."),
{ NULL, NULL, NULL, 0 }
};
diff --git a/src/feature/control/control_getinfo.h b/src/feature/control/control_getinfo.h
index 0ada49258e..f61d632446 100644
--- a/src/feature/control/control_getinfo.h
+++ b/src/feature/control/control_getinfo.h
@@ -60,6 +60,10 @@ STATIC int getinfo_helper_current_time(
control_connection_t *control_conn,
const char *question, char **answer,
const char **errmsg);
+STATIC int getinfo_helper_rephist(
+ control_connection_t *control_conn,
+ const char *question, char **answer,
+ const char **errmsg);
#endif /* defined(CONTROL_GETINFO_PRIVATE) */
#endif /* !defined(TOR_CONTROL_GETINFO_H) */
diff --git a/src/feature/dirauth/dirauth_config.c b/src/feature/dirauth/dirauth_config.c
index a0b6de7eca..1ffd33e5f1 100644
--- a/src/feature/dirauth/dirauth_config.c
+++ b/src/feature/dirauth/dirauth_config.c
@@ -77,8 +77,8 @@ options_validate_dirauth_mode(const or_options_t *old_options,
return 0;
/* confirm that our address isn't broken, so we can complain now */
- uint32_t tmp;
- if (resolve_my_address(LOG_WARN, options, &tmp, NULL, NULL) < 0)
+ tor_addr_t tmp;
+ if (!find_my_address(options, AF_INET, LOG_WARN, &tmp, NULL, NULL))
REJECT("Failed to resolve/guess local address. See logs for details.");
if (!options->ContactInfo && !options->TestingTorNetwork)
diff --git a/src/feature/dirauth/dirauth_options.inc b/src/feature/dirauth/dirauth_options.inc
index 21f4996c39..40ef7c3bab 100644
--- a/src/feature/dirauth/dirauth_options.inc
+++ b/src/feature/dirauth/dirauth_options.inc
@@ -44,6 +44,13 @@ CONF_VAR(AuthDirSharedRandomness, BOOL, 0, "1")
/* NOTE: remove this option someday. */
CONF_VAR(AuthDirTestEd25519LinkKeys, BOOL, 0, "1")
+/**
+ * Bool (default 1): As an authority, should we launch tests for
+ * reachability, and use those results to vote on "Running"? If 0,
+ * we assume that every relay is Runnning.
+ **/
+CONF_VAR(AuthDirTestReachability, BOOL, 0, "1")
+
/** Authority only: key=value pairs that we add to our networkstatus
* consensus vote on the 'params' line. */
CONF_VAR(ConsensusParams, STRING, 0, NULL)
diff --git a/src/feature/dirauth/dirvote.c b/src/feature/dirauth/dirvote.c
index 79651563b4..5fda842246 100644
--- a/src/feature/dirauth/dirvote.c
+++ b/src/feature/dirauth/dirvote.c
@@ -4463,7 +4463,7 @@ dirserv_generate_networkstatus_vote_obj(crypto_pk_t *private_key,
const or_options_t *options = get_options();
const dirauth_options_t *d_options = dirauth_get_options();
networkstatus_t *v3_out = NULL;
- uint32_t addr;
+ tor_addr_t addr;
char *hostname = NULL, *client_versions = NULL, *server_versions = NULL;
const char *contact;
smartlist_t *routers, *routerstatuses;
@@ -4492,13 +4492,13 @@ dirserv_generate_networkstatus_vote_obj(crypto_pk_t *private_key,
log_err(LD_BUG, "Error computing identity key digest");
return NULL;
}
- if (resolve_my_address(LOG_WARN, options, &addr, NULL, &hostname)<0) {
+ if (!find_my_address(options, AF_INET, LOG_WARN, &addr, NULL, &hostname)) {
log_warn(LD_NET, "Couldn't resolve my hostname");
return NULL;
}
if (!hostname || !strchr(hostname, '.')) {
tor_free(hostname);
- hostname = tor_dup_ip(addr);
+ hostname = tor_addr_to_str_dup(&addr);
}
if (!hostname) {
@@ -4722,7 +4722,7 @@ dirserv_generate_networkstatus_vote_obj(crypto_pk_t *private_key,
memcpy(voter->identity_digest, identity_digest, DIGEST_LEN);
voter->sigs = smartlist_new();
voter->address = hostname;
- voter->addr = addr;
+ voter->addr = tor_addr_to_ipv4h(&addr);
voter->dir_port = router_get_advertised_dir_port(options, 0);
voter->or_port = router_get_advertised_or_port(options);
voter->contact = tor_strdup(contact);
diff --git a/src/feature/dirauth/process_descs.c b/src/feature/dirauth/process_descs.c
index 5025d0ae39..bc659d032d 100644
--- a/src/feature/dirauth/process_descs.c
+++ b/src/feature/dirauth/process_descs.c
@@ -409,11 +409,11 @@ dirserv_rejects_tor_version(const char *platform,
return true;
}
- /* Series between Tor 0.3.6 and 0.4.1.4-rc inclusive are unsupported.
- * Reject them. 0.3.6.0-alpha-dev only existed for a short time, before
- * it was renamed to 0.4.0.0-alpha-dev. */
+ /* Series between Tor 0.3.6 and 0.4.1 inclusive are unsupported. Reject
+ * them. 0.3.6.0-alpha-dev only existed for a short time, before it was
+ * renamed to 0.4.0.0-alpha-dev. */
if (tor_version_as_new_as(platform,"0.3.6.0-alpha-dev") &&
- !tor_version_as_new_as(platform,"0.4.1.5")) {
+ !tor_version_as_new_as(platform,"0.4.2.1-alpha")) {
if (msg) {
*msg = please_upgrade_string;
}
diff --git a/src/feature/dirauth/reachability.c b/src/feature/dirauth/reachability.c
index 65fa27ed80..30938f528d 100644
--- a/src/feature/dirauth/reachability.c
+++ b/src/feature/dirauth/reachability.c
@@ -105,6 +105,8 @@ dirserv_should_launch_reachability_test(const routerinfo_t *ri,
{
if (!authdir_mode_handles_descs(get_options(), ri->purpose))
return 0;
+ if (! dirauth_get_options()->AuthDirTestReachability)
+ return 0;
if (!ri_old) {
/* New router: Launch an immediate reachability test, so we will have an
* opinion soon in case we're generating a consensus soon */
@@ -189,6 +191,9 @@ dirserv_test_reachability(time_t now)
* the testing, and directory authorities are easy to upgrade. Let's
* wait til 0.2.0. -RD */
// time_t cutoff = now - ROUTER_MAX_AGE_TO_PUBLISH;
+ if (! dirauth_get_options()->AuthDirTestReachability)
+ return;
+
routerlist_t *rl = router_get_routerlist();
static char ctr = 0;
int bridge_auth = authdir_mode_bridge(get_options());
diff --git a/src/feature/dirauth/voteflags.c b/src/feature/dirauth/voteflags.c
index 477eb6f0b7..3938b61adb 100644
--- a/src/feature/dirauth/voteflags.c
+++ b/src/feature/dirauth/voteflags.c
@@ -487,7 +487,6 @@ dirserv_set_router_is_running(routerinfo_t *router, time_t now)
unreachable.
*/
int answer;
- const or_options_t *options = get_options();
const dirauth_options_t *dirauth_options = dirauth_get_options();
node_t *node = node_get_mutable_by_id(router->cache_info.identity_digest);
tor_assert(node);
@@ -501,8 +500,9 @@ dirserv_set_router_is_running(routerinfo_t *router, time_t now)
/* A hibernating router is down unless we (somehow) had contact with it
* since it declared itself to be hibernating. */
answer = 0;
- } else if (options->AssumeReachable) {
- /* If AssumeReachable, everybody is up unless they say they are down! */
+ } else if (! dirauth_options->AuthDirTestReachability) {
+ /* If we aren't testing reachability, then everybody is up unless they say
+ * they are down. */
answer = 1;
} else {
/* Otherwise, a router counts as up if we found all announced OR
diff --git a/src/feature/dircache/dircache.c b/src/feature/dircache/dircache.c
index ca127720f2..691c100974 100644
--- a/src/feature/dircache/dircache.c
+++ b/src/feature/dircache/dircache.c
@@ -142,7 +142,7 @@ write_http_response_header_impl(dir_connection_t *conn, ssize_t length,
if (type) {
buf_add_printf(buf, "Content-Type: %s\r\n", type);
}
- if (!is_local_addr(&conn->base_.addr)) {
+ if (!is_local_to_resolve_addr(&conn->base_.addr)) {
/* Don't report the source address for a nearby/private connection.
* Otherwise we tend to mis-report in cases where incoming ports are
* being forwarded to a Tor server running behind the firewall. */
diff --git a/src/feature/feature.md b/src/feature/feature.md
index acc3487e55..d9f7bd5c0e 100644
--- a/src/feature/feature.md
+++ b/src/feature/feature.md
@@ -5,3 +5,26 @@ The "feature" directory has modules that Tor uses only for a particular
role or service, such as maintaining/using an onion service, operating as a
relay or a client, or being a directory authority.
+Current subdirectories are:
+
+ - \refdir{feature/api} -- Support for making Tor embeddable
+ - \refdir{feature/client} -- Functionality which only Tor clients need
+ - \refdir{feature/control} -- Controller implementation
+ - \refdir{feature/dirauth} -- Directory authority
+ - \refdir{feature/dircache} -- Directory cache
+ - \refdir{feature/dirclient} -- Directory client
+ - \refdir{feature/dircommon} -- Shared code between the other directory modules
+ - \refdir{feature/dirparse} -- Directory parsing code.
+ - \refdir{feature/hibernate} -- Hibernating when Tor is out of bandwidth
+ or shutting down
+ - \refdir{feature/hs} -- v3 onion service implementation
+ - \refdir{feature/hs_common} -- shared code between both onion service
+ implementations
+ - \refdir{feature/keymgt} -- shared code for key management between
+ relays and onion services.
+ - \refdir{feature/nodelist} -- storing and accessing the list of relays on
+ the network.
+ - \refdir{feature/relay} -- code that only relay servers and exit servers
+ need.
+ - \refdir{feature/rend} -- v2 onion service implementation
+ - \refdir{feature/stats} -- statistics and history
diff --git a/src/feature/hs/hs_circuit.c b/src/feature/hs/hs_circuit.c
index 447f664f81..5e7a3ac9c8 100644
--- a/src/feature/hs/hs_circuit.c
+++ b/src/feature/hs/hs_circuit.c
@@ -16,6 +16,7 @@
#include "core/or/policies.h"
#include "core/or/relay.h"
#include "core/or/crypt_path.h"
+#include "core/or/extendinfo.h"
#include "feature/client/circpathbias.h"
#include "feature/hs/hs_cell.h"
#include "feature/hs/hs_circuit.h"
diff --git a/src/feature/hs/hs_client.c b/src/feature/hs/hs_client.c
index 892f69a3a0..09f0657fa8 100644
--- a/src/feature/hs/hs_client.c
+++ b/src/feature/hs/hs_client.c
@@ -16,6 +16,7 @@
#include "core/or/circuitlist.h"
#include "core/or/circuituse.h"
#include "core/or/connection_edge.h"
+#include "core/or/extendinfo.h"
#include "core/or/reasons.h"
#include "feature/client/circpathbias.h"
#include "feature/dirclient/dirclient.h"
diff --git a/src/feature/hs/hs_common.c b/src/feature/hs/hs_common.c
index 4639cdb68a..706b42529f 100644
--- a/src/feature/hs/hs_common.c
+++ b/src/feature/hs/hs_common.c
@@ -16,6 +16,7 @@
#include "app/config/config.h"
#include "core/or/circuitbuild.h"
#include "core/or/policies.h"
+#include "core/or/extendinfo.h"
#include "feature/dirauth/shared_random_state.h"
#include "feature/hs/hs_cache.h"
#include "feature/hs/hs_circuitmap.h"
diff --git a/src/feature/hs/hs_service.c b/src/feature/hs/hs_service.c
index a42879a48f..995c1ca78b 100644
--- a/src/feature/hs/hs_service.c
+++ b/src/feature/hs/hs_service.c
@@ -16,6 +16,7 @@
#include "core/or/circuitbuild.h"
#include "core/or/circuitlist.h"
#include "core/or/circuituse.h"
+#include "core/or/extendinfo.h"
#include "core/or/relay.h"
#include "feature/client/circpathbias.h"
#include "feature/dirclient/dirclient.h"
@@ -2873,6 +2874,9 @@ upload_descriptor_to_hsdir(const hs_service_t *service,
hsdir->hsdir_index.store_first;
char *blinded_pubkey_log_str =
tor_strdup(hex_str((char*)&desc->blinded_kp.pubkey.pubkey, 32));
+ /* This log message is used by Chutney as part of its bootstrap
+ * detection mechanism. Please don't change without first checking
+ * Chutney. */
log_info(LD_REND, "Service %s %s descriptor of revision %" PRIu64
" initiated upload request to %s with index %s (%s)",
safe_str_client(service->onion_address),
diff --git a/src/feature/nodelist/describe.c b/src/feature/nodelist/describe.c
index 00896d5a44..f118436499 100644
--- a/src/feature/nodelist/describe.c
+++ b/src/feature/nodelist/describe.c
@@ -12,6 +12,7 @@
#define DESCRIBE_PRIVATE
#include "core/or/or.h"
+#include "core/or/extendinfo.h"
#include "feature/nodelist/describe.h"
#include "core/or/extend_info_st.h"
@@ -208,11 +209,16 @@ extend_info_describe(const extend_info_t *ei)
if (!ei)
return "<null>";
+ const tor_addr_port_t *ap4 = extend_info_get_orport(ei, AF_INET);
+ const tor_addr_port_t *ap6 = extend_info_get_orport(ei, AF_INET6);
+ uint32_t addr4 = ap4 ? tor_addr_to_ipv4h(&ap4->addr) : 0;
+ const tor_addr_t *addr6 = ap6 ? &ap6->addr : NULL;
+
return format_node_description(buf,
ei->identity_digest,
ei->nickname,
- &ei->addr,
- 0);
+ addr6,
+ addr4);
}
/** Set <b>buf</b> (which must have MAX_VERBOSE_NICKNAME_LEN+1 bytes) to the
diff --git a/src/feature/nodelist/dirlist.c b/src/feature/nodelist/dirlist.c
index 33d1bfc4d0..bd647ab530 100644
--- a/src/feature/nodelist/dirlist.c
+++ b/src/feature/nodelist/dirlist.c
@@ -294,7 +294,7 @@ dir_server_new(int is_authority,
ent->is_authority = is_authority;
ent->type = type;
ent->weight = weight;
- if (addrport_ipv6) {
+ if (addrport_ipv6 && tor_addr_port_is_valid_ap(addrport_ipv6, 0)) {
if (tor_addr_family(&addrport_ipv6->addr) != AF_INET6) {
log_warn(LD_BUG, "Hey, I got a non-ipv6 addr as addrport_ipv6.");
tor_addr_make_unspec(&ent->ipv6_addr);
@@ -343,25 +343,25 @@ trusted_dir_server_new(const char *nickname, const char *address,
const char *digest, const char *v3_auth_digest,
dirinfo_type_t type, double weight)
{
- uint32_t a;
tor_addr_t addr;
char *hostname=NULL;
dir_server_t *result;
if (!address) { /* The address is us; we should guess. */
- if (resolve_my_address(LOG_WARN, get_options(),
- &a, NULL, &hostname) < 0) {
+ if (!find_my_address(get_options(), AF_INET, LOG_WARN, &addr,
+ NULL, &hostname)) {
log_warn(LD_CONFIG,
"Couldn't find a suitable address when adding ourself as a "
"trusted directory server.");
return NULL;
}
if (!hostname)
- hostname = tor_dup_ip(a);
+ hostname = tor_addr_to_str_dup(&addr);
if (!hostname)
return NULL;
} else {
+ uint32_t a;
if (tor_lookup_hostname(address, &a)) {
log_warn(LD_CONFIG,
"Unable to lookup address for directory server at '%s'",
@@ -369,8 +369,8 @@ trusted_dir_server_new(const char *nickname, const char *address,
return NULL;
}
hostname = tor_strdup(address);
+ tor_addr_from_ipv4h(&addr, a);
}
- tor_addr_from_ipv4h(&addr, a);
result = dir_server_new(1, nickname, &addr, hostname,
dir_port, or_port,
diff --git a/src/feature/nodelist/networkstatus.c b/src/feature/nodelist/networkstatus.c
index e07d58c91c..f63d598ef7 100644
--- a/src/feature/nodelist/networkstatus.c
+++ b/src/feature/nodelist/networkstatus.c
@@ -1670,7 +1670,35 @@ notify_before_networkstatus_changes(const networkstatus_t *old_c,
static void
notify_after_networkstatus_changes(void)
{
+ const networkstatus_t *c = networkstatus_get_latest_consensus();
+ const or_options_t *options = get_options();
+ const time_t now = approx_time();
+
scheduler_notify_networkstatus_changed();
+
+ /* The "current" consensus has just been set and it is a usable flavor so
+ * the first thing we need to do is recalculate the voting schedule static
+ * object so we can use the timings in there needed by some subsystems
+ * such as hidden service and shared random. */
+ dirauth_sched_recalculate_timing(options, now);
+ reschedule_dirvote(options);
+
+ nodelist_set_consensus(c);
+
+ update_consensus_networkstatus_fetch_time(now);
+
+ /* Change the cell EWMA settings */
+ cmux_ewma_set_options(options, c);
+
+ /* XXXX this call might be unnecessary here: can changing the
+ * current consensus really alter our view of any OR's rate limits? */
+ connection_or_update_token_buckets(get_connection_array(), options);
+
+ circuit_build_times_new_consensus_params(
+ get_circuit_build_times_mutable(), c);
+ channelpadding_new_consensus_params(c);
+ circpad_new_consensus_params(c);
+ router_new_consensus_params(c);
}
/** Copy all the ancillary information (like router download status and so on)
@@ -2115,29 +2143,6 @@ networkstatus_set_current_consensus(const char *consensus,
/* Notify that we just changed the consensus so the current global value
* can be looked at. */
notify_after_networkstatus_changes();
-
- /* The "current" consensus has just been set and it is a usable flavor so
- * the first thing we need to do is recalculate the voting schedule static
- * object so we can use the timings in there needed by some subsystems
- * such as hidden service and shared random. */
- dirauth_sched_recalculate_timing(options, now);
- reschedule_dirvote(options);
-
- nodelist_set_consensus(c);
-
- update_consensus_networkstatus_fetch_time(now);
-
- /* Change the cell EWMA settings */
- cmux_ewma_set_options(options, c);
-
- /* XXXX this call might be unnecessary here: can changing the
- * current consensus really alter our view of any OR's rate limits? */
- connection_or_update_token_buckets(get_connection_array(), options);
-
- circuit_build_times_new_consensus_params(
- get_circuit_build_times_mutable(), c);
- channelpadding_new_consensus_params(c);
- circpad_new_consensus_params(c);
}
/* Reset the failure count only if this consensus is actually valid. */
diff --git a/src/feature/nodelist/node_select.c b/src/feature/nodelist/node_select.c
index e831248413..25904d4c63 100644
--- a/src/feature/nodelist/node_select.c
+++ b/src/feature/nodelist/node_select.c
@@ -321,8 +321,12 @@ router_pick_directory_server_impl(dirinfo_type_t type, int flags,
overloaded_direct = smartlist_new();
overloaded_tunnel = smartlist_new();
- const int skip_or_fw = router_skip_or_reachability(options, try_ip_pref);
- const int skip_dir_fw = router_skip_dir_reachability(options, try_ip_pref);
+ const int skip_or_fw = router_or_conn_should_skip_reachable_address_check(
+ options,
+ try_ip_pref);
+ const int skip_dir_fw = router_dir_conn_should_skip_reachable_address_check(
+ options,
+ try_ip_pref);
const int must_have_or = dirclient_must_use_begindir(options);
/* Find all the running dirservers we know about. */
@@ -926,64 +930,67 @@ nodelist_subtract(smartlist_t *sl, const smartlist_t *excluded)
bitarray_free(excluded_idx);
}
-/** Return a random running node from the nodelist. Never
- * pick a node that is in
- * <b>excludedsmartlist</b>, or which matches <b>excludedset</b>,
- * even if they are the only nodes available.
- * If <b>CRN_NEED_UPTIME</b> is set in flags and any router has more than
- * a minimum uptime, return one of those.
- * If <b>CRN_NEED_CAPACITY</b> is set in flags, weight your choice by the
- * advertised capacity of each router.
- * If <b>CRN_NEED_GUARD</b> is set in flags, consider only Guard routers.
- * If <b>CRN_WEIGHT_AS_EXIT</b> is set in flags, we weight bandwidths as if
- * picking an exit node, otherwise we weight bandwidths for picking a relay
- * node (that is, possibly discounting exit nodes).
- * If <b>CRN_NEED_DESC</b> is set in flags, we only consider nodes that
- * have a routerinfo or microdescriptor -- that is, enough info to be
- * used to build a circuit.
- * If <b>CRN_PREF_ADDR</b> is set in flags, we only consider nodes that
- * have an address that is preferred by the ClientPreferIPv6ORPort setting
- * (regardless of this flag, we exclude nodes that aren't allowed by the
- * firewall, including ClientUseIPv4 0 and fascist_firewall_use_ipv6() == 0).
+/* Node selection helper for router_choose_random_node().
+ *
+ * Populates a node list based on <b>flags</b>, ignoring nodes in
+ * <b>excludednodes</b> and <b>excludedset</b>. Chooses the node based on
+ * <b>rule</b>. */
+static const node_t *
+router_choose_random_node_helper(smartlist_t *excludednodes,
+ routerset_t *excludedset,
+ router_crn_flags_t flags,
+ bandwidth_weight_rule_t rule)
+{
+ smartlist_t *sl=smartlist_new();
+ const node_t *choice = NULL;
+
+ router_add_running_nodes_to_smartlist(sl, flags);
+ log_debug(LD_CIRC,
+ "We found %d running nodes.",
+ smartlist_len(sl));
+
+ nodelist_subtract(sl, excludednodes);
+
+ if (excludedset) {
+ routerset_subtract_nodes(sl,excludedset);
+ log_debug(LD_CIRC,
+ "We removed excludedset, leaving %d nodes.",
+ smartlist_len(sl));
+ }
+
+ // Always weight by bandwidth
+ choice = node_sl_choose_by_bandwidth(sl, rule);
+
+ smartlist_free(sl);
+
+ return choice;
+}
+
+/** Return a random running node from the nodelist. Never pick a node that is
+ * in <b>excludedsmartlist</b>, or which matches <b>excludedset</b>, even if
+ * they are the only nodes available.
+ *
+ * <b>flags</b> is a set of CRN_* flags, see
+ * router_add_running_nodes_to_smartlist() for details.
*/
const node_t *
router_choose_random_node(smartlist_t *excludedsmartlist,
routerset_t *excludedset,
router_crn_flags_t flags)
-{ /* XXXX MOVE */
- const int need_uptime = (flags & CRN_NEED_UPTIME) != 0;
- const int need_capacity = (flags & CRN_NEED_CAPACITY) != 0;
- const int need_guard = (flags & CRN_NEED_GUARD) != 0;
- const int weight_for_exit = (flags & CRN_WEIGHT_AS_EXIT) != 0;
- const int need_desc = (flags & CRN_NEED_DESC) != 0;
- const int pref_addr = (flags & CRN_PREF_ADDR) != 0;
- const int direct_conn = (flags & CRN_DIRECT_CONN) != 0;
- const int rendezvous_v3 = (flags & CRN_RENDEZVOUS_V3) != 0;
-
- const smartlist_t *node_list = nodelist_get_list();
- smartlist_t *sl=smartlist_new(),
- *excludednodes=smartlist_new();
+{
+ /* A limited set of flags, used for fallback node selection.
+ */
+ const bool need_uptime = (flags & CRN_NEED_UPTIME) != 0;
+ const bool need_capacity = (flags & CRN_NEED_CAPACITY) != 0;
+ const bool need_guard = (flags & CRN_NEED_GUARD) != 0;
+ const bool pref_addr = (flags & CRN_PREF_ADDR) != 0;
+
+ smartlist_t *excludednodes=smartlist_new();
const node_t *choice = NULL;
const routerinfo_t *r;
bandwidth_weight_rule_t rule;
- tor_assert(!(weight_for_exit && need_guard));
- rule = weight_for_exit ? WEIGHT_FOR_EXIT :
- (need_guard ? WEIGHT_FOR_GUARD : WEIGHT_FOR_MID);
-
- SMARTLIST_FOREACH_BEGIN(node_list, const node_t *, node) {
- if (node_allows_single_hop_exits(node)) {
- /* Exclude relays that allow single hop exit circuits. This is an
- * obsolete option since 0.2.9.2-alpha and done by default in
- * 0.3.1.0-alpha. */
- smartlist_add(excludednodes, (node_t*)node);
- } else if (rendezvous_v3 &&
- !node_supports_v3_rendezvous_point(node)) {
- /* Exclude relays that do not support to rendezvous for a hidden service
- * version 3. */
- smartlist_add(excludednodes, (node_t*)node);
- }
- } SMARTLIST_FOREACH_END(node);
+ rule = (need_guard ? WEIGHT_FOR_GUARD : WEIGHT_FOR_MID);
/* If the node_t is not found we won't be to exclude ourself but we
* won't be able to pick ourself in router_choose_random_node() so
@@ -991,41 +998,30 @@ router_choose_random_node(smartlist_t *excludedsmartlist,
if ((r = router_get_my_routerinfo()))
routerlist_add_node_and_family(excludednodes, r);
- router_add_running_nodes_to_smartlist(sl, need_uptime, need_capacity,
- need_guard, need_desc, pref_addr,
- direct_conn);
- log_debug(LD_CIRC,
- "We found %d running nodes.",
- smartlist_len(sl));
-
if (excludedsmartlist) {
smartlist_add_all(excludednodes, excludedsmartlist);
}
- nodelist_subtract(sl, excludednodes);
- if (excludedset) {
- routerset_subtract_nodes(sl,excludedset);
- log_debug(LD_CIRC,
- "We removed excludedset, leaving %d nodes.",
- smartlist_len(sl));
- }
+ choice = router_choose_random_node_helper(excludednodes,
+ excludedset,
+ flags,
+ rule);
- // Always weight by bandwidth
- choice = node_sl_choose_by_bandwidth(sl, rule);
-
- smartlist_free(sl);
if (!choice && (need_uptime || need_capacity || need_guard || pref_addr)) {
- /* try once more -- recurse but with fewer restrictions. */
+ /* try once more, with fewer restrictions. */
log_info(LD_CIRC,
- "We couldn't find any live%s%s%s routers; falling back "
+ "We couldn't find any live%s%s%s%s routers; falling back "
"to list of all routers.",
need_capacity?", fast":"",
need_uptime?", stable":"",
- need_guard?", guard":"");
+ need_guard?", guard":"",
+ pref_addr?", preferred address":"");
flags &= ~ (CRN_NEED_UPTIME|CRN_NEED_CAPACITY|CRN_NEED_GUARD|
CRN_PREF_ADDR);
- choice = router_choose_random_node(
- excludedsmartlist, excludedset, flags);
+ choice = router_choose_random_node_helper(excludednodes,
+ excludedset,
+ flags,
+ rule);
}
smartlist_free(excludednodes);
if (!choice) {
@@ -1120,8 +1116,12 @@ router_pick_trusteddirserver_impl(const smartlist_t *sourcelist,
overloaded_direct = smartlist_new();
overloaded_tunnel = smartlist_new();
- const int skip_or_fw = router_skip_or_reachability(options, try_ip_pref);
- const int skip_dir_fw = router_skip_dir_reachability(options, try_ip_pref);
+ const int skip_or_fw = router_or_conn_should_skip_reachable_address_check(
+ options,
+ try_ip_pref);
+ const int skip_dir_fw = router_dir_conn_should_skip_reachable_address_check(
+ options,
+ try_ip_pref);
const int must_have_or = dirclient_must_use_begindir(options);
SMARTLIST_FOREACH_BEGIN(sourcelist, const dir_server_t *, d)
diff --git a/src/feature/nodelist/node_select.h b/src/feature/nodelist/node_select.h
index 2e67f990f6..1776d8ea1a 100644
--- a/src/feature/nodelist/node_select.h
+++ b/src/feature/nodelist/node_select.h
@@ -14,20 +14,26 @@
/** Flags to be passed to control router_choose_random_node() to indicate what
* kind of nodes to pick according to what algorithm. */
typedef enum router_crn_flags_t {
+ /* Try to choose stable nodes. */
CRN_NEED_UPTIME = 1<<0,
+ /* Try to choose nodes with a reasonable amount of bandwidth. */
CRN_NEED_CAPACITY = 1<<1,
- CRN_NEED_GUARD = 1<<2,
- /* XXXX not used, apparently. */
- CRN_WEIGHT_AS_EXIT = 1<<5,
- CRN_NEED_DESC = 1<<6,
- /* On clients, only provide nodes that satisfy ClientPreferIPv6OR */
- CRN_PREF_ADDR = 1<<7,
+ /* Only choose nodes if we have downloaded their descriptor or
+ * microdescriptor. */
+ CRN_NEED_DESC = 1<<2,
+ /* Choose nodes that can be used as Guard relays. */
+ CRN_NEED_GUARD = 1<<3,
/* On clients, only provide nodes that we can connect to directly, based on
- * our firewall rules */
- CRN_DIRECT_CONN = 1<<8,
- /* On clients, only provide nodes with HSRend >= 2 protocol version which
- * is required for hidden service version >= 3. */
- CRN_RENDEZVOUS_V3 = 1<<9,
+ * our firewall rules. */
+ CRN_DIRECT_CONN = 1<<4,
+ /* On clients, if choosing a node for a direct connection, only provide
+ * nodes that satisfy ClientPreferIPv6OR. */
+ CRN_PREF_ADDR = 1<<5,
+ /* On clients, only provide nodes with HSRend=2 protocol version which
+ * is required for hidden service version 3. */
+ CRN_RENDEZVOUS_V3 = 1<<6,
+ /* On clients, only provide nodes that can initiate IPv6 extends. */
+ CRN_INITIATE_IPV6_EXTEND = 1<<7,
} router_crn_flags_t;
/** Possible ways to weight routers when choosing one randomly. See
diff --git a/src/feature/nodelist/node_st.h b/src/feature/nodelist/node_st.h
index b1ec4db202..3769f9dc84 100644
--- a/src/feature/nodelist/node_st.h
+++ b/src/feature/nodelist/node_st.h
@@ -84,12 +84,11 @@ struct node_t {
/* Local info: derived. */
- /** True if the IPv6 OR port is preferred over the IPv4 OR port.
- * XX/teor - can this become out of date if the torrc changes? */
+ /** True if the IPv6 OR port is preferred over the IPv4 OR port. */
unsigned int ipv6_preferred:1;
/** According to the geoip db what country is this router in? */
- /* XXXprop186 what is this suppose to mean with multiple OR ports? */
+ /* IPv6: what is this supposed to mean with multiple OR ports? */
country_t country;
/* The below items are used only by authdirservers for
diff --git a/src/feature/nodelist/nodelist.c b/src/feature/nodelist/nodelist.c
index 7454f342f9..a3c94554ec 100644
--- a/src/feature/nodelist/nodelist.c
+++ b/src/feature/nodelist/nodelist.c
@@ -621,7 +621,7 @@ get_estimated_address_per_node, (void))
* and grab microdescriptors into nodes as appropriate.
*/
void
-nodelist_set_consensus(networkstatus_t *ns)
+nodelist_set_consensus(const networkstatus_t *ns)
{
const or_options_t *options = get_options();
int authdir = authdir_mode_v3(options);
@@ -952,7 +952,7 @@ nodelist_assert_ok(void)
/** Ensure that the nodelist has been created with the most recent consensus.
* If that's not the case, make it so. */
void
-nodelist_ensure_freshness(networkstatus_t *ns)
+nodelist_ensure_freshness(const networkstatus_t *ns)
{
tor_assert(ns);
@@ -1133,7 +1133,7 @@ node_ed25519_id_matches(const node_t *node, const ed25519_public_key_t *id)
/** Dummy object that should be unreturnable. Used to ensure that
* node_get_protover_summary_flags() always returns non-NULL. */
static const protover_summary_flags_t zero_protover_flags = {
- 0,0,0,0,0,0,0,0,0
+ 0,0,0,0,0,0,0,0,0,0,0,0
};
/** Return the protover_summary_flags for a given node. */
@@ -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. */
-MOCK_IMPL(int,
+MOCK_IMPL(bool,
node_supports_ed25519_link_authentication,(const node_t *node,
- int compatible_with_us))
+ bool compatible_with_us))
{
if (! node_get_ed25519_id(node))
return 0;
@@ -1175,7 +1175,7 @@ node_supports_ed25519_link_authentication,(const node_t *node,
/** Return true iff <b>node</b> supports the hidden service directory version
* 3 protocol (proposal 224). */
-int
+bool
node_supports_v3_hsdir(const node_t *node)
{
tor_assert(node);
@@ -1185,7 +1185,7 @@ node_supports_v3_hsdir(const node_t *node)
/** Return true iff <b>node</b> supports ed25519 authentication as an hidden
* service introduction point.*/
-int
+bool
node_supports_ed25519_hs_intro(const node_t *node)
{
tor_assert(node);
@@ -1193,9 +1193,24 @@ node_supports_ed25519_hs_intro(const node_t *node)
return node_get_protover_summary_flags(node)->supports_ed25519_hs_intro;
}
+/** Return true iff <b>node</b> can be a rendezvous point for hidden
+ * service version 3 (HSRend=2). */
+bool
+node_supports_v3_rendezvous_point(const node_t *node)
+{
+ tor_assert(node);
+
+ /* We can't use a v3 rendezvous point without the curve25519 onion pk. */
+ if (!node_get_curve25519_onion_key(node)) {
+ return 0;
+ }
+
+ return node_get_protover_summary_flags(node)->supports_v3_rendezvous_point;
+}
+
/** Return true iff <b>node</b> supports the DoS ESTABLISH_INTRO cell
* extenstion. */
-int
+bool
node_supports_establish_intro_dos_extension(const node_t *node)
{
tor_assert(node);
@@ -1204,19 +1219,54 @@ node_supports_establish_intro_dos_extension(const node_t *node)
supports_establish_intro_dos_extension;
}
-/** Return true iff <b>node</b> supports to be a rendezvous point for hidden
- * service version 3 (HSRend=2). */
-int
-node_supports_v3_rendezvous_point(const node_t *node)
+/** Return true iff <b>node</b> can initiate IPv6 extends (Relay=3).
+ *
+ * This check should only be performed by client path selection code.
+ *
+ * Extending relays should check their own IPv6 support using
+ * router_can_extend_over_ipv6(). Like other extends, they should not verify
+ * the link specifiers in the extend cell against the consensus, because it
+ * may be out of date. */
+bool
+node_supports_initiating_ipv6_extends(const node_t *node)
{
tor_assert(node);
- /* We can't use a v3 rendezvous point without the curve25519 onion pk. */
- if (!node_get_curve25519_onion_key(node)) {
+ /* Relays can't initiate an IPv6 extend, unless they have an IPv6 ORPort. */
+ if (!node_has_ipv6_orport(node)) {
return 0;
}
- return node_get_protover_summary_flags(node)->supports_v3_rendezvous_point;
+ /* Initiating relays also need to support the relevant protocol version. */
+ return
+ node_get_protover_summary_flags(node)->supports_initiating_ipv6_extends;
+}
+
+/** Return true iff <b>node</b> can accept IPv6 extends (Relay=2 or Relay=3)
+ * from other relays. If <b>need_canonical_ipv6_conn</b> is true, also check
+ * if the relay supports canonical IPv6 connections (Relay=3 only).
+ *
+ * This check should only be performed by client path selection code.
+ */
+bool
+node_supports_accepting_ipv6_extends(const node_t *node,
+ bool need_canonical_ipv6_conn)
+{
+ tor_assert(node);
+
+ /* Relays can't accept an IPv6 extend, unless they have an IPv6 ORPort. */
+ if (!node_has_ipv6_orport(node)) {
+ return 0;
+ }
+
+ /* Accepting relays also need to support the relevant protocol version. */
+ if (need_canonical_ipv6_conn) {
+ return
+ node_get_protover_summary_flags(node)->supports_canonical_ipv6_conns;
+ } else {
+ return
+ node_get_protover_summary_flags(node)->supports_accepting_ipv6_extends;
+ }
}
/** Return the RSA ID key's SHA1 digest for the provided node. */
@@ -1984,7 +2034,7 @@ nodelist_refresh_countries(void)
/** Return true iff router1 and router2 have similar enough network addresses
* that we should treat them as being in the same family */
int
-addrs_in_same_network_family(const tor_addr_t *a1,
+router_addrs_in_same_network(const tor_addr_t *a1,
const tor_addr_t *a2)
{
if (tor_addr_is_null(a1) || tor_addr_is_null(a2))
@@ -2100,8 +2150,8 @@ nodes_in_same_family(const node_t *node1, const node_t *node2)
node_get_pref_ipv6_orport(node1, &ap6_1);
node_get_pref_ipv6_orport(node2, &ap6_2);
- if (addrs_in_same_network_family(&a1, &a2) ||
- addrs_in_same_network_family(&ap6_1.addr, &ap6_2.addr))
+ if (router_addrs_in_same_network(&a1, &a2) ||
+ router_addrs_in_same_network(&ap6_1.addr, &ap6_2.addr))
return 1;
}
@@ -2159,8 +2209,8 @@ nodelist_add_node_and_family(smartlist_t *sl, const node_t *node)
tor_addr_port_t ap6;
node_get_addr(node2, &a);
node_get_pref_ipv6_orport(node2, &ap6);
- if (addrs_in_same_network_family(&a, &node_addr) ||
- addrs_in_same_network_family(&ap6.addr, &node_ap6.addr))
+ if (router_addrs_in_same_network(&a, &node_addr) ||
+ router_addrs_in_same_network(&ap6.addr, &node_ap6.addr))
smartlist_add(sl, (void*)node2);
} SMARTLIST_FOREACH_END(node2);
}
diff --git a/src/feature/nodelist/nodelist.h b/src/feature/nodelist/nodelist.h
index 57ab2d5913..06cd7916ff 100644
--- a/src/feature/nodelist/nodelist.h
+++ b/src/feature/nodelist/nodelist.h
@@ -32,8 +32,8 @@ const node_t *node_get_by_hex_id(const char *identity_digest,
unsigned flags);
node_t *nodelist_set_routerinfo(routerinfo_t *ri, routerinfo_t **ri_old_out);
node_t *nodelist_add_microdesc(microdesc_t *md);
-void nodelist_set_consensus(networkstatus_t *ns);
-void nodelist_ensure_freshness(networkstatus_t *ns);
+void nodelist_set_consensus(const networkstatus_t *ns);
+void nodelist_ensure_freshness(const networkstatus_t *ns);
int nodelist_probably_contains_address(const tor_addr_t *addr);
void nodelist_add_addr4_to_address_set(const uint32_t addr);
void nodelist_add_addr6_to_address_set(const tor_addr_t *addr);
@@ -74,13 +74,17 @@ 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);
-MOCK_DECL(int,node_supports_ed25519_link_authentication,
+MOCK_DECL(bool,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);
-int node_supports_establish_intro_dos_extension(const node_t *node);
+ bool compatible_with_us));
+bool node_supports_v3_hsdir(const node_t *node);
+bool node_supports_ed25519_hs_intro(const node_t *node);
+bool node_supports_v3_rendezvous_point(const node_t *node);
+bool node_supports_establish_intro_dos_extension(const node_t *node);
+bool node_supports_initiating_ipv6_extends(const node_t *node);
+bool node_supports_accepting_ipv6_extends(const node_t *node,
+ bool need_canonical_ipv6_conn);
+
const uint8_t *node_get_rsa_id_digest(const node_t *node);
MOCK_DECL(smartlist_t *,node_get_link_specifier_smartlist,(const node_t *node,
bool direct_conn));
@@ -124,7 +128,7 @@ int node_is_unreliable(const node_t *router, int need_uptime,
int router_exit_policy_all_nodes_reject(const tor_addr_t *addr, uint16_t port,
int need_uptime);
void router_set_status(const char *digest, int up);
-int addrs_in_same_network_family(const tor_addr_t *a1,
+int router_addrs_in_same_network(const tor_addr_t *a1,
const tor_addr_t *a2);
/** router_have_minimum_dir_info tests to see if we have enough
diff --git a/src/feature/nodelist/routerinfo.c b/src/feature/nodelist/routerinfo.c
index 0bf2a977f5..55f21dfe67 100644
--- a/src/feature/nodelist/routerinfo.c
+++ b/src/feature/nodelist/routerinfo.c
@@ -17,14 +17,37 @@
#include "feature/nodelist/node_st.h"
#include "feature/nodelist/routerinfo_st.h"
-/** Copy the primary (IPv4) OR port (IP address and TCP port) for
- * <b>router</b> into *<b>ap_out</b>. */
-void
-router_get_prim_orport(const routerinfo_t *router, tor_addr_port_t *ap_out)
+/** Copy the OR port (IP address and TCP port) for <b>router</b> and
+ * <b>family</b> into *<b>ap_out</b>.
+ *
+ * If the requested ORPort does not exist, sets *<b>ap_out</b> to the null
+ * address and port, and returns -1. Otherwise, returns 0. */
+int
+router_get_orport(const routerinfo_t *router,
+ tor_addr_port_t *ap_out,
+ int family)
{
tor_assert(ap_out != NULL);
- tor_addr_from_ipv4h(&ap_out->addr, router->addr);
- ap_out->port = router->or_port;
+ if (family == AF_INET) {
+ tor_addr_from_ipv4h(&ap_out->addr, router->addr);
+ ap_out->port = router->or_port;
+ return 0;
+ } else if (family == AF_INET6) {
+ /* IPv6 addresses are optional, so check if it is valid. */
+ if (tor_addr_port_is_valid(&router->ipv6_addr, router->ipv6_orport, 0)) {
+ tor_addr_copy(&ap_out->addr, &router->ipv6_addr);
+ ap_out->port = router->ipv6_orport;
+ return 0;
+ } else {
+ tor_addr_port_make_null_ap(ap_out, AF_INET6);
+ return -1;
+ }
+ } else {
+ /* Unsupported address family */
+ tor_assert_nonfatal_unreached();
+ tor_addr_port_make_null_ap(ap_out, AF_UNSPEC);
+ return -1;
+ }
}
int
diff --git a/src/feature/nodelist/routerinfo.h b/src/feature/nodelist/routerinfo.h
index 604e478999..2e12cbeba3 100644
--- a/src/feature/nodelist/routerinfo.h
+++ b/src/feature/nodelist/routerinfo.h
@@ -12,8 +12,9 @@
#ifndef TOR_ROUTERINFO_H
#define TOR_ROUTERINFO_H
-void router_get_prim_orport(const routerinfo_t *router,
- tor_addr_port_t *addr_port_out);
+int router_get_orport(const routerinfo_t *router,
+ tor_addr_port_t *addr_port_out,
+ int family);
int router_has_orport(const routerinfo_t *router,
const tor_addr_port_t *orport);
diff --git a/src/feature/nodelist/routerlist.c b/src/feature/nodelist/routerlist.c
index 96bea5a670..1afbdf056f 100644
--- a/src/feature/nodelist/routerlist.c
+++ b/src/feature/nodelist/routerlist.c
@@ -465,11 +465,20 @@ router_reload_router_list(void)
return 0;
}
-/* When iterating through the routerlist, can OR address/port preference
- * and reachability checks be skipped?
+/* When selecting a router for a direct connection, can OR address/port
+ * preference and reachability checks be skipped?
+ *
+ * Servers never check ReachableAddresses or ClientPreferIPv6. Returns
+ * true for servers.
+ *
+ * Otherwise, if <b>try_ip_pref</b> is true, returns false. Used to make
+ * clients check ClientPreferIPv6, even if ReachableAddresses is not set.
+ * Finally, return true if ReachableAddresses is set.
*/
int
-router_skip_or_reachability(const or_options_t *options, int try_ip_pref)
+router_or_conn_should_skip_reachable_address_check(
+ const or_options_t *options,
+ int try_ip_pref)
{
/* Servers always have and prefer IPv4.
* And if clients are checking against the firewall for reachability only,
@@ -477,11 +486,15 @@ router_skip_or_reachability(const or_options_t *options, int try_ip_pref)
return server_mode(options) || (!try_ip_pref && !firewall_is_fascist_or());
}
-/* When iterating through the routerlist, can Dir address/port preference
+/* When selecting a router for a direct connection, can Dir address/port
* and reachability checks be skipped?
+ *
+ * This function is obsolete, because clients only use ORPorts.
*/
int
-router_skip_dir_reachability(const or_options_t *options, int try_ip_pref)
+router_dir_conn_should_skip_reachable_address_check(
+ const or_options_t *options,
+ int try_ip_pref)
{
/* Servers always have and prefer IPv4.
* And if clients are checking against the firewall for reachability only,
@@ -498,40 +511,109 @@ routers_have_same_or_addrs(const routerinfo_t *r1, const routerinfo_t *r2)
r1->ipv6_orport == r2->ipv6_orport;
}
+/* Returns true if <b>node</b> can be chosen based on <b>flags</b>.
+ *
+ * The following conditions are applied to all nodes:
+ * - is running;
+ * - is valid;
+ * - supports EXTEND2 cells;
+ * - has an ntor circuit crypto key; and
+ * - does not allow single-hop exits.
+ *
+ * If the node has a routerinfo, we're checking for a direct connection, and
+ * we're using bridges, the following condition is applied:
+ * - has a bridge-purpose routerinfo;
+ * and for all other nodes:
+ * - has a general-purpose routerinfo (or no routerinfo).
+ *
+ * Nodes that don't have a routerinfo must be general-purpose nodes, because
+ * routerstatuses and microdescriptors only come via consensuses.
+ *
+ * The <b>flags</b> chech that <b>node</b>:
+ * - <b>CRN_NEED_UPTIME</b>: has more than a minimum uptime;
+ * - <b>CRN_NEED_CAPACITY</b>: has more than a minimum capacity;
+ * - <b>CRN_NEED_GUARD</b>: is a Guard;
+ * - <b>CRN_NEED_DESC</b>: has a routerinfo or microdescriptor -- that is,
+ * enough info to be used to build a circuit;
+ * - <b>CRN_DIRECT_CONN</b>: is suitable for direct connections. Checks
+ * for the relevant descriptors. Checks the address
+ * against ReachableAddresses, ClientUseIPv4 0, and
+ * fascist_firewall_use_ipv6() == 0);
+ * - <b>CRN_PREF_ADDR</b>: if we are connecting directly to the node, it has
+ * an address that is preferred by the
+ * ClientPreferIPv6ORPort setting;
+ * - <b>CRN_RENDEZVOUS_V3</b>: can become a v3 onion service rendezvous point;
+ * - <b>CRN_INITIATE_IPV6_EXTEND</b>: can initiate IPv6 extends.
+ */
+bool
+router_can_choose_node(const node_t *node, int flags)
+{
+ /* The full set of flags used for node selection. */
+ const bool need_uptime = (flags & CRN_NEED_UPTIME) != 0;
+ const bool need_capacity = (flags & CRN_NEED_CAPACITY) != 0;
+ const bool need_guard = (flags & CRN_NEED_GUARD) != 0;
+ const bool need_desc = (flags & CRN_NEED_DESC) != 0;
+ const bool pref_addr = (flags & CRN_PREF_ADDR) != 0;
+ const bool direct_conn = (flags & CRN_DIRECT_CONN) != 0;
+ const bool rendezvous_v3 = (flags & CRN_RENDEZVOUS_V3) != 0;
+ const bool initiate_ipv6_extend = (flags & CRN_INITIATE_IPV6_EXTEND) != 0;
+
+ const or_options_t *options = get_options();
+ const bool check_reach =
+ !router_or_conn_should_skip_reachable_address_check(options, pref_addr);
+ const bool direct_bridge = direct_conn && options->UseBridges;
+
+ if (!node->is_running || !node->is_valid)
+ return false;
+ if (need_desc && !node_has_preferred_descriptor(node, direct_conn))
+ return false;
+ if (node->ri) {
+ if (direct_bridge && node->ri->purpose != ROUTER_PURPOSE_BRIDGE)
+ return false;
+ else if (node->ri->purpose != ROUTER_PURPOSE_GENERAL)
+ return false;
+ }
+ if (node_is_unreliable(node, need_uptime, need_capacity, need_guard))
+ return false;
+ /* Don't choose nodes if we are certain they can't do EXTEND2 cells */
+ if (node->rs && !routerstatus_version_supports_extend2_cells(node->rs, 1))
+ return false;
+ /* Don't choose nodes if we are certain they can't do ntor. */
+ if ((node->ri || node->md) && !node_has_curve25519_onion_key(node))
+ return false;
+ /* Exclude relays that allow single hop exit circuits. This is an
+ * obsolete option since 0.2.9.2-alpha and done by default in
+ * 0.3.1.0-alpha. */
+ if (node_allows_single_hop_exits(node))
+ return false;
+ /* Exclude relays that can not become a rendezvous for a hidden service
+ * version 3. */
+ if (rendezvous_v3 &&
+ !node_supports_v3_rendezvous_point(node))
+ return false;
+ /* Choose a node with an OR address that matches the firewall rules */
+ if (direct_conn && check_reach &&
+ !fascist_firewall_allows_node(node,
+ FIREWALL_OR_CONNECTION,
+ pref_addr))
+ return false;
+ if (initiate_ipv6_extend && !node_supports_initiating_ipv6_extends(node))
+ return false;
+
+ return true;
+}
+
/** Add every suitable node from our nodelist to <b>sl</b>, so that
- * we can pick a node for a circuit.
+ * we can pick a node for a circuit based on <b>flags</b>.
+ *
+ * See router_can_choose_node() for details of <b>flags</b>.
*/
void
-router_add_running_nodes_to_smartlist(smartlist_t *sl, int need_uptime,
- int need_capacity, int need_guard,
- int need_desc, int pref_addr,
- int direct_conn)
-{
- const int check_reach = !router_skip_or_reachability(get_options(),
- pref_addr);
- /* XXXX MOVE */
+router_add_running_nodes_to_smartlist(smartlist_t *sl, int flags)
+{
SMARTLIST_FOREACH_BEGIN(nodelist_get_list(), const node_t *, node) {
- if (!node->is_running || !node->is_valid)
- continue;
- if (need_desc && !node_has_preferred_descriptor(node, direct_conn))
- continue;
- if (node->ri && node->ri->purpose != ROUTER_PURPOSE_GENERAL)
+ if (!router_can_choose_node(node, flags))
continue;
- if (node_is_unreliable(node, need_uptime, need_capacity, need_guard))
- continue;
- /* Don't choose nodes if we are certain they can't do EXTEND2 cells */
- if (node->rs && !routerstatus_version_supports_extend2_cells(node->rs, 1))
- continue;
- /* Don't choose nodes if we are certain they can't do ntor. */
- if ((node->ri || node->md) && !node_has_curve25519_onion_key(node))
- continue;
- /* Choose a node with an OR address that matches the firewall rules */
- if (direct_conn && check_reach &&
- !fascist_firewall_allows_node(node,
- FIREWALL_OR_CONNECTION,
- pref_addr))
- continue;
-
smartlist_add(sl, (void *)node);
} SMARTLIST_FOREACH_END(node);
}
diff --git a/src/feature/nodelist/routerlist.h b/src/feature/nodelist/routerlist.h
index 81a2343540..98472b2771 100644
--- a/src/feature/nodelist/routerlist.h
+++ b/src/feature/nodelist/routerlist.h
@@ -50,14 +50,16 @@ typedef enum was_router_added_t {
int router_reload_router_list(void);
-int router_skip_or_reachability(const or_options_t *options, int try_ip_pref);
-int router_skip_dir_reachability(const or_options_t *options, int try_ip_pref);
+int router_or_conn_should_skip_reachable_address_check(
+ const or_options_t *options,
+ int try_ip_pref);
+int router_dir_conn_should_skip_reachable_address_check(
+ const or_options_t *options,
+ int try_ip_pref);
void router_reset_status_download_failures(void);
int routers_have_same_or_addrs(const routerinfo_t *r1, const routerinfo_t *r2);
-void router_add_running_nodes_to_smartlist(smartlist_t *sl, int need_uptime,
- int need_capacity, int need_guard,
- int need_desc, int pref_addr,
- int direct_conn);
+bool router_can_choose_node(const node_t *node, int flags);
+void router_add_running_nodes_to_smartlist(smartlist_t *sl, int flags);
const routerinfo_t *routerlist_find_my_routerinfo(void);
uint32_t router_get_advertised_bandwidth(const routerinfo_t *router);
diff --git a/src/feature/nodelist/routerset.c b/src/feature/nodelist/routerset.c
index 2e06ecbf04..cba7203d44 100644
--- a/src/feature/nodelist/routerset.c
+++ b/src/feature/nodelist/routerset.c
@@ -223,11 +223,11 @@ routerset_len(const routerset_t *set)
*
* (If country is -1, then we take the country
* from addr.) */
-STATIC int
-routerset_contains(const routerset_t *set, const tor_addr_t *addr,
- uint16_t orport,
- const char *nickname, const char *id_digest,
- country_t country)
+static int
+routerset_contains2(const routerset_t *set, const tor_addr_t *addr,
+ uint16_t orport, const tor_addr_t *addr2,
+ uint16_t orport2, const char *nickname,
+ const char *id_digest, country_t country)
{
if (!set || !set->list)
return 0;
@@ -238,6 +238,9 @@ routerset_contains(const routerset_t *set, const tor_addr_t *addr,
if (addr && compare_tor_addr_to_addr_policy(addr, orport, set->policies)
== ADDR_POLICY_REJECTED)
return 3;
+ if (addr2 && compare_tor_addr_to_addr_policy(addr2, orport2, set->policies)
+ == ADDR_POLICY_REJECTED)
+ return 3;
if (set->countries) {
if (country < 0 && addr)
country = geoip_get_country_by_addr(addr);
@@ -249,6 +252,17 @@ routerset_contains(const routerset_t *set, const tor_addr_t *addr,
return 0;
}
+/** Helper. Like routerset_contains2() but for a single IP/port combo.
+ */
+STATIC int
+routerset_contains(const routerset_t *set, const tor_addr_t *addr,
+ uint16_t orport, const char *nickname,
+ const char *id_digest, country_t country)
+{
+ return routerset_contains2(set, addr, orport, NULL, 0,
+ nickname, id_digest, country);
+}
+
/** If *<b>setp</b> includes at least one country code, or if
* <b>only_some_cc_set</b> is 0, add the ?? and A1 country codes to
* *<b>setp</b>, creating it as needed. Return true iff *<b>setp</b> changed.
@@ -292,12 +306,19 @@ routerset_add_unknown_ccs(routerset_t **setp, int only_if_some_cc_set)
int
routerset_contains_extendinfo(const routerset_t *set, const extend_info_t *ei)
{
- return routerset_contains(set,
- &ei->addr,
- ei->port,
- ei->nickname,
- ei->identity_digest,
- -1 /*country*/);
+ const tor_addr_port_t *ap1 = NULL, *ap2 = NULL;
+ if (! tor_addr_is_null(&ei->orports[0].addr))
+ ap1 = &ei->orports[0];
+ if (! tor_addr_is_null(&ei->orports[1].addr))
+ ap2 = &ei->orports[1];
+ return routerset_contains2(set,
+ ap1 ? &ap1->addr : NULL,
+ ap1 ? ap1->port : 0,
+ ap2 ? &ap2->addr : NULL,
+ ap2 ? ap2->port : 0,
+ ei->nickname,
+ ei->identity_digest,
+ -1 /*country*/);
}
/** Return true iff <b>ri</b> is in <b>set</b>. If country is <b>-1</b>, we
@@ -306,14 +327,11 @@ int
routerset_contains_router(const routerset_t *set, const routerinfo_t *ri,
country_t country)
{
- tor_addr_t addr;
- tor_addr_from_ipv4h(&addr, ri->addr);
- return routerset_contains(set,
- &addr,
- ri->or_port,
- ri->nickname,
- ri->cache_info.identity_digest,
- country);
+ tor_addr_t addr_v4;
+ tor_addr_from_ipv4h(&addr_v4, ri->addr);
+ return routerset_contains2(set, &addr_v4, ri->or_port, &ri->ipv6_addr,
+ ri->ipv6_orport, ri->nickname,
+ ri->cache_info.identity_digest, country);
}
/** Return true iff <b>rs</b> is in <b>set</b>. If country is <b>-1</b>, we
diff --git a/src/feature/relay/circuitbuild_relay.c b/src/feature/relay/circuitbuild_relay.c
index b89866b477..881cbd51be 100644
--- a/src/feature/relay/circuitbuild_relay.c
+++ b/src/feature/relay/circuitbuild_relay.c
@@ -33,6 +33,7 @@
#include "core/or/channel.h"
#include "core/or/circuitbuild.h"
#include "core/or/circuitlist.h"
+#include "core/or/extendinfo.h"
#include "core/or/onion.h"
#include "core/or/relay.h"
@@ -122,6 +123,52 @@ circuit_extend_add_ed25519_helper(struct extend_cell_t *ec)
return 0;
}
+/* Make sure the extend cell <b>ec</b> has an IPv4 address if the relay
+ * supports in, and if not, fill it in. */
+STATIC int
+circuit_extend_add_ipv4_helper(struct extend_cell_t *ec)
+{
+ IF_BUG_ONCE(!ec) {
+ return -1;
+ }
+
+ const node_t *node = node_get_by_id((const char *) ec->node_id);
+ if (node) {
+ tor_addr_port_t node_ipv4;
+ node_get_prim_orport(node, &node_ipv4);
+ if (tor_addr_is_null(&ec->orport_ipv4.addr) &&
+ !tor_addr_is_null(&node_ipv4.addr)) {
+ tor_addr_copy(&ec->orport_ipv4.addr, &node_ipv4.addr);
+ ec->orport_ipv4.port = node_ipv4.port;
+ }
+ }
+
+ return 0;
+}
+
+/* Make sure the extend cell <b>ec</b> has an IPv6 address if the relay
+ * supports in, and if not, fill it in. */
+STATIC int
+circuit_extend_add_ipv6_helper(struct extend_cell_t *ec)
+{
+ IF_BUG_ONCE(!ec) {
+ return -1;
+ }
+
+ const node_t *node = node_get_by_id((const char *) ec->node_id);
+ if (node) {
+ tor_addr_port_t node_ipv6;
+ node_get_pref_ipv6_orport(node, &node_ipv6);
+ if (tor_addr_is_null(&ec->orport_ipv6.addr) &&
+ !tor_addr_is_null(&node_ipv6.addr)) {
+ tor_addr_copy(&ec->orport_ipv6.addr, &node_ipv6.addr);
+ ec->orport_ipv6.port = node_ipv6.port;
+ }
+ }
+
+ 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.
*
@@ -354,11 +401,7 @@ circuit_open_connection_for_extend(const struct extend_cell_t *ec,
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);
+ channel_t *n_chan = channel_connect_for_circuit(circ->n_hop);
if (!n_chan) {
log_info(LD_CIRC,"Launching n_chan failed. Closing circuit.");
circuit_mark_for_close(circ, END_CIRC_REASON_CONNECTFAILED);
@@ -412,6 +455,12 @@ circuit_extend(struct cell_t *cell, struct circuit_t *circ)
if (circuit_extend_lspec_valid_helper(&ec, circ) < 0)
return -1;
+ if (circuit_extend_add_ipv4_helper(&ec) < 0)
+ return -1;
+
+ if (circuit_extend_add_ipv6_helper(&ec) < 0)
+ return -1;
+
/* Check the addresses, without logging */
const int ipv4_valid = circuit_extend_addr_port_is_valid(&ec.orport_ipv4,
false, false, 0);
@@ -542,7 +591,11 @@ onionskin_answer(struct or_circuit_t *circ,
/* 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();
+ tor_addr_t remote_addr;
+ if (channel_get_addr_if_possible(circ->p_chan, &remote_addr)) {
+ int family = tor_addr_family(&remote_addr);
+ router_orport_found_reachable(family);
+ }
}
return 0;
diff --git a/src/feature/relay/circuitbuild_relay.h b/src/feature/relay/circuitbuild_relay.h
index 0783161538..dc0b886a34 100644
--- a/src/feature/relay/circuitbuild_relay.h
+++ b/src/feature/relay/circuitbuild_relay.h
@@ -73,6 +73,8 @@ onionskin_answer(struct or_circuit_t *circ,
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_add_ipv4_helper(struct extend_cell_t *ec);
+STATIC int circuit_extend_add_ipv6_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(
diff --git a/src/feature/relay/relay_config.c b/src/feature/relay/relay_config.c
index fac6a2f577..bd1c1e8fe8 100644
--- a/src/feature/relay/relay_config.c
+++ b/src/feature/relay/relay_config.c
@@ -1029,7 +1029,7 @@ options_transition_affects_descriptor(const or_options_t *old_options,
YES_IF_CHANGED_STRING(DataDirectory);
YES_IF_CHANGED_STRING(Nickname);
- YES_IF_CHANGED_STRING(Address);
+ YES_IF_CHANGED_LINELIST(Address);
YES_IF_CHANGED_LINELIST(ExitPolicy);
YES_IF_CHANGED_BOOL(ExitRelay);
YES_IF_CHANGED_BOOL(ExitPolicyRejectPrivate);
@@ -1114,8 +1114,6 @@ options_act_relay(const or_options_t *old_options)
if (server_mode_turned_on) {
ip_address_changed(0);
- if (have_completed_a_circuit() || !any_predicted_circuits(time(NULL)))
- inform_testing_reachability();
}
cpuworkers_rotate_keyinfo();
}
diff --git a/src/feature/relay/relay_find_addr.c b/src/feature/relay/relay_find_addr.c
index 86cd799d42..a51457ddbb 100644
--- a/src/feature/relay/relay_find_addr.c
+++ b/src/feature/relay/relay_find_addr.c
@@ -45,8 +45,7 @@ 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. */
+ tor_addr_t addr, my_addr, last_resolved_addr;
const or_options_t *options = get_options();
/* first, learn what the IP address actually is */
@@ -64,14 +63,22 @@ router_new_address_suggestion(const char *suggestion,
}
/* XXXX ipv6 */
- cur = get_last_resolved_addr();
- if (cur ||
- resolve_my_address(LOG_INFO, options, &cur, NULL, NULL) >= 0) {
+ resolved_addr_get_last(AF_INET, &last_resolved_addr);
+ if (!tor_addr_is_null(&last_resolved_addr)) {
+ /* Lets use this one. */
+ tor_addr_copy(&last_guessed_ip, &last_resolved_addr);
+ return;
+ }
+
+ /* Attempt to find our address. */
+ if (find_my_address(options, AF_INET, LOG_INFO, &my_addr, NULL, NULL)) {
/* 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 */
+ tor_addr_copy(&last_guessed_ip, &my_addr); /* store it in case we
+ need it later */
return;
}
+
+ /* Consider the suggestion from the directory. */
if (tor_addr_is_internal(&addr, 0)) {
/* Don't believe anybody who says our IP is, say, 127.0.0.1. */
return;
@@ -111,15 +118,21 @@ 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)
+ tor_addr_t last_resolved_addr;
+
+ /* First, check the cached output from find_my_address(). */
+ resolved_addr_get_last(AF_INET, &last_resolved_addr);
+ if (!tor_addr_is_null(&last_resolved_addr)) {
+ *addr = tor_addr_to_ipv4h(&last_resolved_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));
+ tor_addr_t my_addr;
+ if (find_my_address(options, AF_INET, LOG_INFO, &my_addr, NULL, NULL)) {
+ log_info(LD_CONFIG,"Success: chose address '%s'.", fmt_addr(&my_addr));
+ *addr = tor_addr_to_ipv4h(&my_addr);
return 0;
}
}
diff --git a/src/feature/relay/relay_periodic.c b/src/feature/relay/relay_periodic.c
index 08ad110cf6..0c056bdeb1 100644
--- a/src/feature/relay/relay_periodic.c
+++ b/src/feature/relay/relay_periodic.c
@@ -201,23 +201,49 @@ reachability_warnings_callback(time_t now, const or_options_t *options)
have_completed_a_circuit()) {
/* every 20 minutes, check and complain if necessary */
const routerinfo_t *me = router_get_my_routerinfo();
- if (me && !check_whether_orport_reachable(options)) {
- char *address = tor_dup_ip(me->addr);
- if (address) {
+ bool v4_ok =
+ router_orport_seems_reachable(options,AF_INET);
+ bool v6_ok =
+ router_orport_seems_reachable(options,AF_INET6);
+ if (me && !(v4_ok && v6_ok)) {
+ /* We need to warn that one or more of our ORPorts isn't reachable.
+ * Determine which, and give a reasonable warning. */
+ char *address4 = tor_dup_ip(me->addr);
+ char *address6 = tor_addr_to_str_dup(&me->ipv6_addr);
+ if (address4 || address6) {
+ char *where4=NULL, *where6=NULL;
+ if (!v4_ok)
+ tor_asprintf(&where4, "%s:%d", address4, me->or_port);
+ if (!v6_ok)
+ tor_asprintf(&where6, "[%s]:%d", address6, me->or_port);
+ const char *opt_and = (!v4_ok && !v6_ok) ? "and" : "";
+
log_warn(LD_CONFIG,
- "Your server (%s:%d) has not managed to confirm that "
- "its ORPort is reachable. Relays do not publish descriptors "
+ "Your server has not managed to confirm reachability for "
+ "its ORPort(s) at %s%s%s. Relays do not publish descriptors "
"until their ORPort and DirPort are reachable. Please check "
"your firewalls, ports, address, /etc/hosts file, etc.",
- address, me->or_port);
- control_event_server_status(LOG_WARN,
- "REACHABILITY_FAILED ORADDRESS=%s:%d",
- address, me->or_port);
- tor_free(address);
+ where4?where4:"",
+ opt_and,
+ where6?where6:"");
+ tor_free(where4);
+ tor_free(where6);
+ if (!v4_ok) {
+ control_event_server_status(LOG_WARN,
+ "REACHABILITY_FAILED ORADDRESS=%s:%d",
+ address4, me->or_port);
+ }
+ if (!v6_ok) {
+ control_event_server_status(LOG_WARN,
+ "REACHABILITY_FAILED ORADDRESS=[%s]:%d",
+ address6, me->ipv6_orport);
+ }
}
+ tor_free(address4);
+ tor_free(address6);
}
- if (me && !check_whether_dirport_reachable(options)) {
+ if (me && !router_dirport_seems_reachable(options)) {
char *address = tor_dup_ip(me->addr);
if (address) {
log_warn(LD_CONFIG,
diff --git a/src/feature/relay/router.c b/src/feature/relay/router.c
index 34d8163c36..57da735e87 100644
--- a/src/feature/relay/router.c
+++ b/src/feature/relay/router.c
@@ -831,30 +831,37 @@ router_initialize_tls_context(void)
* -1 if Tor should die,
*/
STATIC int
-router_write_fingerprint(int hashed)
+router_write_fingerprint(int hashed, int ed25519_identity)
{
char *keydir = NULL, *cp = NULL;
const char *fname = hashed ? "hashed-fingerprint" :
- "fingerprint";
+ (ed25519_identity ? "fingerprint-ed25519" :
+ "fingerprint");
char fingerprint[FINGERPRINT_LEN+1];
const or_options_t *options = get_options();
char *fingerprint_line = NULL;
int result = -1;
keydir = get_datadir_fname(fname);
- log_info(LD_GENERAL,"Dumping %sfingerprint to \"%s\"...",
- hashed ? "hashed " : "", keydir);
- if (!hashed) {
- if (crypto_pk_get_fingerprint(get_server_identity_key(),
- fingerprint, 0) < 0) {
- log_err(LD_GENERAL,"Error computing fingerprint");
- goto done;
- }
- } else {
- if (crypto_pk_get_hashed_fingerprint(get_server_identity_key(),
- fingerprint) < 0) {
- log_err(LD_GENERAL,"Error computing hashed fingerprint");
- goto done;
+ log_info(LD_GENERAL,"Dumping %s%s to \"%s\"...", hashed ? "hashed " : "",
+ ed25519_identity ? "ed25519 identity" : "fingerprint", keydir);
+
+ if (ed25519_identity) { /* ed25519 identity */
+ digest256_to_base64(fingerprint, (const char *)
+ get_master_identity_key()->pubkey);
+ } else { /* RSA identity */
+ if (!hashed) {
+ if (crypto_pk_get_fingerprint(get_server_identity_key(),
+ fingerprint, 0) < 0) {
+ log_err(LD_GENERAL,"Error computing fingerprint");
+ goto done;
+ }
+ } else {
+ if (crypto_pk_get_hashed_fingerprint(get_server_identity_key(),
+ fingerprint) < 0) {
+ log_err(LD_GENERAL,"Error computing hashed fingerprint");
+ goto done;
+ }
}
}
@@ -865,15 +872,17 @@ router_write_fingerprint(int hashed)
cp = read_file_to_str(keydir, RFTS_IGNORE_MISSING, NULL);
if (!cp || strcmp(cp, fingerprint_line)) {
if (write_str_to_file(keydir, fingerprint_line, 0)) {
- log_err(LD_FS, "Error writing %sfingerprint line to file",
- hashed ? "hashed " : "");
+ log_err(LD_FS, "Error writing %s%s line to file",
+ hashed ? "hashed " : "",
+ ed25519_identity ? "ed25519 identity" : "fingerprint");
goto done;
}
}
- log_notice(LD_GENERAL, "Your Tor %s identity key fingerprint is '%s %s'",
- hashed ? "bridge's hashed" : "server's", options->Nickname,
- fingerprint);
+ log_notice(LD_GENERAL, "Your Tor %s identity key %s fingerprint is '%s %s'",
+ hashed ? "bridge's hashed" : "server's",
+ ed25519_identity ? "ed25519" : "",
+ options->Nickname, fingerprint);
result = 0;
done:
@@ -1109,15 +1118,20 @@ init_keys(void)
}
}
- /* 5. Dump fingerprint and possibly hashed fingerprint to files. */
- if (router_write_fingerprint(0)) {
+ /* 5. Dump fingerprint, ed25519 identity and possibly hashed fingerprint
+ * to files. */
+ if (router_write_fingerprint(0, 0)) {
log_err(LD_FS, "Error writing fingerprint to file");
return -1;
}
- if (!public_server_mode(options) && router_write_fingerprint(1)) {
+ if (!public_server_mode(options) && router_write_fingerprint(1, 0)) {
log_err(LD_FS, "Error writing hashed fingerprint to file");
return -1;
}
+ if (router_write_fingerprint(0, 1)) {
+ log_err(LD_FS, "Error writing ed25519 identity to file");
+ return -1;
+ }
if (!authdir_mode(options))
return 0;
@@ -1134,10 +1148,12 @@ init_keys(void)
ds = router_get_trusteddirserver_by_digest(digest);
if (!ds) {
+ tor_addr_port_t ipv6_orport;
+ router_get_advertised_ipv6_or_ap(options, &ipv6_orport);
ds = trusted_dir_server_new(options->Nickname, NULL,
router_get_advertised_dir_port(options, 0),
router_get_advertised_or_port(options),
- NULL,
+ &ipv6_orport,
digest,
v3_digest,
type, 0.0);
@@ -1335,6 +1351,17 @@ should_refuse_unknown_exits(const or_options_t *options)
}
}
+/**
+ * If true, then we will publish our descriptor even if our own IPv4 ORPort
+ * seems to be unreachable.
+ **/
+static bool publish_even_when_ipv4_orport_unreachable = false;
+/**
+ * If true, then we will publish our descriptor even if our own IPv6 ORPort
+ * seems to be unreachable.
+ **/
+static bool publish_even_when_ipv6_orport_unreachable = false;
+
/** Decide if we're a publishable server. We are a publishable server if:
* - We don't have the ClientOnly option set
* and
@@ -1363,14 +1390,24 @@ decide_if_publishable_server(void)
return 1;
if (!router_get_advertised_or_port(options))
return 0;
- if (!check_whether_orport_reachable(options))
- return 0;
+ if (!router_orport_seems_reachable(options, AF_INET)) {
+ // We have an ipv4 orport, and it doesn't seem reachable.
+ if (!publish_even_when_ipv4_orport_unreachable) {
+ return 0;
+ }
+ }
+ if (!router_orport_seems_reachable(options, AF_INET6)) {
+ // We have an ipv6 orport, and it doesn't seem reachable.
+ if (!publish_even_when_ipv6_orport_unreachable) {
+ return 0;
+ }
+ }
if (router_have_consensus_path() == CONSENSUS_PATH_INTERNAL) {
/* All set: there are no exits in the consensus (maybe this is a tiny
* test network), so we can't check our DirPort reachability. */
return 1;
} else {
- return check_whether_dirport_reachable(options);
+ return router_dirport_seems_reachable(options);
}
}
@@ -1501,7 +1538,22 @@ router_has_advertised_ipv6_orport(const or_options_t *options)
return tor_addr_port_is_valid_ap(&ipv6_ap, 0);
}
-/** Returns true if this router has an advertised IPv6 ORPort. */
+/** Returns true if this router can extend over IPv6.
+ *
+ * This check should only be performed by relay extend code.
+ *
+ * Clients should check if relays can initiate and accept IPv6 extends using
+ * node_supports_initiating_ipv6_extends() and
+ * node_supports_accepting_ipv6_extends().
+ *
+ * As with other extends, relays should assume the client has already
+ * performed the relevant checks for the next hop. (Otherwise, relays that
+ * have just added IPv6 ORPorts won't be able to self-test those ORPorts.)
+ *
+ * Accepting relays don't need to perform any IPv6-specific checks before
+ * accepting a connection, because having an IPv6 ORPort implies support for
+ * the relevant protocol version.
+ */
MOCK_IMPL(bool,
router_can_extend_over_ipv6,(const or_options_t *options))
{
@@ -2373,6 +2425,24 @@ router_rebuild_descriptor(int force)
return 0;
}
+/** Called when we have a new set of consensus parameters. */
+void
+router_new_consensus_params(const networkstatus_t *ns)
+{
+ const int32_t DEFAULT_ASSUME_REACHABLE = 0;
+ const int32_t DEFAULT_ASSUME_REACHABLE_IPV6 = 0;
+ int ar, ar6;
+ ar = networkstatus_get_param(ns,
+ "assume-reachable",
+ DEFAULT_ASSUME_REACHABLE, 0, 1);
+ ar6 = networkstatus_get_param(ns,
+ "assume-reachable-ipv6",
+ DEFAULT_ASSUME_REACHABLE_IPV6, 0, 1);
+
+ publish_even_when_ipv4_orport_unreachable = ar;
+ publish_even_when_ipv6_orport_unreachable = ar || ar6;
+}
+
/** If our router descriptor ever goes this long without being regenerated
* because something changed, we force an immediate regenerate-and-upload. */
#define FORCE_REGENERATE_DESCRIPTOR_INTERVAL (18*60*60)
@@ -2525,6 +2595,7 @@ void
check_descriptor_ipaddress_changed(time_t now)
{
uint32_t prev, cur;
+ tor_addr_t addr;
const or_options_t *options = get_options();
const char *method = NULL;
char *hostname = NULL;
@@ -2537,10 +2608,12 @@ check_descriptor_ipaddress_changed(time_t now)
/* XXXX ipv6 */
prev = my_ri->addr;
- if (resolve_my_address(LOG_INFO, options, &cur, &method, &hostname) < 0) {
+ if (!find_my_address(options, AF_INET, LOG_INFO, &addr, &method,
+ &hostname)) {
log_info(LD_CONFIG,"options->Address didn't resolve into an IP.");
return;
}
+ cur = tor_addr_to_ipv4h(&addr);
if (prev != cur) {
char *source;
diff --git a/src/feature/relay/router.h b/src/feature/relay/router.h
index 50790a73dd..fab109be7c 100644
--- a/src/feature/relay/router.h
+++ b/src/feature/relay/router.h
@@ -81,6 +81,7 @@ int router_should_advertise_dirport(const or_options_t *options,
void consider_publishable_server(int force);
int should_refuse_unknown_exits(const or_options_t *options);
+void router_new_consensus_params(const networkstatus_t *);
void router_upload_dir_desc_to_dirservers(int force);
void mark_my_descriptor_dirty_if_too_old(time_t now);
void mark_my_descriptor_dirty(const char *reason);
@@ -124,7 +125,7 @@ void router_free_all(void);
#ifdef ROUTER_PRIVATE
/* Used only by router.c and the unit tests */
STATIC void get_platform_str(char *platform, size_t len);
-STATIC int router_write_fingerprint(int hashed);
+STATIC int router_write_fingerprint(int hashed, int ed25519_identity);
STATIC smartlist_t *get_my_declared_family(const or_options_t *options);
#ifdef TOR_UNIT_TESTS
diff --git a/src/feature/relay/selftest.c b/src/feature/relay/selftest.c
index 18fe25b989..77c04abdd7 100644
--- a/src/feature/relay/selftest.c
+++ b/src/feature/relay/selftest.c
@@ -15,38 +15,53 @@
#include "core/or/or.h"
#include "app/config/config.h"
+
#include "core/mainloop/connection.h"
#include "core/mainloop/mainloop.h"
#include "core/mainloop/netstatus.h"
+
#include "core/or/circuitbuild.h"
#include "core/or/circuitlist.h"
#include "core/or/circuituse.h"
#include "core/or/crypt_path_st.h"
+#include "core/or/extendinfo.h"
+#include "core/or/extend_info_st.h"
#include "core/or/origin_circuit_st.h"
#include "core/or/relay.h"
+
#include "feature/control/control_events.h"
+
#include "feature/dirclient/dirclient.h"
#include "feature/dircommon/directory.h"
+
#include "feature/nodelist/authority_cert_st.h"
#include "feature/nodelist/routerinfo.h"
#include "feature/nodelist/routerinfo_st.h"
#include "feature/nodelist/routerlist.h" // but...
#include "feature/nodelist/routerset.h"
#include "feature/nodelist/torcert.h"
+
#include "feature/relay/relay_periodic.h"
#include "feature/relay/router.h"
#include "feature/relay/selftest.h"
-/** Whether we can reach our ORPort from the outside. */
-static int can_reach_or_port = 0;
+static bool have_orport_for_family(int family);
+static void inform_testing_reachability(const tor_addr_t *addr,
+ uint16_t port,
+ bool is_dirport);
+
+/** Whether we can reach our IPv4 ORPort from the outside. */
+static bool can_reach_or_port_ipv4 = false;
+/** Whether we can reach our IPv6 ORPort from the outside. */
+static bool can_reach_or_port_ipv6 = false;
/** Whether we can reach our DirPort from the outside. */
-static int can_reach_dir_port = 0;
+static bool can_reach_dir_port = false;
/** Forget what we have learned about our reachability status. */
void
router_reset_reachability(void)
{
- can_reach_or_port = can_reach_dir_port = 0;
+ can_reach_or_port_ipv4 = can_reach_or_port_ipv6 = can_reach_dir_port = false;
}
/** Return 1 if we won't do reachability checks, because:
@@ -68,13 +83,43 @@ router_reachability_checks_disabled(const or_options_t *options)
* - we've seen a successful reachability check, or
* - AssumeReachable is set, or
* - the network is disabled.
+
+ * If `family'`is AF_INET or AF_INET6, return true only when we should skip
+ * the given family's orport check (Because it's been checked, or because we
+ * aren't checking it.) If `family` is 0, return true if we can skip _all_
+ * orport checks.
*/
int
-check_whether_orport_reachable(const or_options_t *options)
+router_orport_seems_reachable(const or_options_t *options,
+ int family)
{
+ tor_assert_nonfatal(family == AF_INET || family == AF_INET6 || family == 0);
int reach_checks_disabled = router_reachability_checks_disabled(options);
- return reach_checks_disabled ||
- can_reach_or_port;
+ if (reach_checks_disabled) {
+ return true;
+ }
+
+ // Note that we do a == 1 here, not just a boolean check. This value
+ // is also an autobool, so CFG_AUTO does not mean that we should
+ // assume IPv6 ports are reachable.
+ const bool ipv6_assume_reachable = (options->AssumeReachableIPv6 == 1);
+
+ // Which reachability flags should we look at?
+ const bool checking_ipv4 = (family == AF_INET || family == 0);
+ const bool checking_ipv6 = (family == AF_INET6 || family == 0);
+
+ if (checking_ipv4) {
+ if (have_orport_for_family(AF_INET) && !can_reach_or_port_ipv4) {
+ return false;
+ }
+ }
+ if (checking_ipv6 && !ipv6_assume_reachable) {
+ if (have_orport_for_family(AF_INET6) && !can_reach_or_port_ipv6) {
+ return false;
+ }
+ }
+
+ return true;
}
/** Return 0 if we need to do a DirPort reachability check, because:
@@ -87,7 +132,7 @@ check_whether_orport_reachable(const or_options_t *options)
* - the network is disabled.
*/
int
-check_whether_dirport_reachable(const or_options_t *options)
+router_dirport_seems_reachable(const or_options_t *options)
{
int reach_checks_disabled = router_reachability_checks_disabled(options) ||
!options->DirPort_set;
@@ -107,6 +152,7 @@ router_should_check_reachability(int test_or, int test_dir)
if (!me)
return 0;
+ /* Doesn't check our IPv6 address, see #34065. */
if (routerset_contains_router(options->ExcludeNodes, me, -1) &&
options->StrictNodes) {
/* If we've excluded ourself, and StrictNodes is set, we can't test
@@ -125,19 +171,51 @@ router_should_check_reachability(int test_or, int test_dir)
return 1;
}
+/**
+ * Return true if we have configured an ORPort for the given family that
+ * we would like to advertise.
+ *
+ * Like other self-testing functions, this function looks at our most
+ * recently built descriptor.
+ **/
+static bool
+have_orport_for_family(int family)
+{
+ const routerinfo_t *me = router_get_my_routerinfo();
+
+ if (!me)
+ return false;
+
+ tor_addr_port_t ap;
+ if (router_get_orport(me, &ap, family) < 0) {
+ return false;
+ }
+ return true;
+}
+
/** Allocate and return a new extend_info_t that can be used to build
- * a circuit to or through the router <b>r</b>. Uses the primary
- * address of the router, so should only be called on a server. */
+ * a circuit to or through the router <b>r</b>, using an address from
+ * <b>family</b> (if available).
+ *
+ * Clients don't have routerinfos, so this function should only be called on a
+ * server.
+ *
+ * If the requested address is not available, returns NULL. */
static extend_info_t *
-extend_info_from_router(const routerinfo_t *r)
+extend_info_from_router(const routerinfo_t *r, int family)
{
crypto_pk_t *rsa_pubkey;
extend_info_t *info;
tor_addr_port_t ap;
- tor_assert(r);
- /* Make sure we don't need to check address reachability */
- tor_assert_nonfatal(router_skip_or_reachability(get_options(), 0));
+ if (BUG(!r)) {
+ return NULL;
+ }
+
+ /* Relays always assume that the first hop is reachable. They ignore
+ * ReachableAddresses. */
+ tor_assert_nonfatal(router_or_conn_should_skip_reachable_address_check(
+ get_options(), 0));
const ed25519_public_key_t *ed_id_key;
if (r->cache_info.signing_key_cert)
@@ -145,7 +223,10 @@ extend_info_from_router(const routerinfo_t *r)
else
ed_id_key = NULL;
- router_get_prim_orport(r, &ap);
+ if (router_get_orport(r, &ap, family) < 0) {
+ /* We don't have an ORPort for the requested family. */
+ return NULL;
+ }
rsa_pubkey = router_get_rsa_onion_pkey(r->onion_pkey, r->onion_pkey_len);
info = extend_info_new(r->nickname, r->cache_info.identity_digest,
ed_id_key,
@@ -155,6 +236,78 @@ extend_info_from_router(const routerinfo_t *r)
return info;
}
+/** Launch a self-testing circuit to one of our ORPorts, using an address from
+ * <b>family</b> (if available). The circuit can be used to test reachability
+ * or bandwidth. <b>me</b> is our own routerinfo.
+ *
+ * Logs an info-level status message. If <b>orport_reachable</b> is false,
+ * call it a reachability circuit. Otherwise, call it a bandwidth circuit.
+ *
+ * See router_do_reachability_checks() for details. */
+static void
+router_do_orport_reachability_checks(const routerinfo_t *me,
+ int family,
+ int orport_reachable)
+{
+ extend_info_t *ei = extend_info_from_router(me, family);
+ int ipv6_flags = (family == AF_INET6 ? CIRCLAUNCH_IS_IPV6_SELFTEST : 0);
+
+ /* If we're trying to test IPv6, but we don't have an IPv6 ORPort, ei will
+ * be NULL. */
+ if (ei) {
+ const char *family_name = fmt_af_family(family);
+ const tor_addr_port_t *ap = extend_info_get_orport(ei, family);
+ log_info(LD_CIRC, "Testing %s of my %s ORPort: %s.",
+ !orport_reachable ? "reachability" : "bandwidth",
+ family_name, fmt_addrport_ap(ap));
+ if (!orport_reachable) {
+ /* This is only a 'reachability test' if we don't already think that
+ * the port is reachable. If we _do_ think it's reachable, then
+ * it counts as a 'bandwidth test'. */
+ inform_testing_reachability(&ap->addr, ap->port, false);
+ }
+ circuit_launch_by_extend_info(CIRCUIT_PURPOSE_TESTING, ei,
+ CIRCLAUNCH_NEED_CAPACITY|
+ CIRCLAUNCH_IS_INTERNAL|
+ ipv6_flags);
+ extend_info_free(ei);
+ }
+}
+
+/** Launch a self-testing circuit, and ask an exit to connect to our DirPort.
+ * <b>me</b> is our own routerinfo.
+ *
+ * Relays don't advertise IPv6 DirPorts, so this function only supports IPv4.
+ *
+ * See router_do_reachability_checks() for details. */
+static void
+router_do_dirport_reachability_checks(const routerinfo_t *me)
+{
+ tor_addr_port_t my_dirport;
+ tor_addr_from_ipv4h(&my_dirport.addr, me->addr);
+ my_dirport.port = me->dir_port;
+
+ /* If there is already a pending connection, don't open another one. */
+ if (!connection_get_by_type_addr_port_purpose(
+ CONN_TYPE_DIR,
+ &my_dirport.addr, my_dirport.port,
+ DIR_PURPOSE_FETCH_SERVERDESC)) {
+ /* ask myself, via tor, for my server descriptor. */
+ directory_request_t *req =
+ directory_request_new(DIR_PURPOSE_FETCH_SERVERDESC);
+ directory_request_set_dir_addr_port(req, &my_dirport);
+ directory_request_set_directory_id_digest(req,
+ me->cache_info.identity_digest);
+ /* ask via an anon circuit, connecting to our dirport. */
+ directory_request_set_indirection(req, DIRIND_ANON_DIRPORT);
+ directory_request_set_resource(req, "authority.z");
+ directory_initiate_request(req);
+ directory_request_free(req);
+
+ inform_testing_reachability(&my_dirport.addr, my_dirport.port, true);
+ }
+}
+
/** Some time has passed, or we just got new directory information.
* See if we currently believe our ORPort or DirPort to be
* unreachable. If so, launch a new test for it.
@@ -171,104 +324,104 @@ router_do_reachability_checks(int test_or, int test_dir)
{
const routerinfo_t *me = router_get_my_routerinfo();
const or_options_t *options = get_options();
- int orport_reachable = check_whether_orport_reachable(options);
- tor_addr_t addr;
+ int orport_reachable_v4 =
+ router_orport_seems_reachable(options, AF_INET);
+ int orport_reachable_v6 =
+ router_orport_seems_reachable(options, AF_INET6);
if (router_should_check_reachability(test_or, test_dir)) {
- if (test_or && (!orport_reachable || !circuit_enough_testing_circs())) {
- extend_info_t *ei = extend_info_from_router(me);
- /* XXX IPv6 self testing */
- log_info(LD_CIRC, "Testing %s of my ORPort: %s:%d.",
- !orport_reachable ? "reachability" : "bandwidth",
- fmt_addr32(me->addr), me->or_port);
- circuit_launch_by_extend_info(CIRCUIT_PURPOSE_TESTING, ei,
- CIRCLAUNCH_NEED_CAPACITY|CIRCLAUNCH_IS_INTERNAL);
- extend_info_free(ei);
+ bool need_testing = !circuit_enough_testing_circs();
+ /* At the moment, tor relays believe that they are reachable when they
+ * receive any create cell on an inbound connection, if the address
+ * family is correct.
+ */
+ if (test_or && (!orport_reachable_v4 || need_testing)) {
+ router_do_orport_reachability_checks(me, AF_INET, orport_reachable_v4);
+ }
+ if (test_or && (!orport_reachable_v6 || need_testing)) {
+ router_do_orport_reachability_checks(me, AF_INET6, orport_reachable_v6);
}
- /* XXX IPv6 self testing */
- tor_addr_from_ipv4h(&addr, me->addr);
- if (test_dir && !check_whether_dirport_reachable(options) &&
- !connection_get_by_type_addr_port_purpose(
- CONN_TYPE_DIR, &addr, me->dir_port,
- DIR_PURPOSE_FETCH_SERVERDESC)) {
- tor_addr_port_t my_orport, my_dirport;
- memcpy(&my_orport.addr, &addr, sizeof(addr));
- memcpy(&my_dirport.addr, &addr, sizeof(addr));
- my_orport.port = me->or_port;
- my_dirport.port = me->dir_port;
- /* ask myself, via tor, for my server descriptor. */
- directory_request_t *req =
- directory_request_new(DIR_PURPOSE_FETCH_SERVERDESC);
- directory_request_set_or_addr_port(req, &my_orport);
- directory_request_set_dir_addr_port(req, &my_dirport);
- directory_request_set_directory_id_digest(req,
- me->cache_info.identity_digest);
- // ask via an anon circuit, connecting to our dirport.
- directory_request_set_indirection(req, DIRIND_ANON_DIRPORT);
- directory_request_set_resource(req, "authority.z");
- directory_initiate_request(req);
- directory_request_free(req);
+ if (test_dir && !router_dirport_seems_reachable(options)) {
+ router_do_dirport_reachability_checks(me);
}
}
}
-/** 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)
+/** Log a message informing the user that we are testing a port for
+ * reachability.
+ *
+ * If @a is_dirport is true, then the port is a DirPort; otherwise it is an
+ * ORPort. */
+static void
+inform_testing_reachability(const tor_addr_t *addr,
+ uint16_t port,
+ bool is_dirport)
{
- char dirbuf[128];
- char *address;
- const routerinfo_t *me = router_get_my_routerinfo();
- if (!me)
- return 0;
+ if (!router_get_my_routerinfo())
+ return;
- address = tor_dup_ip(me->addr);
- if (!address)
- return 0;
+ char addr_buf[TOR_ADDRPORT_BUF_LEN];
+ strlcpy(addr_buf, fmt_addrport(addr, port), sizeof(addr_buf));
+
+ const char *control_addr_type = is_dirport ? "DIRADDRESS" : "ORADDRESS";
+ const char *port_type = is_dirport ? "DirPort" : "ORPort";
+ const char *afname = fmt_af_family(tor_addr_family(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;
+ "CHECKING_REACHABILITY %s=%s",
+ control_addr_type, addr_buf);
+
+ log_notice(LD_OR, "Now checking whether %s %s %s is reachable... "
+ "(this may take up to %d minutes -- look for log "
+ "messages indicating success)",
+ afname, port_type, addr_buf,
+ TIMEOUT_UNTIL_UNREACHABILITY_COMPLAINT/60);
}
-/** Annotate that we found our ORPort reachable. */
+/**
+ * Return true if this module knows of no reason why we shouldn't publish
+ * a server descriptor.
+ **/
+static bool
+ready_to_publish(const or_options_t *options)
+{
+ return options->PublishServerDescriptor_ != NO_DIRINFO &&
+ router_dirport_seems_reachable(options) &&
+ router_all_orports_seem_reachable(options);
+}
+
+/** Annotate that we found our ORPort reachable with a given address
+ * family. */
void
-router_orport_found_reachable(void)
+router_orport_found_reachable(int family)
{
const routerinfo_t *me = router_get_my_routerinfo();
const or_options_t *options = get_options();
- if (!can_reach_or_port && me) {
- char *address = tor_dup_ip(me->addr);
-
- if (!address)
+ bool *can_reach_ptr;
+ if (family == AF_INET) {
+ can_reach_ptr = &can_reach_or_port_ipv4;
+ } else if (family == AF_INET6) {
+ can_reach_ptr = &can_reach_or_port_ipv6;
+ } else {
+ tor_assert_nonfatal_unreached();
+ return;
+ }
+ if (!*can_reach_ptr && me) {
+ tor_addr_port_t ap;
+ if (router_get_orport(me, &ap, family) < 0) {
return;
+ }
+ char *address = tor_strdup(fmt_addrport_ap(&ap));
+
+ *can_reach_ptr = true;
- log_notice(LD_OR,"Self-testing indicates your ORPort is reachable from "
+ log_notice(LD_OR,"Self-testing indicates your ORPort %s is reachable from "
"the outside. Excellent.%s",
- options->PublishServerDescriptor_ != NO_DIRINFO
- && check_whether_dirport_reachable(options) ?
- " Publishing server descriptor." : "");
- can_reach_or_port = 1;
+ address,
+ ready_to_publish(options) ?
+ " Publishing server descriptor." : "");
+
mark_my_descriptor_dirty("ORPort found reachable");
/* This is a significant enough change to upload immediately,
* at least in a test network */
@@ -276,8 +429,8 @@ router_orport_found_reachable(void)
reschedule_descriptor_update_check();
}
control_event_server_status(LOG_NOTICE,
- "REACHABILITY_SUCCEEDED ORADDRESS=%s:%d",
- address, me->or_port);
+ "REACHABILITY_SUCCEEDED ORADDRESS=%s",
+ address);
tor_free(address);
}
}
@@ -288,18 +441,19 @@ router_dirport_found_reachable(void)
{
const routerinfo_t *me = router_get_my_routerinfo();
const or_options_t *options = get_options();
+
if (!can_reach_dir_port && me) {
char *address = tor_dup_ip(me->addr);
if (!address)
return;
+ can_reach_dir_port = true;
log_notice(LD_DIRSERV,"Self-testing indicates your DirPort is reachable "
"from the outside. Excellent.%s",
- options->PublishServerDescriptor_ != NO_DIRINFO
- && check_whether_orport_reachable(options) ?
+ ready_to_publish(options) ?
" Publishing server descriptor." : "");
- can_reach_dir_port = 1;
+
if (router_should_advertise_dirport(options, me->dir_port)) {
mark_my_descriptor_dirty("DirPort found reachable");
/* This is a significant enough change to upload immediately,
@@ -316,7 +470,9 @@ router_dirport_found_reachable(void)
}
/** We have enough testing circuits open. Send a bunch of "drop"
- * cells down each of them, to exercise our bandwidth. */
+ * cells down each of them, to exercise our bandwidth.
+ *
+ * May use IPv4 and IPv6 testing circuits (if available). */
void
router_perform_bandwidth_test(int num_circs, time_t now)
{
diff --git a/src/feature/relay/selftest.h b/src/feature/relay/selftest.h
index f5babc95da..e09c0e7898 100644
--- a/src/feature/relay/selftest.h
+++ b/src/feature/relay/selftest.h
@@ -15,23 +15,29 @@
#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);
+#define router_all_orports_seem_reachable(opts) \
+ router_orport_seems_reachable((opts),0)
+int router_orport_seems_reachable(
+ const struct or_options_t *options,
+ int family);
+int router_dirport_seems_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_orport_found_reachable(int family);
void router_dirport_found_reachable(void);
void router_reset_reachability(void);
#else /* !defined(HAVE_MODULE_RELAY) */
-#define check_whether_orport_reachable(opts) \
+#define router_all_orports_seem_reachable(opts) \
((void)(opts), 0)
-#define check_whether_dirport_reachable(opts) \
+#define router_orport_seems_reachable(opts, fam) \
+ ((void)(opts), (void)(fam), 0)
+#define router_dirport_seems_reachable(opts) \
((void)(opts), 0)
static inline void
diff --git a/src/feature/rend/rendclient.c b/src/feature/rend/rendclient.c
index 09db7045fa..e171562d17 100644
--- a/src/feature/rend/rendclient.c
+++ b/src/feature/rend/rendclient.c
@@ -15,6 +15,7 @@
#include "core/or/circuitlist.h"
#include "core/or/circuituse.h"
#include "core/or/connection_edge.h"
+#include "core/or/extendinfo.h"
#include "core/or/relay.h"
#include "feature/client/circpathbias.h"
#include "feature/control/control_events.h"
@@ -234,9 +235,15 @@ rend_client_send_introduction(origin_circuit_t *introcirc,
/* version 2 format */
extend_info_t *extend_info = rendcirc->build_state->chosen_exit;
int klen;
+ const tor_addr_port_t *orport =
+ extend_info_get_orport(extend_info, AF_INET);
+ IF_BUG_ONCE(! orport) {
+ /* we should never put an IPv6 address here. */
+ goto perm_err;
+ }
/* nul pads */
- set_uint32(tmp+v3_shift+1, tor_addr_to_ipv4n(&extend_info->addr));
- set_uint16(tmp+v3_shift+5, htons(extend_info->port));
+ set_uint32(tmp+v3_shift+1, tor_addr_to_ipv4n(&orport->addr));
+ set_uint16(tmp+v3_shift+5, htons(orport->port));
memcpy(tmp+v3_shift+7, extend_info->identity_digest, DIGEST_LEN);
klen = crypto_pk_asn1_encode(extend_info->onion_key,
tmp+v3_shift+7+DIGEST_LEN+2,
diff --git a/src/feature/rend/rendcommon.c b/src/feature/rend/rendcommon.c
index 5d04755819..775d487805 100644
--- a/src/feature/rend/rendcommon.c
+++ b/src/feature/rend/rendcommon.c
@@ -14,6 +14,7 @@
#include "core/or/circuitbuild.h"
#include "core/or/circuitlist.h"
#include "core/or/circuituse.h"
+#include "core/or/extendinfo.h"
#include "app/config/config.h"
#include "feature/control/control_events.h"
#include "lib/crypt_ops/crypto_rand.h"
@@ -233,7 +234,12 @@ rend_encode_v2_intro_points(char **encoded, rend_service_descriptor_t *desc)
goto done;
}
/* Assemble everything for this introduction point. */
- address = tor_addr_to_str_dup(&info->addr);
+ const tor_addr_port_t *orport = extend_info_get_orport(info, AF_INET);
+ IF_BUG_ONCE(!orport) {
+ /* There must be an IPv4 address for v2 hs. */
+ goto done;
+ }
+ address = tor_addr_to_str_dup(&orport->addr);
res = tor_snprintf(unenc + unenc_written, unenc_len - unenc_written,
"introduction-point %s\n"
"ip-address %s\n"
@@ -242,7 +248,7 @@ rend_encode_v2_intro_points(char **encoded, rend_service_descriptor_t *desc)
"service-key\n%s",
id_base32,
address,
- info->port,
+ orport->port,
onion_key,
service_key);
tor_free(address);
diff --git a/src/feature/rend/rendparse.c b/src/feature/rend/rendparse.c
index 0979d767a7..c28add5ca9 100644
--- a/src/feature/rend/rendparse.c
+++ b/src/feature/rend/rendparse.c
@@ -10,6 +10,7 @@
**/
#include "core/or/or.h"
+#include "core/or/extendinfo.h"
#include "feature/dirparse/parsecommon.h"
#include "feature/dirparse/sigcommon.h"
#include "feature/rend/rendcommon.h"
@@ -428,7 +429,8 @@ rend_parse_introduction_points(rend_service_descriptor_t *parsed,
}
/* Allocate new intro point and extend info. */
intro = tor_malloc_zero(sizeof(rend_intro_point_t));
- info = intro->extend_info = tor_malloc_zero(sizeof(extend_info_t));
+ info = intro->extend_info =
+ extend_info_new(NULL, NULL, NULL, NULL, NULL, NULL, 0);
/* Parse identifier. */
tok = find_by_keyword(tokens, R_IPO_IDENTIFIER);
if (base32_decode(info->identity_digest, DIGEST_LEN,
@@ -446,12 +448,13 @@ rend_parse_introduction_points(rend_service_descriptor_t *parsed,
info->identity_digest, DIGEST_LEN);
/* Parse IP address. */
tok = find_by_keyword(tokens, R_IPO_IP_ADDRESS);
- if (tor_addr_parse(&info->addr, tok->args[0])<0) {
+ tor_addr_t addr;
+ if (tor_addr_parse(&addr, tok->args[0])<0) {
log_warn(LD_REND, "Could not parse introduction point address.");
rend_intro_point_free(intro);
goto err;
}
- if (tor_addr_family(&info->addr) != AF_INET) {
+ if (tor_addr_family(&addr) != AF_INET) {
log_warn(LD_REND, "Introduction point address was not ipv4.");
rend_intro_point_free(intro);
goto err;
@@ -459,14 +462,18 @@ rend_parse_introduction_points(rend_service_descriptor_t *parsed,
/* Parse onion port. */
tok = find_by_keyword(tokens, R_IPO_ONION_PORT);
- info->port = (uint16_t) tor_parse_long(tok->args[0],10,1,65535,
+ uint16_t port = (uint16_t) tor_parse_long(tok->args[0],10,1,65535,
&num_ok,NULL);
- if (!info->port || !num_ok) {
+ if (!port || !num_ok) {
log_warn(LD_REND, "Introduction point onion port %s is invalid",
escaped(tok->args[0]));
rend_intro_point_free(intro);
goto err;
}
+
+ /* Add the address and port. */
+ extend_info_add_orport(info, &addr, port);
+
/* Parse onion key. */
tok = find_by_keyword(tokens, R_IPO_ONION_KEY);
if (!crypto_pk_public_exponent_ok(tok->key)) {
diff --git a/src/feature/rend/rendservice.c b/src/feature/rend/rendservice.c
index 83388a72eb..585fdb532e 100644
--- a/src/feature/rend/rendservice.c
+++ b/src/feature/rend/rendservice.c
@@ -16,6 +16,7 @@
#include "core/or/circuitbuild.h"
#include "core/or/circuitlist.h"
#include "core/or/circuituse.h"
+#include "core/or/extendinfo.h"
#include "core/or/policies.h"
#include "core/or/relay.h"
#include "core/or/crypt_path.h"
@@ -1850,8 +1851,11 @@ rend_service_use_direct_connection(const or_options_t* options,
/* We'll connect directly all reachable addresses, whether preferred or not.
* The prefer_ipv6 argument to fascist_firewall_allows_address_addr is
* ignored, because pref_only is 0. */
+ const tor_addr_port_t *ap = extend_info_get_orport(ei, AF_INET);
+ if (!ap)
+ return 0;
return (rend_service_allow_non_anonymous_connection(options) &&
- fascist_firewall_allows_address_addr(&ei->addr, ei->port,
+ fascist_firewall_allows_address_addr(&ap->addr, ap->port,
FIREWALL_OR_CONNECTION, 0, 0));
}
@@ -2280,7 +2284,8 @@ find_rp_for_intro(const rend_intro_cell_t *intro,
/* Make sure the RP we are being asked to connect to is _not_ a private
* address unless it's allowed. Let's avoid to build a circuit to our
* second middle node and fail right after when extending to the RP. */
- if (!extend_info_addr_is_allowed(&rp->addr)) {
+ const tor_addr_port_t *orport = extend_info_get_orport(rp, AF_INET);
+ if (! orport || !extend_info_addr_is_allowed(&orport->addr)) {
if (err_msg_out) {
tor_asprintf(&err_msg,
"Relay IP in INTRODUCE2 cell is private address.");
@@ -2549,9 +2554,11 @@ rend_service_parse_intro_for_v2(
goto err;
}
- extend_info = tor_malloc_zero(sizeof(extend_info_t));
- tor_addr_from_ipv4n(&extend_info->addr, get_uint32(buf + 1));
- extend_info->port = ntohs(get_uint16(buf + 5));
+ extend_info = extend_info_new(NULL, NULL, NULL, NULL, NULL, NULL, 0);
+ tor_addr_t addr;
+ tor_addr_from_ipv4n(&addr, get_uint32(buf + 1));
+ uint16_t port = ntohs(get_uint16(buf + 5));
+ extend_info_add_orport(extend_info, &addr, port);
memcpy(extend_info->identity_digest, buf + 7, DIGEST_LEN);
extend_info->nickname[0] = '$';
base16_encode(extend_info->nickname + 1, sizeof(extend_info->nickname) - 1,
@@ -3839,6 +3846,9 @@ upload_service_descriptor(rend_service_t *service)
rend_get_service_id(service->desc->pk, serviceid);
if (get_options()->PublishHidServDescriptors) {
/* Post the current descriptors to the hidden service directories. */
+ /* This log message is used by Chutney as part of its bootstrap
+ * detection mechanism. Please don't change without first checking
+ * Chutney. */
log_info(LD_REND, "Launching upload for hidden service %s",
serviceid);
directory_post_to_hs_dir(service->desc, descs, NULL, serviceid,
diff --git a/src/feature/stats/predict_ports.c b/src/feature/stats/predict_ports.c
index d728f106a2..57463952e7 100644
--- a/src/feature/stats/predict_ports.c
+++ b/src/feature/stats/predict_ports.c
@@ -270,10 +270,10 @@ rep_hist_circbuilding_dormant(time_t now)
/* see if we'll still need to build testing circuits */
if (server_mode(options) &&
- (!check_whether_orport_reachable(options) ||
+ (!router_all_orports_seem_reachable(options) ||
!circuit_enough_testing_circs()))
return 0;
- if (!check_whether_dirport_reachable(options))
+ if (!router_dirport_seems_reachable(options))
return 0;
return 1;
diff --git a/src/feature/stats/rephist.c b/src/feature/stats/rephist.c
index 71e2e00086..d4826cd1a9 100644
--- a/src/feature/stats/rephist.c
+++ b/src/feature/stats/rephist.c
@@ -2455,6 +2455,26 @@ rep_hist_note_circuit_handshake_assigned(uint16_t type)
onion_handshakes_assigned[type]++;
}
+/** Get the circuit handshake value that is requested. */
+MOCK_IMPL(int,
+rep_hist_get_circuit_handshake_requested, (uint16_t type))
+{
+ if (BUG(type > MAX_ONION_HANDSHAKE_TYPE)) {
+ return 0;
+ }
+ return onion_handshakes_requested[type];
+}
+
+/** Get the circuit handshake value that is assigned. */
+MOCK_IMPL(int,
+rep_hist_get_circuit_handshake_assigned, (uint16_t type))
+{
+ if (BUG(type > MAX_ONION_HANDSHAKE_TYPE)) {
+ return 0;
+ }
+ return onion_handshakes_assigned[type];
+}
+
/** Log our onionskin statistics since the last time we were called. */
void
rep_hist_log_circuit_handshake_stats(time_t now)
diff --git a/src/feature/stats/rephist.h b/src/feature/stats/rephist.h
index 92c3d2a5a5..d08b8833cc 100644
--- a/src/feature/stats/rephist.h
+++ b/src/feature/stats/rephist.h
@@ -77,6 +77,9 @@ void rep_hist_note_circuit_handshake_requested(uint16_t type);
void rep_hist_note_circuit_handshake_assigned(uint16_t type);
void rep_hist_log_circuit_handshake_stats(time_t now);
+MOCK_DECL(int, rep_hist_get_circuit_handshake_requested, (uint16_t type));
+MOCK_DECL(int, rep_hist_get_circuit_handshake_assigned, (uint16_t type));
+
void rep_hist_hs_stats_init(time_t now);
void rep_hist_hs_stats_term(void);
time_t rep_hist_hs_stats_write(time_t now);
diff --git a/src/lib/net/address.c b/src/lib/net/address.c
index 6d46f9b955..b51fc7cb13 100644
--- a/src/lib/net/address.c
+++ b/src/lib/net/address.c
@@ -1217,20 +1217,28 @@ fmt_addr32(uint32_t addr)
return buf;
}
-/** Return a string representing the family of <b>addr</b>.
+/** Like fmt_addrport(), but takes <b>addr</b> as a host-order IPv4
+ * addresses. Also not thread-safe, also clobbers its return buffer on
+ * repeated calls. */
+const char *
+fmt_addr32_port(uint32_t addr, uint16_t port)
+{
+ static char buf[INET_NTOA_BUF_LEN + 6];
+ snprintf(buf, sizeof(buf), "%s:%u", fmt_addr32(addr), port);
+ return buf;
+}
+
+/** Return a string representing <b>family</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)
+fmt_af_family(sa_family_t family)
{
static int default_bug_once = 0;
- IF_BUG_ONCE(!addr)
- return "NULL pointer";
-
- switch (tor_addr_family(addr)) {
+ switch (family) {
case AF_INET6:
return "IPv6";
case AF_INET:
@@ -1242,7 +1250,7 @@ fmt_addr_family(const tor_addr_t *addr)
default:
if (!default_bug_once) {
log_warn(LD_BUG, "Called with unknown address family %d",
- (int)tor_addr_family(addr));
+ (int)family);
default_bug_once = 1;
}
return "unknown";
@@ -1250,6 +1258,20 @@ fmt_addr_family(const tor_addr_t *addr)
//return "(unreachable code)";
}
+/** 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)
+{
+ IF_BUG_ONCE(!addr)
+ return "NULL pointer";
+
+ return fmt_af_family(tor_addr_family(addr));
+}
+
/** 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.
*
diff --git a/src/lib/net/address.h b/src/lib/net/address.h
index e5016ee4fe..6b18919f6d 100644
--- a/src/lib/net/address.h
+++ b/src/lib/net/address.h
@@ -95,6 +95,7 @@ static inline uint32_t tor_addr_to_ipv4n(const tor_addr_t *a);
static inline uint32_t tor_addr_to_ipv4h(const tor_addr_t *a);
static inline uint32_t tor_addr_to_mapped_ipv4h(const tor_addr_t *a);
static inline sa_family_t tor_addr_family(const tor_addr_t *a);
+static inline bool tor_addr_is_unspec(const tor_addr_t *a);
static inline const struct in_addr *tor_addr_to_in(const tor_addr_t *a);
static inline int tor_addr_eq_ipv4h(const tor_addr_t *a, uint32_t u);
@@ -188,6 +189,15 @@ tor_addr_family(const tor_addr_t *a)
return a->family;
}
+/**
+ * Return true if the address @a is in the UNSPEC family.
+ **/
+static inline bool
+tor_addr_is_unspec(const tor_addr_t *a)
+{
+ return a->family == AF_UNSPEC;
+}
+
/** Return an in_addr* equivalent to <b>a</b>, or NULL if <b>a</b> is not
* an IPv4 address. */
static inline const struct in_addr *
@@ -236,6 +246,8 @@ const char *fmt_addr_impl(const tor_addr_t *addr, int decorate);
const char *fmt_addrport(const tor_addr_t *addr, uint16_t port);
#define fmt_addrport_ap(ap) fmt_addrport(&(ap)->addr, (ap)->port)
const char *fmt_addr32(uint32_t addr);
+const char *fmt_addr32_port(uint32_t addr, uint16_t port);
+const char *fmt_af_family(sa_family_t family);
const char *fmt_addr_family(const tor_addr_t *addr);
MOCK_DECL(int,get_interface_address6,(int severity, sa_family_t family,
diff --git a/src/lib/tls/buffers_tls.c b/src/lib/tls/buffers_tls.c
index b92a14d6a1..1b99467d2b 100644
--- a/src/lib/tls/buffers_tls.c
+++ b/src/lib/tls/buffers_tls.c
@@ -59,6 +59,9 @@ read_to_chunk_tls(buf_t *buf, chunk_t *chunk, tor_tls_t *tls,
* Second, the TLS stream's events do not correspond directly to network
* events: sometimes, before a TLS stream can read, the network must be
* ready to write -- or vice versa.
+ *
+ * On success, return the number of bytes read. On error, a TOR_TLS_* negative
+ * code is returned (expect any of them except TOR_TLS_DONE).
*/
int
buf_read_from_tls(buf_t *buf, tor_tls_t *tls, size_t at_most)
@@ -92,8 +95,6 @@ buf_read_from_tls(buf_t *buf, tor_tls_t *tls, size_t at_most)
return r; /* Error */
tor_assert(total_read+r <= BUF_MAX_LEN);
total_read += r;
- if ((size_t)r < readlen) /* eof, block, or no more to read. */
- break;
}
return (int)total_read;
}
diff --git a/src/mainpage.md b/src/mainpage.md
index 2c4c494354..91ceb7dbf7 100644
--- a/src/mainpage.md
+++ b/src/mainpage.md
@@ -83,8 +83,9 @@ will be scheduled.
The codebase is divided into a few top-level subdirectories, each of
which contains several sub-modules.
- - `ext` -- Code maintained elsewhere that we include in the Tor
- source distribution.
+ - \refdir{ext} -- Code maintained elsewhere that we include in the Tor
+ source distribution. You should not edit this code if you can
+ avoid it: we try to keep it identical to the upstream versions.
- \refdir{lib} -- Lower-level utility code, not necessarily
tor-specific.
diff --git a/src/rust/protover/ffi.rs b/src/rust/protover/ffi.rs
index 14170d0353..2bf8d3a987 100644
--- a/src/rust/protover/ffi.rs
+++ b/src/rust/protover/ffi.rs
@@ -84,7 +84,7 @@ pub extern "C" fn protocol_list_supports_protocol(
version: uint32_t,
) -> c_int {
if c_protocol_list.is_null() {
- return 1;
+ return 0;
}
// Require an unsafe block to read the version from a C string. The pointer
@@ -93,7 +93,7 @@ pub extern "C" fn protocol_list_supports_protocol(
let protocol_list = match c_str.to_str() {
Ok(n) => n,
- Err(_) => return 1,
+ Err(_) => return 0,
};
let proto_entry: UnvalidatedProtoEntry = match protocol_list.parse() {
Ok(n) => n,
@@ -140,7 +140,7 @@ pub extern "C" fn protocol_list_supports_protocol_or_later(
version: uint32_t,
) -> c_int {
if c_protocol_list.is_null() {
- return 1;
+ return 0;
}
// Require an unsafe block to read the version from a C string. The pointer
@@ -149,7 +149,7 @@ pub extern "C" fn protocol_list_supports_protocol_or_later(
let protocol_list = match c_str.to_str() {
Ok(n) => n,
- Err(_) => return 1,
+ Err(_) => return 0,
};
let protocol = match translate_to_rust(c_protocol) {
@@ -159,7 +159,7 @@ pub extern "C" fn protocol_list_supports_protocol_or_later(
let proto_entry: UnvalidatedProtoEntry = match protocol_list.parse() {
Ok(n) => n,
- Err(_) => return 1,
+ Err(_) => return 0,
};
if proto_entry.supports_protocol_or_later(&protocol.into(), &version) {
diff --git a/src/rust/protover/protover.rs b/src/rust/protover/protover.rs
index 6d2ef33eec..076cd5301e 100644
--- a/src/rust/protover/protover.rs
+++ b/src/rust/protover/protover.rs
@@ -163,13 +163,13 @@ pub(crate) fn get_supported_protocols_cstr() -> &'static CStr {
DirCache=1-2 \
FlowCtrl=1 \
HSDir=1-2 \
- HSIntro=3-4 \
+ HSIntro=3-5 \
HSRend=1-2 \
Link=1-5 \
LinkAuth=3 \
Microdesc=1-2 \
Padding=2 \
- Relay=1-2"
+ Relay=1-3"
)
} else {
cstr!(
@@ -178,13 +178,13 @@ pub(crate) fn get_supported_protocols_cstr() -> &'static CStr {
DirCache=1-2 \
FlowCtrl=1 \
HSDir=1-2 \
- HSIntro=3-4 \
+ HSIntro=3-5 \
HSRend=1-2 \
Link=1-5 \
LinkAuth=1,3 \
Microdesc=1-2 \
Padding=2 \
- Relay=1-2"
+ Relay=1-3"
)
}
}
diff --git a/src/test/conf_examples/dirauth_3/error_no_dirauth b/src/test/conf_examples/dirauth_3/error_no_dirauth
new file mode 100644
index 0000000000..e6bd5db69c
--- /dev/null
+++ b/src/test/conf_examples/dirauth_3/error_no_dirauth
@@ -0,0 +1 @@
+This tor was built with dirauth mode disabled.
diff --git a/src/test/conf_examples/dirauth_3/error_no_dirauth_relay b/src/test/conf_examples/dirauth_3/error_no_dirauth_relay
new file mode 100644
index 0000000000..e6bd5db69c
--- /dev/null
+++ b/src/test/conf_examples/dirauth_3/error_no_dirauth_relay
@@ -0,0 +1 @@
+This tor was built with dirauth mode disabled.
diff --git a/src/test/conf_examples/dirauth_3/expected b/src/test/conf_examples/dirauth_3/expected
new file mode 100644
index 0000000000..23eac3a5f8
--- /dev/null
+++ b/src/test/conf_examples/dirauth_3/expected
@@ -0,0 +1,9 @@
+Address 192.0.2.1
+AuthoritativeDirectory 1
+ContactInfo tor_parse_test@example.net
+DirPort 192.0.2.1:2
+DownloadExtraInfo 1
+Nickname Unnamed
+ORPort 192.0.2.1:1
+ORPort [2001:DB8::1]:3
+V3AuthoritativeDirectory 1
diff --git a/src/test/conf_examples/dirauth_3/expected_log b/src/test/conf_examples/dirauth_3/expected_log
new file mode 100644
index 0000000000..3127c9b125
--- /dev/null
+++ b/src/test/conf_examples/dirauth_3/expected_log
@@ -0,0 +1 @@
+Read configuration file .*dirauth_3[./]*torrc
diff --git a/src/test/conf_examples/dirauth_3/torrc b/src/test/conf_examples/dirauth_3/torrc
new file mode 100644
index 0000000000..9663a9bc0c
--- /dev/null
+++ b/src/test/conf_examples/dirauth_3/torrc
@@ -0,0 +1,13 @@
+# Authority with IPv6 address
+
+AuthoritativeDirectory 1
+V3AuthoritativeDirectory 1
+
+ContactInfo tor_parse_test@example.net
+
+Address 192.0.2.1
+
+ORPort 192.0.2.1:1
+DirPort 192.0.2.1:2
+
+ORPort [2001:DB8::1]:3
diff --git a/src/test/rend_test_helpers.c b/src/test/rend_test_helpers.c
index 61bacb4d2e..8e40167aeb 100644
--- a/src/test/rend_test_helpers.c
+++ b/src/test/rend_test_helpers.c
@@ -2,6 +2,7 @@
/* See LICENSE for licensing information */
#include "core/or/or.h"
+#include "core/or/extendinfo.h"
#include "lib/crypt_ops/crypto_rand.h"
#include "test/test.h"
#include "feature/rend/rendcommon.h"
@@ -58,7 +59,8 @@ create_descriptor(rend_service_descriptor_t **generated, char **service_id,
for (i = 0; i < intro_points; i++) {
rend_intro_point_t *intro = tor_malloc_zero(sizeof(rend_intro_point_t));
crypto_pk_t *okey = pk_generate(2 + i);
- intro->extend_info = tor_malloc_zero(sizeof(extend_info_t));
+ intro->extend_info =
+ extend_info_new(NULL, NULL, NULL, NULL, NULL, NULL, 0);
intro->extend_info->onion_key = okey;
crypto_pk_get_digest(intro->extend_info->onion_key,
intro->extend_info->identity_digest);
@@ -66,8 +68,12 @@ create_descriptor(rend_service_descriptor_t **generated, char **service_id,
base16_encode(intro->extend_info->nickname + 1,
sizeof(intro->extend_info->nickname) - 1,
intro->extend_info->identity_digest, DIGEST_LEN);
- tor_addr_from_ipv4h(&intro->extend_info->addr, crypto_rand_int(65536));
- intro->extend_info->port = 1 + crypto_rand_int(65535);
+ tor_addr_t addr;
+ uint16_t port;
+ /* Does not cover all IP addresses. */
+ tor_addr_from_ipv4h(&addr, crypto_rand_int(65536) + 1);
+ port = 1 + crypto_rand_int(65535);
+ extend_info_add_orport(intro->extend_info, &addr, port);
intro->intro_key = crypto_pk_dup_key(pk2);
smartlist_add((*generated)->intro_nodes, intro);
}
@@ -91,4 +97,3 @@ mock_rend_data(const char *onion_address)
DIGEST_LEN));
return rend_query;
}
-
diff --git a/src/test/test-memwipe.c b/src/test/test-memwipe.c
index 4faf7bc5a1..5e4cc7678e 100644
--- a/src/test/test-memwipe.c
+++ b/src/test/test-memwipe.c
@@ -30,8 +30,8 @@ const char *s = NULL;
#define BUF_LEN 2048
#define FILL_BUFFER_IMPL() \
+ do { \
unsigned int i; \
- unsigned sum = 0; \
\
/* Fill up a 1k buffer with a recognizable pattern. */ \
for (i = 0; i < BUF_LEN; i += strlen(s)) { \
@@ -42,7 +42,8 @@ const char *s = NULL;
/* optimized away. */ \
for (i = 0; i < BUF_LEN; ++i) { \
sum += (unsigned char)buf[i]; \
- }
+ } \
+ } while (0)
#ifdef OpenBSD
/* Disable some of OpenBSD's malloc protections for this test. This helps
@@ -55,7 +56,8 @@ static unsigned
fill_a_buffer_memset(void)
{
char buf[BUF_LEN];
- FILL_BUFFER_IMPL()
+ unsigned sum = 0;
+ FILL_BUFFER_IMPL();
memset(buf, 0, sizeof(buf));
return sum;
}
@@ -64,7 +66,8 @@ static unsigned
fill_a_buffer_memwipe(void)
{
char buf[BUF_LEN];
- FILL_BUFFER_IMPL()
+ unsigned sum = 0;
+ FILL_BUFFER_IMPL();
memwipe(buf, 0, sizeof(buf));
return sum;
}
@@ -73,7 +76,8 @@ static unsigned
fill_a_buffer_nothing(void)
{
char buf[BUF_LEN];
- FILL_BUFFER_IMPL()
+ unsigned sum = 0;
+ FILL_BUFFER_IMPL();
return sum;
}
@@ -116,7 +120,8 @@ static unsigned
fill_heap_buffer_memset(void)
{
char *buf = heap_buf = raw_malloc(BUF_LEN);
- FILL_BUFFER_IMPL()
+ unsigned sum = 0;
+ FILL_BUFFER_IMPL();
memset(buf, 0, BUF_LEN);
raw_free(buf);
return sum;
@@ -126,7 +131,8 @@ static unsigned
fill_heap_buffer_memwipe(void)
{
char *buf = heap_buf = raw_malloc(BUF_LEN);
- FILL_BUFFER_IMPL()
+ unsigned sum = 0;
+ FILL_BUFFER_IMPL();
memwipe(buf, 0, BUF_LEN);
raw_free(buf);
return sum;
@@ -136,7 +142,8 @@ static unsigned
fill_heap_buffer_nothing(void)
{
char *buf = heap_buf = raw_malloc(BUF_LEN);
- FILL_BUFFER_IMPL()
+ unsigned sum = 0;
+ FILL_BUFFER_IMPL();
raw_free(buf);
return sum;
}
diff --git a/src/test/test.c b/src/test/test.c
index 4b6082ce4f..2961669c46 100644
--- a/src/test/test.c
+++ b/src/test/test.c
@@ -1,5 +1,5 @@
/* Copyright (c) 2001-2004, Roger Dingledine.
- * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
+->a * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
* Copyright (c) 2007-2020, The Tor Project, Inc. */
/* See LICENSE for licensing information */
@@ -44,6 +44,7 @@
#include "lib/compress/compress.h"
#include "app/config/config.h"
#include "core/or/connection_edge.h"
+#include "core/or/extendinfo.h"
#include "feature/rend/rendcommon.h"
#include "feature/rend/rendcache.h"
#include "feature/rend/rendparse.h"
@@ -564,7 +565,8 @@ test_rend_fns(void *arg)
for (i = 0; i < 3; i++) {
rend_intro_point_t *intro = tor_malloc_zero(sizeof(rend_intro_point_t));
crypto_pk_t *okey = pk_generate(2 + i);
- intro->extend_info = tor_malloc_zero(sizeof(extend_info_t));
+ intro->extend_info =
+ extend_info_new(NULL, NULL, NULL, NULL, NULL, NULL, 0);
intro->extend_info->onion_key = okey;
crypto_pk_get_digest(intro->extend_info->onion_key,
intro->extend_info->identity_digest);
@@ -573,9 +575,12 @@ test_rend_fns(void *arg)
base16_encode(intro->extend_info->nickname + 1,
sizeof(intro->extend_info->nickname) - 1,
intro->extend_info->identity_digest, DIGEST_LEN);
+ tor_addr_t addr;
+ uint16_t port;
/* Does not cover all IP addresses. */
- tor_addr_from_ipv4h(&intro->extend_info->addr, crypto_rand_int(65536));
- intro->extend_info->port = 1 + crypto_rand_int(65535);
+ tor_addr_from_ipv4h(&addr, crypto_rand_int(65536) + 1);
+ port = 1 + crypto_rand_int(65535);
+ extend_info_add_orport(intro->extend_info, &addr, port);
intro->intro_key = crypto_pk_dup_key(pk2);
smartlist_add(generated->intro_nodes, intro);
}
@@ -613,8 +618,12 @@ test_rend_fns(void *arg)
tt_mem_op(gen_info->identity_digest,OP_EQ, par_info->identity_digest,
DIGEST_LEN);
tt_str_op(gen_info->nickname,OP_EQ, par_info->nickname);
- tt_assert(tor_addr_eq(&gen_info->addr, &par_info->addr));
- tt_int_op(gen_info->port,OP_EQ, par_info->port);
+ const tor_addr_port_t *a1, *a2;
+ a1 = extend_info_get_orport(gen_info, AF_INET);
+ a2 = extend_info_get_orport(par_info, AF_INET);
+ tt_assert(a1 && a2);
+ tt_assert(tor_addr_eq(&a1->addr, &a2->addr));
+ tt_int_op(a2->port,OP_EQ, a2->port);
}
rend_service_descriptor_free(parsed);
diff --git a/src/test/test_address.c b/src/test/test_address.c
index 4cedbda347..8a46630088 100644
--- a/src/test/test_address.c
+++ b/src/test/test_address.c
@@ -1152,23 +1152,23 @@ test_address_tor_addr_in_same_network_family(void *ignored)
tor_addr_parse(&a, "8.8.8.8");
tor_addr_parse(&b, "8.8.4.4");
- tt_int_op(addrs_in_same_network_family(&a, &b), OP_EQ, 1);
+ tt_int_op(router_addrs_in_same_network(&a, &b), OP_EQ, 1);
tor_addr_parse(&a, "8.8.8.8");
tor_addr_parse(&b, "1.1.1.1");
- tt_int_op(addrs_in_same_network_family(&a, &b), OP_EQ, 0);
+ tt_int_op(router_addrs_in_same_network(&a, &b), OP_EQ, 0);
tor_addr_parse(&a, "8.8.8.8");
tor_addr_parse(&b, "2001:4860:4860::8844");
- tt_int_op(addrs_in_same_network_family(&a, &b), OP_EQ, 0);
+ tt_int_op(router_addrs_in_same_network(&a, &b), OP_EQ, 0);
tor_addr_parse(&a, "2001:4860:4860::8888");
tor_addr_parse(&b, "2001:4860:4860::8844");
- tt_int_op(addrs_in_same_network_family(&a, &b), OP_EQ, 1);
+ tt_int_op(router_addrs_in_same_network(&a, &b), OP_EQ, 1);
tor_addr_parse(&a, "2001:4860:4860::8888");
tor_addr_parse(&b, "2001:470:20::2");
- tt_int_op(addrs_in_same_network_family(&a, &b), OP_EQ, 0);
+ tt_int_op(router_addrs_in_same_network(&a, &b), OP_EQ, 0);
done:
return;
diff --git a/src/test/test_channeltls.c b/src/test/test_channeltls.c
index f4f5cb447e..f682c57acf 100644
--- a/src/test/test_channeltls.c
+++ b/src/test/test_channeltls.c
@@ -38,13 +38,13 @@ static or_connection_t * tlschan_connection_or_connect_mock(
const char *digest,
const ed25519_public_key_t *ed_id,
channel_tls_t *tlschan);
-static int tlschan_is_local_addr_mock(const tor_addr_t *addr);
+static bool tlschan_resolved_addr_is_local_mock(const tor_addr_t *addr);
/* Fake close method */
static void tlschan_fake_close_method(channel_t *chan);
/* Flags controlling behavior of channeltls unit test mocks */
-static int tlschan_local = 0;
+static bool tlschan_local = false;
static const buf_t * tlschan_buf_datalen_mock_target = NULL;
static size_t tlschan_buf_datalen_mock_size = 0;
@@ -67,9 +67,9 @@ test_channeltls_create(void *arg)
test_addr.addr.in_addr.s_addr = htonl(0x01020304);
/* For this test we always want the address to be treated as non-local */
- tlschan_local = 0;
- /* Install is_local_addr() mock */
- MOCK(is_local_addr, tlschan_is_local_addr_mock);
+ tlschan_local = false;
+ /* Install is_local_to_resolve_addr() mock */
+ MOCK(is_local_to_resolve_addr, tlschan_resolved_addr_is_local_mock);
/* Install mock for connection_or_connect() */
MOCK(connection_or_connect, tlschan_connection_or_connect_mock);
@@ -92,7 +92,7 @@ test_channeltls_create(void *arg)
}
UNMOCK(connection_or_connect);
- UNMOCK(is_local_addr);
+ UNMOCK(is_local_to_resolve_addr);
return;
}
@@ -116,9 +116,9 @@ test_channeltls_num_bytes_queued(void *arg)
test_addr.addr.in_addr.s_addr = htonl(0x01020304);
/* For this test we always want the address to be treated as non-local */
- tlschan_local = 0;
- /* Install is_local_addr() mock */
- MOCK(is_local_addr, tlschan_is_local_addr_mock);
+ tlschan_local = false;
+ /* Install is_local_to_resolve_addr() mock */
+ MOCK(is_local_to_resolve_addr, tlschan_resolved_addr_is_local_mock);
/* Install mock for connection_or_connect() */
MOCK(connection_or_connect, tlschan_connection_or_connect_mock);
@@ -178,7 +178,7 @@ test_channeltls_num_bytes_queued(void *arg)
}
UNMOCK(connection_or_connect);
- UNMOCK(is_local_addr);
+ UNMOCK(is_local_to_resolve_addr);
return;
}
@@ -201,9 +201,9 @@ test_channeltls_overhead_estimate(void *arg)
test_addr.addr.in_addr.s_addr = htonl(0x01020304);
/* For this test we always want the address to be treated as non-local */
- tlschan_local = 0;
- /* Install is_local_addr() mock */
- MOCK(is_local_addr, tlschan_is_local_addr_mock);
+ tlschan_local = false;
+ /* Install is_local_to_resolve_addr() mock */
+ MOCK(is_local_to_resolve_addr, tlschan_resolved_addr_is_local_mock);
/* Install mock for connection_or_connect() */
MOCK(connection_or_connect, tlschan_connection_or_connect_mock);
@@ -252,7 +252,7 @@ test_channeltls_overhead_estimate(void *arg)
}
UNMOCK(connection_or_connect);
- UNMOCK(is_local_addr);
+ UNMOCK(is_local_to_resolve_addr);
return;
}
@@ -321,8 +321,8 @@ tlschan_fake_close_method(channel_t *chan)
return;
}
-static int
-tlschan_is_local_addr_mock(const tor_addr_t *addr)
+static bool
+tlschan_resolved_addr_is_local_mock(const tor_addr_t *addr)
{
tt_ptr_op(addr, OP_NE, NULL);
diff --git a/src/test/test_circuitbuild.c b/src/test/test_circuitbuild.c
index 03fd176ead..8f0e8b54e8 100644
--- a/src/test/test_circuitbuild.c
+++ b/src/test/test_circuitbuild.c
@@ -19,6 +19,7 @@
#include "core/or/channel.h"
#include "core/or/circuitbuild.h"
#include "core/or/circuitlist.h"
+#include "core/or/circuituse.h"
#include "core/or/onion.h"
#include "core/or/cell_st.h"
@@ -29,11 +30,13 @@
#include "feature/client/entrynodes.h"
#include "feature/nodelist/nodelist.h"
+#include "feature/nodelist/node_select.h"
#include "feature/relay/circuitbuild_relay.h"
#include "feature/relay/router.h"
#include "feature/relay/routermode.h"
#include "feature/nodelist/node_st.h"
+#include "feature/nodelist/routerinfo_st.h"
/* Dummy nodes smartlist for testing */
static smartlist_t dummy_nodes;
@@ -279,10 +282,10 @@ mock_node_get_by_id(const char *identity_digest)
return mocked_node;
}
-static int mocked_supports_ed25519_link_authentication = 0;
-static int
+static bool mocked_supports_ed25519_link_authentication = 0;
+static bool
mock_node_supports_ed25519_link_authentication(const node_t *node,
- int compatible_with_us)
+ bool compatible_with_us)
{
(void)node;
(void)compatible_with_us;
@@ -821,6 +824,77 @@ test_circuit_extend_lspec_valid(void *arg)
tor_free(p_chan);
}
+#define NODE_SET_IPV4(node, ipv4_addr, ipv4_port) { \
+ tor_addr_t addr; \
+ tor_addr_parse(&addr, ipv4_addr); \
+ node->ri->addr = tor_addr_to_ipv4h(&addr); \
+ node->ri->or_port = ipv4_port; \
+ }
+
+#define NODE_CLEAR_IPV4(node) { \
+ node->ri->addr = 0; \
+ node->ri->or_port = 0; \
+ }
+
+#define NODE_SET_IPV6(node, ipv6_addr_str, ipv6_port) { \
+ tor_addr_parse(&node->ri->ipv6_addr, ipv6_addr_str); \
+ node->ri->ipv6_orport = ipv6_port; \
+ }
+
+/* Test the different cases in circuit_extend_add_ed25519_helper(). */
+static void
+test_circuit_extend_add_ip(void *arg)
+{
+ (void) arg;
+ tor_addr_t ipv4_tmp;
+ extend_cell_t *ec = tor_malloc_zero(sizeof(extend_cell_t));
+ extend_cell_t *old_ec = tor_malloc_zero(sizeof(extend_cell_t));
+
+ node_t *fake_node = tor_malloc_zero(sizeof(node_t));
+ routerinfo_t *ri = tor_malloc_zero(sizeof(routerinfo_t));
+
+ MOCK(node_get_by_id, mock_node_get_by_id);
+
+ /* Set up the fake variables for the IPv4 test */
+ fake_node->ri = ri;
+ mocked_node = fake_node;
+ memset(ec->node_id, 0xAA, sizeof(ec->node_id));
+ memcpy(old_ec, ec, sizeof(extend_cell_t));
+ NODE_SET_IPV4(fake_node, PUBLIC_IPV4, VALID_PORT);
+
+ /* Do the IPv4 test */
+ tt_int_op(circuit_extend_add_ipv4_helper(ec), OP_EQ, 0);
+ tor_addr_from_ipv4h(&ipv4_tmp, fake_node->ri->addr);
+ /* The IPv4 should match */
+ tt_int_op(tor_addr_compare(&ec->orport_ipv4.addr, &ipv4_tmp, CMP_SEMANTIC),
+ OP_EQ, 0);
+ tt_int_op(ec->orport_ipv4.port, OP_EQ, VALID_PORT);
+
+ /* Set up the fake variables for the IPv6 test */
+ memcpy(ec, old_ec, sizeof(extend_cell_t));
+ NODE_CLEAR_IPV4(fake_node);
+ NODE_SET_IPV6(fake_node, PUBLIC_IPV6, VALID_PORT);
+
+ /* Do the IPv6 test */
+ tt_int_op(circuit_extend_add_ipv6_helper(ec), OP_EQ, 0);
+ /* The IPv6 should match */
+ tt_int_op(tor_addr_compare(&ec->orport_ipv6.addr, &fake_node->ri->ipv6_addr,
+ CMP_SEMANTIC), OP_EQ, 0);
+ tt_int_op(ec->orport_ipv6.port, OP_EQ, VALID_PORT);
+
+ /* Cleanup */
+ mocked_node = NULL;
+
+ done:
+ UNMOCK(node_get_by_id);
+
+ tor_free(ec);
+ tor_free(old_ec);
+
+ tor_free(ri);
+ tor_free(fake_node);
+}
+
static bool can_extend_over_ipv6_result = false;
static int mock_router_can_extend_over_ipv6_calls = 0;
static bool
@@ -927,15 +1001,9 @@ mock_circuit_mark_for_close_(circuit_t *circ, int reason,
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)
+mock_channel_connect_for_circuit(const extend_info_t *ei)
{
- (void)addr;
- (void)port;
- (void)id_digest;
- (void)ed_id;
+ (void)ei;
mock_channel_connect_calls++;
return mock_channel_connect_nchan;
}
@@ -1176,6 +1244,8 @@ mock_channel_get_canonical_remote_descr(channel_t *chan)
return "mock_channel_get_canonical_remote_descr()";
}
+/* Should mock_circuit_deliver_create_cell() expect a direct connection? */
+static bool mock_circuit_deliver_create_cell_expect_direct = false;
static int mock_circuit_deliver_create_cell_calls = 0;
static int mock_circuit_deliver_create_cell_result = 0;
static int
@@ -1188,10 +1258,13 @@ mock_circuit_deliver_create_cell(circuit_t *circ,
/* 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 expect n_chan for relayed cells. But should we also expect it for
+ * direct connections? */
+ if (!mock_circuit_deliver_create_cell_expect_direct)
+ 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);
+ tt_int_op(relayed, OP_EQ, !mock_circuit_deliver_create_cell_expect_direct);
mock_circuit_deliver_create_cell_calls++;
return mock_circuit_deliver_create_cell_result;
@@ -1352,6 +1425,7 @@ test_circuit_extend(void *arg)
/* Mock circuit_deliver_create_cell(), so it doesn't crash */
mock_circuit_deliver_create_cell_calls = 0;
+ mock_circuit_deliver_create_cell_expect_direct = false;
MOCK(circuit_deliver_create_cell, mock_circuit_deliver_create_cell);
/* Test circuit established, re-using channel, successful delivery */
@@ -1516,6 +1590,355 @@ test_onionskin_answer(void *arg)
tor_free(or_circ);
}
+/* Test the different cases in origin_circuit_init(). */
+static void
+test_origin_circuit_init(void *arg)
+{
+ (void)arg;
+ origin_circuit_t *origin_circ = NULL;
+
+ /* Init with 0 purpose and 0 flags */
+ origin_circ = origin_circuit_init(0, 0);
+ tt_int_op(origin_circ->base_.purpose, OP_EQ, 0);
+ tt_int_op(origin_circ->base_.state, OP_EQ, CIRCUIT_STATE_CHAN_WAIT);
+ tt_ptr_op(origin_circ->build_state, OP_NE, NULL);
+ tt_int_op(origin_circ->build_state->is_internal, OP_EQ, 0);
+ tt_int_op(origin_circ->build_state->is_ipv6_selftest, OP_EQ, 0);
+ tt_int_op(origin_circ->build_state->need_capacity, OP_EQ, 0);
+ tt_int_op(origin_circ->build_state->need_uptime, OP_EQ, 0);
+ tt_int_op(origin_circ->build_state->onehop_tunnel, OP_EQ, 0);
+ /* The circuits are automatically freed by the circuitlist. */
+
+ /* Init with a purpose */
+ origin_circ = origin_circuit_init(CIRCUIT_PURPOSE_C_GENERAL, 0);
+ tt_int_op(origin_circ->base_.purpose, OP_EQ, CIRCUIT_PURPOSE_C_GENERAL);
+
+ /* Init with each flag */
+ origin_circ = origin_circuit_init(0, CIRCLAUNCH_IS_INTERNAL);
+ tt_ptr_op(origin_circ->build_state, OP_NE, NULL);
+ tt_int_op(origin_circ->build_state->is_internal, OP_EQ, 1);
+ tt_int_op(origin_circ->build_state->is_ipv6_selftest, OP_EQ, 0);
+ tt_int_op(origin_circ->build_state->need_capacity, OP_EQ, 0);
+ tt_int_op(origin_circ->build_state->need_uptime, OP_EQ, 0);
+ tt_int_op(origin_circ->build_state->onehop_tunnel, OP_EQ, 0);
+
+ origin_circ = origin_circuit_init(0, CIRCLAUNCH_IS_IPV6_SELFTEST);
+ tt_ptr_op(origin_circ->build_state, OP_NE, NULL);
+ tt_int_op(origin_circ->build_state->is_internal, OP_EQ, 0);
+ tt_int_op(origin_circ->build_state->is_ipv6_selftest, OP_EQ, 1);
+ tt_int_op(origin_circ->build_state->need_capacity, OP_EQ, 0);
+ tt_int_op(origin_circ->build_state->need_uptime, OP_EQ, 0);
+ tt_int_op(origin_circ->build_state->onehop_tunnel, OP_EQ, 0);
+
+ origin_circ = origin_circuit_init(0, CIRCLAUNCH_NEED_CAPACITY);
+ tt_ptr_op(origin_circ->build_state, OP_NE, NULL);
+ tt_int_op(origin_circ->build_state->is_internal, OP_EQ, 0);
+ tt_int_op(origin_circ->build_state->is_ipv6_selftest, OP_EQ, 0);
+ tt_int_op(origin_circ->build_state->need_capacity, OP_EQ, 1);
+ tt_int_op(origin_circ->build_state->need_uptime, OP_EQ, 0);
+ tt_int_op(origin_circ->build_state->onehop_tunnel, OP_EQ, 0);
+
+ origin_circ = origin_circuit_init(0, CIRCLAUNCH_NEED_UPTIME);
+ tt_ptr_op(origin_circ->build_state, OP_NE, NULL);
+ tt_int_op(origin_circ->build_state->is_internal, OP_EQ, 0);
+ tt_int_op(origin_circ->build_state->is_ipv6_selftest, OP_EQ, 0);
+ tt_int_op(origin_circ->build_state->need_capacity, OP_EQ, 0);
+ tt_int_op(origin_circ->build_state->need_uptime, OP_EQ, 1);
+ tt_int_op(origin_circ->build_state->onehop_tunnel, OP_EQ, 0);
+
+ origin_circ = origin_circuit_init(0, CIRCLAUNCH_ONEHOP_TUNNEL);
+ tt_ptr_op(origin_circ->build_state, OP_NE, NULL);
+ tt_int_op(origin_circ->build_state->is_internal, OP_EQ, 0);
+ tt_int_op(origin_circ->build_state->is_ipv6_selftest, OP_EQ, 0);
+ tt_int_op(origin_circ->build_state->need_capacity, OP_EQ, 0);
+ tt_int_op(origin_circ->build_state->need_uptime, OP_EQ, 0);
+ tt_int_op(origin_circ->build_state->onehop_tunnel, OP_EQ, 1);
+
+ done:
+ /* The circuits are automatically freed by the circuitlist. */
+ ;
+}
+
+/* Test the different cases in circuit_send_next_onion_skin(). */
+static void
+test_circuit_send_next_onion_skin(void *arg)
+{
+ (void)arg;
+ origin_circuit_t *origin_circ = NULL;
+ struct timeval circ_start_time;
+ memset(&circ_start_time, 0, sizeof(circ_start_time));
+
+ extend_info_t fakehop;
+ memset(&fakehop, 0, sizeof(fakehop));
+ extend_info_t *single_fakehop = &fakehop;
+ extend_info_t *multi_fakehop[DEFAULT_ROUTE_LEN] = {&fakehop,
+ &fakehop,
+ &fakehop};
+
+ extend_info_t ipv6_hop;
+ memset(&ipv6_hop, 0, sizeof(ipv6_hop));
+ tor_addr_parse(&ipv6_hop.orports[0].addr, "1::2");
+ extend_info_t *multi_ipv6_hop[DEFAULT_ROUTE_LEN] = {&ipv6_hop,
+ &ipv6_hop,
+ &ipv6_hop};
+
+ extend_info_t ipv4_hop;
+ memset(&ipv4_hop, 0, sizeof(ipv4_hop));
+ tor_addr_from_ipv4h(&ipv4_hop.orports[0].addr, 0x20304050);
+ extend_info_t *multi_ipv4_hop[DEFAULT_ROUTE_LEN] = {&ipv4_hop,
+ &ipv4_hop,
+ &ipv4_hop};
+
+ mock_circuit_deliver_create_cell_expect_direct = false;
+ MOCK(circuit_deliver_create_cell, mock_circuit_deliver_create_cell);
+ server = 0;
+ MOCK(server_mode, mock_server_mode);
+
+ /* Try a direct connection, and succeed on a client */
+ server = 0;
+ origin_circ = new_test_origin_circuit(false,
+ circ_start_time,
+ 1,
+ &single_fakehop);
+ tt_ptr_op(origin_circ, OP_NE, NULL);
+ /* Skip some of the multi-hop checks */
+ origin_circ->build_state->onehop_tunnel = 1;
+ /* This is a direct connection */
+ mock_circuit_deliver_create_cell_expect_direct = true;
+ tt_int_op(circuit_send_next_onion_skin(origin_circ), OP_EQ, 0);
+ /* The circuits are automatically freed by the circuitlist. */
+
+ /* Try a direct connection, and succeed on a server */
+ server = 1;
+ origin_circ = new_test_origin_circuit(false,
+ circ_start_time,
+ 1,
+ &single_fakehop);
+ tt_ptr_op(origin_circ, OP_NE, NULL);
+ origin_circ->build_state->onehop_tunnel = 1;
+ mock_circuit_deliver_create_cell_expect_direct = true;
+ tt_int_op(circuit_send_next_onion_skin(origin_circ), OP_EQ, 0);
+
+ /* Start capturing bugs */
+ setup_full_capture_of_logs(LOG_WARN);
+ tor_capture_bugs_(1);
+
+ /* Try an extend, but fail the client valid address family check */
+ server = 0;
+ origin_circ = new_test_origin_circuit(true,
+ circ_start_time,
+ ARRAY_LENGTH(multi_fakehop),
+ multi_fakehop);
+ tt_ptr_op(origin_circ, OP_NE, NULL);
+ /* Fix the state */
+ origin_circ->base_.state = 0;
+ /* This is an indirect connection */
+ mock_circuit_deliver_create_cell_expect_direct = false;
+ /* Fail because the address family is invalid */
+ tt_int_op(circuit_send_next_onion_skin(origin_circ), OP_EQ,
+ -END_CIRC_REASON_INTERNAL);
+ expect_log_msg("No supported address family found in extend_info.\n");
+ mock_clean_saved_logs();
+
+ /* Try an extend, but fail the server valid address check */
+ server = 1;
+ origin_circ = new_test_origin_circuit(true,
+ circ_start_time,
+ ARRAY_LENGTH(multi_fakehop),
+ multi_fakehop);
+ tt_ptr_op(origin_circ, OP_NE, NULL);
+ origin_circ->base_.state = 0;
+ mock_circuit_deliver_create_cell_expect_direct = false;
+ tt_int_op(circuit_send_next_onion_skin(origin_circ), OP_EQ,
+ -END_CIRC_REASON_INTERNAL);
+ expect_log_msg("No supported address family found in extend_info.\n");
+ mock_clean_saved_logs();
+
+ /* Try an extend, but fail in the client code, with an IPv6 address */
+ server = 0;
+ origin_circ = new_test_origin_circuit(true,
+ circ_start_time,
+ ARRAY_LENGTH(multi_ipv6_hop),
+ multi_ipv6_hop);
+ tt_ptr_op(origin_circ, OP_NE, NULL);
+ origin_circ->base_.state = 0;
+ mock_circuit_deliver_create_cell_expect_direct = false;
+ tt_int_op(circuit_send_next_onion_skin(origin_circ), OP_EQ,
+ -END_CIRC_REASON_INTERNAL);
+ expect_log_msg("No supported address family found in extend_info.\n");
+ mock_clean_saved_logs();
+
+ /* Stop capturing bugs, but keep capturing logs */
+ tor_end_capture_bugs_();
+
+ /* Try an extend, pass the client IPv4 check, but fail later */
+ server = 0;
+ origin_circ = new_test_origin_circuit(true,
+ circ_start_time,
+ ARRAY_LENGTH(multi_ipv4_hop),
+ multi_ipv4_hop);
+ tt_ptr_op(origin_circ, OP_NE, NULL);
+ origin_circ->base_.state = 0;
+ mock_circuit_deliver_create_cell_expect_direct = false;
+ /* Fail because the circuit data is invalid */
+ tt_int_op(circuit_send_next_onion_skin(origin_circ), OP_EQ,
+ -END_CIRC_REASON_INTERNAL);
+ expect_log_msg("onion_skin_create failed.\n");
+ mock_clean_saved_logs();
+
+ /* Try an extend, pass the server IPv4 check, but fail later */
+ server = 1;
+ origin_circ = new_test_origin_circuit(true,
+ circ_start_time,
+ ARRAY_LENGTH(multi_ipv4_hop),
+ multi_ipv4_hop);
+ tt_ptr_op(origin_circ, OP_NE, NULL);
+ origin_circ->base_.state = 0;
+ mock_circuit_deliver_create_cell_expect_direct = false;
+ tt_int_op(circuit_send_next_onion_skin(origin_circ), OP_EQ,
+ -END_CIRC_REASON_INTERNAL);
+ expect_log_msg("onion_skin_create failed.\n");
+ mock_clean_saved_logs();
+
+ /* Try an extend, pass the server IPv6 check, but fail later */
+ server = 1;
+ origin_circ = new_test_origin_circuit(true,
+ circ_start_time,
+ ARRAY_LENGTH(multi_ipv6_hop),
+ multi_ipv6_hop);
+ tt_ptr_op(origin_circ, OP_NE, NULL);
+ origin_circ->base_.state = 0;
+ mock_circuit_deliver_create_cell_expect_direct = false;
+ tt_int_op(circuit_send_next_onion_skin(origin_circ), OP_EQ,
+ -END_CIRC_REASON_INTERNAL);
+ expect_log_msg("onion_skin_create failed.\n");
+ mock_clean_saved_logs();
+
+ /* Things we're not testing right now:
+ * - the addresses in the extend cell inside
+ * circuit_send_intermediate_onion_skin() matches the address in the
+ * supplied extend_info.
+ * - valid circuit data.
+ * - actually extending the circuit to each hop. */
+
+ done:
+ tor_end_capture_bugs_();
+ mock_clean_saved_logs();
+ teardown_capture_of_logs();
+
+ UNMOCK(circuit_deliver_create_cell);
+ UNMOCK(server_mode);
+ server = 0;
+
+ /* The circuits are automatically freed by the circuitlist. */
+}
+
+/* Test the different cases in cpath_build_state_to_crn_flags(). */
+static void
+test_cpath_build_state_to_crn_flags(void *arg)
+{
+ (void)arg;
+
+ cpath_build_state_t state;
+ memset(&state, 0, sizeof(state));
+
+ tt_int_op(cpath_build_state_to_crn_flags(&state), OP_EQ,
+ 0);
+
+ memset(&state, 0, sizeof(state));
+ state.need_uptime = 1;
+ tt_int_op(cpath_build_state_to_crn_flags(&state), OP_EQ,
+ CRN_NEED_UPTIME);
+
+ memset(&state, 0, sizeof(state));
+ state.need_capacity = 1;
+ tt_int_op(cpath_build_state_to_crn_flags(&state), OP_EQ,
+ CRN_NEED_CAPACITY);
+
+ memset(&state, 0, sizeof(state));
+ state.need_capacity = 1;
+ state.need_uptime = 1;
+ tt_int_op(cpath_build_state_to_crn_flags(&state), OP_EQ,
+ CRN_NEED_CAPACITY | CRN_NEED_UPTIME);
+
+ /* Check that no other flags are handled */
+ memset(&state, 0xff, sizeof(state));
+ tt_int_op(cpath_build_state_to_crn_flags(&state), OP_EQ,
+ CRN_NEED_CAPACITY | CRN_NEED_UPTIME);
+
+ done:
+ ;
+}
+
+/* Test the different cases in cpath_build_state_to_crn_ipv6_extend_flag(). */
+static void
+test_cpath_build_state_to_crn_ipv6_extend_flag(void *arg)
+{
+ (void)arg;
+
+ cpath_build_state_t state;
+
+ memset(&state, 0, sizeof(state));
+ state.desired_path_len = DEFAULT_ROUTE_LEN;
+ tt_int_op(cpath_build_state_to_crn_ipv6_extend_flag(&state, 0), OP_EQ,
+ 0);
+
+ /* Pass the state flag check, but not the length check */
+ memset(&state, 0, sizeof(state));
+ state.desired_path_len = DEFAULT_ROUTE_LEN;
+ state.is_ipv6_selftest = 1;
+ tt_int_op(cpath_build_state_to_crn_ipv6_extend_flag(&state, 0), OP_EQ,
+ 0);
+
+ /* Pass the length check, but not the state flag check */
+ memset(&state, 0, sizeof(state));
+ state.desired_path_len = DEFAULT_ROUTE_LEN;
+ tt_int_op(
+ cpath_build_state_to_crn_ipv6_extend_flag(&state,
+ DEFAULT_ROUTE_LEN - 2),
+ OP_EQ, 0);
+
+ /* Pass both checks */
+ memset(&state, 0, sizeof(state));
+ state.desired_path_len = DEFAULT_ROUTE_LEN;
+ state.is_ipv6_selftest = 1;
+ tt_int_op(
+ cpath_build_state_to_crn_ipv6_extend_flag(&state,
+ DEFAULT_ROUTE_LEN - 2),
+ OP_EQ, CRN_INITIATE_IPV6_EXTEND);
+
+ /* Check that no other flags are handled */
+ memset(&state, 0xff, sizeof(state));
+ state.desired_path_len = INT_MAX;
+ tt_int_op(cpath_build_state_to_crn_ipv6_extend_flag(&state, INT_MAX), OP_EQ,
+ 0);
+
+#ifndef ALL_BUGS_ARE_FATAL
+ /* Start capturing bugs */
+ setup_full_capture_of_logs(LOG_INFO);
+ tor_capture_bugs_(1);
+
+ /* Now test the single hop circuit case */
+#define SINGLE_HOP_ROUTE_LEN 1
+ memset(&state, 0, sizeof(state));
+ state.desired_path_len = SINGLE_HOP_ROUTE_LEN;
+ state.is_ipv6_selftest = 1;
+ tt_int_op(
+ cpath_build_state_to_crn_ipv6_extend_flag(&state,
+ SINGLE_HOP_ROUTE_LEN - 2),
+ 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_(state->desired_path_len < 2))");
+ mock_clean_saved_logs();
+#endif /* !defined(ALL_BUGS_ARE_FATAL) */
+
+ done:
+ tor_end_capture_bugs_();
+ mock_clean_saved_logs();
+ teardown_capture_of_logs();
+}
+
#define TEST(name, flags, setup, cleanup) \
{ #name, test_ ## name, flags, setup, cleanup }
@@ -1525,6 +1948,9 @@ test_onionskin_answer(void *arg)
#define TEST_CIRCUIT(name, flags) \
{ #name, test_circuit_ ## name, flags, NULL, NULL }
+#define TEST_CPATH(name, flags) \
+ { #name, test_cpath_ ## name, flags, NULL, NULL }
+
#ifndef COCCI
#define TEST_CIRCUIT_PASSTHROUGH(name, flags, arg) \
{ #name "/" arg, test_circuit_ ## name, flags, \
@@ -1542,13 +1968,21 @@ struct testcase_t circuitbuild_tests[] = {
TEST_CIRCUIT(extend_state_valid, TT_FORK),
TEST_CIRCUIT(extend_add_ed25519, TT_FORK),
TEST_CIRCUIT(extend_lspec_valid, TT_FORK),
+ TEST_CIRCUIT(extend_add_ip, 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),
+ TEST(origin_circuit_init, TT_FORK, NULL, NULL),
+ TEST_CIRCUIT(send_next_onion_skin, TT_FORK),
+ TEST_CPATH(build_state_to_crn_flags, 0),
+ TEST_CPATH(build_state_to_crn_ipv6_extend_flag, TT_FORK),
+
END_OF_TESTCASES
};
diff --git a/src/test/test_circuitpadding.c b/src/test/test_circuitpadding.c
index cfb24c032c..c3346e2e03 100644
--- a/src/test/test_circuitpadding.c
+++ b/src/test/test_circuitpadding.c
@@ -23,6 +23,7 @@
#include "core/or/circuitbuild.h"
#include "core/or/circuitpadding.h"
#include "core/or/circuitpadding_machines.h"
+#include "core/or/extendinfo.h"
#include "core/mainloop/netstatus.h"
#include "core/crypto/relay_crypto.h"
#include "core/or/protover.h"
@@ -1361,7 +1362,7 @@ test_circuitpadding_wronghop(void *arg)
/* 5. Test that asking to stop the wrong machine does nothing */
circpad_negotiate_padding(TO_ORIGIN_CIRCUIT(client_side),
- 255, 2, CIRCPAD_COMMAND_STOP);
+ 255, 2, CIRCPAD_COMMAND_STOP, 0);
tt_ptr_op(client_side->padding_machine[0], OP_NE, NULL);
tt_ptr_op(client_side->padding_info[0], OP_NE, NULL);
tt_ptr_op(relay_side->padding_machine[0], OP_NE, NULL);
@@ -1409,7 +1410,7 @@ test_circuitpadding_wronghop(void *arg)
circpad_padding_negotiated(relay_side,
CIRCPAD_MACHINE_CIRC_SETUP,
CIRCPAD_COMMAND_START,
- CIRCPAD_RESPONSE_OK);
+ CIRCPAD_RESPONSE_OK, 0);
/* verify no padding was negotiated */
tt_ptr_op(relay_side->padding_machine[0], OP_EQ, NULL);
@@ -1418,7 +1419,7 @@ test_circuitpadding_wronghop(void *arg)
circpad_padding_negotiated(relay_side,
CIRCPAD_MACHINE_CIRC_SETUP,
CIRCPAD_COMMAND_START,
- CIRCPAD_RESPONSE_ERR);
+ CIRCPAD_RESPONSE_ERR, 0);
/* verify no padding was negotiated */
tt_ptr_op(relay_side->padding_machine[0], OP_EQ, NULL);
@@ -1521,7 +1522,7 @@ test_circuitpadding_negotiation(void *arg)
/* Force negotiate padding. */
circpad_negotiate_padding(TO_ORIGIN_CIRCUIT(client_side),
CIRCPAD_MACHINE_CIRC_SETUP,
- 2, CIRCPAD_COMMAND_START);
+ 2, CIRCPAD_COMMAND_START, 0);
/* verify no padding was negotiated */
tt_ptr_op(relay_side->padding_machine[0], OP_EQ, NULL);
@@ -1732,9 +1733,9 @@ helper_create_conditional_machines(void)
add->conditions.requires_vanguards = 0;
add->conditions.min_hops = 2;
- add->conditions.state_mask = CIRCPAD_CIRC_BUILDING|
+ add->conditions.apply_state_mask = CIRCPAD_CIRC_BUILDING|
CIRCPAD_CIRC_NO_STREAMS|CIRCPAD_CIRC_HAS_RELAY_EARLY;
- add->conditions.purpose_mask = CIRCPAD_PURPOSE_ALL;
+ add->conditions.apply_purpose_mask = CIRCPAD_PURPOSE_ALL;
circpad_register_padding_machine(add, origin_padding_machines);
add = helper_create_conditional_machine();
@@ -1751,9 +1752,9 @@ helper_create_conditional_machines(void)
add->conditions.requires_vanguards = 1;
add->conditions.min_hops = 3;
- add->conditions.state_mask = CIRCPAD_CIRC_OPENED|
+ add->conditions.apply_state_mask = CIRCPAD_CIRC_OPENED|
CIRCPAD_CIRC_STREAMS|CIRCPAD_CIRC_HAS_NO_RELAY_EARLY;
- add->conditions.purpose_mask = CIRCPAD_PURPOSE_ALL;
+ add->conditions.apply_purpose_mask = CIRCPAD_PURPOSE_ALL;
circpad_register_padding_machine(add, origin_padding_machines);
add = helper_create_conditional_machine();
@@ -2727,8 +2728,8 @@ helper_create_ender_machine(void)
circ_client_machine.states[CIRCPAD_STATE_START].
next_state[CIRCPAD_EVENT_NONPADDING_RECV] = CIRCPAD_STATE_END;
- circ_client_machine.conditions.state_mask = CIRCPAD_STATE_ALL;
- circ_client_machine.conditions.purpose_mask = CIRCPAD_PURPOSE_ALL;
+ circ_client_machine.conditions.apply_state_mask = CIRCPAD_STATE_ALL;
+ circ_client_machine.conditions.apply_purpose_mask = CIRCPAD_PURPOSE_ALL;
}
static time_t mocked_timeofday;
diff --git a/src/test/test_circuitstats.c b/src/test/test_circuitstats.c
index e15dec5a01..00ca1b544c 100644
--- a/src/test/test_circuitstats.c
+++ b/src/test/test_circuitstats.c
@@ -17,18 +17,13 @@
#include "core/or/circuituse.h"
#include "core/or/channel.h"
-#include "core/or/cpath_build_state_st.h"
#include "core/or/crypt_path_st.h"
#include "core/or/extend_info_st.h"
#include "core/or/origin_circuit_st.h"
-void test_circuitstats_timeout(void *arg);
-void test_circuitstats_hoplen(void *arg);
-origin_circuit_t *subtest_fourhop_circuit(struct timeval, int);
-origin_circuit_t *add_opened_threehop(void);
-origin_circuit_t *build_unopened_fourhop(struct timeval);
-
-int cpath_append_hop(crypt_path_t **head_ptr, extend_info_t *choice);
+static origin_circuit_t *add_opened_threehop(void);
+static origin_circuit_t *build_unopened_fourhop(struct timeval);
+static origin_circuit_t *subtest_fourhop_circuit(struct timeval, int);
static int marked_for_close;
/* Mock function because we are not trying to test the close circuit that does
@@ -45,85 +40,71 @@ mock_circuit_mark_for_close(circuit_t *circ, int reason, int line,
return;
}
-origin_circuit_t *
+static origin_circuit_t *
add_opened_threehop(void)
{
- origin_circuit_t *or_circ = origin_circuit_new();
+ struct timeval circ_start_time;
+ memset(&circ_start_time, 0, sizeof(circ_start_time));
extend_info_t fakehop;
memset(&fakehop, 0, sizeof(fakehop));
-
- TO_CIRCUIT(or_circ)->purpose = CIRCUIT_PURPOSE_C_GENERAL;
-
- or_circ->build_state = tor_malloc_zero(sizeof(cpath_build_state_t));
- or_circ->build_state->desired_path_len = DEFAULT_ROUTE_LEN;
-
- cpath_append_hop(&or_circ->cpath, &fakehop);
- cpath_append_hop(&or_circ->cpath, &fakehop);
- cpath_append_hop(&or_circ->cpath, &fakehop);
-
- or_circ->has_opened = 1;
- TO_CIRCUIT(or_circ)->state = CIRCUIT_STATE_OPEN;
- TO_CIRCUIT(or_circ)->purpose = CIRCUIT_PURPOSE_C_GENERAL;
-
- return or_circ;
+ extend_info_t *fakehop_list[DEFAULT_ROUTE_LEN] = {&fakehop,
+ &fakehop,
+ &fakehop};
+
+ return new_test_origin_circuit(true,
+ circ_start_time,
+ DEFAULT_ROUTE_LEN,
+ fakehop_list);
}
-origin_circuit_t *
+static origin_circuit_t *
build_unopened_fourhop(struct timeval circ_start_time)
{
- origin_circuit_t *or_circ = origin_circuit_new();
- extend_info_t *fakehop = tor_malloc_zero(sizeof(extend_info_t));
- memset(fakehop, 0, sizeof(extend_info_t));
-
- TO_CIRCUIT(or_circ)->purpose = CIRCUIT_PURPOSE_C_GENERAL;
- TO_CIRCUIT(or_circ)->timestamp_began = circ_start_time;
- TO_CIRCUIT(or_circ)->timestamp_created = circ_start_time;
-
- or_circ->build_state = tor_malloc_zero(sizeof(cpath_build_state_t));
- or_circ->build_state->desired_path_len = 4;
-
- cpath_append_hop(&or_circ->cpath, fakehop);
- cpath_append_hop(&or_circ->cpath, fakehop);
- cpath_append_hop(&or_circ->cpath, fakehop);
- cpath_append_hop(&or_circ->cpath, fakehop);
-
- tor_free(fakehop);
-
- return or_circ;
+ extend_info_t fakehop;
+ memset(&fakehop, 0, sizeof(fakehop));
+ extend_info_t *fakehop_list[4] = {&fakehop,
+ &fakehop,
+ &fakehop,
+ &fakehop};
+
+ return new_test_origin_circuit(false,
+ circ_start_time,
+ 4,
+ fakehop_list);
}
-origin_circuit_t *
+static origin_circuit_t *
subtest_fourhop_circuit(struct timeval circ_start_time, int should_timeout)
{
- origin_circuit_t *or_circ = build_unopened_fourhop(circ_start_time);
+ origin_circuit_t *origin_circ = build_unopened_fourhop(circ_start_time);
// Now make them open one at a time and call
// circuit_build_times_handle_completed_hop();
- or_circ->cpath->state = CPATH_STATE_OPEN;
- circuit_build_times_handle_completed_hop(or_circ);
+ origin_circ->cpath->state = CPATH_STATE_OPEN;
+ circuit_build_times_handle_completed_hop(origin_circ);
tt_int_op(get_circuit_build_times()->total_build_times, OP_EQ, 0);
- or_circ->cpath->next->state = CPATH_STATE_OPEN;
- circuit_build_times_handle_completed_hop(or_circ);
+ origin_circ->cpath->next->state = CPATH_STATE_OPEN;
+ circuit_build_times_handle_completed_hop(origin_circ);
tt_int_op(get_circuit_build_times()->total_build_times, OP_EQ, 0);
// Third hop: We should count it now.
- or_circ->cpath->next->next->state = CPATH_STATE_OPEN;
- circuit_build_times_handle_completed_hop(or_circ);
+ origin_circ->cpath->next->next->state = CPATH_STATE_OPEN;
+ circuit_build_times_handle_completed_hop(origin_circ);
tt_int_op(get_circuit_build_times()->total_build_times, OP_EQ,
!should_timeout); // 1 if counted, 0 otherwise
// Fourth hop: Don't double count
- or_circ->cpath->next->next->next->state = CPATH_STATE_OPEN;
- circuit_build_times_handle_completed_hop(or_circ);
+ origin_circ->cpath->next->next->next->state = CPATH_STATE_OPEN;
+ circuit_build_times_handle_completed_hop(origin_circ);
tt_int_op(get_circuit_build_times()->total_build_times, OP_EQ,
!should_timeout);
done:
- return or_circ;
+ return origin_circ;
}
-void
+static void
test_circuitstats_hoplen(void *arg)
{
/* Plan:
diff --git a/src/test/test_config.c b/src/test/test_config.c
index cb0d9bba28..50e1a9dc43 100644
--- a/src/test/test_config.c
+++ b/src/test/test_config.c
@@ -53,6 +53,7 @@
#include "test/test_helpers.h"
#include "test/resolve_test_helpers.h"
+#include "test/log_test_helpers.h"
#include "feature/dirclient/dir_server_st.h"
#include "core/or/port_cfg_st.h"
@@ -989,53 +990,72 @@ test_config_fix_my_family(void *arg)
}
static int n_hostname_01010101 = 0;
+static const char *ret_addr_lookup_01010101[2] = {
+ "1.1.1.1", "0101::0101",
+};
-/** This mock function is meant to replace tor_lookup_hostname().
+/** This mock function is meant to replace tor_addr_lookup().
* It answers with 1.1.1.1 as IP adddress that resulted from lookup.
* This function increments <b>n_hostname_01010101</b> counter by one
* every time it is called.
*/
static int
-tor_lookup_hostname_01010101(const char *name, uint32_t *addr)
+tor_addr_lookup_01010101(const char *name, uint16_t family, tor_addr_t *addr)
{
n_hostname_01010101++;
- if (name && addr) {
- *addr = ntohl(0x01010101);
+ if (family == AF_INET) {
+ if (name && addr) {
+ int ret = tor_addr_parse(addr, ret_addr_lookup_01010101[0]);
+ tt_int_op(ret, OP_EQ, family);
+ }
+ } else if (family == AF_INET6) {
+ if (name && addr) {
+ int ret = tor_addr_parse(addr, ret_addr_lookup_01010101[1]);
+ tt_int_op(ret, OP_EQ, family);
+ }
}
-
+ done:
return 0;
}
static int n_hostname_localhost = 0;
-/** This mock function is meant to replace tor_lookup_hostname().
+/** This mock function is meant to replace tor_addr_lookup().
* It answers with 127.0.0.1 as IP adddress that resulted from lookup.
* This function increments <b>n_hostname_localhost</b> counter by one
* every time it is called.
*/
static int
-tor_lookup_hostname_localhost(const char *name, uint32_t *addr)
+tor_addr_lookup_localhost(const char *name, uint16_t family, tor_addr_t *addr)
{
n_hostname_localhost++;
- if (name && addr) {
- *addr = 0x7f000001;
+ if (family == AF_INET) {
+ if (name && addr) {
+ tor_addr_from_ipv4h(addr, 0x7f000001);
+ }
+ } else if (family == AF_INET6) {
+ if (name && addr) {
+ int ret = tor_addr_parse(addr, "::1");
+ tt_int_op(ret, OP_EQ, AF_INET6);
+ }
}
-
+ done:
return 0;
}
static int n_hostname_failure = 0;
-/** This mock function is meant to replace tor_lookup_hostname().
+/** This mock function is meant to replace tor_addr_lookup().
* It pretends to fail by returning -1 to caller. Also, this function
* increments <b>n_hostname_failure</b> every time it is called.
*/
static int
-tor_lookup_hostname_failure(const char *name, uint32_t *addr)
+tor_addr_lookup_failure(const char *name, uint16_t family, tor_addr_t *addr)
{
(void)name;
+ (void)family;
(void)addr;
n_hostname_failure++;
@@ -1043,6 +1063,46 @@ tor_lookup_hostname_failure(const char *name, uint32_t *addr)
return -1;
}
+/** Mock function for tor_addr_lookup().
+ *
+ * Depending on the given hostname and family, resolve either to IPv4 or IPv6.
+ *
+ * If the requested hostname family is not the same as the family provided, an
+ * error is returned.
+ *
+ * Possible hostnames:
+ * - www.torproject.org.v4 for IPv4 -> 1.1.1.1
+ * - www.torproject.org.v6 for IPv6 -> [0101::0101]
+ */
+static int
+tor_addr_lookup_mixed(const char *name, uint16_t family, tor_addr_t *addr)
+{
+ tt_assert(addr);
+ tt_assert(name);
+
+ if (!strcmp(name, "www.torproject.org.v4")) {
+ if (family == AF_INET) {
+ tor_addr_from_ipv4h(addr, 0x01010101);
+ return 0;
+ }
+ /* Resolving AF_INET but the asked family is different. Failure. */
+ return -1;
+ }
+
+ if (!strcmp(name, "www.torproject.org.v6")) {
+ if (family == AF_INET6) {
+ int ret = tor_addr_parse(addr, "0101::0101");
+ tt_int_op(ret, OP_EQ, AF_INET6);
+ return 0;
+ }
+ /* Resolving AF_INET6 but the asked family is not. Failure. */
+ return -1;
+ }
+
+ done:
+ return 0;
+}
+
static int n_gethostname_replacement = 0;
/** This mock function is meant to replace tor_gethostname(). It
@@ -1097,29 +1157,39 @@ tor_gethostname_failure(char *name, size_t namelen)
return -1;
}
-static int n_get_interface_address = 0;
+static int n_get_interface_address6 = 0;
+static sa_family_t last_address6_family;
+static const char *ret_get_interface_address6_08080808[2] = {
+ "8.8.8.8", "0808::0808",
+};
/** This mock function is meant to replace get_interface_address().
* It answers with address 8.8.8.8. This function increments
* <b>n_get_interface_address</b> by one every time it is called.
*/
static int
-get_interface_address_08080808(int severity, uint32_t *addr)
+get_interface_address6_08080808(int severity, sa_family_t family,
+ tor_addr_t *addr)
{
(void)severity;
- n_get_interface_address++;
+ n_get_interface_address6++;
- if (addr) {
- *addr = ntohl(0x08080808);
+ if (family == AF_INET) {
+ if (addr) {
+ int ret = tor_addr_parse(addr, ret_get_interface_address6_08080808[0]);
+ tt_int_op(ret, OP_EQ, AF_INET);
+ }
+ } else if (family == AF_INET6) {
+ if (addr) {
+ int ret = tor_addr_parse(addr, ret_get_interface_address6_08080808[1]);
+ tt_int_op(ret, OP_EQ, AF_INET6);
+ }
}
-
+ done:
return 0;
}
-static int n_get_interface_address6 = 0;
-static sa_family_t last_address6_family;
-
/** This mock function is meant to replace get_interface_address6().
* It answers with IP address 9.9.9.9 iff both of the following are true:
* - <b>family</b> is AF_INET
@@ -1127,6 +1197,7 @@ static sa_family_t last_address6_family;
* This function increments <b>n_get_interface_address6</b> by one every
* time it is called.
*/
+#if 0
static int
get_interface_address6_replacement(int severity, sa_family_t family,
tor_addr_t *addr)
@@ -1144,25 +1215,7 @@ get_interface_address6_replacement(int severity, sa_family_t family,
return 0;
}
-
-static int n_get_interface_address_failure = 0;
-
-/**
- * This mock function is meant to replace get_interface_address().
- * It pretends to fail getting interface address by returning -1.
- * <b>n_get_interface_address_failure</b> is incremented by one
- * every time this function is called.
- */
-static int
-get_interface_address_failure(int severity, uint32_t *addr)
-{
- (void)severity;
- (void)addr;
-
- n_get_interface_address_failure++;
-
- return -1;
-}
+#endif
static int n_get_interface_address6_failure = 0;
@@ -1185,24 +1238,44 @@ get_interface_address6_failure(int severity, sa_family_t family,
return -1;
}
+/** Helper macro: to validate the returned value from find_my_address() so we
+ * don't copy those all the time. */
+#undef VALIDATE_FOUND_ADDRESS
+#define VALIDATE_FOUND_ADDRESS(ret, method, hostname) \
+ do { \
+ tt_int_op(retval, OP_EQ, ret); \
+ if (method == NULL) tt_assert(!method_used); \
+ else tt_str_op(method_used, OP_EQ, method); \
+ if (hostname == NULL) tt_assert(!hostname_out); \
+ else tt_str_op(hostname_out, OP_EQ, hostname); \
+ if (ret == true) { \
+ tt_assert(tor_addr_eq(&resolved_addr, &test_addr)); \
+ } \
+ } while (0)
+
+/** Helper macro: Cleanup the address and variables used after a
+ * find_my_address() call. */
+#undef CLEANUP_FOUND_ADDRESS
+#define CLEANUP_FOUND_ADDRESS \
+ do { \
+ config_free_lines(options->Address); \
+ config_free_lines(options->ORPort_lines); \
+ options->ORPort_set = 0; \
+ tor_free(options->DirAuthorities); \
+ tor_free(hostname_out); \
+ tor_addr_make_unspec(&resolved_addr); \
+ tor_addr_make_unspec(&test_addr); \
+ } while (0)
+
+/** Test both IPv4 and IPv6 coexisting together in the configuration. */
static void
-test_config_resolve_my_address(void *arg)
+test_config_find_my_address_mixed(void *arg)
{
or_options_t *options;
- uint32_t resolved_addr;
+ tor_addr_t resolved_addr, test_addr;
const char *method_used;
char *hostname_out = NULL;
- int retval;
- int prev_n_hostname_01010101;
- int prev_n_hostname_localhost;
- int prev_n_hostname_failure;
- int prev_n_gethostname_replacement;
- int prev_n_gethostname_failure;
- int prev_n_gethostname_localhost;
- int prev_n_get_interface_address;
- int prev_n_get_interface_address_failure;
- int prev_n_get_interface_address6;
- int prev_n_get_interface_address6_failure;
+ bool retval;
(void)arg;
@@ -1210,369 +1283,538 @@ test_config_resolve_my_address(void *arg)
options_init(options);
- /*
- * CASE 1:
- * If options->Address is a valid IPv4 address string, we want
- * the corresponding address to be parsed and returned.
- */
+ /*
+ * CASE 1: Only IPv6 address. Accepted.
+ */
+ config_line_append(&options->Address, "Address",
+ "2a01:4f8:fff0:4f:266:37ff:fe2c:5d19");
+ tor_addr_parse(&test_addr, "2a01:4f8:fff0:4f:266:37ff:fe2c:5d19");
- options->Address = tor_strdup("128.52.128.105");
+ /* IPv4 address not guessed since one Address statement exists. */
+ retval = find_my_address(options, AF_INET, LOG_NOTICE, &resolved_addr,
+ &method_used, &hostname_out);
+ VALIDATE_FOUND_ADDRESS(false, NULL, NULL);
+ /* IPv6 address should be found and considered configured. */
+ retval = find_my_address(options, AF_INET6, LOG_NOTICE, &resolved_addr,
+ &method_used, &hostname_out);
+ VALIDATE_FOUND_ADDRESS(true, "CONFIGURED", NULL);
- retval = resolve_my_address(LOG_NOTICE,options,&resolved_addr,
- &method_used,&hostname_out);
+ CLEANUP_FOUND_ADDRESS;
- tt_want(retval == 0);
- tt_want_str_op(method_used,OP_EQ,"CONFIGURED");
- tt_want(hostname_out == NULL);
- tt_assert(resolved_addr == 0x80348069);
+ /*
+ * Case 2: IPv4 _and_ IPv6 given. Accepted.
+ */
+ config_line_append(&options->Address, "Address",
+ "2a01:4f8:fff0:4f:266:37ff:fe2c:5d19");
+ config_line_append(&options->Address, "Address", "1.1.1.1");
+ tor_addr_parse(&test_addr, "1.1.1.1");
- tor_free(options->Address);
+ /* IPv4 address should be found and considered configured. */
+ retval = find_my_address(options, AF_INET, LOG_NOTICE, &resolved_addr,
+ &method_used, &hostname_out);
+ VALIDATE_FOUND_ADDRESS(true, "CONFIGURED", NULL);
-/*
- * CASE 2:
- * If options->Address is a valid DNS address, we want resolve_my_address()
- * function to ask tor_lookup_hostname() for help with resolving it
- * and return the address that was resolved (in host order).
- */
+ /* IPv6 address should be found and considered configured. */
+ tor_addr_parse(&test_addr, "2a01:4f8:fff0:4f:266:37ff:fe2c:5d19");
+ retval = find_my_address(options, AF_INET6, LOG_NOTICE, &resolved_addr,
+ &method_used, &hostname_out);
+ VALIDATE_FOUND_ADDRESS(true, "CONFIGURED", NULL);
- MOCK(tor_lookup_hostname,tor_lookup_hostname_01010101);
+ CLEANUP_FOUND_ADDRESS;
- tor_free(options->Address);
- options->Address = tor_strdup("www.torproject.org");
+ /*
+ * Case 3: Two hostnames, IPv4 and IPv6.
+ */
+ config_line_append(&options->Address, "Address", "www.torproject.org.v4");
+ config_line_append(&options->Address, "Address", "www.torproject.org.v6");
- prev_n_hostname_01010101 = n_hostname_01010101;
+ /* Looks at specific hostname to learn which address family to use. */
+ MOCK(tor_addr_lookup, tor_addr_lookup_mixed);
- retval = resolve_my_address(LOG_NOTICE,options,&resolved_addr,
- &method_used,&hostname_out);
+ /* IPv4 address should be found and considered resolved. */
+ tor_addr_parse(&test_addr, "1.1.1.1");
+ retval = find_my_address(options, AF_INET, LOG_NOTICE, &resolved_addr,
+ &method_used, &hostname_out);
+ VALIDATE_FOUND_ADDRESS(true, "RESOLVED", "www.torproject.org.v4");
+ tor_free(hostname_out);
- tt_want(retval == 0);
- tt_want(n_hostname_01010101 == prev_n_hostname_01010101 + 1);
- tt_want_str_op(method_used,OP_EQ,"RESOLVED");
- tt_want_str_op(hostname_out,OP_EQ,"www.torproject.org");
- tt_assert(resolved_addr == 0x01010101);
+ /* IPv6 address should be found and considered resolved. */
+ tor_addr_parse(&test_addr, "0101::0101");
+ retval = find_my_address(options, AF_INET6, LOG_NOTICE, &resolved_addr,
+ &method_used, &hostname_out);
+ VALIDATE_FOUND_ADDRESS(true, "RESOLVED", "www.torproject.org.v6");
- UNMOCK(tor_lookup_hostname);
+ CLEANUP_FOUND_ADDRESS;
+ UNMOCK(tor_addr_lookup);
- tor_free(options->Address);
- tor_free(hostname_out);
+ /*
+ * Case 4: IPv4 address and a hostname resolving to IPV6.
+ */
+ config_line_append(&options->Address, "Address", "1.1.1.1");
+ config_line_append(&options->Address, "Address", "www.torproject.org.v6");
-/*
- * CASE 3:
- * Given that options->Address is NULL, we want resolve_my_address()
- * to try and use tor_gethostname() to get hostname AND use
- * tor_lookup_hostname() to get IP address.
- */
+ /* Looks at specific hostname to learn which address family to use. */
+ MOCK(tor_addr_lookup, tor_addr_lookup_mixed);
- resolved_addr = 0;
- tor_free(options->Address);
- options->Address = NULL;
+ /* IPv4 address should be found and configured. */
+ tor_addr_parse(&test_addr, "1.1.1.1");
+ retval = find_my_address(options, AF_INET, LOG_NOTICE, &resolved_addr,
+ &method_used, &hostname_out);
+ VALIDATE_FOUND_ADDRESS(true, "CONFIGURED", NULL);
- MOCK(tor_gethostname,tor_gethostname_replacement);
- MOCK(tor_lookup_hostname,tor_lookup_hostname_01010101);
+ /* IPv6 address should be found and considered resolved. */
+ tor_addr_parse(&test_addr, "0101::0101");
+ retval = find_my_address(options, AF_INET6, LOG_NOTICE, &resolved_addr,
+ &method_used, &hostname_out);
+ VALIDATE_FOUND_ADDRESS(true, "RESOLVED", "www.torproject.org.v6");
- prev_n_gethostname_replacement = n_gethostname_replacement;
- prev_n_hostname_01010101 = n_hostname_01010101;
+ CLEANUP_FOUND_ADDRESS;
+ UNMOCK(tor_addr_lookup);
+
+ /*
+ * Case 5: Hostname resolving to IPv4 and an IPv6 address.
+ */
+ config_line_append(&options->Address, "Address", "0101::0101");
+ config_line_append(&options->Address, "Address", "www.torproject.org.v4");
- retval = resolve_my_address(LOG_NOTICE,options,&resolved_addr,
- &method_used,&hostname_out);
+ /* Looks at specific hostname to learn which address family to use. */
+ MOCK(tor_addr_lookup, tor_addr_lookup_mixed);
- tt_want(retval == 0);
- tt_want(n_gethostname_replacement == prev_n_gethostname_replacement + 1);
- tt_want(n_hostname_01010101 == prev_n_hostname_01010101 + 1);
- tt_want_str_op(method_used,OP_EQ,"GETHOSTNAME");
- tt_want_str_op(hostname_out,OP_EQ,"onionrouter!");
- tt_assert(resolved_addr == 0x01010101);
+ /* IPv4 address should be found and resolved. */
+ tor_addr_parse(&test_addr, "1.1.1.1");
+ retval = find_my_address(options, AF_INET, LOG_NOTICE, &resolved_addr,
+ &method_used, &hostname_out);
+ VALIDATE_FOUND_ADDRESS(true, "RESOLVED", "www.torproject.org.v4");
+ tor_free(hostname_out);
- UNMOCK(tor_gethostname);
- UNMOCK(tor_lookup_hostname);
+ /* IPv6 address should be found and considered resolved. */
+ tor_addr_parse(&test_addr, "0101::0101");
+ retval = find_my_address(options, AF_INET6, LOG_NOTICE, &resolved_addr,
+ &method_used, &hostname_out);
+ VALIDATE_FOUND_ADDRESS(true, "CONFIGURED", NULL);
+ CLEANUP_FOUND_ADDRESS;
+ UNMOCK(tor_addr_lookup);
+
+ done:
+ config_free_lines(options->Address);
+ or_options_free(options);
tor_free(hostname_out);
-/*
- * CASE 4:
- * Given that options->Address is a local host address, we want
- * resolve_my_address() function to fail.
- */
+ UNMOCK(tor_addr_lookup);
+}
- resolved_addr = 0;
- tor_free(options->Address);
- options->Address = tor_strdup("127.0.0.1");
+/** Parameters for the find_my_address() test. We test both AF_INET and
+ * AF_INET6 but we have one interface to do so thus we run the same exact unit
+ * tests for both without copying them. */
+typedef struct find_my_address_params_t {
+ /* Index where the mock function results are located. For intance,
+ * tor_addr_lookup_01010101() will have its returned value depending on the
+ * family in ret_addr_lookup_01010101[].
+ *
+ * Values that can be found:
+ * AF_INET : index 0.
+ * AF_INET6: index 1.
+ */
+ int idx;
+ int family;
+ const char *public_ip;
+ const char *internal_ip;
+ const char *orport;
+} find_my_address_params_t;
+
+static find_my_address_params_t addr_param_v4 = {
+ .idx = 0,
+ .family = AF_INET,
+ .public_ip = "128.52.128.105",
+ .internal_ip = "127.0.0.1",
+};
- retval = resolve_my_address(LOG_NOTICE,options,&resolved_addr,
- &method_used,&hostname_out);
+static find_my_address_params_t addr_param_v6 = {
+ .idx = 1,
+ .family = AF_INET6,
+ .public_ip = "[4242::4242]",
+ .internal_ip = "[::1]",
+};
- tt_want(resolved_addr == 0);
- tt_int_op(retval, OP_EQ, -1);
+static void
+test_config_find_my_address(void *arg)
+{
+ or_options_t *options;
+ tor_addr_t resolved_addr, test_addr;
+ const char *method_used;
+ char *hostname_out = NULL;
+ bool retval;
+ int prev_n_hostname_01010101;
+ int prev_n_hostname_failure;
+ int prev_n_hostname_localhost;
+ int prev_n_gethostname_replacement;
+ int prev_n_gethostname_failure;
+ int prev_n_gethostname_localhost;
+ int prev_n_get_interface_address6;
+ int prev_n_get_interface_address6_failure;
- tor_free(options->Address);
- tor_free(hostname_out);
+ const find_my_address_params_t *p = arg;
-/*
- * CASE 5:
- * We want resolve_my_address() to fail if DNS address in options->Address
- * cannot be resolved.
- */
+ options = options_new();
+ options_init(options);
- MOCK(tor_lookup_hostname,tor_lookup_hostname_failure);
+ /*
+ * Case 1:
+ * 1. Address is a valid address.
+ *
+ * Expected to succeed.
+ */
+ config_line_append(&options->Address, "Address", p->public_ip);
+ tor_addr_parse(&test_addr, p->public_ip);
- prev_n_hostname_failure = n_hostname_failure;
+ retval = find_my_address(options, p->family, LOG_NOTICE, &resolved_addr,
+ &method_used, &hostname_out);
- tor_free(options->Address);
- options->Address = tor_strdup("www.tor-project.org");
+ VALIDATE_FOUND_ADDRESS(true, "CONFIGURED", NULL);
+ CLEANUP_FOUND_ADDRESS;
- retval = resolve_my_address(LOG_NOTICE,options,&resolved_addr,
- &method_used,&hostname_out);
+ /*
+ * Case 2: Address is a resolvable address. Expected to succeed.
+ */
+ MOCK(tor_addr_lookup, tor_addr_lookup_01010101);
- tt_want(n_hostname_failure == prev_n_hostname_failure + 1);
- tt_int_op(retval, OP_EQ, -1);
+ config_line_append(&options->Address, "Address", "www.torproject.org");
+ tor_addr_parse(&test_addr, ret_addr_lookup_01010101[p->idx]);
- UNMOCK(tor_lookup_hostname);
+ prev_n_hostname_01010101 = n_hostname_01010101;
- tor_free(options->Address);
- tor_free(hostname_out);
+ retval = find_my_address(options, p->family, LOG_NOTICE, &resolved_addr,
+ &method_used, &hostname_out);
-/*
- * CASE 6:
- * If options->Address is NULL AND gettting local hostname fails, we want
- * resolve_my_address() to fail as well.
- */
+ tt_int_op(n_hostname_01010101, OP_EQ, ++prev_n_hostname_01010101);
+ VALIDATE_FOUND_ADDRESS(true, "RESOLVED", "www.torproject.org");
+ CLEANUP_FOUND_ADDRESS;
- MOCK(tor_gethostname,tor_gethostname_failure);
+ UNMOCK(tor_addr_lookup);
- prev_n_gethostname_failure = n_gethostname_failure;
+ /*
+ * Case 3: Address is a local addressi (internal). Expected to fail.
+ */
+ config_line_append(&options->Address, "Address", p->internal_ip);
- retval = resolve_my_address(LOG_NOTICE,options,&resolved_addr,
- &method_used,&hostname_out);
+ setup_full_capture_of_logs(LOG_NOTICE);
- tt_want(n_gethostname_failure == prev_n_gethostname_failure + 1);
- tt_int_op(retval, OP_EQ, -1);
+ retval = find_my_address(options, p->family, LOG_NOTICE, &resolved_addr,
+ &method_used, &hostname_out);
- UNMOCK(tor_gethostname);
- tor_free(hostname_out);
+ expect_log_msg_containing("is a private IP address. Tor relays that "
+ "use the default DirAuthorities must have "
+ "public IP addresses.");
+ teardown_capture_of_logs();
-/*
- * CASE 7:
- * We want resolve_my_address() to try and get network interface address via
- * get_interface_address() if hostname returned by tor_gethostname() cannot be
- * resolved into IP address.
- */
+ VALIDATE_FOUND_ADDRESS(false, NULL, NULL);
+ CLEANUP_FOUND_ADDRESS;
- MOCK(tor_gethostname,tor_gethostname_replacement);
- MOCK(tor_lookup_hostname,tor_lookup_hostname_failure);
- MOCK(get_interface_address,get_interface_address_08080808);
+ /*
+ * Case 4: Address is a local address but custom authorities. Expected to
+ * succeed.
+ */
+ config_line_append(&options->Address, "Address", p->internal_ip);
+ options->DirAuthorities = tor_malloc_zero(sizeof(config_line_t));
+ tor_addr_parse(&test_addr, p->internal_ip);
- prev_n_gethostname_replacement = n_gethostname_replacement;
- prev_n_get_interface_address = n_get_interface_address;
+ retval = find_my_address(options, p->family, LOG_NOTICE, &resolved_addr,
+ &method_used, &hostname_out);
- retval = resolve_my_address(LOG_NOTICE,options,&resolved_addr,
- &method_used,&hostname_out);
+ VALIDATE_FOUND_ADDRESS(true, "CONFIGURED", NULL);
+ CLEANUP_FOUND_ADDRESS;
- tt_want(retval == 0);
- tt_want_int_op(n_gethostname_replacement, OP_EQ,
- prev_n_gethostname_replacement + 1);
- tt_want_int_op(n_get_interface_address, OP_EQ,
- prev_n_get_interface_address + 1);
- tt_want_str_op(method_used,OP_EQ,"INTERFACE");
- tt_want(hostname_out == NULL);
- tt_assert(resolved_addr == 0x08080808);
+ /*
+ * Case 5: Multiple address in Address. Expected to fail.
+ */
+ config_line_append(&options->Address, "Address", p->public_ip);
+ config_line_append(&options->Address, "Address", p->public_ip);
- UNMOCK(get_interface_address);
- tor_free(hostname_out);
+ setup_full_capture_of_logs(LOG_NOTICE);
-/*
- * CASE 8:
- * Suppose options->Address is NULL AND hostname returned by tor_gethostname()
- * is unresolvable. We want resolve_my_address to fail if
- * get_interface_address() fails.
- */
+ retval = find_my_address(options, p->family, LOG_NOTICE, &resolved_addr,
+ &method_used, &hostname_out);
- MOCK(get_interface_address,get_interface_address_failure);
+ expect_log_msg_containing("Found 2 Address statement of address family");
+ teardown_capture_of_logs();
- prev_n_get_interface_address_failure = n_get_interface_address_failure;
- prev_n_gethostname_replacement = n_gethostname_replacement;
+ VALIDATE_FOUND_ADDRESS(false, NULL, NULL);
+ CLEANUP_FOUND_ADDRESS;
- retval = resolve_my_address(LOG_NOTICE,options,&resolved_addr,
- &method_used,&hostname_out);
+ /*
+ * Case 6: Another address family is configured. Expected to fail.
+ */
+ if (p->family == AF_INET) {
+ config_line_append(&options->Address, "Address", "4242::4242");
+ } else {
+ config_line_append(&options->Address, "Address", "1.1.1.1");
+ }
- tt_want(n_get_interface_address_failure ==
- prev_n_get_interface_address_failure + 1);
- tt_want(n_gethostname_replacement ==
- prev_n_gethostname_replacement + 1);
- tt_int_op(retval, OP_EQ, -1);
+ setup_full_capture_of_logs(LOG_NOTICE);
- UNMOCK(get_interface_address);
- tor_free(hostname_out);
+ retval = find_my_address(options, p->family, LOG_NOTICE, &resolved_addr,
+ &method_used, &hostname_out);
-/*
- * CASE 9:
- * Given that options->Address is NULL AND tor_lookup_hostname()
- * fails AND hostname returned by gethostname() resolves
- * to local IP address, we want resolve_my_address() function to
- * call get_interface_address6(.,AF_INET,.) and return IP address
- * the latter function has found.
- */
+ expect_log_msg_containing("No Address option found for family");
+ teardown_capture_of_logs();
- MOCK(tor_lookup_hostname,tor_lookup_hostname_failure);
- MOCK(tor_gethostname,tor_gethostname_replacement);
- MOCK(get_interface_address6,get_interface_address6_replacement);
+ VALIDATE_FOUND_ADDRESS(false, NULL, NULL);
+ CLEANUP_FOUND_ADDRESS;
- prev_n_gethostname_replacement = n_gethostname_replacement;
+ /*
+ * Case 7: Address is a non resolvable hostname. Expected to fail.
+ */
+ MOCK(tor_addr_lookup, tor_addr_lookup_failure);
+
+ config_line_append(&options->Address, "Address", "www.torproject.org");
prev_n_hostname_failure = n_hostname_failure;
- prev_n_get_interface_address6 = n_get_interface_address6;
- retval = resolve_my_address(LOG_NOTICE,options,&resolved_addr,
- &method_used,&hostname_out);
+ setup_full_capture_of_logs(LOG_NOTICE);
- tt_want(last_address6_family == AF_INET);
- tt_want(n_get_interface_address6 == prev_n_get_interface_address6 + 1);
- tt_want(n_hostname_failure == prev_n_hostname_failure + 1);
- tt_want(n_gethostname_replacement == prev_n_gethostname_replacement + 1);
- tt_want(retval == 0);
- tt_want_str_op(method_used,OP_EQ,"INTERFACE");
- tt_assert(resolved_addr == 0x09090909);
+ retval = find_my_address(options, p->family, LOG_NOTICE, &resolved_addr,
+ &method_used, &hostname_out);
- UNMOCK(tor_lookup_hostname);
- UNMOCK(tor_gethostname);
- UNMOCK(get_interface_address6);
+ expect_log_msg_containing("Could not resolve local Address "
+ "'www.torproject.org'. Failing.");
+ teardown_capture_of_logs();
- tor_free(hostname_out);
+ tt_int_op(n_hostname_failure, OP_EQ, ++prev_n_hostname_failure);
+ VALIDATE_FOUND_ADDRESS(false, NULL, NULL);
+ CLEANUP_FOUND_ADDRESS;
+
+ UNMOCK(tor_addr_lookup);
/*
- * CASE 10: We want resolve_my_address() to fail if all of the following
- * are true:
- * 1. options->Address is not NULL
- * 2. ... but it cannot be converted to struct in_addr by
- * tor_inet_aton()
- * 3. ... and tor_lookup_hostname() fails to resolve the
- * options->Address
+ * Case 8:
+ * 1. Address is NULL
+ * 2. Interface address is a valid address.
+ *
+ * Expected to succeed.
*/
+ options->Address = NULL;
+ tor_addr_parse(&test_addr, ret_get_interface_address6_08080808[p->idx]);
- MOCK(tor_lookup_hostname,tor_lookup_hostname_failure);
+ MOCK(get_interface_address6, get_interface_address6_08080808);
- prev_n_hostname_failure = n_hostname_failure;
+ prev_n_get_interface_address6 = n_get_interface_address6;
+
+ retval = find_my_address(options, p->family, LOG_NOTICE, &resolved_addr,
+ &method_used, &hostname_out);
- tor_free(options->Address);
- options->Address = tor_strdup("some_hostname");
+ tt_int_op(n_get_interface_address6, OP_EQ, ++prev_n_get_interface_address6);
+ VALIDATE_FOUND_ADDRESS(true, "INTERFACE", NULL);
+ CLEANUP_FOUND_ADDRESS;
- retval = resolve_my_address(LOG_NOTICE, options, &resolved_addr,
- &method_used,&hostname_out);
+ UNMOCK(get_interface_address6);
- tt_want(n_hostname_failure == prev_n_hostname_failure + 1);
- tt_int_op(retval, OP_EQ, -1);
+ /*
+ * Case 9:
+ * 1. Address is NULL
+ * 2. Interface address fails to be found.
+ * 3. Local hostname resolves to a valid address.
+ *
+ * Expected to succeed.
+ */
+ options->Address = NULL;
+ tor_addr_parse(&test_addr, ret_addr_lookup_01010101[p->idx]);
- UNMOCK(tor_gethostname);
- UNMOCK(tor_lookup_hostname);
+ MOCK(get_interface_address6, get_interface_address6_failure);
+ MOCK(tor_gethostname, tor_gethostname_replacement);
+ MOCK(tor_addr_lookup, tor_addr_lookup_01010101);
- tor_free(hostname_out);
+ prev_n_get_interface_address6_failure = n_get_interface_address6_failure;
+ prev_n_hostname_01010101 = n_hostname_01010101;
+ prev_n_gethostname_replacement = n_gethostname_replacement;
+
+ retval = find_my_address(options, p->family, LOG_NOTICE, &resolved_addr,
+ &method_used, &hostname_out);
+
+ tt_int_op(n_get_interface_address6_failure, OP_EQ,
+ ++prev_n_get_interface_address6_failure);
+ tt_int_op(n_hostname_01010101, OP_EQ,
+ ++prev_n_hostname_01010101);
+ tt_int_op(n_gethostname_replacement, OP_EQ,
+ ++prev_n_gethostname_replacement);
+ VALIDATE_FOUND_ADDRESS(true, "GETHOSTNAME", "onionrouter!");
+ CLEANUP_FOUND_ADDRESS;
+
+ UNMOCK(get_interface_address6);
+ UNMOCK(tor_gethostname);
+ UNMOCK(tor_addr_lookup);
/*
- * CASE 11:
- * Suppose the following sequence of events:
- * 1. options->Address is NULL
- * 2. tor_gethostname() succeeds to get hostname of machine Tor
- * if running on.
- * 3. Hostname from previous step cannot be converted to
- * address by using tor_inet_aton() function.
- * 4. However, tor_lookup_hostname() succeeds in resolving the
- * hostname from step 2.
- * 5. Unfortunately, tor_addr_is_internal() deems this address
- * to be internal.
- * 6. get_interface_address6(.,AF_INET,.) returns non-internal
- * IPv4
+ * Case 10:
+ * 1. Address is NULL
+ * 2. Interface address fails to be found.
+ * 3. Local hostname resolves to an internal address.
*
- * We want resolve_my_addr() to succeed with method "INTERFACE"
- * and address from step 6.
+ * Expected to fail.
*/
-
- tor_free(options->Address);
options->Address = NULL;
- MOCK(tor_gethostname,tor_gethostname_replacement);
- MOCK(tor_lookup_hostname,tor_lookup_hostname_localhost);
- MOCK(get_interface_address6,get_interface_address6_replacement);
+ MOCK(get_interface_address6, get_interface_address6_failure);
+ MOCK(tor_gethostname, tor_gethostname_localhost);
+ MOCK(tor_addr_lookup, tor_addr_lookup_localhost);
- prev_n_gethostname_replacement = n_gethostname_replacement;
+ prev_n_get_interface_address6_failure = n_get_interface_address6_failure;
prev_n_hostname_localhost = n_hostname_localhost;
- prev_n_get_interface_address6 = n_get_interface_address6;
+ prev_n_gethostname_localhost = n_gethostname_localhost;
- retval = resolve_my_address(LOG_DEBUG, options, &resolved_addr,
- &method_used,&hostname_out);
+ retval = find_my_address(options, p->family, LOG_NOTICE, &resolved_addr,
+ &method_used, &hostname_out);
- tt_want(n_gethostname_replacement == prev_n_gethostname_replacement + 1);
- tt_want(n_hostname_localhost == prev_n_hostname_localhost + 1);
- tt_want(n_get_interface_address6 == prev_n_get_interface_address6 + 1);
+ tt_int_op(n_get_interface_address6_failure, OP_EQ,
+ ++prev_n_get_interface_address6_failure);
+ tt_int_op(n_hostname_localhost, OP_EQ,
+ ++prev_n_hostname_localhost);
+ tt_int_op(n_gethostname_localhost, OP_EQ,
+ ++prev_n_gethostname_localhost);
+ VALIDATE_FOUND_ADDRESS(false, NULL, NULL);
+ CLEANUP_FOUND_ADDRESS;
- tt_str_op(method_used,OP_EQ,"INTERFACE");
- tt_ptr_op(hostname_out, OP_EQ, NULL);
- tt_int_op(retval, OP_EQ, 0);
+ UNMOCK(get_interface_address6);
+ UNMOCK(tor_gethostname);
+ UNMOCK(tor_addr_lookup);
/*
- * CASE 11b:
- * 1-5 as above.
- * 6. get_interface_address6() fails.
+ * Case 11:
+ * 1. Address is NULL
+ * 2. Interface address fails to be found.
+ * 3. Local hostname fails to be found.
*
- * In this subcase, we want resolve_my_address() to fail.
+ * Expected to fail.
*/
+ options->Address = NULL;
- UNMOCK(get_interface_address6);
- MOCK(get_interface_address6,get_interface_address6_failure);
+ MOCK(get_interface_address6, get_interface_address6_failure);
+ MOCK(tor_gethostname, tor_gethostname_failure);
- prev_n_gethostname_replacement = n_gethostname_replacement;
- prev_n_hostname_localhost = n_hostname_localhost;
prev_n_get_interface_address6_failure = n_get_interface_address6_failure;
+ prev_n_gethostname_failure = n_gethostname_failure;
- retval = resolve_my_address(LOG_DEBUG, options, &resolved_addr,
- &method_used,&hostname_out);
-
- tt_want(n_gethostname_replacement == prev_n_gethostname_replacement + 1);
- tt_want(n_hostname_localhost == prev_n_hostname_localhost + 1);
- tt_want(n_get_interface_address6_failure ==
- prev_n_get_interface_address6_failure + 1);
+ retval = find_my_address(options, p->family, LOG_NOTICE, &resolved_addr,
+ &method_used, &hostname_out);
- tt_int_op(retval, OP_EQ, -1);
+ tt_int_op(n_get_interface_address6_failure, OP_EQ,
+ ++prev_n_get_interface_address6_failure);
+ tt_int_op(n_gethostname_failure, OP_EQ,
+ ++prev_n_gethostname_failure);
+ VALIDATE_FOUND_ADDRESS(false, NULL, NULL);
+ CLEANUP_FOUND_ADDRESS;
- UNMOCK(tor_gethostname);
- UNMOCK(tor_lookup_hostname);
UNMOCK(get_interface_address6);
+ UNMOCK(tor_gethostname);
- /* CASE 12:
- * Suppose the following happens:
- * 1. options->Address is NULL AND options->DirAuthorities is non-NULL
- * 2. tor_gethostname() succeeds in getting hostname of a machine ...
- * 3. ... which is successfully parsed by tor_inet_aton() ...
- * 4. into IPv4 address that tor_addr_is_inernal() considers to be
- * internal.
+ /*
+ * Case 12:
+ * 1. Address is NULL
+ * 2. Interface address fails to be found.
+ * 3. Local hostname can't be resolved.
*
- * In this case, we want resolve_my_address() to fail.
+ * Expected to fail.
*/
-
- tor_free(options->Address);
options->Address = NULL;
- options->DirAuthorities = tor_malloc_zero(sizeof(config_line_t));
- MOCK(tor_gethostname,tor_gethostname_localhost);
+ MOCK(get_interface_address6, get_interface_address6_failure);
+ MOCK(tor_gethostname, tor_gethostname_replacement);
+ MOCK(tor_addr_lookup, tor_addr_lookup_failure);
- prev_n_gethostname_localhost = n_gethostname_localhost;
+ prev_n_get_interface_address6_failure = n_get_interface_address6_failure;
+ prev_n_gethostname_replacement = n_gethostname_replacement;
+ prev_n_hostname_failure = n_hostname_failure;
- retval = resolve_my_address(LOG_DEBUG, options, &resolved_addr,
- &method_used,&hostname_out);
+ retval = find_my_address(options, p->family, LOG_NOTICE, &resolved_addr,
+ &method_used, &hostname_out);
- tt_want(n_gethostname_localhost == prev_n_gethostname_localhost + 1);
- tt_int_op(retval, OP_EQ, -1);
+ tt_int_op(n_get_interface_address6_failure, OP_EQ,
+ ++prev_n_get_interface_address6_failure);
+ tt_int_op(n_gethostname_replacement, OP_EQ,
+ ++prev_n_gethostname_replacement);
+ tt_int_op(n_hostname_failure, OP_EQ,
+ ++prev_n_hostname_failure);
+ VALIDATE_FOUND_ADDRESS(false, NULL, NULL);
+ CLEANUP_FOUND_ADDRESS;
+ /*
+ * Case 13:
+ * 1. Address is NULL.
+ * 2. ORPort has a valid public address.
+ */
+ {
+ char *msg = NULL;
+ int n, w, ret;
+ char *orport_line = NULL;
+
+ options->Address = NULL;
+ tor_asprintf(&orport_line, "%s:9001", p->public_ip);
+ config_line_append(&options->ORPort_lines, "ORPort", orport_line);
+ tor_free(orport_line);
+
+ if (p->family == AF_INET6) {
+ /* XXX: Tor does _not_ allow an IPv6 only ORPort thus we need to add a
+ * bogus IPv4 at the moment. */
+ config_line_append(&options->ORPort_lines, "ORPort", "1.1.1.1:9001");
+ }
+
+ ret = parse_ports(options, 0, &msg, &n, &w);
+ tt_int_op(ret, OP_EQ, 0);
+ tor_addr_parse(&test_addr, p->public_ip);
+ }
+
+ retval = find_my_address(options, p->family, LOG_NOTICE, &resolved_addr,
+ &method_used, &hostname_out);
+ VALIDATE_FOUND_ADDRESS(true, "CONFIGURED_ORPORT", NULL);
+ CLEANUP_FOUND_ADDRESS;
+
+ /*
+ * Case 14:
+ * 1. Address is NULL.
+ * 2. ORPort has an internal address thus fails.
+ * 3. Interface as a valid address.
+ */
+ {
+ char *msg = NULL;
+ int n, w, ret;
+ char *orport_line = NULL;
+
+ options->Address = NULL;
+ tor_asprintf(&orport_line, "%s:9001", p->internal_ip);
+ config_line_append(&options->ORPort_lines, "ORPort", orport_line);
+ tor_free(orport_line);
+
+ if (p->family == AF_INET6) {
+ /* XXX: Tor does _not_ allow an IPv6 only ORPort thus we need to add a
+ * bogus IPv4 at the moment. */
+ config_line_append(&options->ORPort_lines, "ORPort", "1.1.1.1:9001");
+ }
+
+ ret = parse_ports(options, 0, &msg, &n, &w);
+ tt_int_op(ret, OP_EQ, 0);
+ }
+ tor_addr_parse(&test_addr, ret_get_interface_address6_08080808[p->idx]);
+
+ MOCK(get_interface_address6, get_interface_address6_08080808);
+
+ prev_n_get_interface_address6 = n_get_interface_address6;
+
+ retval = find_my_address(options, p->family, LOG_NOTICE, &resolved_addr,
+ &method_used, &hostname_out);
+
+ tt_int_op(n_get_interface_address6, OP_EQ, ++prev_n_get_interface_address6);
+ VALIDATE_FOUND_ADDRESS(true, "INTERFACE", NULL);
+ CLEANUP_FOUND_ADDRESS;
+
+ UNMOCK(get_interface_address6);
UNMOCK(tor_gethostname);
+ UNMOCK(tor_addr_lookup);
done:
- tor_free(options->Address);
- tor_free(options->DirAuthorities);
or_options_free(options);
- tor_free(hostname_out);
UNMOCK(tor_gethostname);
- UNMOCK(tor_lookup_hostname);
- UNMOCK(get_interface_address);
+ UNMOCK(tor_addr_lookup);
UNMOCK(get_interface_address6);
- UNMOCK(tor_gethostname);
}
static void
@@ -6241,9 +6483,14 @@ test_config_getinfo_config_names(void *arg)
tor_free(answer);
}
+#ifndef COCCI
#define CONFIG_TEST(name, flags) \
{ #name, test_config_ ## name, flags, NULL, NULL }
+#define CONFIG_TEST_SETUP(suffix, name, flags, setup, setup_data) \
+ { #name#suffix, test_config_ ## name, flags, setup, setup_data }
+#endif
+
struct testcase_t config_tests[] = {
CONFIG_TEST(adding_trusted_dir_server, TT_FORK),
CONFIG_TEST(adding_fallback_dir_server, TT_FORK),
@@ -6254,7 +6501,11 @@ struct testcase_t config_tests[] = {
CONFIG_TEST(adding_dir_servers, TT_FORK),
CONFIG_TEST(default_dir_servers, TT_FORK),
CONFIG_TEST(default_fallback_dirs, 0),
- CONFIG_TEST(resolve_my_address, TT_FORK),
+ CONFIG_TEST_SETUP(_v4, find_my_address, TT_FORK,
+ &passthrough_setup, &addr_param_v4),
+ CONFIG_TEST_SETUP(_v6, find_my_address, TT_FORK,
+ &passthrough_setup, &addr_param_v6),
+ CONFIG_TEST(find_my_address_mixed, TT_FORK),
CONFIG_TEST(addressmap, 0),
CONFIG_TEST(parse_bridge_line, 0),
CONFIG_TEST(parse_transport_options_line, 0),
diff --git a/src/test/test_controller.c b/src/test/test_controller.c
index a69ec17db8..49efeb5f88 100644
--- a/src/test/test_controller.c
+++ b/src/test/test_controller.c
@@ -19,6 +19,7 @@
#include "feature/rend/rendservice.h"
#include "feature/nodelist/authcert.h"
#include "feature/nodelist/nodelist.h"
+#include "feature/stats/rephist.h"
#include "test/test.h"
#include "test/test_helpers.h"
#include "lib/net/resolve.h"
@@ -2112,6 +2113,91 @@ test_control_getconf(void *arg)
smartlist_free(reply_strs);
}
+static int
+mock_rep_hist_get_circuit_handshake(uint16_t type)
+{
+ int ret;
+
+ switch (type) {
+ case ONION_HANDSHAKE_TYPE_NTOR:
+ ret = 80;
+ break;
+ case ONION_HANDSHAKE_TYPE_TAP:
+ ret = 86;
+ break;
+ default:
+ ret = 0;
+ break;
+ }
+
+ return ret;
+}
+
+static void
+test_stats(void *arg)
+{
+ /* We just need one of these to pass, it doesn't matter what's in it */
+ control_connection_t dummy;
+ /* Get results out */
+ char *answer = NULL;
+ const char *errmsg = NULL;
+
+ (void) arg;
+
+ /* We need these for returning the (mock) rephist. */
+ MOCK(rep_hist_get_circuit_handshake_requested,
+ mock_rep_hist_get_circuit_handshake);
+ MOCK(rep_hist_get_circuit_handshake_assigned,
+ mock_rep_hist_get_circuit_handshake);
+
+ /* NTor tests */
+ getinfo_helper_rephist(&dummy, "stats/ntor/requested",
+ &answer, &errmsg);
+ tt_ptr_op(answer, OP_NE, NULL);
+ tt_ptr_op(errmsg, OP_EQ, NULL);
+ tt_str_op(answer, OP_EQ, "80");
+ tor_free(answer);
+ errmsg = NULL;
+
+ getinfo_helper_rephist(&dummy, "stats/ntor/assigned",
+ &answer, &errmsg);
+ tt_ptr_op(answer, OP_NE, NULL);
+ tt_ptr_op(errmsg, OP_EQ, NULL);
+ tt_str_op(answer, OP_EQ, "80");
+ tor_free(answer);
+ errmsg = NULL;
+
+ /* TAP tests */
+ getinfo_helper_rephist(&dummy, "stats/tap/requested",
+ &answer, &errmsg);
+ tt_ptr_op(answer, OP_NE, NULL);
+ tt_ptr_op(errmsg, OP_EQ, NULL);
+ tt_str_op(answer, OP_EQ, "86");
+ tor_free(answer);
+ errmsg = NULL;
+
+ getinfo_helper_rephist(&dummy, "stats/tap/assigned",
+ &answer, &errmsg);
+ tt_ptr_op(answer, OP_NE, NULL);
+ tt_ptr_op(errmsg, OP_EQ, NULL);
+ tt_str_op(answer, OP_EQ, "86");
+ tor_free(answer);
+ errmsg = NULL;
+
+ getinfo_helper_rephist(&dummy, "stats/tap/onion_circuits_ddosed",
+ &answer, &errmsg);
+ tt_ptr_op(answer, OP_EQ, NULL);
+ tt_str_op(errmsg, OP_EQ, "Unrecognized handshake type");
+ errmsg = NULL;
+
+ done:
+ UNMOCK(rep_hist_get_circuit_handshake_requested);
+ UNMOCK(rep_hist_get_circuit_handshake_assigned);
+ tor_free(answer);
+
+ return;
+}
+
#ifndef COCCI
#define PARSER_TEST(type) \
{ "parse/" #type, test_controller_parse_cmd, 0, &passthrough_setup, \
@@ -2146,5 +2232,6 @@ struct testcase_t controller_tests[] = {
{ "getinfo_md_all", test_getinfo_md_all, 0, NULL, NULL },
{ "control_reply", test_control_reply, 0, NULL, NULL },
{ "control_getconf", test_control_getconf, 0, NULL, NULL },
+ { "stats", test_stats, 0, NULL, NULL },
END_OF_TESTCASES
};
diff --git a/src/test/test_helpers.c b/src/test/test_helpers.c
index f31c28b24d..14913b4b40 100644
--- a/src/test/test_helpers.c
+++ b/src/test/test_helpers.c
@@ -16,28 +16,35 @@
#include "core/or/or.h"
#include "lib/buf/buffers.h"
-#include "app/config/config.h"
#include "lib/confmgt/confmgt.h"
-#include "app/main/subsysmgr.h"
-#include "core/mainloop/connection.h"
-#include "core/or/connection_or.h"
#include "lib/crypt_ops/crypto_rand.h"
-#include "core/mainloop/mainloop.h"
-#include "feature/nodelist/nodelist.h"
-#include "core/or/relay.h"
-#include "feature/nodelist/routerlist.h"
#include "lib/dispatch/dispatch.h"
#include "lib/dispatch/dispatch_naming.h"
-#include "lib/pubsub/pubsub_build.h"
-#include "lib/pubsub/pubsub_connect.h"
#include "lib/encoding/confline.h"
#include "lib/net/resolve.h"
+#include "lib/pubsub/pubsub_build.h"
+#include "lib/pubsub/pubsub_connect.h"
+
+#include "core/mainloop/connection.h"
+#include "core/mainloop/mainloop.h"
+#include "core/or/connection_or.h"
+#include "core/or/crypt_path.h"
+#include "core/or/relay.h"
+
+#include "feature/nodelist/nodelist.h"
+#include "feature/nodelist/routerlist.h"
+
+#include "app/config/config.h"
+#include "app/main/subsysmgr.h"
#include "core/or/cell_st.h"
#include "core/or/connection_st.h"
+#include "core/or/cpath_build_state_st.h"
+#include "core/or/crypt_path_st.h"
+#include "core/or/origin_circuit_st.h"
#include "core/or/or_connection_st.h"
+
#include "feature/nodelist/node_st.h"
-#include "core/or/origin_circuit_st.h"
#include "feature/nodelist/routerlist_st.h"
#include "test/test.h"
@@ -441,3 +448,36 @@ helper_cleanup_pubsub(const struct testcase_t *testcase, void *dispatcher_)
const struct testcase_setup_t helper_pubsub_setup = {
helper_setup_pubsub, helper_cleanup_pubsub
};
+
+origin_circuit_t *
+new_test_origin_circuit(bool has_opened,
+ struct timeval circ_start_time,
+ int path_len,
+ extend_info_t **ei_list)
+{
+ origin_circuit_t *origin_circ = origin_circuit_new();
+
+ TO_CIRCUIT(origin_circ)->purpose = CIRCUIT_PURPOSE_C_GENERAL;
+
+ origin_circ->build_state = tor_malloc_zero(sizeof(cpath_build_state_t));
+ origin_circ->build_state->desired_path_len = path_len;
+
+ if (ei_list) {
+ for (int i = 0; i < path_len; i++) {
+ extend_info_t *ei = ei_list[i];
+ cpath_append_hop(&origin_circ->cpath, ei);
+ }
+ }
+
+ if (has_opened) {
+ origin_circ->has_opened = 1;
+ TO_CIRCUIT(origin_circ)->state = CIRCUIT_STATE_OPEN;
+ origin_circ->cpath->state = CPATH_STATE_OPEN;
+ } else {
+ TO_CIRCUIT(origin_circ)->timestamp_began = circ_start_time;
+ TO_CIRCUIT(origin_circ)->timestamp_created = circ_start_time;
+ origin_circ->cpath->state = CPATH_STATE_CLOSED;
+ }
+
+ return origin_circ;
+}
diff --git a/src/test/test_helpers.h b/src/test/test_helpers.h
index eaf18e19e2..66007873d1 100644
--- a/src/test/test_helpers.h
+++ b/src/test/test_helpers.h
@@ -40,5 +40,10 @@ int helper_cleanup_pubsub(const struct testcase_t *, void *);
extern const struct testcase_setup_t helper_pubsub_setup;
+origin_circuit_t *new_test_origin_circuit(bool has_opened,
+ struct timeval circ_start_time,
+ int path_len,
+ extend_info_t **ei_list);
+
#endif /* !defined(TOR_TEST_HELPERS_H) */
diff --git a/src/test/test_hs_client.c b/src/test/test_hs_client.c
index ae5cc5ed84..f965344ce0 100644
--- a/src/test/test_hs_client.c
+++ b/src/test/test_hs_client.c
@@ -41,6 +41,7 @@
#include "feature/rend/rendcache.h"
#include "core/or/circuitlist.h"
#include "core/or/circuitbuild.h"
+#include "core/or/extendinfo.h"
#include "core/mainloop/connection.h"
#include "core/or/connection_edge.h"
#include "feature/nodelist/networkstatus.h"
@@ -529,7 +530,7 @@ test_client_pick_intro(void *arg)
get_options_mutable()->ClientUseIPv6 = 1;
intro_ei = hs_get_extend_info_from_lspecs(ip->link_specifiers,
&ip->onion_key, 1);
- tt_assert(tor_addr_family(&intro_ei->addr) == AF_INET6);
+ tt_assert(tor_addr_family(&intro_ei->orports[0].addr) == AF_INET6);
}
tt_assert(intro_ei);
if (intro_ei) {
@@ -537,7 +538,8 @@ test_client_pick_intro(void *arg)
char ip_addr[TOR_ADDR_BUF_LEN];
/* We need to decorate in case it is an IPv6 else routerset_parse()
* doesn't like it. */
- ptr = tor_addr_to_str(ip_addr, &intro_ei->addr, sizeof(ip_addr), 1);
+ ptr = tor_addr_to_str(ip_addr, &intro_ei->orports[0].addr,
+ sizeof(ip_addr), 1);
tt_assert(ptr == ip_addr);
ret = routerset_parse(get_options_mutable()->ExcludeNodes,
ip_addr, "");
diff --git a/src/test/test_hs_service.c b/src/test/test_hs_service.c
index 80383baff8..68ec5af391 100644
--- a/src/test/test_hs_service.c
+++ b/src/test/test_hs_service.c
@@ -1619,7 +1619,7 @@ test_build_update_descriptors(void *arg)
/* We won't test the service IP object because there is a specific test
* already for this but we'll make sure that the state is coherent.*/
- /* Three link specifiers are mandatoy so make sure we do have them. */
+ /* Three link specifiers are mandatory so make sure we do have them. */
tt_int_op(smartlist_len(ip_cur->base.link_specifiers), OP_EQ, 3);
/* Make sure we have a valid encryption keypair generated when we pick an
* intro point in the update process. */
diff --git a/src/test/test_nodelist.c b/src/test/test_nodelist.c
index fbbbf0a99f..93d1ce453b 100644
--- a/src/test/test_nodelist.c
+++ b/src/test/test_nodelist.c
@@ -1182,11 +1182,11 @@ test_nodelist_extend_info_describe(void *arg)
sizeof(mock_ei_ipv4.identity_digest));
strlcpy(mock_ei_ipv4.nickname, "TestOR7890123456789",
sizeof(mock_ei_ipv4.nickname));
- tor_addr_parse(&mock_ei_ipv4.addr, "111.222.233.244");
+ tor_addr_parse(&mock_ei_ipv4.orports[0].addr, "111.222.233.244");
/* Create and modify the other extend info. */
memcpy(&mock_ei_ipv6, &mock_ei_ipv4, sizeof(mock_ei_ipv6));
- tor_addr_parse(&mock_ei_ipv6.addr,
+ tor_addr_parse(&mock_ei_ipv6.orports[0].addr,
"[1111:2222:3333:4444:5555:6666:7777:8888]");
/* We don't test the no-nickname and no-IP cases, because they're covered by
diff --git a/src/test/test_policy.c b/src/test/test_policy.c
index 7949e90e9e..388b5c74c9 100644
--- a/src/test/test_policy.c
+++ b/src/test/test_policy.c
@@ -8,6 +8,7 @@
#include "app/config/config.h"
#include "core/or/circuitbuild.h"
#include "core/or/policies.h"
+#include "core/or/extendinfo.h"
#include "feature/dirparse/policy_parse.h"
#include "feature/hs/hs_common.h"
#include "feature/hs/hs_descriptor.h"
@@ -2084,8 +2085,8 @@ test_policies_fascist_firewall_allows_address(void *arg)
expect_single_log_msg("Specified link specifiers is null"); \
} else { \
expect_no_log_entry(); \
- tt_assert(tor_addr_eq(&(expect_ap).addr, &ei->addr)); \
- tt_int_op((expect_ap).port, OP_EQ, ei->port); \
+ tt_assert(tor_addr_eq(&(expect_ap).addr, &ei->orports[0].addr)); \
+ tt_int_op((expect_ap).port, OP_EQ, ei->orports[0].port); \
extend_info_free(ei); \
} \
teardown_capture_of_logs(); \
diff --git a/src/test/test_process_descs.c b/src/test/test_process_descs.c
index 14865cff13..5c2301f873 100644
--- a/src/test/test_process_descs.c
+++ b/src/test/test_process_descs.c
@@ -38,10 +38,10 @@ test_process_descs_versions(void *arg)
{ "Tor 0.4.0.5", true },
{ "Tor 0.4.1.1-alpha", true },
{ "Tor 0.4.1.4-rc", true },
+ { "Tor 0.4.1.5", true },
// new enough to be supported
{ "Tor 0.3.5.7", false },
{ "Tor 0.3.5.8", false },
- { "Tor 0.4.1.5", false },
{ "Tor 0.4.2.1-alpha", false },
{ "Tor 0.4.2.4-rc", false },
{ "Tor 0.4.3.0-alpha-dev", false },
diff --git a/src/test/test_protover.c b/src/test/test_protover.c
index 8fccae1a45..5e74265550 100644
--- a/src/test/test_protover.c
+++ b/src/test/test_protover.c
@@ -7,14 +7,18 @@
#include "orconfig.h"
#include "test/test.h"
-#include "core/or/protover.h"
+#include "lib/tls/tortls.h"
#include "core/or/or.h"
+
#include "core/or/connection_or.h"
-#include "lib/tls/tortls.h"
+#include "core/or/protover.h"
+#include "core/or/versions.h"
#include "feature/dirauth/dirvote.h"
+#include "feature/relay/relay_handshake.h"
+
static void
test_protover_parse(void *arg)
{
@@ -409,23 +413,21 @@ test_protover_supports_version(void *arg)
* Hard-coded here, because they are not in the code, or not exposed in the
* headers. */
#define PROTOVER_LINKAUTH_V1 1
-#define PROTOVER_LINKAUTH_V3 3
-
+#define PROTOVER_LINKAUTH_V2 2
#define PROTOVER_RELAY_V1 1
-#define PROTOVER_RELAY_V2 2
+/* Deprecated HSIntro versions */
+#define PROTOVER_HS_INTRO_DEPRECATED_1 1
+#define PROTOVER_HS_INTRO_DEPRECATED_2 2
/* Highest supported HSv2 introduce protocol version.
- * Hard-coded here, because it does not appear anywhere in the code.
* It's not clear if we actually support version 2, see #25068. */
-#define PROTOVER_HSINTRO_V2 3
+#define PROTOVER_HS_INTRO_V2 3
-/* HSv2 Rend and HSDir protocol versions.
- * Hard-coded here, because they do not appear anywhere in the code. */
+/* HSv2 Rend and HSDir protocol versions. */
#define PROTOVER_HS_RENDEZVOUS_POINT_V2 1
#define PROTOVER_HSDIR_V2 1
-/* DirCache, Desc, Microdesc, and Cons protocol versions.
- * Hard-coded here, because they do not appear anywhere in the code. */
+/* DirCache, Desc, Microdesc, and Cons protocol versions. */
#define PROTOVER_DIRCACHE_V1 1
#define PROTOVER_DIRCACHE_V2 2
@@ -438,6 +440,10 @@ test_protover_supports_version(void *arg)
#define PROTOVER_CONS_V1 1
#define PROTOVER_CONS_V2 2
+#define PROTOVER_PADDING_V1 1
+
+#define PROTOVER_FLOWCTRL_V1 1
+
/* Make sure we haven't forgotten any supported protocols */
static void
test_protover_supported_protocols(void *arg)
@@ -452,24 +458,27 @@ test_protover_supported_protocols(void *arg)
PRT_LINK,
MAX_LINK_PROTO));
for (uint16_t i = 0; i < MAX_PROTOCOLS_TO_TEST; i++) {
- if (is_or_protocol_version_known(i)) {
- tt_assert(protocol_list_supports_protocol(supported_protocols,
+ tt_int_op(protocol_list_supports_protocol(supported_protocols,
PRT_LINK,
- i));
- }
+ i),
+ OP_EQ,
+ is_or_protocol_version_known(i));
}
-#ifdef HAVE_WORKING_TOR_TLS_GET_TLSSECRETS
- /* Legacy LinkAuth does not appear anywhere in the code. */
- tt_assert(protocol_list_supports_protocol(supported_protocols,
- PRT_LINKAUTH,
- PROTOVER_LINKAUTH_V1));
-#endif /* defined(HAVE_WORKING_TOR_TLS_GET_TLSSECRETS) */
- /* Latest LinkAuth is not exposed in the headers. */
- tt_assert(protocol_list_supports_protocol(supported_protocols,
+ /* Legacy LinkAuth is only supported on OpenSSL and similar. */
+ tt_int_op(protocol_list_supports_protocol(supported_protocols,
PRT_LINKAUTH,
- PROTOVER_LINKAUTH_V3));
- /* Is there any way to test for new LinkAuth? */
+ PROTOVER_LINKAUTH_V1),
+ OP_EQ,
+ authchallenge_type_is_supported(AUTHTYPE_RSA_SHA256_TLSSECRET));
+ /* LinkAuth=2 is unused */
+ tt_assert(!protocol_list_supports_protocol(supported_protocols,
+ PRT_LINKAUTH,
+ PROTOVER_LINKAUTH_V2));
+ tt_assert(
+ protocol_list_supports_protocol(supported_protocols,
+ PRT_LINKAUTH,
+ PROTOVER_LINKAUTH_ED25519_HANDSHAKE));
/* Relay protovers do not appear anywhere in the code. */
tt_assert(protocol_list_supports_protocol(supported_protocols,
@@ -477,20 +486,38 @@ test_protover_supported_protocols(void *arg)
PROTOVER_RELAY_V1));
tt_assert(protocol_list_supports_protocol(supported_protocols,
PRT_RELAY,
- PROTOVER_RELAY_V2));
- /* Is there any way to test for new Relay? */
+ PROTOVER_RELAY_EXTEND2));
+ tt_assert(protocol_list_supports_protocol(supported_protocols,
+ PRT_RELAY,
+ PROTOVER_RELAY_ACCEPT_IPV6));
+ tt_assert(protocol_list_supports_protocol(supported_protocols,
+ PRT_RELAY,
+ PROTOVER_RELAY_EXTEND_IPV6));
+ tt_assert(protocol_list_supports_protocol(supported_protocols,
+ PRT_RELAY,
+ PROTOVER_RELAY_CANONICAL_IPV6));
+ /* These HSIntro versions are deprecated */
+ tt_assert(!protocol_list_supports_protocol(supported_protocols,
+ PRT_HSINTRO,
+ PROTOVER_HS_INTRO_DEPRECATED_1));
+ tt_assert(!protocol_list_supports_protocol(supported_protocols,
+ PRT_HSINTRO,
+ PROTOVER_HS_INTRO_DEPRECATED_2));
/* We could test legacy HSIntro by calling rend_service_update_descriptor(),
* and checking the protocols field. But that's unlikely to change, so
* we just use a hard-coded value. */
tt_assert(protocol_list_supports_protocol(supported_protocols,
PRT_HSINTRO,
- PROTOVER_HSINTRO_V2));
+ PROTOVER_HS_INTRO_V2));
/* Test for HSv3 HSIntro */
tt_assert(protocol_list_supports_protocol(supported_protocols,
PRT_HSINTRO,
PROTOVER_HS_INTRO_V3));
- /* Is there any way to test for new HSIntro? */
+ /* Test for HSIntro DoS */
+ tt_assert(protocol_list_supports_protocol(supported_protocols,
+ PRT_HSINTRO,
+ PROTOVER_HS_INTRO_DOS));
/* Legacy HSRend does not appear anywhere in the code. */
tt_assert(protocol_list_supports_protocol(supported_protocols,
@@ -500,7 +527,6 @@ test_protover_supported_protocols(void *arg)
tt_assert(protocol_list_supports_protocol(supported_protocols,
PRT_HSREND,
PROTOVER_HS_RENDEZVOUS_POINT_V3));
- /* Is there any way to test for new HSRend? */
/* Legacy HSDir does not appear anywhere in the code. */
tt_assert(protocol_list_supports_protocol(supported_protocols,
@@ -510,7 +536,6 @@ test_protover_supported_protocols(void *arg)
tt_assert(protocol_list_supports_protocol(supported_protocols,
PRT_HSDIR,
PROTOVER_HSDIR_V3));
- /* Is there any way to test for new HSDir? */
/* No DirCache versions appear anywhere in the code. */
tt_assert(protocol_list_supports_protocol(supported_protocols,
@@ -519,7 +544,6 @@ test_protover_supported_protocols(void *arg)
tt_assert(protocol_list_supports_protocol(supported_protocols,
PRT_DIRCACHE,
PROTOVER_DIRCACHE_V2));
- /* Is there any way to test for new DirCache? */
/* No Desc versions appear anywhere in the code. */
tt_assert(protocol_list_supports_protocol(supported_protocols,
@@ -537,7 +561,6 @@ test_protover_supported_protocols(void *arg)
tt_assert(protocol_list_supports_protocol(supported_protocols,
PRT_MICRODESC,
PROTOVER_MICRODESC_V2));
- /* Is there any way to test for new Microdesc? */
/* No Cons versions appear anywhere in the code. */
tt_assert(protocol_list_supports_protocol(supported_protocols,
@@ -546,7 +569,19 @@ test_protover_supported_protocols(void *arg)
tt_assert(protocol_list_supports_protocol(supported_protocols,
PRT_CONS,
PROTOVER_CONS_V2));
- /* Is there any way to test for new Cons? */
+
+ /* Padding=1 is deprecated. */
+ tt_assert(!protocol_list_supports_protocol(supported_protocols,
+ PRT_PADDING,
+ PROTOVER_PADDING_V1));
+ tt_assert(protocol_list_supports_protocol(supported_protocols,
+ PRT_PADDING,
+ PROTOVER_HS_SETUP_PADDING));
+
+ /* FlowCtrl */
+ tt_assert(protocol_list_supports_protocol(supported_protocols,
+ PRT_FLOWCTRL,
+ PROTOVER_FLOWCTRL_V1));
done:
;
@@ -676,6 +711,228 @@ test_protover_vote_roundtrip_ours(void *args)
tor_free(result);
}
+/* Stringifies its argument.
+ * 4 -> "4" */
+#define STR(x) #x
+
+#ifdef COCCI
+#define PROTOVER(proto_string, version_macro)
+#else
+/* Generate a protocol version string using proto_string and version_macro.
+ * PROTOVER("HSIntro", PROTOVER_HS_INTRO_DOS) -> "HSIntro" "=" "5"
+ * Uses two levels of macros to turn PROTOVER_HS_INTRO_DOS into "5".
+ */
+#define PROTOVER(proto_string, version_macro) \
+ (proto_string "=" STR(version_macro))
+#endif
+
+#define DEBUG_PROTOVER(flags) \
+ STMT_BEGIN \
+ log_debug(LD_GENERAL, \
+ "protovers:\n" \
+ "protocols_known: %d,\n" \
+ "supports_extend2_cells: %d,\n" \
+ "supports_accepting_ipv6_extends: %d,\n" \
+ "supports_initiating_ipv6_extends: %d,\n" \
+ "supports_canonical_ipv6_conns: %d,\n" \
+ "supports_ed25519_link_handshake_compat: %d,\n" \
+ "supports_ed25519_link_handshake_any: %d,\n" \
+ "supports_ed25519_hs_intro: %d,\n" \
+ "supports_establish_intro_dos_extension: %d,\n" \
+ "supports_v3_hsdir: %d,\n" \
+ "supports_v3_rendezvous_point: %d,\n" \
+ "supports_hs_setup_padding: %d.", \
+ (flags).protocols_known, \
+ (flags).supports_extend2_cells, \
+ (flags).supports_accepting_ipv6_extends, \
+ (flags).supports_initiating_ipv6_extends, \
+ (flags).supports_canonical_ipv6_conns, \
+ (flags).supports_ed25519_link_handshake_compat, \
+ (flags).supports_ed25519_link_handshake_any, \
+ (flags).supports_ed25519_hs_intro, \
+ (flags).supports_establish_intro_dos_extension, \
+ (flags).supports_v3_hsdir, \
+ (flags).supports_v3_rendezvous_point, \
+ (flags).supports_hs_setup_padding); \
+ STMT_END
+
+/* Test that the proto_string version version_macro sets summary_flag. */
+#define TEST_PROTOVER(proto_string, version_macro, summary_flag) \
+ STMT_BEGIN \
+ memset(&flags, 0, sizeof(flags)); \
+ summarize_protover_flags(&flags, \
+ PROTOVER(proto_string, version_macro), \
+ NULL); \
+ DEBUG_PROTOVER(flags); \
+ tt_int_op(flags.protocols_known, OP_EQ, 1); \
+ tt_int_op(flags.summary_flag, OP_EQ, 1); \
+ flags.protocols_known = 0; \
+ flags.summary_flag = 0; \
+ tt_mem_op(&flags, OP_EQ, &zero_flags, sizeof(flags)); \
+ STMT_END
+
+static void
+test_protover_summarize_flags(void *args)
+{
+ (void) args;
+ char pv[30];
+ memset(&pv, 0, sizeof(pv));
+
+ protover_summary_cache_free_all();
+
+ protover_summary_flags_t zero_flags;
+ memset(&zero_flags, 0, sizeof(zero_flags));
+ protover_summary_flags_t flags;
+
+ memset(&flags, 0, sizeof(flags));
+ summarize_protover_flags(&flags, NULL, NULL);
+ DEBUG_PROTOVER(flags);
+ tt_mem_op(&flags, OP_EQ, &zero_flags, sizeof(flags));
+
+ memset(&flags, 0, sizeof(flags));
+ summarize_protover_flags(&flags, "", "");
+ DEBUG_PROTOVER(flags);
+ tt_mem_op(&flags, OP_EQ, &zero_flags, sizeof(flags));
+
+ /* Now check version exceptions */
+
+ /* EXTEND2 cell support */
+ memset(&flags, 0, sizeof(flags));
+ summarize_protover_flags(&flags, NULL, "Tor 0.2.4.8-alpha");
+ DEBUG_PROTOVER(flags);
+ tt_int_op(flags.protocols_known, OP_EQ, 1);
+ tt_int_op(flags.supports_extend2_cells, OP_EQ, 1);
+ /* Now clear those flags, and check the rest are zero */
+ flags.protocols_known = 0;
+ flags.supports_extend2_cells = 0;
+ tt_mem_op(&flags, OP_EQ, &zero_flags, sizeof(flags));
+
+ /* disabling HSDir v3 support for buggy versions */
+ memset(&flags, 0, sizeof(flags));
+ summarize_protover_flags(&flags,
+ PROTOVER("HSDir", PROTOVER_HSDIR_V3),
+ NULL);
+ DEBUG_PROTOVER(flags);
+ tt_int_op(flags.protocols_known, OP_EQ, 1);
+ tt_int_op(flags.supports_v3_hsdir, OP_EQ, 1);
+ /* Now clear those flags, and check the rest are zero */
+ flags.protocols_known = 0;
+ flags.supports_v3_hsdir = 0;
+ tt_mem_op(&flags, OP_EQ, &zero_flags, sizeof(flags));
+
+ memset(&flags, 0, sizeof(flags));
+ summarize_protover_flags(&flags,
+ PROTOVER("HSDir", PROTOVER_HSDIR_V3),
+ "Tor 0.3.0.7");
+ DEBUG_PROTOVER(flags);
+ tt_int_op(flags.protocols_known, OP_EQ, 1);
+ /* Now clear that flag, and check the rest are zero */
+ flags.protocols_known = 0;
+ tt_mem_op(&flags, OP_EQ, &zero_flags, sizeof(flags));
+
+ /* Now check standard summaries */
+
+ /* LinkAuth */
+ memset(&flags, 0, sizeof(flags));
+ summarize_protover_flags(&flags,
+ PROTOVER("LinkAuth",
+ PROTOVER_LINKAUTH_ED25519_HANDSHAKE),
+ NULL);
+ DEBUG_PROTOVER(flags);
+ tt_int_op(flags.protocols_known, OP_EQ, 1);
+ tt_int_op(flags.supports_ed25519_link_handshake_compat, OP_EQ, 1);
+ tt_int_op(flags.supports_ed25519_link_handshake_any, OP_EQ, 1);
+ /* Now clear those flags, and check the rest are zero */
+ flags.protocols_known = 0;
+ flags.supports_ed25519_link_handshake_compat = 0;
+ flags.supports_ed25519_link_handshake_any = 0;
+ tt_mem_op(&flags, OP_EQ, &zero_flags, sizeof(flags));
+
+ /* Test one greater */
+ memset(&flags, 0, sizeof(flags));
+ snprintf(pv, sizeof(pv),
+ "%s=%d", "LinkAuth", PROTOVER_LINKAUTH_ED25519_HANDSHAKE + 1);
+ summarize_protover_flags(&flags, pv, NULL);
+ DEBUG_PROTOVER(flags);
+ tt_int_op(flags.protocols_known, OP_EQ, 1);
+ tt_int_op(flags.supports_ed25519_link_handshake_compat, OP_EQ, 0);
+ tt_int_op(flags.supports_ed25519_link_handshake_any, OP_EQ, 1);
+ /* Now clear those flags, and check the rest are zero */
+ flags.protocols_known = 0;
+ flags.supports_ed25519_link_handshake_compat = 0;
+ flags.supports_ed25519_link_handshake_any = 0;
+ tt_mem_op(&flags, OP_EQ, &zero_flags, sizeof(flags));
+
+ /* Test one less */
+ memset(&flags, 0, sizeof(flags));
+ snprintf(pv, sizeof(pv),
+ "%s=%d", "LinkAuth", PROTOVER_LINKAUTH_ED25519_HANDSHAKE - 1);
+ summarize_protover_flags(&flags, pv, NULL);
+ DEBUG_PROTOVER(flags);
+ tt_int_op(flags.protocols_known, OP_EQ, 1);
+ tt_int_op(flags.supports_ed25519_link_handshake_compat, OP_EQ, 0);
+ tt_int_op(flags.supports_ed25519_link_handshake_any, OP_EQ, 0);
+ /* Now clear those flags, and check the rest are zero */
+ flags.protocols_known = 0;
+ flags.supports_ed25519_link_handshake_compat = 0;
+ flags.supports_ed25519_link_handshake_any = 0;
+ tt_mem_op(&flags, OP_EQ, &zero_flags, sizeof(flags));
+
+ /* We don't test "one more" and "one less" for each protocol version.
+ * But that could be a useful thing to add. */
+
+ /* Relay */
+ memset(&flags, 0, sizeof(flags));
+ /* This test relies on these versions being equal */
+ tt_int_op(PROTOVER_RELAY_EXTEND2, OP_EQ, PROTOVER_RELAY_ACCEPT_IPV6);
+ summarize_protover_flags(&flags,
+ PROTOVER("Relay", PROTOVER_RELAY_EXTEND2), NULL);
+ DEBUG_PROTOVER(flags);
+ tt_int_op(flags.protocols_known, OP_EQ, 1);
+ tt_int_op(flags.supports_extend2_cells, OP_EQ, 1);
+ tt_int_op(flags.supports_accepting_ipv6_extends, OP_EQ, 1);
+ /* Now clear those flags, and check the rest are zero */
+ flags.protocols_known = 0;
+ flags.supports_extend2_cells = 0;
+ flags.supports_accepting_ipv6_extends = 0;
+ tt_mem_op(&flags, OP_EQ, &zero_flags, sizeof(flags));
+
+ memset(&flags, 0, sizeof(flags));
+ /* This test relies on these versions being equal */
+ tt_int_op(PROTOVER_RELAY_EXTEND_IPV6, OP_EQ, PROTOVER_RELAY_CANONICAL_IPV6);
+ summarize_protover_flags(&flags,
+ PROTOVER("Relay", PROTOVER_RELAY_EXTEND_IPV6),
+ NULL);
+ DEBUG_PROTOVER(flags);
+ tt_int_op(flags.protocols_known, OP_EQ, 1);
+ tt_int_op(flags.supports_accepting_ipv6_extends, OP_EQ, 1);
+ tt_int_op(flags.supports_initiating_ipv6_extends, OP_EQ, 1);
+ tt_int_op(flags.supports_canonical_ipv6_conns, OP_EQ, 1);
+ /* Now clear those flags, and check the rest are zero */
+ flags.protocols_known = 0;
+ flags.supports_accepting_ipv6_extends = 0;
+ flags.supports_initiating_ipv6_extends = 0;
+ flags.supports_canonical_ipv6_conns = 0;
+ tt_mem_op(&flags, OP_EQ, &zero_flags, sizeof(flags));
+
+ TEST_PROTOVER("HSIntro", PROTOVER_HS_INTRO_V3,
+ supports_ed25519_hs_intro);
+ TEST_PROTOVER("HSIntro", PROTOVER_HS_INTRO_DOS,
+ supports_establish_intro_dos_extension);
+
+ TEST_PROTOVER("HSRend", PROTOVER_HS_RENDEZVOUS_POINT_V3,
+ supports_v3_rendezvous_point);
+
+ TEST_PROTOVER("HSDir", PROTOVER_HSDIR_V3,
+ supports_v3_hsdir);
+
+ TEST_PROTOVER("Padding", PROTOVER_HS_SETUP_PADDING,
+ supports_hs_setup_padding);
+
+ done:
+ ;
+}
+
#define PV_TEST(name, flags) \
{ #name, test_protover_ ##name, (flags), NULL, NULL }
@@ -690,5 +947,7 @@ struct testcase_t protover_tests[] = {
PV_TEST(supported_protocols, 0),
PV_TEST(vote_roundtrip, 0),
PV_TEST(vote_roundtrip_ours, 0),
+ /* fork, because we memoize flags internally */
+ PV_TEST(summarize_flags, TT_FORK),
END_OF_TESTCASES
};
diff --git a/src/test/test_routerkeys.c b/src/test/test_routerkeys.c
index fc437dccc0..bafc886bc6 100644
--- a/src/test/test_routerkeys.c
+++ b/src/test/test_routerkeys.c
@@ -51,7 +51,7 @@ test_routerkeys_write_fingerprint(void *arg)
tt_int_op(crypto_pk_cmp_keys(get_server_identity_key(),key),OP_EQ,0);
/* Write fingerprint file */
- tt_int_op(0, OP_EQ, router_write_fingerprint(0));
+ tt_int_op(0, OP_EQ, router_write_fingerprint(0, 0));
cp = read_file_to_str(get_fname("write_fingerprint/fingerprint"),
0, NULL);
crypto_pk_get_fingerprint(key, fp, 0);
@@ -61,7 +61,7 @@ test_routerkeys_write_fingerprint(void *arg)
tor_free(cp2);
/* Write hashed-fingerprint file */
- tt_int_op(0, OP_EQ, router_write_fingerprint(1));
+ tt_int_op(0, OP_EQ, router_write_fingerprint(1, 0));
cp = read_file_to_str(get_fname("write_fingerprint/hashed-fingerprint"),
0, NULL);
crypto_pk_get_hashed_fingerprint(key, fp);
@@ -73,7 +73,7 @@ test_routerkeys_write_fingerprint(void *arg)
/* Replace outdated file */
write_str_to_file(get_fname("write_fingerprint/hashed-fingerprint"),
"junk goes here", 0);
- tt_int_op(0, OP_EQ, router_write_fingerprint(1));
+ tt_int_op(0, OP_EQ, router_write_fingerprint(1, 0));
cp = read_file_to_str(get_fname("write_fingerprint/hashed-fingerprint"),
0, NULL);
crypto_pk_get_hashed_fingerprint(key, fp);
@@ -90,6 +90,52 @@ test_routerkeys_write_fingerprint(void *arg)
}
static void
+test_routerkeys_write_ed25519_identity(void *arg)
+{
+ crypto_pk_t *key = pk_generate(2);
+ or_options_t *options = get_options_mutable();
+ time_t now = time(NULL);
+ const char *ddir = get_fname("write_fingerprint");
+ char *cp = NULL, *cp2 = NULL;
+ char ed25519_id[BASE64_DIGEST256_LEN + 1];
+
+ (void) arg;
+
+ tt_assert(key);
+
+ options->ORPort_set = 1; /* So that we can get the server ID key */
+ tor_free(options->DataDirectory);
+ options->DataDirectory = tor_strdup(ddir);
+ options->Nickname = tor_strdup("haflinger");
+ set_server_identity_key(key);
+ set_client_identity_key(crypto_pk_dup_key(key));
+
+ load_ed_keys(options, now);
+ generate_ed_link_cert(options, now, 0);
+ tt_assert(get_master_identity_key());
+
+ tt_int_op(0, OP_EQ, check_private_dir(ddir, CPD_CREATE, NULL));
+
+ /* Write fingerprint file */
+ tt_int_op(0, OP_EQ, router_write_fingerprint(0, 1));
+ cp = read_file_to_str(get_fname("write_fingerprint/fingerprint-ed25519"),
+ 0, NULL);
+ digest256_to_base64(ed25519_id,
+ (const char *) get_master_identity_key()->pubkey);
+ tor_asprintf(&cp2, "haflinger %s\n", ed25519_id);
+ tt_str_op(cp, OP_EQ, cp2);
+ tor_free(cp);
+ tor_free(cp2);
+
+ done:
+ crypto_pk_free(key);
+ set_client_identity_key(NULL);
+ tor_free(cp);
+ tor_free(cp2);
+ routerkeys_free_all();
+}
+
+static void
test_routerkeys_ed_certs(void *args)
{
(void)args;
@@ -695,6 +741,7 @@ test_routerkeys_rsa_ed_crosscert(void *arg)
struct testcase_t routerkeys_tests[] = {
TEST(write_fingerprint, TT_FORK),
+ TEST(write_ed25519_identity, TT_FORK),
TEST(ed_certs, TT_FORK),
TEST(ed_key_create, TT_FORK),
TEST(ed_key_init_basic, TT_FORK),
diff --git a/src/test/test_routerset.c b/src/test/test_routerset.c
index 892ac6e210..7601d5ba0f 100644
--- a/src/test/test_routerset.c
+++ b/src/test/test_routerset.c
@@ -1417,12 +1417,62 @@ test_rset_contains_router(void *arg)
ri.nickname = (char *)nickname;
r = routerset_contains_router(set, &ri, country);
-
tt_int_op(r, OP_EQ, 4);
+
done:
routerset_free(set);
}
+static void
+test_rset_contains_router_ipv4(void *arg)
+{
+ routerset_t *set;
+ routerinfo_t ri;
+ country_t country = 1;
+ int r;
+ const char *s;
+ (void) arg;
+
+ /* IPv4 address test. */
+ memset(&ri, 0, sizeof(ri));
+ set = routerset_new();
+ s = "10.0.0.1";
+ r = routerset_parse(set, s, "");
+ ri.addr = htonl(0x0a000001); /* 10.0.0.1 */
+ ri.or_port = 1234;
+
+ r = routerset_contains_router(set, &ri, country);
+ tt_int_op(r, OP_EQ, 3);
+
+ done:
+ routerset_free(set);
+}
+
+static void
+test_rset_contains_router_ipv6(void *arg)
+{
+ routerset_t *set;
+ routerinfo_t ri;
+ country_t country = 1;
+ int r;
+ const char *s;
+ (void) arg;
+
+ /* IPv6 address test. */
+ memset(&ri, 0, sizeof(ri));
+ set = routerset_new();
+ s = "2600::1";
+ r = routerset_parse(set, s, "");
+ tor_addr_parse(&ri.ipv6_addr, "2600::1");
+ ri.ipv6_orport = 12345;
+
+ r = routerset_contains_router(set, &ri, country);
+ tt_int_op(r, OP_EQ, 3);
+
+ done:
+ routerset_free(set);
+}
+
/*
* Functional test for routerset_contains_routerstatus.
*/
@@ -2144,6 +2194,10 @@ struct testcase_t routerset_tests[] = {
{ "contains_extendinfo", test_rset_contains_extendinfo,
TT_FORK, NULL, NULL },
{ "contains_router", test_rset_contains_router, TT_FORK, NULL, NULL },
+ { "contains_router_ipv4", test_rset_contains_router_ipv4,
+ TT_FORK, NULL, NULL },
+ { "contains_router_ipv6", test_rset_contains_router_ipv6,
+ TT_FORK, NULL, NULL },
{ "contains_routerstatus", test_rset_contains_routerstatus,
TT_FORK, NULL, NULL },
{ "contains_none", test_rset_contains_none, TT_FORK, NULL, NULL },
diff --git a/src/trunnel/circpad_negotiation.c b/src/trunnel/circpad_negotiation.c
index 547818f2ec..4e3ee3d5bd 100644
--- a/src/trunnel/circpad_negotiation.c
+++ b/src/trunnel/circpad_negotiation.c
@@ -112,6 +112,17 @@ circpad_negotiate_set_echo_request(circpad_negotiate_t *inp, uint8_t val)
inp->echo_request = val;
return 0;
}
+uint32_t
+circpad_negotiate_get_machine_ctr(const circpad_negotiate_t *inp)
+{
+ return inp->machine_ctr;
+}
+int
+circpad_negotiate_set_machine_ctr(circpad_negotiate_t *inp, uint32_t val)
+{
+ inp->machine_ctr = val;
+ return 0;
+}
const char *
circpad_negotiate_check(const circpad_negotiate_t *obj)
{
@@ -148,6 +159,9 @@ circpad_negotiate_encoded_len(const circpad_negotiate_t *obj)
/* Length of u8 echo_request IN [0, 1] */
result += 1;
+
+ /* Length of u32 machine_ctr */
+ result += 4;
return result;
}
int
@@ -203,6 +217,13 @@ circpad_negotiate_encode(uint8_t *output, const size_t avail, const circpad_nego
trunnel_set_uint8(ptr, (obj->echo_request));
written += 1; ptr += 1;
+ /* Encode u32 machine_ctr */
+ trunnel_assert(written <= avail);
+ if (avail - written < 4)
+ goto truncated;
+ trunnel_set_uint32(ptr, trunnel_htonl(obj->machine_ctr));
+ written += 4; ptr += 4;
+
trunnel_assert(ptr == output + written);
#ifdef TRUNNEL_CHECK_ENCODED_LEN
@@ -263,6 +284,11 @@ circpad_negotiate_parse_into(circpad_negotiate_t *obj, const uint8_t *input, con
remaining -= 1; ptr += 1;
if (! (obj->echo_request == 0 || obj->echo_request == 1))
goto fail;
+
+ /* Parse u32 machine_ctr */
+ CHECK_REMAINING(4, truncated);
+ obj->machine_ctr = trunnel_ntohl(trunnel_get_uint32(ptr));
+ remaining -= 4; ptr += 4;
trunnel_assert(ptr + remaining == input + len_in);
return len_in - remaining;
@@ -372,6 +398,17 @@ circpad_negotiated_set_machine_type(circpad_negotiated_t *inp, uint8_t val)
inp->machine_type = val;
return 0;
}
+uint32_t
+circpad_negotiated_get_machine_ctr(const circpad_negotiated_t *inp)
+{
+ return inp->machine_ctr;
+}
+int
+circpad_negotiated_set_machine_ctr(circpad_negotiated_t *inp, uint32_t val)
+{
+ inp->machine_ctr = val;
+ return 0;
+}
const char *
circpad_negotiated_check(const circpad_negotiated_t *obj)
{
@@ -408,6 +445,9 @@ circpad_negotiated_encoded_len(const circpad_negotiated_t *obj)
/* Length of u8 machine_type */
result += 1;
+
+ /* Length of u32 machine_ctr */
+ result += 4;
return result;
}
int
@@ -463,6 +503,13 @@ circpad_negotiated_encode(uint8_t *output, const size_t avail, const circpad_neg
trunnel_set_uint8(ptr, (obj->machine_type));
written += 1; ptr += 1;
+ /* Encode u32 machine_ctr */
+ trunnel_assert(written <= avail);
+ if (avail - written < 4)
+ goto truncated;
+ trunnel_set_uint32(ptr, trunnel_htonl(obj->machine_ctr));
+ written += 4; ptr += 4;
+
trunnel_assert(ptr == output + written);
#ifdef TRUNNEL_CHECK_ENCODED_LEN
@@ -523,6 +570,11 @@ circpad_negotiated_parse_into(circpad_negotiated_t *obj, const uint8_t *input, c
CHECK_REMAINING(1, truncated);
obj->machine_type = (trunnel_get_uint8(ptr));
remaining -= 1; ptr += 1;
+
+ /* Parse u32 machine_ctr */
+ CHECK_REMAINING(4, truncated);
+ obj->machine_ctr = trunnel_ntohl(trunnel_get_uint32(ptr));
+ remaining -= 4; ptr += 4;
trunnel_assert(ptr + remaining == input + len_in);
return len_in - remaining;
diff --git a/src/trunnel/circpad_negotiation.h b/src/trunnel/circpad_negotiation.h
index ba9155019e..9004540d43 100644
--- a/src/trunnel/circpad_negotiation.h
+++ b/src/trunnel/circpad_negotiation.h
@@ -26,6 +26,7 @@ struct circpad_negotiate_st {
uint8_t machine_type;
/** If true, send a relay_drop reply.. */
uint8_t echo_request;
+ uint32_t machine_ctr;
uint8_t trunnel_error_code_;
};
#endif
@@ -42,6 +43,14 @@ struct circpad_negotiated_st {
/** Machine type is left unbounded because we can specify
* new machines in the consensus */
uint8_t machine_type;
+ /**
+ * This field is used for shutdown synchronization. It is OK if
+ * it wraps, because all we need to do is make sure the STOP
+ * command is actually for the currently active machine.
+ * For backward-compatibility, though, 0 has special meaning
+ * (it means match any machine).
+ */
+ uint32_t machine_ctr;
uint8_t trunnel_error_code_;
};
#endif
@@ -118,6 +127,15 @@ uint8_t circpad_negotiate_get_echo_request(const circpad_negotiate_t *inp);
* code on 'inp' on failure.
*/
int circpad_negotiate_set_echo_request(circpad_negotiate_t *inp, uint8_t val);
+/** Return the value of the machine_ctr field of the
+ * circpad_negotiate_t in 'inp'
+ */
+uint32_t circpad_negotiate_get_machine_ctr(const circpad_negotiate_t *inp);
+/** Set the value of the machine_ctr field of the circpad_negotiate_t
+ * in 'inp' to 'val'. Return 0 on success; return -1 and set the error
+ * code on 'inp' on failure.
+ */
+int circpad_negotiate_set_machine_ctr(circpad_negotiate_t *inp, uint32_t val);
/** Return a newly allocated circpad_negotiated with all elements set
* to zero.
*/
@@ -190,6 +208,15 @@ uint8_t circpad_negotiated_get_machine_type(const circpad_negotiated_t *inp);
* -1 and set the error code on 'inp' on failure.
*/
int circpad_negotiated_set_machine_type(circpad_negotiated_t *inp, uint8_t val);
+/** Return the value of the machine_ctr field of the
+ * circpad_negotiated_t in 'inp'
+ */
+uint32_t circpad_negotiated_get_machine_ctr(const circpad_negotiated_t *inp);
+/** Set the value of the machine_ctr field of the circpad_negotiated_t
+ * in 'inp' to 'val'. Return 0 on success; return -1 and set the error
+ * code on 'inp' on failure.
+ */
+int circpad_negotiated_set_machine_ctr(circpad_negotiated_t *inp, uint32_t val);
#endif
diff --git a/src/trunnel/circpad_negotiation.trunnel b/src/trunnel/circpad_negotiation.trunnel
index abbc929cc5..68fed6a013 100644
--- a/src/trunnel/circpad_negotiation.trunnel
+++ b/src/trunnel/circpad_negotiation.trunnel
@@ -27,6 +27,13 @@ struct circpad_negotiate {
// FIXME-MP-AP: Maybe we just say to transition to the first state
// here instead.. Also what about delay before responding?
u8 echo_request IN [0,1];
+
+ // This field is used for shutdown synchronization. It is OK if
+ // it wraps, because all we need to do is make sure the STOP
+ // command is actually for the currently active machine.
+ // For backward-compatibility, though, 0 has special meaning
+ // (it means match any machine).
+ u32 machine_ctr;
};
/**
@@ -41,4 +48,14 @@ struct circpad_negotiated {
/** Machine type is left unbounded because we can specify
* new machines in the consensus */
u8 machine_type;
+
+ /**
+ * This field is used for shutdown synchronization. It is OK if
+ * it wraps, because all we need to do is make sure the STOP
+ * command is actually for the currently active machine.
+ * For backward-compatibility, though, 0 has special meaning
+ * (it means match any machine).
+ */
+ u32 machine_ctr;
+
};
diff --git a/src/win32/orconfig.h b/src/win32/orconfig.h
index beb2561eec..3c7b2ab5fc 100644
--- a/src/win32/orconfig.h
+++ b/src/win32/orconfig.h
@@ -217,7 +217,7 @@
#define USING_TWOS_COMPLEMENT
/* Version number of package */
-#define VERSION "0.4.4.2-alpha"
+#define VERSION "0.4.5.0-alpha-dev"
#define HAVE_STRUCT_SOCKADDR_IN6
#define HAVE_STRUCT_IN6_ADDR