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/ticket329105
-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/ticket332634
-rw-r--r--changes/ticket332644
-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/ticket339193
-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--changes/ticket400224
-rw-r--r--configure.ac94
-rw-r--r--contrib/win32build/tor-mingw.nsi.in2
-rw-r--r--doc/HACKING/CircuitPaddingQuickStart.md22
-rw-r--r--doc/HACKING/CodeStructure.md123
-rw-r--r--doc/HACKING/CodingStandards.md117
-rw-r--r--doc/HACKING/CodingStandardsRust.md262
-rw-r--r--doc/HACKING/Fuzzing.md38
-rw-r--r--doc/HACKING/GettingStarted.md8
-rw-r--r--doc/HACKING/GettingStartedRust.md40
-rw-r--r--doc/HACKING/HelpfulTools.md130
-rw-r--r--doc/HACKING/Module.md6
-rw-r--r--doc/HACKING/README.1st.md4
-rw-r--r--doc/HACKING/ReleasingTor.md15
-rw-r--r--doc/HACKING/Tracing.md166
-rw-r--r--doc/HACKING/WritingTests.md148
-rw-r--r--doc/HACKING/android/Simpleperf.md8
-rw-r--r--doc/include.am1
-rw-r--r--doc/tor.1.txt29
-rwxr-xr-xscripts/git/git-install-tools.sh4
-rwxr-xr-xscripts/git/git-list-tor-branches.sh6
-rwxr-xr-xscripts/git/git-pull-all.sh16
-rwxr-xr-xscripts/git/git-setup-dirs.sh31
-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.txt23
-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/or_state_st.h8
-rw-r--r--src/app/config/resolve_addr.c905
-rw-r--r--src/app/config/resolve_addr.h23
-rw-r--r--src/app/config/statefile.c14
-rw-r--r--src/app/config/testnet.inc1
-rw-r--r--src/app/include.am4
-rw-r--r--src/app/main/main.c17
-rw-r--r--src/app/main/shutdown.c2
-rw-r--r--src/app/main/subsystem_list.c3
-rw-r--r--src/core/crypto/onion_crypto.c2
-rw-r--r--src/core/mainloop/connection.c17
-rw-r--r--src/core/mainloop/mainloop.c3
-rw-r--r--src/core/or/channel.c11
-rw-r--r--src/core/or/channel.h9
-rw-r--r--src/core/or/channelpadding.c2
-rw-r--r--src/core/or/channelpadding.h3
-rw-r--r--src/core/or/channeltls.c154
-rw-r--r--src/core/or/circuit_st.h6
-rw-r--r--src/core/or/circuitbuild.c425
-rw-r--r--src/core/or/circuitbuild.h27
-rw-r--r--src/core/or/circuitlist.c22
-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.c42
-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.am9
-rw-r--r--src/core/or/lttng_circuit.inc322
-rw-r--r--src/core/or/onion.h3
-rw-r--r--src/core/or/or.h21
-rw-r--r--src/core/or/protover.c16
-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/trace_probes_circuit.c30
-rw-r--r--src/core/or/trace_probes_circuit.h22
-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.c40
-rw-r--r--src/feature/nodelist/dirlist.h5
-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.c9
-rw-r--r--src/feature/relay/relay_find_addr.c95
-rw-r--r--src/feature/relay/relay_find_addr.h4
-rw-r--r--src/feature/relay/relay_periodic.c48
-rw-r--r--src/feature/relay/router.c138
-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/bwhist.c592
-rw-r--r--src/feature/stats/bwhist.h40
-rw-r--r--src/feature/stats/connstats.c283
-rw-r--r--src/feature/stats/connstats.h25
-rw-r--r--src/feature/stats/include.am4
-rw-r--r--src/feature/stats/predict_ports.c4
-rw-r--r--src/feature/stats/rephist.c820
-rw-r--r--src/feature/stats/rephist.h28
-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/lib/trace/.may_include1
-rw-r--r--src/lib/trace/debug.h30
-rw-r--r--src/lib/trace/events.h84
-rw-r--r--src/lib/trace/include.am26
-rw-r--r--src/lib/trace/lttng/include.am3
-rw-r--r--src/lib/trace/lttng/lttng.h28
-rw-r--r--src/lib/trace/trace.c8
-rw-r--r--src/lib/trace/trace.h30
-rw-r--r--src/lib/trace/trace_stub.c19
-rw-r--r--src/lib/trace/trace_sys.c36
-rw-r--r--src/lib/trace/trace_sys.h22
-rw-r--r--src/lib/trace/usdt/include.am3
-rw-r--r--src/lib/trace/usdt/usdt.h33
-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/fuzz/include.am2
-rw-r--r--src/test/include.am18
-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_addr.c1
-rw-r--r--src/test/test_address.c10
-rw-r--r--src/test/test_channel.c56
-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_dos.c2
-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_relay.c4
-rw-r--r--src/test/test_router.c6
-rw-r--r--src/test/test_routerkeys.c53
-rw-r--r--src/test/test_routerset.c56
-rw-r--r--src/test/test_stats.c45
-rw-r--r--src/test/testing_common.c2
-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
297 files changed, 8792 insertions, 3609 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/ticket32910 b/changes/ticket32910
new file mode 100644
index 0000000000..e3d64d4333
--- /dev/null
+++ b/changes/ticket32910
@@ -0,0 +1,5 @@
+ o Major feature (tracing):
+ - Add a tracing library with USDT and LTTng-UST support. Few tracepoints
+ were added in the circuit subsystem. More will come incrementally. This
+ feature is compiled out by default. It needs to be enabled at configure
+ time. See documentation in doc/HACKING/Tracing.md. Closes ticket 32910.
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/ticket33263 b/changes/ticket33263
new file mode 100644
index 0000000000..ab5d9c9693
--- /dev/null
+++ b/changes/ticket33263
@@ -0,0 +1,4 @@
+ o Minor features (statistics, ipv6):
+ - Relays now publish their IPv6 read and write statistics over time,
+ if statistics are enabled.
+ Closes ticket 33263.
diff --git a/changes/ticket33264 b/changes/ticket33264
new file mode 100644
index 0000000000..c72ea1c57a
--- /dev/null
+++ b/changes/ticket33264
@@ -0,0 +1,4 @@
+ o Minor features (statistics, ipv6):
+ - Relays now publish IPv6-specific counts of single-direction
+ versus bidirectional relay connections.
+ Closes ticket 33264.
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/ticket33919 b/changes/ticket33919
new file mode 100644
index 0000000000..a9991b7419
--- /dev/null
+++ b/changes/ticket33919
@@ -0,0 +1,3 @@
+ o Minor features (testing):
+ - Added unit tests for channel_matches_target_addr_for_extend().
+ Closes Ticket 33919. Patch by MrSquanchee.
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/changes/ticket40022 b/changes/ticket40022
new file mode 100644
index 0000000000..aa7bb256e6
--- /dev/null
+++ b/changes/ticket40022
@@ -0,0 +1,4 @@
+ o Minor feature (relay):
+ - If a relay is unable to discover its address, attempt to learn it from the
+ NETINFO cell. Closes ticket 40022.
+
diff --git a/configure.ac b/configure.ac
index 723c4ebbdb..75fd709f9b 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-dev])
+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-dev
+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
@@ -256,15 +256,69 @@ AC_ARG_ENABLE(seccomp,
AC_ARG_ENABLE(libscrypt,
AS_HELP_STRING(--disable-libscrypt, [do not attempt to use libscrypt]))
-dnl Enable event tracing which are transformed to debug log statement.
-AC_ARG_ENABLE(event-tracing-debug,
- AS_HELP_STRING(--enable-event-tracing-debug, [build with event tracing to debug log]))
-AM_CONDITIONAL([USE_EVENT_TRACING_DEBUG], [test "x$enable_event_tracing_debug" = "xyes"])
-
-if test x$enable_event_tracing_debug = xyes; then
- AC_DEFINE([USE_EVENT_TRACING_DEBUG], [1], [Tracing framework to log debug])
- AC_DEFINE([TOR_EVENT_TRACING_ENABLED], [1], [Compile the event tracing instrumentation])
-fi
+dnl --- Tracing Options. ---
+
+TOR_TRACE_LIBS=
+
+dnl LTTng instrumentation option.
+AC_ARG_ENABLE(tracing-instrumentation-lttng,
+ AS_HELP_STRING([--enable-tracing-instrumentation-lttng],
+ [build with LTTng-UST instrumentation]))
+AM_CONDITIONAL([USE_TRACING_INSTRUMENTATION_LTTNG],
+ [test "x$enable_tracing_instrumentation_lttng" = "xyes"])
+
+if test "x$enable_tracing_instrumentation_lttng" = "xyes"; then
+ AC_CHECK_HEADERS([lttng/tracepoint.h], [],
+ [AC_MSG_ERROR([LTTng instrumentation headers not found.
+ On Debian, apt install liblttng-ust-dev"])], [])
+ AC_DEFINE([USE_TRACING_INSTRUMENTATION_LTTNG], [1], [Using LTTng instrumentation])
+ TOR_TRACE_LIBS="-llttng-ust -ldl"
+ have_tracing=1
+fi
+
+dnl USDT instrumentation option.
+AC_ARG_ENABLE(tracing-instrumentation-usdt,
+ AS_HELP_STRING([--enable-tracing-instrumentation-usdt],
+ [build with tracing USDT instrumentation]))
+AM_CONDITIONAL([USE_TRACING_INSTRUMENTATION_USDT],
+ [test "x$enable_tracing_instrumentation_usdt" = "xyes"])
+
+if test "x$enable_tracing_instrumentation_usdt" = "xyes"; then
+ AC_CHECK_HEADERS([sys/sdt.h], [],
+ [AC_MSG_ERROR([USDT instrumentation requires sys/sdt.h header.
+ On Debian, apt install systemtap-sdt-dev])], [])
+ dnl LTTng generates USDT probes if the UST library was built with
+ dnl --with-sdt. There is unfortunately no way to check that so we always
+ dnl build the USDT probes even though LTTng instrumentation was requested.
+ AC_DEFINE([USE_TRACING_INSTRUMENTATION_USDT], [1], [Using USDT instrumentation])
+ have_tracing=1
+fi
+
+dnl Tracepoints event to debug logs.
+AC_ARG_ENABLE(tracing-instrumentation-log-debug,
+ AS_HELP_STRING([--enable-tracing-instrumentation-log-debug],
+ [build with tracing event to debug log]),
+ AC_DEFINE([USE_TRACING_INSTRUMENTATION_LOG_DEBUG], [1],
+ [Tracepoints to log debug]), [])
+AM_CONDITIONAL([USE_TRACING_INSTRUMENTATION_LOG_DEBUG],
+ [test "x$enable_tracing_instrumentation_log_debug" = "xyes"])
+if test "x$enable_tracing_instrumentation_log_debug" = "xyes"; then
+ have_tracing=1
+fi
+
+dnl Define that tracing is supported if any instrumentation is used.
+AM_COND_IF([USE_TRACING_INSTRUMENTATION_LOG_DEBUG],
+ AC_DEFINE([HAVE_TRACING], [1], [Compiled with tracing support]))
+AM_COND_IF([USE_TRACING_INSTRUMENTATION_USDT],
+ AC_DEFINE([HAVE_TRACING], [1], [Compiled with tracing support]))
+AM_COND_IF([USE_TRACING_INSTRUMENTATION_LTTNG],
+ AC_DEFINE([HAVE_TRACING], [1], [Compiled with tracing support]))
+AM_CONDITIONAL([USE_TRACING], [test "x$have_tracing" = x1 ])
+
+dnl Finally, define the trace libs.
+AC_SUBST([TOR_TRACE_LIBS])
+
+dnl -- End Tracing Options. --
dnl Enable Android only features.
AC_ARG_ENABLE(android,
@@ -679,12 +733,10 @@ AC_CHECK_FUNCS(
getdelim \
getifaddrs \
getline \
- getpass \
getrlimit \
gettimeofday \
gmtime_r \
gnu_get_libc_version \
- htonll \
inet_aton \
ioctl \
issetugid \
@@ -1042,7 +1094,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 +1620,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 +1640,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 \
@@ -2725,6 +2773,18 @@ test "x$enable_oss_fuzz" = "xyes" && value=1 || value=0
PPRINT_PROP_BOOL([OSS-Fuzz support (--enable-oss-fuzz)], $value)
AS_ECHO
+PPRINT_SUBTITLE([Tracing (--enable-tracing-instrumentation-<type>)])
+
+test "x$enable_tracing_instrumentation_log_debug" = "xyes" && value=1 || value=0
+PPRINT_PROP_BOOL([Tracepoints to log_debug() (log-debug)], $value)
+
+test "x$enable_tracing_instrumentation_usdt" = "xyes" && value=1 || value=0
+PPRINT_PROP_BOOL([USDT Instrumentation (usdt)], $value)
+
+test "x$enable_tracing_instrumentation_lttng" = "xyes" && value=1 || value=0
+PPRINT_PROP_BOOL([LTTng Instrumentation (lttng)], $value)
+
+AS_ECHO
PPRINT_SUBTITLE([Install Directories])
report_mandir="`eval eval echo $mandir`"
diff --git a/contrib/win32build/tor-mingw.nsi.in b/contrib/win32build/tor-mingw.nsi.in
index 5e96677266..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-dev"
+!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/CircuitPaddingQuickStart.md b/doc/HACKING/CircuitPaddingQuickStart.md
index 2780b5c6ea..2b01dae074 100644
--- a/doc/HACKING/CircuitPaddingQuickStart.md
+++ b/doc/HACKING/CircuitPaddingQuickStart.md
@@ -18,20 +18,20 @@ The quick and dirty plan is to:
## Clone and compile tor
-```bash
-git clone https://git.torproject.org/tor.git
-cd tor
-git checkout tor-0.4.1.5
+```console
+$ git clone https://git.torproject.org/tor.git
+$ cd tor
+$ git checkout tor-0.4.1.5
```
Above we use the tag for tor-0.4.1.5 where the circuit padding framework was
released. Note that this version of the framework is missing many features and
fixes that have since been merged to origin/master. If you need the newest
framework features, you should use that master instead.
-```bash
-sh autogen.sh
-./configure
-make
+```console
+$ sh autogen.sh
+$ ./configure
+$ make
```
When you run `./configure` you'll be told of missing dependencies and packages
to install on debian-based distributions. Important: if you plan to run `tor` on
@@ -186,9 +186,9 @@ We also have to modify `circpad_machines_init()` in `circuitpadding.c` to
register our machines:
```c
- /* Register machines for the APE WF defense */
- circpad_machine_client_wf_ape(origin_padding_machines);
- circpad_machine_relay_wf_ape(relay_padding_machines);
+/* Register machines for the APE WF defense */
+circpad_machine_client_wf_ape(origin_padding_machines);
+circpad_machine_relay_wf_ape(relay_padding_machines);
```
We run `make` to get a new `tor` binary and copy it to our local TB.
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/HACKING/CodingStandards.md b/doc/HACKING/CodingStandards.md
index 150acf1852..e9bb75b986 100644
--- a/doc/HACKING/CodingStandards.md
+++ b/doc/HACKING/CodingStandards.md
@@ -118,27 +118,32 @@ instance of the feature (--reverse).
For example, for #30224, we wanted to know when the bridge-distribution-request
feature was introduced into Tor:
- $ git log -S bridge-distribution-request --reverse
- commit ebab521525
- Author: Roger Dingledine <arma@torproject.org>
- Date: Sun Nov 13 02:39:16 2016 -0500
- Add new BridgeDistribution config option
+```console
+$ git log -S bridge-distribution-request --reverse commit ebab521525
+Author: Roger Dingledine <arma@torproject.org>
+Date: Sun Nov 13 02:39:16 2016 -0500
- $ git describe --contains ebab521525
- tor-0.3.2.3-alpha~15^2~4
+ Add new BridgeDistribution config option
+
+$ git describe --contains ebab521525
+tor-0.3.2.3-alpha~15^2~4
+```
If you need to know all the Tor versions that contain a commit, use:
- $ git tag --contains 9f2efd02a1 | sort -V
- tor-0.2.5.16
- tor-0.2.8.17
- tor-0.2.9.14
- tor-0.2.9.15
- ...
- tor-0.3.0.13
- tor-0.3.1.9
- tor-0.3.1.10
- ...
+
+```console
+$ git tag --contains 9f2efd02a1 | sort -V
+tor-0.2.5.16
+tor-0.2.8.17
+tor-0.2.9.14
+tor-0.2.9.15
+...
+tor-0.3.0.13
+tor-0.3.1.9
+tor-0.3.1.10
+...
+```
If at all possible, try to create the changes file in the same commit where
you are making the change. Please give it a distinctive name that no other
@@ -438,8 +443,10 @@ use `tor_assert_nonfatal()` in place of `tor_assert()`. If you'd like to
write a conditional that incorporates a nonfatal assertion, use the `BUG()`
macro, as in:
- if (BUG(ptr == NULL))
- return -1;
+```c
+if (BUG(ptr == NULL))
+ return -1;
+```
## Allocator conventions
@@ -451,33 +458,39 @@ Also, a type named `abc_t` should be freed by a function named `abc_free_()`.
Don't call this `abc_free_()` function directly -- instead, wrap it in a
macro called `abc_free()`, using the `FREE_AND_NULL` macro:
- void abc_free_(abc_t *obj);
- #define abc_free(obj) FREE_AND_NULL(abc_t, abc_free_, (obj))
+```c
+void abc_free_(abc_t *obj);
+#define abc_free(obj) FREE_AND_NULL(abc_t, abc_free_, (obj))
+```
This macro will free the underlying `abc_t` object, and will also set
the object pointer to NULL.
You should define all `abc_free_()` functions to accept NULL inputs:
- void
- abc_free_(abc_t *obj)
- {
- if (!obj)
- return;
- tor_free(obj->name);
- thing_free(obj->thing);
- tor_free(obj);
- }
+```c
+void
+abc_free_(abc_t *obj)
+{
+ if (!obj)
+ return;
+ tor_free(obj->name);
+ thing_free(obj->thing);
+ tor_free(obj);
+}
+```
If you need a free function that takes a `void *` argument (for example,
to use it as a function callback), define it with a name like
`abc_free_void()`:
- static void
- abc_free_void_(void *obj)
- {
- abc_free_(obj);
- }
+```c
+static void
+abc_free_void_(void *obj)
+{
+ abc_free_(obj);
+}
+```
When deallocating, don't say e.g. `if (x) tor_free(x)`. The convention is to
have deallocators do nothing when NULL pointer is passed.
@@ -488,24 +501,28 @@ Say what functions do as a series of one or more imperative sentences, as
though you were telling somebody how to be the function. In other words, DO
NOT say:
- /** The strtol function parses a number.
- *
- * nptr -- the string to parse. It can include whitespace.
- * endptr -- a string pointer to hold the first thing that is not part
- * of the number, if present.
- * base -- the numeric base.
- * returns: the resulting number.
- */
- long strtol(const char *nptr, char **nptr, int base);
+```c
+/** The strtol function parses a number.
+ *
+ * nptr -- the string to parse. It can include whitespace.
+ * endptr -- a string pointer to hold the first thing that is not part
+ * of the number, if present.
+ * base -- the numeric base.
+ * returns: the resulting number.
+ */
+long strtol(const char *nptr, char **nptr, int base);
+```
Instead, please DO say:
- /** Parse a number in radix <b>base</b> from the string <b>nptr</b>,
- * and return the result. Skip all leading whitespace. If
- * <b>endptr</b> is not NULL, set *<b>endptr</b> to the first character
- * after the number parsed.
- **/
- long strtol(const char *nptr, char **nptr, int base);
+```c
+/** Parse a number in radix <b>base</b> from the string <b>nptr</b>,
+ * and return the result. Skip all leading whitespace. If
+ * <b>endptr</b> is not NULL, set *<b>endptr</b> to the first character
+ * after the number parsed.
+ **/
+long strtol(const char *nptr, char **nptr, int base);
+```
Doxygen comments are the contract in our abstraction-by-contract world: if
the functions that call your function rely on it doing something, then your
diff --git a/doc/HACKING/CodingStandardsRust.md b/doc/HACKING/CodingStandardsRust.md
index 36a0dcda2a..c821465173 100644
--- a/doc/HACKING/CodingStandardsRust.md
+++ b/doc/HACKING/CodingStandardsRust.md
@@ -22,20 +22,26 @@ For example, in a hypothetical `tor_addition` Rust module:
In `src/rust/tor_addition/addition.rs`:
- pub fn get_sum(a: i32, b: i32) -> i32 {
- a + b
- }
+```rust
+pub fn get_sum(a: i32, b: i32) -> i32 {
+ a + b
+}
+```
In `src/rust/tor_addition/lib.rs`:
- pub use addition::*;
+```rust
+pub use addition::*;
+```
In `src/rust/tor_addition/ffi.rs`:
- #[no_mangle]
- pub extern "C" fn tor_get_sum(a: c_int, b: c_int) -> c_int {
- get_sum(a, b)
- }
+```rust
+#[no_mangle]
+pub extern "C" fn tor_get_sum(a: c_int, b: c_int) -> c_int {
+ get_sum(a, b)
+}
+```
If your Rust code must call out to parts of Tor's C code, you must
declare the functions you are calling in the `external` crate, located
@@ -129,16 +135,18 @@ crate. Unittests SHOULD go into their own module inside the module
they are testing, e.g. in `src/rust/tor_addition/addition.rs` you
should put:
- #[cfg(test)]
- mod test {
- use super::*;
+```rust
+#[cfg(test)]
+mod test {
+ use super::*;
- #[test]
- fn addition_with_zero() {
- let sum: i32 = get_sum(5i32, 0i32);
- assert_eq!(sum, 5);
- }
+#[test]
+ fn addition_with_zero() {
+ let sum: i32 = get_sum(5i32, 0i32);
+ assert_eq!(sum, 5);
}
+}
+```
## Benchmarking
@@ -151,13 +159,17 @@ benchmarks in the following manner.
If you wish to benchmark some of your Rust code, you MUST put the
following in the `[features]` section of your crate's `Cargo.toml`:
- [features]
- bench = []
+```toml
+[features]
+bench = []
+```
Next, in your crate's `lib.rs` you MUST put:
- #[cfg(all(test, feature = "bench"))]
- extern crate test;
+```rust
+#[cfg(all(test, feature = "bench"))]
+extern crate test;
+```
This ensures that the external crate `test`, which contains utilities
for basic benchmarks, is only used when running benchmarks via `cargo
@@ -166,16 +178,18 @@ bench --features bench`.
Finally, to write your benchmark code, in
`src/rust/tor_addition/addition.rs` you SHOULD put:
- #[cfg(all(test, features = "bench"))]
- mod bench {
- use test::Bencher;
- use super::*;
+```rust
+#[cfg(all(test, features = "bench"))]
+mod bench {
+ use test::Bencher;
+ use super::*;
- #[bench]
- fn addition_small_integers(b: &mut Bencher) {
- b.iter(| | get_sum(5i32, 0i32));
- }
+#[bench]
+ fn addition_small_integers(b: &mut Bencher) {
+ b.iter(| | get_sum(5i32, 0i32));
}
+}
+```
## Fuzzing
@@ -247,39 +261,47 @@ Here are some additional bits of advice and rules:
potential error with the eel operator, `?` or another non panicking way.
For example, consider a function which parses a string into an integer:
- fn parse_port_number(config_string: &str) -> u16 {
- u16::from_str_radix(config_string, 10).unwrap()
- }
+ ```rust
+ fn parse_port_number(config_string: &str) -> u16 {
+ u16::from_str_radix(config_string, 10).unwrap()
+ }
+ ```
There are numerous ways this can fail, and the `unwrap()` will cause the
whole program to byte the dust! Instead, either you SHOULD use `ok()`
(or another equivalent function which will return an `Option` or a `Result`)
and change the return type to be compatible:
- fn parse_port_number(config_string: &str) -> Option<u16> {
- u16::from_str_radix(config_string, 10).ok()
- }
+ ```rust
+ fn parse_port_number(config_string: &str) -> Option<u16> {
+ u16::from_str_radix(config_string, 10).ok()
+ }
+ ```
or you SHOULD use `or()` (or another similar method):
- fn parse_port_number(config_string: &str) -> Option<u16> {
- u16::from_str_radix(config_string, 10).or(Err("Couldn't parse port into a u16")
- }
+ ```rust
+ fn parse_port_number(config_string: &str) -> Option<u16> {
+ u16::from_str_radix(config_string, 10).or(Err("Couldn't parse port into a u16")
+ }
+ ```
Using methods like `or()` can be particularly handy when you must do
something afterwards with the data, for example, if we wanted to guarantee
that the port is high. Combining these methods with the eel operator (`?`)
makes this even easier:
- fn parse_port_number(config_string: &str) -> Result<u16, Err> {
- let port = u16::from_str_radix(config_string, 10).or(Err("Couldn't parse port into a u16"))?;
+ ```rust
+ fn parse_port_number(config_string: &str) -> Result<u16, Err> {
+ let port = u16::from_str_radix(config_string, 10).or(Err("Couldn't parse port into a u16"))?;
- if port > 1024 {
- return Ok(port);
- } else {
- return Err("Low ports not allowed");
- }
+ if port > 1024 {
+ return Ok(port);
+ } else {
+ return Err("Low ports not allowed");
}
+ }
+ ```
2. `unsafe`
@@ -292,25 +314,29 @@ Here are some additional bits of advice and rules:
When creating an FFI in Rust for C code to call, it is NOT REQUIRED
to declare the entire function `unsafe`. For example, rather than doing:
- #[no_mangle]
- pub unsafe extern "C" fn increment_and_combine_numbers(mut numbers: [u8; 4]) -> u32 {
- for number in &mut numbers {
- *number += 1;
- }
- std::mem::transmute::<[u8; 4], u32>(numbers)
+ ```rust
+ #[no_mangle]
+ pub unsafe extern "C" fn increment_and_combine_numbers(mut numbers: [u8; 4]) -> u32 {
+ for number in &mut numbers {
+ *number += 1;
}
+ std::mem::transmute::<[u8; 4], u32>(numbers)
+ }
+ ```
You SHOULD instead do:
- #[no_mangle]
- pub extern "C" fn increment_and_combine_numbers(mut numbers: [u8; 4]) -> u32 {
- for index in 0..numbers.len() {
- numbers[index] += 1;
- }
- unsafe {
- std::mem::transmute::<[u8; 4], u32>(numbers)
- }
+ ```rust
+ #[no_mangle]
+ pub extern "C" fn increment_and_combine_numbers(mut numbers: [u8; 4]) -> u32 {
+ for index in 0..numbers.len() {
+ numbers[index] += 1;
}
+ unsafe {
+ std::mem::transmute::<[u8; 4], u32>(numbers)
+ }
+ }
+ ```
3. Pass only C-compatible primitive types and bytes over the boundary
@@ -385,45 +411,51 @@ Here are some additional bits of advice and rules:
rather than using an untyped mapping between strings and integers
like so:
- use std::collections::HashMap;
+ ```rust
+ use std::collections::HashMap;
- pub fn get_elements_with_over_9000_points(map: &HashMap<String, usize>) -> Vec<String> {
- ...
- }
+ pub fn get_elements_with_over_9000_points(map: &HashMap<String, usize>) -> Vec<String> {
+ ...
+ }
+ ```
It would be safer to define a new type, such that some other usage
of `HashMap<String, usize>` cannot be confused for this type:
- pub struct DragonBallZPowers(pub HashMap<String, usize>);
+ ```rust
+ pub struct DragonBallZPowers(pub HashMap<String, usize>);
- impl DragonBallZPowers {
- pub fn over_nine_thousand<'a>(&'a self) -> Vec<&'a String> {
- let mut powerful_enough: Vec<&'a String> = Vec::with_capacity(5);
+ impl DragonBallZPowers {
+ pub fn over_nine_thousand<'a>(&'a self) -> Vec<&'a String> {
+ let mut powerful_enough: Vec<&'a String> = Vec::with_capacity(5);
- for (character, power) in &self.0 {
- if *power > 9000 {
- powerful_enough.push(character);
- }
- }
- powerful_enough
- }
- }
+ for (character, power) in &self.0 {
+ if *power > 9000 {
+ powerful_enough.push(character);
+ }
+ }
+ powerful_enough
+ }
+ }
+ ```
Note the following code, which uses Rust's type aliasing, is valid
but it does NOT meet the desired type safety goals:
- pub type Power = usize;
+ ```rust
+ pub type Power = usize;
- pub fn over_nine_thousand(power: &Power) -> bool {
- if *power > 9000 {
- return true;
- }
- false
+ pub fn over_nine_thousand(power: &Power) -> bool {
+ if *power > 9000 {
+ return true;
}
+ false
+ }
- // We can still do the following:
- let his_power: usize = 9001;
- over_nine_thousand(&his_power);
+ // We can still do the following:
+ let his_power: usize = 9001;
+ over_nine_thousand(&his_power);
+ ```
7. Unsafe mucking around with lifetimes
@@ -431,15 +463,17 @@ Here are some additional bits of advice and rules:
family of types, individual lifetimes can be treated as types. For example,
one can arbitrarily extend and shorten lifetime using `std::mem::transmute`:
- struct R<'a>(&'a i32);
+ ```rust
+ struct R<'a>(&'a i32);
- unsafe fn extend_lifetime<'b>(r: R<'b>) -> R<'static> {
- std::mem::transmute::<R<'b>, R<'static>>(r)
- }
+ unsafe fn extend_lifetime<'b>(r: R<'b>) -> R<'static> {
+ std::mem::transmute::<R<'b>, R<'static>>(r)
+ }
- unsafe fn shorten_invariant_lifetime<'b, 'c>(r: &'b mut R<'static>) -> &'b mut R<'c> {
- std::mem::transmute::<&'b mut R<'static>, &'b mut R<'c>>(r)
- }
+ unsafe fn shorten_invariant_lifetime<'b, 'c>(r: &'b mut R<'static>) -> &'b mut R<'c> {
+ std::mem::transmute::<&'b mut R<'static>, &'b mut R<'c>>(r)
+ }
+ ```
Calling `extend_lifetime()` would cause an `R` passed into it to live forever
for the life of the program (the `'static` lifetime). Similarly,
@@ -460,12 +494,14 @@ Here are some additional bits of advice and rules:
For example, `std::mem::transmute` can be abused in ways where casting with
`as` would be both simpler and safer:
- // Don't do this
- let ptr = &0;
- let ptr_num_transmute = unsafe { std::mem::transmute::<&i32, usize>(ptr)};
+ ```rust
+ // Don't do this
+ let ptr = &0;
+ let ptr_num_transmute = unsafe { std::mem::transmute::<&i32, usize>(ptr)};
- // Use an `as` cast instead
- let ptr_num_cast = ptr as *const i32 as usize;
+ // Use an `as` cast instead
+ let ptr_num_cast = ptr as *const i32 as usize;
+ ```
In fact, using `std::mem::transmute` for *any* reason is a code smell and as
such SHOULD be avoided.
@@ -475,8 +511,10 @@ Here are some additional bits of advice and rules:
This is generally fine to do, but it has some behaviours which you should be
aware of. Casting down chops off the high bits, e.g.:
- let x: u32 = 4294967295;
- println!("{}", x as u16); // prints 65535
+ ```rust
+ let x: u32 = 4294967295;
+ println!("{}", x as u16); // prints 65535
+ ```
Some cases which you MUST NOT do include:
@@ -487,24 +525,28 @@ Here are some additional bits of advice and rules:
* Casting between integers and floats when the thing being cast
cannot fit into the type it is being casted into, e.g.:
- println!("{}", 42949.0f32 as u8); // prints 197 in debug mode and 0 in release
- println!("{}", 1.04E+17 as u8); // prints 0 in both modes
- println!("{}", (0.0/0.0) as i64); // prints whatever the heck LLVM wants
+ ```rust
+ println!("{}", 42949.0f32 as u8); // prints 197 in debug mode and 0 in release
+ println!("{}", 1.04E+17 as u8); // prints 0 in both modes
+ println!("{}", (0.0/0.0) as i64); // prints whatever the heck LLVM wants
+ ```
Because this behaviour is undefined, it can even produce segfaults in
safe Rust code. For example, the following program built in release
mode segfaults:
- #[inline(never)]
- pub fn trigger_ub(sl: &[u8; 666]) -> &[u8] {
- // Note that the float is out of the range of `usize`, invoking UB when casting.
- let idx = 1e99999f64 as usize;
- &sl[idx..] // The bound check is elided due to `idx` being of an undefined value.
- }
-
- fn main() {
- println!("{}", trigger_ub(&[1; 666])[999999]); // ~ out of bound
- }
+ ```rust
+ #[inline(never)]
+ pub fn trigger_ub(sl: &[u8; 666]) -> &[u8] {
+ // Note that the float is out of the range of `usize`, invoking UB when casting.
+ let idx = 1e99999f64 as usize;
+ &sl[idx..] // The bound check is elided due to `idx` being of an undefined value.
+ }
+
+ fn main() {
+ println!("{}", trigger_ub(&[1; 666])[999999]); // ~ out of bound
+ }
+ ```
And in debug mode panics with:
diff --git a/doc/HACKING/Fuzzing.md b/doc/HACKING/Fuzzing.md
index 487716bb6d..d9e133008a 100644
--- a/doc/HACKING/Fuzzing.md
+++ b/doc/HACKING/Fuzzing.md
@@ -6,7 +6,10 @@ Check out fuzzing-corpora, and set TOR_FUZZ_CORPORA to point to the place
where you checked it out.
To run the fuzzing test cases in a deterministic fashion, use:
- make test-fuzz-corpora
+
+```console
+$ make test-fuzz-corpora
+```
This won't actually fuzz Tor! It will just run all the fuzz binaries
on our existing set of testcases for the fuzzer.
@@ -58,11 +61,13 @@ machine you care about, anyway.
To Build:
Get AFL from http://lcamtuf.coredump.cx/afl/ and unpack it
- cd afl
- make
- cd ../tor
- PATH=$PATH:../afl/ CC="../afl/afl-gcc" ./configure --enable-expensive-hardening
- AFL_HARDEN=1 make clean fuzzers
+ ```console
+ $ cd afl
+ $ make
+ $ cd ../tor
+ $ PATH=$PATH:../afl/ CC="../afl/afl-gcc" ./configure --enable-expensive-hardening
+ $ AFL_HARDEN=1 make clean fuzzers
+ ```
To Find The ASAN Memory Limit: (64-bit only)
@@ -75,10 +80,12 @@ Read afl/docs/notes_for_asan.txt for more details.
Download recidivm from https://jwilk.net/software/recidivm
Download the signature
Check the signature
- tar xvzf recidivm*.tar.gz
- cd recidivm*
- make
- /path/to/recidivm -v src/test/fuzz/fuzz-http
+ ```console
+ $ tar xvzf recidivm*.tar.gz
+ $ cd recidivm*
+ $ make
+ $ /path/to/recidivm -v src/test/fuzz/fuzz-http
+ ```
Use the final "ok" figure as the input to -m when calling afl-fuzz
(Normally, recidivm would output a figure automatically, but in some cases,
the fuzzing harness will hang when the memory limit is too small.)
@@ -88,9 +95,11 @@ don't care about memory limits.
To Run:
- mkdir -p src/test/fuzz/fuzz_http_findings
- ../afl/afl-fuzz -i ${TOR_FUZZ_CORPORA}/http -o src/test/fuzz/fuzz_http_findings -m <asan-memory-limit> -- src/test/fuzz/fuzz-http
+```console
+$ mkdir -p src/test/fuzz/fuzz_http_findings
+$ ../afl/afl-fuzz -i ${TOR_FUZZ_CORPORA}/http -o src/test/fuzz/fuzz_http_findings -m <asan-memory-limit> -- src/test/fuzz/fuzz-http
+```
AFL has a multi-core mode, check the documentation for details.
You might find the included fuzz-multi.sh script useful for this.
@@ -109,7 +118,10 @@ valid inputs may take a second or so, particularly with the fuzzer and
sanitizers enabled.
To see what fuzz-http is doing with a test case, call it like this:
- src/test/fuzz/fuzz-http --debug < /path/to/test.case
+
+```console
+$ src/test/fuzz/fuzz-http --debug < /path/to/test.case
+```
(Logging is disabled while fuzzing to increase fuzzing speed.)
diff --git a/doc/HACKING/GettingStarted.md b/doc/HACKING/GettingStarted.md
index 633a7f0417..ee3da10a4b 100644
--- a/doc/HACKING/GettingStarted.md
+++ b/doc/HACKING/GettingStarted.md
@@ -37,13 +37,17 @@ Once you've reached this point, here's what you need to know.
We keep our source under version control in Git. To get the latest
version, run:
- git clone https://git.torproject.org/git/tor
+ ```console
+ $ git clone https://git.torproject.org/git/tor
+ ```
This will give you a checkout of the master branch. If you're
going to fix a bug that appears in a stable version, check out the
appropriate "maint" branch, as in:
- git checkout maint-0.4.3
+ ```console
+ $ git checkout maint-0.4.3
+ ```
2. Find your way around the source.
diff --git a/doc/HACKING/GettingStartedRust.md b/doc/HACKING/GettingStartedRust.md
index af80018f4e..adacf8afc2 100644
--- a/doc/HACKING/GettingStartedRust.md
+++ b/doc/HACKING/GettingStartedRust.md
@@ -54,7 +54,9 @@ fetching dependencies from Cargo or specifying a local directory.
**Fetch dependencies from Cargo**
- ./configure --enable-rust --enable-cargo-online-mode
+```console
+$ ./configure --enable-rust --enable-cargo-online-mode
+```
**Using a local dependency cache**
@@ -66,13 +68,17 @@ We vendor our Rust dependencies in a separate repo using
[cargo-vendor](https://github.com/alexcrichton/cargo-vendor). To use
them, do:
- git submodule init
- git submodule update
+```console
+$ git submodule init
+$ git submodule update
+```
To specify the local directory containing the dependencies, (assuming
you are in the top level of the repository) configure tor with:
- TOR_RUST_DEPENDENCIES='path_to_dependencies_directory' ./configure --enable-rust
+```console
+$ TOR_RUST_DEPENDENCIES='path_to_dependencies_directory' ./configure --enable-rust
+```
(Note that `TOR_RUST_DEPENDENCIES` must be the full path to the directory; it
cannot be relative.)
@@ -80,7 +86,9 @@ cannot be relative.)
Assuming you used the above `git submodule` commands and you're in the
topmost directory of the repository, this would be:
- TOR_RUST_DEPENDENCIES=`pwd`/src/ext/rust/crates ./configure --enable-rust
+```console
+$ TOR_RUST_DEPENDENCIES=`pwd`/src/ext/rust/crates ./configure --enable-rust
+```
## Identifying which modules to rewrite
@@ -102,10 +110,12 @@ areas of responsibility.
A good first step is to build a module-level callgraph to understand how
interconnected your target module is.
- git clone https://git.torproject.org/user/nickm/calltool.git
- cd tor
- CFLAGS=0 ./configure
- ../calltool/src/main.py module_callgraph
+```console
+$ git clone https://git.torproject.org/user/nickm/calltool.git
+$ cd tor
+$ CFLAGS=0 ./configure
+$ ../calltool/src/main.py module_callgraph
+```
The output will tell you each module name, along with a set of every module that
the module calls. Modules which call fewer other modules are better targets.
@@ -156,15 +166,21 @@ run on your crate.
Configure Tor's build system to build with Rust enabled:
- ./configure --enable-fatal-warnings --enable-rust --enable-cargo-online-mode
+```console
+$ ./configure --enable-fatal-warnings --enable-rust --enable-cargo-online-mode
+```
Tor's test should be run by doing:
- make check
+```console
+$ make check
+```
Tor's integration tests should also pass:
- make test-stem
+```console
+$ make test-stem
+```
## Submitting a patch
diff --git a/doc/HACKING/HelpfulTools.md b/doc/HACKING/HelpfulTools.md
index 15bd153318..0ce59576f0 100644
--- a/doc/HACKING/HelpfulTools.md
+++ b/doc/HACKING/HelpfulTools.md
@@ -43,7 +43,9 @@ Builds should show up on the web at jenkins.torproject.org and on IRC at
## Valgrind
- valgrind --leak-check=yes --error-limit=no --show-reachable=yes src/app/tor
+```console
+$ valgrind --leak-check=yes --error-limit=no --show-reachable=yes src/app/tor
+```
(Note that if you get a zillion openssl warnings, you will also need to
pass `--undef-value-errors=no` to valgrind, or rebuild your openssl
@@ -77,10 +79,12 @@ we wish to permit are also documented in the blacklist file.
Lcov is a utility that generates pretty HTML reports of test code coverage.
To generate such a report:
- ./configure --enable-coverage
- make
- make coverage-html
- $BROWSER ./coverage_html/index.html
+```console
+$ ./configure --enable-coverage
+$ make
+$ make coverage-html
+$ $BROWSER ./coverage_html/index.html
+```
This will run the tor unit test suite `./src/test/test` and generate the HTML
coverage code report under the directory `./coverage_html/`. To change the
@@ -93,36 +97,48 @@ investigated (as of July 2014).
To quickly run all the tests distributed with Tor:
- make check
+```console
+$ make check
+```
To run the fast unit tests only:
- make test
+```console
+$ make test
+```
To selectively run just some tests (the following can be combined
arbitrarily):
- ./src/test/test <name_of_test> [<name of test 2>] ...
- ./src/test/test <prefix_of_name_of_test>.. [<prefix_of_name_of_test2>..] ...
- ./src/test/test :<name_of_excluded_test> [:<name_of_excluded_test2]...
+```console
+$ ./src/test/test <name_of_test> [<name of test 2>] ...
+$ ./src/test/test <prefix_of_name_of_test>.. [<prefix_of_name_of_test2>..] ...
+$ ./src/test/test :<name_of_excluded_test> [:<name_of_excluded_test2]...
+```
To run all tests, including those based on Stem or Chutney:
- make test-full
+```console
+$ make test-full
+```
To run all tests, including those based on Stem or Chutney that require a
working connection to the internet:
- make test-full-online
+```console
+$ make test-full-online
+```
## Running gcov for unit test coverage
- ./configure --enable-coverage
- make
- make check
- # or--- make test-full ? make test-full-online?
- mkdir coverage-output
- ./scripts/test/coverage coverage-output
+```console
+$ ./configure --enable-coverage
+$ make
+$ make check
+$ # or--- make test-full ? make test-full-online?
+$ mkdir coverage-output
+$ ./scripts/test/coverage coverage-output
+```
(On OSX, you'll need to start with `--enable-coverage CC=clang`.)
@@ -145,7 +161,9 @@ you can run `make reset-gcov` to clear the intermediary gcov output.
If you have two different `coverage-output` directories, and you want to see
a meaningful diff between them, you can run:
- ./scripts/test/cov-diff coverage-output1 coverage-output2 | less
+```console
+$ ./scripts/test/cov-diff coverage-output1 coverage-output2 | less
+```
In this diff, any lines that were visited at least once will have coverage "1",
and line numbers are deleted. This lets you inspect what you (probably) really
@@ -313,12 +331,16 @@ that you're using the emacs-specific version of `etags` (bundled under the
If you're using vim or emacs, you can also use Universal Ctags to build a tag
file using the syntax:
- ctags -R -D 'MOCK_IMPL(r,h,a)=r h a' .
+```console
+$ ctags -R -D 'MOCK_IMPL(r,h,a)=r h a' .
+```
If you're using an older version of Universal Ctags, you can use the following
instead:
- ctags -R --mline-regex-c='/MOCK_IMPL\([^,]+,\W*([a-zA-Z0-9_]+)\W*,/\1/f/{mgroup=1}' .
+```console
+ctags -R --mline-regex-c='/MOCK_IMPL\([^,]+,\W*([a-zA-Z0-9_]+)\W*,/\1/f/{mgroup=1}' .
+```
A vim-compatible tag file will be generated by default. If you use emacs, add
the `-e` flag to generate an emacs-compatible tag file.
@@ -330,50 +352,58 @@ source code. Here's how to use it:
1. Begin every file that should be documented with
- /**
- * \file filename.c
- * \brief Short description of the file.
- */
+```
+ /**
+ * \file filename.c
+ * \brief Short description of the file.
+ */
+```
- (Doxygen will recognize any comment beginning with /** as special.)
+ (Doxygen will recognize any comment beginning with /** as special.)
2. Before any function, structure, #define, or variable you want to
document, add a comment of the form:
- /** Describe the function's actions in imperative sentences.
- *
- * Use blank lines for paragraph breaks
- * - and
- * - hyphens
- * - for
- * - lists.
- *
- * Write <b>argument_names</b> in boldface.
- *
- * \code
- * place_example_code();
- * between_code_and_endcode_commands();
- * \endcode
- */
+```
+/** Describe the function's actions in imperative sentences.
+ *
+ * Use blank lines for paragraph breaks
+ * - and
+ * - hyphens
+ * - for
+ * - lists.
+ *
+ * Write <b>argument_names</b> in boldface.
+ *
+ * \code
+ * place_example_code();
+ * between_code_and_endcode_commands();
+ * \endcode
+ */
+```
3. Make sure to escape the characters `<`, `>`, `\`, `%` and `#` as `\<`,
`\>`, `\\`, `\%` and `\#`.
4. To document structure members, you can use two forms:
- struct foo {
- /** You can put the comment before an element; */
- int a;
- int b; /**< Or use the less-than symbol to put the comment
- * after the element. */
- };
+```c
+struct foo {
+ /** You can put the comment before an element; */
+ int a;
+ int b; /**< Or use the less-than symbol to put the comment
+ * after the element. */
+};
+```
5. To generate documentation from the Tor source code, type:
- $ doxygen -g
+```console
+$ doxygen -g
+```
- to generate a file called `Doxyfile`. Edit that file and run
- `doxygen` to generate the API documentation.
+ to generate a file called `Doxyfile`. Edit that file and run
+ `doxygen` to generate the API documentation.
6. See the Doxygen manual for more information; this summary just
scratches the surface.
diff --git a/doc/HACKING/Module.md b/doc/HACKING/Module.md
index f8a9773d47..b9d3a654eb 100644
--- a/doc/HACKING/Module.md
+++ b/doc/HACKING/Module.md
@@ -70,7 +70,7 @@ There are couples of "rules" you want to follow:
base. Every entry point should have a second definition if the module is
disabled. For instance:
- ```
+ ```c
#ifdef HAVE_MODULE_DIRAUTH
int sr_init(int save_to_disk);
@@ -109,7 +109,9 @@ There are couples of "rules" you want to follow:
* When you include headers from the module, **always** use the full module
path in your statement. Example:
- `#include "feature/dirauth/dirvote.h"`
+```c
+#include "feature/dirauth/dirvote.h"`
+```
The main reason is that we do **not** add the module include path by default
so it needs to be specified. But also, it helps our human brain understand
diff --git a/doc/HACKING/README.1st.md b/doc/HACKING/README.1st.md
index 2278a61d6c..4bc3298c67 100644
--- a/doc/HACKING/README.1st.md
+++ b/doc/HACKING/README.1st.md
@@ -32,7 +32,9 @@ For an explanation of how to change Tor's design to work differently, look at
For the latest version of the code, get a copy of git, and
- git clone https://git.torproject.org/git/tor
+```console
+$ git clone https://git.torproject.org/git/tor
+```
## Stay in touch
diff --git a/doc/HACKING/ReleasingTor.md b/doc/HACKING/ReleasingTor.md
index 2464d8afb4..d9b8d9d823 100644
--- a/doc/HACKING/ReleasingTor.md
+++ b/doc/HACKING/ReleasingTor.md
@@ -38,9 +38,9 @@ new Tor release:
3. Run checks that aren't covered above, including:
- * clang scan-build. (See the script in ./scripts/test/scan_build.sh)
+ * `clang scan-build`. (See the script in ./scripts/test/scan_build.sh)
- * make test-network and make test-network-all (with
+ * `make test-network` and make `test-network-all` (with
--enable-fragile-hardening)
* Running Tor yourself and making sure that it actually works for you.
@@ -57,8 +57,7 @@ new Tor release:
of them and reordering to focus on what users and funders would find
interesting and understandable.
- To do this, run
- `./scripts/maint/sortChanges.py changes/* > changelog.in`
+ To do this, run `./scripts/maint/sortChanges.py changes/* > changelog.inx`
to combine headings and sort the entries. Copy the changelog.in file
into the ChangeLog. Run 'format_changelog.py' (see below) to clean
up the line breaks.
@@ -164,9 +163,11 @@ new Tor release:
1. Sign the tarball, then sign and push the git tag:
- gpg -ba <the_tarball>
- git tag -s tor-0.4.x.y-<status>
- git push origin tag tor-0.4.x.y-<status>
+```console
+$ gpg -ba <the_tarball>
+$ git tag -s tor-0.4.x.y-<status>
+$ git push origin tag tor-0.4.x.y-<status>
+```
(You must do this before you update the website: the website scripts
rely on finding the version by tag.)
diff --git a/doc/HACKING/Tracing.md b/doc/HACKING/Tracing.md
index e1e97abe6d..0f2196c3f8 100644
--- a/doc/HACKING/Tracing.md
+++ b/doc/HACKING/Tracing.md
@@ -2,90 +2,162 @@
This document describes how the event tracing subsystem works in tor so
developers can add events to the code base but also hook them to an event
-tracing framework.
+tracing framework (i.e. tracer).
-## Basics
+## WARNING ##
-Event tracing is separated in two concepts, trace events and a tracer. The
-tracing subsystem can be found in `src/trace`. The `events.h` header file is
-the main file that maps the different tracers to trace events.
+Tracing the tor daemon **always** generates sensitive data if used in
+production (on the public network).
+
+It **is** ethical for researchers to use tracing for their own tor client (for
+example: building paths, timings, or performance).
+
+It is **NOT** ethical to archive, publish or keep data containing other users'
+activity such as relay data or anything that handles users' traffic. This
+of course includes any logs below notice level.
+
+Publishing analysis of tracing data containing user traffic is **NOT** safe
+either.
+
+In other words, tracing data that contains other users's activity is **NOT**
+safe to publish in any form.
+
+## Basics ###
+
+Tracing is separated in two different concepts. The tracing API and the
+tracing probes.
+
+The API is in `src/lib/trace/` which defines how to call tracepoints in the
+tor code. Every C files should include `src/lib/trace/events.h` if they want
+to call a tracepoint.
+
+The probes are what actually record the tracepoint data. Because they often
+need to access specific subsystem objects, the probes are within each
+subsystem. They are defined in the `trace-probes-<subsystem>.c` files.
### Events
-A trace event is basically a function from which we can pass any data that
-we want to collect. In addition, we specify a context for the event such as
-a subsystem and an event name.
+A trace event is basically a function from which we can pass any data that we
+want to collect. In addition, we specify a context for the event such as the
+subsystem and an event name.
A trace event in tor has the following standard format:
- tor_trace(subsystem, event\_name, args...)
+```c
+tor_trace(subsystem, event\_name, args...);
+```
The `subsystem` parameter is the name of the subsytem the trace event is in.
For example that could be "scheduler" or "vote" or "hs". The idea is to add
some context to the event so when we collect them we know where it's coming
-from. The `event_name` is the name of the event which helps a lot with
-adding some semantic to the event. Finally, `args` is any number of
-arguments we want to collect.
+from.
+
+The `event\_name` is the name of the event which adds better semantic to the
+event.
+
+The `args` can be any number of arguments we want to collect.
Here is an example of a possible tracepoint in main():
- tor_trace(main, init_phase, argc)
+```c
+tor_trace(main, init_phase, argc);
+```
-The above is a tracepoint in the `main` subsystem with `init_phase` as the
-event name and the `int argc` is passed to the event as well.
+The above is a tracepoint in the `main` subsystem with `init\_phase` as the
+event name and the `int argc` is passed to the event as one argument.
How `argc` is collected or used has nothing to do with the instrumentation
(adding trace events to the code). It is the work of the tracer so this is why
the trace events and collection framework (tracer) are decoupled. You _can_
have trace events without a tracer.
-### Tracer
+### Instrumentation ###
+
+In `src/lib/trace/events.h`, we map the high level `tor\_trace()` macro to one
+or many enabled instrumentation.
+
+Currently, we have 3 types of possible instrumentation:
-In `src/trace/events.h`, we map the `tor_trace()` function to the right
-tracer. A tracer support is only enabled at compile time. For instance, the
-file `src/trace/debug.h` contains the mapping of the generic tracing function
-`tor_trace()` to the `log_debug()` function. More specialized function can be
-mapped depending on the tracepoint.
+1. Debug
+
+ This will map every tracepoint to `log\_debug()`. However, none of the
+ arguments will be passed on because we don't know their type nor the string
+ format of the debug log. The output is standardized like this:
+
+```
+[debug] __FUNC__: Tracepoint <event_name> from subsystem <subsystem> hit.
+```
+
+2. USDT
+
+ User Statically-Defined Tracing (USDT) is a kind of probe which can be
+ handled by a variety of tracers such as SystemTap, DTrace, perf, eBPF and
+ ftrace.
+
+ For each tracer, one will need to define the ABI in order for the tracer to
+ be able to extract the data from the tracepoint objects. For instance, the
+ tracer needs to know how to print the circuit state of a `circuit\_t`
+ object.
+
+3. LTTng-UST
+
+ LTTng Userspace is a tracer that has it own type of instrumentation. The
+ probe definitions are created within the C code and is strongly typed.
+
+ For more information, see https://lttng.org/docs.
## Build System
-This section describes how it is integrated into the build system of tor.
+This section describes how the instrumentation is integrated into the build
+system of tor.
+
+By default, every tracing events are disabled in tor that is `tor\_trace()` is
+a NOP thus has no execution cost time.
-By default, every tracing events are disabled in tor that is `tor_trace()`
-is a NOP.
+To enable a specific instrumentation, there are configure options:
-To enable a tracer, there is a configure option on the form of:
+1. Debug: `--enable-tracing-instrumentation-debug`
- --enable-tracing-<tracer>
+2. USDT: `--enable-tracing-instrumentation-usdt`
-We have an option that will send every trace events to a `log_debug()` (as
-mentionned above) which will print you the subsystem and name of the event but
-not the arguments for technical reasons. This is useful if you want to quickly
-see if your trace event is being hit or well written. To do so, use this
-configure option:
+3. LTTng: `--enable-tracing-instrumentation-lttng`
- --enable-tracing-debug
+They can all be used together or independently. If one of them is set,
+`HAVE\_TRACING` define is set. And for each instrumentation, a
+`USE\_TRACING\_INSTRUMENTATION\_<type>` is set.
-## Instrument Tor
+## Adding a Tracepoint ##
This is pretty easy. Let's say you want to add a trace event in
-`src/feature/rend/rendcache.c`, you only have to add this include statement:
+`src/feature/rend/rendcache.c`, you first need to include this file:
+
+```c
+#include "trace/events.h"
+```
+
+Then, the `tor\_trace()` macro can be used with the specific format detailled
+before in a previous section. As an example:
+
+```c
+tor_trace(hs, store_desc_as_client, desc, desc_id);
+```
- #include "trace/events.h"
+For `Debug` instrumentation, you have nothing else to do.
-Once done, you can add as many as you want `tor_trace()` that you need.
-Please use the right subsystem (here it would be `hs`) and a unique name that
-tells what the event is for. For example:
+For `USDT`, instrumentation, you will need to define the probes in a way the
+specific tracer can understand. For instance, SystemTap requires you to define
+a `tapset` for each tracepoints.
- tor_trace(hs, store_desc_as_client, desc, desc_id);
+For `LTTng`, you will need to define the probes in the
+`trace-probes-<subsystem>.{c|h}` file. See the `trace-probes-circuit.{c|h}`
+file as an example and https://lttng.org/docs/v2.11/#doc-instrumenting.
-If you look in `src/trace/events.h`, you'll see that if tracing is enabled it
-will be mapped to a function called:
+## Performance ##
- tor_trace_hs_store_desc_as_client(desc, desc_id)
+A word about performance when a tracepoint is enabled. One of the goal of a
+tracepoint (USDT, LTTng-UST, ...) is that they can be enabled or disabled. By
+default, they are disabled which means the tracer will not record the data but
+it has to do a check thus the cost is basically the one of a `branch`.
-And the point of all this is for that function to be defined in a new file
-that you might want to add named `src/trace/hs.{c|h}` which would defined how
-to collect the data for the `tor_trace_hs_store_desc_as_client()` function
-like for instance sending it to a `log_debug()` or do more complex operations
-or use a userspace tracer like LTTng (https://lttng.org).
+If enabled, then the performance depends on the tracer. In the case of
+LTTng-UST, the event costs around 110nsec.
diff --git a/doc/HACKING/WritingTests.md b/doc/HACKING/WritingTests.md
index d212020525..01e80f3f66 100644
--- a/doc/HACKING/WritingTests.md
+++ b/doc/HACKING/WritingTests.md
@@ -107,7 +107,9 @@ covered or uncovered.
To count new or modified uncovered lines in D2, you can run:
- ./scripts/test/cov-diff ${D1} ${D2}" | grep '^+ *\#' | wc -l
+```console
+$ ./scripts/test/cov-diff ${D1} ${D2}" | grep '^+ *\#' | wc -l
+```
## Marking lines as unreachable by tests
@@ -163,28 +165,30 @@ I use the term "unit test" and "regression tests" very sloppily here.
Here's an example of a test function for a simple function in util.c:
- static void
- test_util_writepid(void *arg)
- {
- (void) arg;
+```c
+static void
+test_util_writepid(void *arg)
+{
+ (void) arg;
- char *contents = NULL;
- const char *fname = get_fname("tmp_pid");
- unsigned long pid;
- char c;
+ char *contents = NULL;
+ const char *fname = get_fname("tmp_pid");
+ unsigned long pid;
+ char c;
- write_pidfile(fname);
+ write_pidfile(fname);
- contents = read_file_to_str(fname, 0, NULL);
- tt_assert(contents);
+ contents = read_file_to_str(fname, 0, NULL);
+ tt_assert(contents);
- int n = sscanf(contents, "%lu\n%c", &pid, &c);
- tt_int_op(n, OP_EQ, 1);
- tt_int_op(pid, OP_EQ, getpid());
+ int n = sscanf(contents, "%lu\n%c", &pid, &c);
+ tt_int_op(n, OP_EQ, 1);
+ tt_int_op(pid, OP_EQ, getpid());
- done:
- tor_free(contents);
- }
+done:
+ tor_free(contents);
+}
+```
This should look pretty familiar to you if you've read the tinytest
manual. One thing to note here is that we use the testing-specific
@@ -214,10 +218,12 @@ macro-protected declaration of the function in the module's header.
For example, `crypto_curve25519.h` contains:
- #ifdef CRYPTO_CURVE25519_PRIVATE
- STATIC int curve25519_impl(uint8_t *output, const uint8_t *secret,
- const uint8_t *basepoint);
- #endif
+```c
+#ifdef CRYPTO_CURVE25519_PRIVATE
+STATIC int curve25519_impl(uint8_t *output, const uint8_t *secret,
+ const uint8_t *basepoint);
+#endif
+```
The `crypto_curve25519.c` file and the `test_crypto.c` file both define
`CRYPTO_CURVE25519_PRIVATE`, so they can see this declaration.
@@ -231,28 +237,29 @@ the test _really tests_ the code.
For example, here is a _bad_ test for the unlink() function (which is
supposed to remove a file).
- static void
- test_unlink_badly(void *arg)
- {
- (void) arg;
- int r;
+```c
+static void
+test_unlink_badly(void *arg)
+{
+ (void) arg;
+ int r;
- const char *fname = get_fname("tmpfile");
+ const char *fname = get_fname("tmpfile");
- /* If the file isn't there, unlink returns -1 and sets ENOENT */
- r = unlink(fname);
- tt_int_op(n, OP_EQ, -1);
- tt_int_op(errno, OP_EQ, ENOENT);
+ /* If the file isn't there, unlink returns -1 and sets ENOENT */
+ r = unlink(fname);
+ tt_int_op(n, OP_EQ, -1);
+ tt_int_op(errno, OP_EQ, ENOENT);
- /* If the file DOES exist, unlink returns 0. */
- write_str_to_file(fname, "hello world", 0);
- r = unlink(fnme);
- tt_int_op(r, OP_EQ, 0);
-
- done:
- tor_free(contents);
- }
+ /* If the file DOES exist, unlink returns 0. */
+ write_str_to_file(fname, "hello world", 0);
+ r = unlink(fnme);
+ tt_int_op(r, OP_EQ, 0);
+done:
+ tor_free(contents);
+}
+```
This test might get very high coverage on unlink(). So why is it a
bad test? Because it doesn't check that unlink() *actually removes the
@@ -273,20 +280,25 @@ To write tests for this case, you can replace the underlying functions
with testing stubs while your unit test is running. You need to declare
the underlying function as 'mockable', as follows:
- MOCK_DECL(returntype, functionname, (argument list));
+```c
+MOCK_DECL(returntype, functionname, (argument list));
+```
and then later implement it as:
- MOCK_IMPL(returntype, functionname, (argument list))
- {
- /* implementation here */
- }
+```c
+MOCK_IMPL(returntype, functionname, (argument list))
+{
+ /* implementation here */
+}
+```
For example, if you had a 'connect to remote server' function, you could
declare it as:
-
- MOCK_DECL(int, connect_to_remote, (const char *name, status_t *status));
+```c
+MOCK_DECL(int, connect_to_remote, (const char *name, status_t *status));
+```
When you declare a function this way, it will be declared as normal in
regular builds, but when the module is built for testing, it is declared
@@ -295,11 +307,15 @@ as a function pointer initialized to the actual implementation.
In your tests, if you want to override the function with a temporary
replacement, you say:
- MOCK(functionname, replacement_function_name);
+```c
+MOCK(functionname, replacement_function_name);
+```
And later, you can restore the original function with:
- UNMOCK(functionname);
+```c
+UNMOCK(functionname);
+```
For more information, see the definitions of this mocking logic in
`testsupport.h`.
@@ -324,11 +340,13 @@ cases and failure csaes.
For example, consider testing this function:
- /** Remove all elements E from sl such that E==element. Preserve
- * the order of any elements before E, but elements after E can be
- * rearranged.
- */
- void smartlist_remove(smartlist_t *sl, const void *element);
+```c
+/** Remove all elements E from sl such that E==element. Preserve
+ * the order of any elements before E, but elements after E can be
+ * rearranged.
+ */
+void smartlist_remove(smartlist_t *sl, const void *element);
+```
In order to test it well, you should write tests for at least all of the
following cases. (These would be black-box tests, since we're only looking
@@ -355,19 +373,21 @@ When you consider edge cases, you might try:
Now let's look at the implementation:
- void
- smartlist_remove(smartlist_t *sl, const void *element)
- {
- int i;
- if (element == NULL)
+```c
+void
+smartlist_remove(smartlist_t *sl, const void *element)
+{
+ int i;
+ if (element == NULL)
return;
- for (i=0; i < sl->num_used; i++)
+ for (i=0; i < sl->num_used; i++)
if (sl->list[i] == element) {
- sl->list[i] = sl->list[--sl->num_used]; /* swap with the end */
- i--; /* so we process the new i'th element */
- sl->list[sl->num_used] = NULL;
+ sl->list[i] = sl->list[--sl->num_used]; /* swap with the end */
+ i--; /* so we process the new i'th element */
+ sl->list[sl->num_used] = NULL;
}
- }
+}
+```
Based on the implementation, we now see three more edge cases to test:
diff --git a/doc/HACKING/android/Simpleperf.md b/doc/HACKING/android/Simpleperf.md
index c7e63a7c86..ed640f912e 100644
--- a/doc/HACKING/android/Simpleperf.md
+++ b/doc/HACKING/android/Simpleperf.md
@@ -29,7 +29,9 @@ the Android Software Development Kit (SDK) and Native Development Kit
3. Install the Android Package you generated in step 1:
+```bash
$ adb install /path/to/your/app-fullperm-debug.apk
+```
4. Check on your device that the newly installed Orbot actually works
and behaves in the way you expect it to.
@@ -76,10 +78,12 @@ was spend on the call.
To access binaries, `torrc` files, and other useful information on
the device do the following:
+```console
$ adb shell
(device):/ $ run-as org.torproject.android
(device):/data/data/org.torproject.android $ ls
app_bin app_data cache databases files lib shared_prefs
+```
Descriptors, control authentication cookie, state, and other files can be
found in the `app_data` directory. The `torrc` can be found in the `app_bin/`
@@ -88,10 +92,14 @@ was spend on the call.
- You can enable logging in Tor via the syslog (or android) log
mechanism with:
+```console
$ adb shell
(device):/ $ run-as org.torproject.android
(device):/data/data/org.torproject.android $ echo -e "\nLog info syslog" >> app_bin/torrc
+```
Start Tor the normal way via Orbot and collect the logs from your computer using
+```console
$ adb logcat
+```
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 f2a1aceb2f..ca54fa125b 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-install-tools.sh b/scripts/git/git-install-tools.sh
index ef8623a018..3b9c3d79f3 100755
--- a/scripts/git/git-install-tools.sh
+++ b/scripts/git/git-install-tools.sh
@@ -146,7 +146,7 @@ if [[ $INSTALL_HOOKS = 1 ]]; then
note "Installing hooks"
for fn in "$SCRIPTS_DIR"/*.git-hook; do
name=$(basename "$fn")
- $RUN install --backup "$fn" "${HOOKS_DIR}/${name%.git-hook}"
+ $RUN install -b "$fn" "${HOOKS_DIR}/${name%.git-hook}"
done
fi
@@ -163,7 +163,7 @@ if [[ $INSTALL_TOOLS = 1 ]]; then
note "Copying scripts"
for tool in "${TOOL_NAMES[@]}"; do
- $RUN install --backup "${SCRIPTS_DIR}/git-${tool}.sh" "${TOR_DEVTOOLS_DIR}/"
+ $RUN install -b "${SCRIPTS_DIR}/git-${tool}.sh" "${TOR_DEVTOOLS_DIR}/"
done
fi
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/git-pull-all.sh b/scripts/git/git-pull-all.sh
index 7f82eda296..52a5c6140c 100755
--- a/scripts/git/git-pull-all.sh
+++ b/scripts/git/git-pull-all.sh
@@ -181,6 +181,19 @@ function fetch_tor_github
fi
}
+# Fetch tor-gitlab pull requests. No arguments.
+function fetch_tor_gitlab
+{
+ local cmd="git fetch tor-gitlab"
+ printf " %s Fetching tor-gitlab..." "$MARKER"
+ if [ $DRY_RUN -eq 0 ]; then
+ msg=$( eval "$cmd" 2>&1 )
+ validate_ret $? "$msg"
+ else
+ printf "\\n %s\\n" "${IWTH}$cmd${CNRM}"
+ fi
+}
+
###############
# Entry point #
###############
@@ -189,6 +202,9 @@ function fetch_tor_github
goto_repo "$ORIGIN_PATH"
fetch_tor_github
+# Then tor-gitlab
+fetch_tor_gitlab
+
# Then, fetch the origin.
fetch_origin
diff --git a/scripts/git/git-setup-dirs.sh b/scripts/git/git-setup-dirs.sh
index 1f61eb8b83..3cc184dafb 100755
--- a/scripts/git/git-setup-dirs.sh
+++ b/scripts/git/git-setup-dirs.sh
@@ -40,6 +40,10 @@ function usage()
echo " (current: $GITHUB_PULL)"
echo " TOR_GITHUB_PUSH: the tor-github remote push URL"
echo " (current: $GITHUB_PUSH)"
+ echo " TOR_GITLAB_PULL: the tor-gitlab remote pull URL"
+ echo " (current: $GITLAB_PULL)"
+ echo " TOR_GITLAB_PUSH: the tor-gitlab remote push URL"
+ echo " (current: $GITLAB_PUSH)"
echo " TOR_EXTRA_CLONE_ARGS: extra arguments to git clone"
echo " (current: $TOR_EXTRA_CLONE_ARGS)"
echo " TOR_EXTRA_REMOTE_NAME: the name of an extra remote"
@@ -83,6 +87,10 @@ fi
GITHUB_PULL=${TOR_GITHUB_PULL:-"https://github.com/torproject/tor.git"}
GITHUB_PUSH=${TOR_GITHUB_PUSH:-"No_Pushing_To_GitHub"}
+# GitLab repositories
+GITLAB_PULL=${TOR_GITLAB_PULL:-"https://gitlab.torproject.org/tpo/core/tor.git"}
+GITLAB_PUSH=${TOR_GITLAB_PUSH:-"No_Pushing_To_GitLab"}
+
##########################
# Git branches to manage #
##########################
@@ -343,6 +351,20 @@ function set_tor_github_pr_fetch_config
"refs/pull.*pr"
}
+# Set up the tor-github PR config, so tor-gitlab/mr/NNNN points to GitHub
+# MR NNNN. In some repositories, "/head" is optional.
+function set_tor_gitlab_mr_fetch_config
+{
+ # standard branches
+ replace_fetch_config tor-gitlab \
+ "+refs/heads/*:refs/remotes/tor-gitlab/*" \
+ "refs/heads"
+ # MRs
+ replace_fetch_config tor-gitlab \
+ "+refs/merge-requests/*/head:refs/remotes/tor-gitlab/mr/*" \
+ "refs/merge-requests.*mr"
+}
+
# Add a new worktree for branch at path.
# If the directory already exists: fail if $USE_EXISTING is 0, otherwise skip.
function add_worktree
@@ -471,6 +493,15 @@ set_tor_github_pr_fetch_config
# Now fetch them all
fetch_remote "tor-github"
+# GitLab remote
+printf "%s Seting up remote %s\\n" "$MARKER" "${BYEL}tor-gitlab${CNRM}"
+add_remote "tor-gitlab" "$GITLAB_PULL"
+set_remote_push "tor-gitlab" "$GITLAB_PUSH"
+# Add custom fetch for MRs
+set_tor_gitlab_mr_fetch_config
+# Now fetch them all
+fetch_remote "tor-gitlab"
+
# Extra remote
if [ "$TOR_EXTRA_REMOTE_NAME" ]; then
printf "%s Setting up remote %s\\n" "$MARKER" \
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..87581b6c8c 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
@@ -323,3 +324,5 @@ problem function-size /src/tools/tor-gencert.c:parse_commandline() 111
problem function-size /src/tools/tor-resolve.c:build_socks5_resolve_request() 102
problem function-size /src/tools/tor-resolve.c:do_resolve() 171
problem function-size /src/tools/tor-resolve.c:main() 112
+problem dependency-violation /src/core/or/trace_probes_circuit.c 1
+problem dependency-violation /src/core/or/trace_probes_circuit.h 1
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 930986483d..10f09d7d98 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/or_state_st.h b/src/app/config/or_state_st.h
index 8c4e9d5e61..31b7f8a983 100644
--- a/src/app/config/or_state_st.h
+++ b/src/app/config/or_state_st.h
@@ -65,6 +65,14 @@ struct or_state_t {
int BWHistoryWriteInterval;
struct smartlist_t *BWHistoryWriteValues;
struct smartlist_t *BWHistoryWriteMaxima;
+ time_t BWHistoryIPv6ReadEnds;
+ int BWHistoryIPv6ReadInterval;
+ struct smartlist_t *BWHistoryIPv6ReadValues;
+ struct smartlist_t *BWHistoryIPv6ReadMaxima;
+ time_t BWHistoryIPv6WriteEnds;
+ int BWHistoryIPv6WriteInterval;
+ struct smartlist_t *BWHistoryIPv6WriteValues;
+ struct smartlist_t *BWHistoryIPv6WriteMaxima;
time_t BWHistoryDirReadEnds;
int BWHistoryDirReadInterval;
struct smartlist_t *BWHistoryDirReadValues;
diff --git a/src/app/config/resolve_addr.c b/src/app/config/resolve_addr.c
index 9d1a8e0260..7ec5ae565a 100644
--- a/src/app/config/resolve_addr.c
+++ b/src/app/config/resolve_addr.c
@@ -15,300 +15,717 @@
#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[] =
+ { TOR_ADDR_NULL, TOR_ADDR_NULL, TOR_ADDR_NULL };
+CTASSERT(ARRAY_LENGTH(last_resolved_addrs) == IDX_SIZE);
+
+/** Last suggested addresses.
+ *
+ * These addresses come from a NETINFO cell from a trusted relay (currently
+ * only authorities). We only use those in last resort. */
+static tor_addr_t last_suggested_addrs[] =
+ { TOR_ADDR_NULL, TOR_ADDR_NULL, TOR_ADDR_NULL };
+CTASSERT(ARRAY_LENGTH(last_suggested_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 suggested address of family into addr_out.
+ *
+ * If no last suggested address exists, the addr_out is a null address (use
+ * tor_addr_is_null() to confirm). */
+void
+resolved_addr_get_suggested(int family, tor_addr_t *addr_out)
{
- return last_resolved_addr;
+ tor_addr_copy(addr_out, &last_suggested_addrs[af_to_idx(family)]);
}
-/** Reset last_resolved_addr from outside this file. */
+/** Set the last suggested address into our cache. This is called when we get
+ * a new NETINFO cell from a trusted source. */
void
-reset_last_resolved_addr(void)
+resolved_addr_set_suggested(const tor_addr_t *addr)
{
- last_resolved_addr = 0;
+ if (BUG(tor_addr_family(addr) != AF_INET &&
+ tor_addr_family(addr) != AF_INET6)) {
+ return;
+ }
+ tor_addr_copy(&last_suggested_addrs[af_to_idx(tor_addr_family(addr))],
+ addr);
}
-/**
- * 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
+/** 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)
+{
+ tor_addr_copy(addr_out, &last_resolved_addrs[af_to_idx(family)]);
+}
+
+/** Reset the last resolved address of family.
+ *
+ * This makes it null address. */
+void
+resolved_addr_reset_last(int family)
+{
+ tor_addr_make_null(&last_resolved_addrs[af_to_idx(family)], family);
+}
+
+/** 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;
+ }
+
+ *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 Set 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).
+ */
+void
+resolved_addr_set_last(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[] = { false, false, false };
+ CTASSERT(ARRAY_LENGTH(have_resolved_once) == IDX_SIZE);
+
+ bool *done_one_resolve;
+ bool have_hostname = false;
+ tor_addr_t *last_resolved;
+
+ tor_assert(addr);
+ tor_assert(method_used);
- if (last_resolved_addr && last_resolved_addr != *addr_out) {
+ /* 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.
*/
+ resolved_addr_set_last(&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..d9a3e28924 100644
--- a/src/app/config/resolve_addr.h
+++ b/src/app/config/resolve_addr.h
@@ -9,16 +9,27 @@
#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);
+
+void resolved_addr_get_last(int family, tor_addr_t *addr_out);
+void resolved_addr_reset_last(int family);
+void resolved_addr_set_last(const tor_addr_t *addr, const char *method_used,
+ const char *hostname_used);
-uint32_t get_last_resolved_addr(void);
-void reset_last_resolved_addr(void);
+void resolved_addr_get_suggested(int family, tor_addr_t *addr_out);
+void resolved_addr_set_suggested(const tor_addr_t *addr);
-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/statefile.c b/src/app/config/statefile.c
index dcc55f1898..b25167d2ec 100644
--- a/src/app/config/statefile.c
+++ b/src/app/config/statefile.c
@@ -40,7 +40,7 @@
#include "feature/control/control_events.h"
#include "feature/client/entrynodes.h"
#include "feature/hibernate/hibernate.h"
-#include "feature/stats/rephist.h"
+#include "feature/stats/bwhist.h"
#include "feature/relay/router.h"
#include "feature/relay/routermode.h"
#include "lib/sandbox/sandbox.h"
@@ -112,6 +112,14 @@ static const config_var_t state_vars_[] = {
V(BWHistoryWriteInterval, POSINT, "900"),
V(BWHistoryWriteValues, CSV, ""),
V(BWHistoryWriteMaxima, CSV, ""),
+ V(BWHistoryIPv6ReadEnds, ISOTIME, NULL),
+ V(BWHistoryIPv6ReadInterval, POSINT, "900"),
+ V(BWHistoryIPv6ReadValues, CSV, ""),
+ V(BWHistoryIPv6ReadMaxima, CSV, ""),
+ V(BWHistoryIPv6WriteEnds, ISOTIME, NULL),
+ V(BWHistoryIPv6WriteInterval, POSINT, "900"),
+ V(BWHistoryIPv6WriteValues, CSV, ""),
+ V(BWHistoryIPv6WriteMaxima, CSV, ""),
V(BWHistoryDirReadEnds, ISOTIME, NULL),
V(BWHistoryDirReadInterval, POSINT, "900"),
V(BWHistoryDirReadValues, CSV, ""),
@@ -324,7 +332,7 @@ or_state_set(or_state_t *new_state)
tor_free(err);
ret = -1;
}
- if (rep_hist_load_state(global_state, &err)<0) {
+ if (bwhist_load_state(global_state, &err)<0) {
log_warn(LD_GENERAL,"Unparseable bandwidth history state: %s",err);
tor_free(err);
ret = -1;
@@ -523,7 +531,7 @@ or_state_save(time_t now)
* to avoid redundant writes. */
(void) subsystems_flush_state(get_state_mgr(), global_state);
entry_guards_update_state(global_state);
- rep_hist_update_state(global_state);
+ bwhist_update_state(global_state);
circuit_build_times_update_state(get_circuit_build_times(), global_state);
if (accounting_is_enabled(get_options()))
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/include.am b/src/app/include.am
index 97d53ec0fd..3caa0bab1c 100644
--- a/src/app/include.am
+++ b/src/app/include.am
@@ -20,7 +20,7 @@ src_app_tor_LDADD = $(TOR_INTERNAL_LIBS) \
@TOR_ZLIB_LIBS@ @TOR_LIB_MATH@ @TOR_LIBEVENT_LIBS@ $(TOR_LIBS_CRYPTLIB) \
@TOR_LIB_WS32@ @TOR_LIB_IPHLPAPI@ @TOR_LIB_GDI@ @TOR_LIB_USERENV@ \
@CURVE25519_LIBS@ @TOR_SYSTEMD_LIBS@ \
- @TOR_LZMA_LIBS@ @TOR_ZSTD_LIBS@
+ @TOR_LZMA_LIBS@ @TOR_ZSTD_LIBS@ @TOR_TRACE_LIBS@
if COVERAGE_ENABLED
src_app_tor_cov_SOURCES = $(src_app_tor_SOURCES)
@@ -31,5 +31,5 @@ src_app_tor_cov_LDADD = $(TOR_INTERNAL_TESTING_LIBS) \
@TOR_ZLIB_LIBS@ @TOR_LIB_MATH@ @TOR_LIBEVENT_LIBS@ $(TOR_LIBS_CRYPTLIB) \
@TOR_LIB_WS32@ @TOR_LIB_IPHLPAPI@ @TOR_LIB_GDI@ \
@CURVE25519_LIBS@ @TOR_SYSTEMD_LIBS@ \
- @TOR_LZMA_LIBS@ @TOR_ZSTD_LIBS@
+ @TOR_LZMA_LIBS@ @TOR_ZSTD_LIBS@ @TOR_TRACE_LIBS@
endif
diff --git a/src/app/main/main.c b/src/app/main/main.c
index dc39611f98..4b1308ddf0 100644
--- a/src/app/main/main.c
+++ b/src/app/main/main.c
@@ -53,12 +53,14 @@
#include "feature/rend/rendcache.h"
#include "feature/rend/rendservice.h"
#include "feature/stats/predict_ports.h"
+#include "feature/stats/bwhist.h"
#include "feature/stats/rephist.h"
#include "lib/compress/compress.h"
#include "lib/buf/buffers.h"
#include "lib/crypt_ops/crypto_rand.h"
#include "lib/crypt_ops/crypto_s2k.h"
#include "lib/net/resolve.h"
+#include "lib/trace/trace.h"
#include "lib/process/waitpid.h"
#include "lib/pubsub/pubsub_build.h"
@@ -549,6 +551,7 @@ tor_init(int argc, char *argv[])
/* Initialize the history structures. */
rep_hist_init();
+ bwhist_init();
/* Initialize the service cache. */
rend_cache_init();
addressmap_init(); /* Init the client dns cache. Do it always, since it's
@@ -602,6 +605,9 @@ tor_init(int argc, char *argv[])
rust_log_welcome_string();
#endif /* defined(HAVE_RUST) */
+ /* Warn _if_ the tracing subsystem is built in. */
+ tracing_log_warning();
+
int init_rv = options_init_from_torrc(argc,argv);
if (init_rv < 0) {
log_err(LD_CONFIG,"Reading config failed--see warnings above.");
@@ -775,12 +781,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 +803,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 +1061,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/app/main/shutdown.c b/src/app/main/shutdown.c
index aac15246b9..4a556333db 100644
--- a/src/app/main/shutdown.c
+++ b/src/app/main/shutdown.c
@@ -47,6 +47,7 @@
#include "feature/relay/relay_config.h"
#include "feature/rend/rendcache.h"
#include "feature/rend/rendclient.h"
+#include "feature/stats/bwhist.h"
#include "feature/stats/geoip_stats.h"
#include "feature/stats/rephist.h"
#include "lib/evloop/compat_libevent.h"
@@ -121,6 +122,7 @@ tor_free_all(int postfork)
rend_cache_free_all();
rend_service_authorization_free_all();
rep_hist_free_all();
+ bwhist_free_all();
circuit_free_all();
circpad_machines_free();
entry_guards_free_all();
diff --git a/src/app/main/subsystem_list.c b/src/app/main/subsystem_list.c
index e32083537f..c6da6f4893 100644
--- a/src/app/main/subsystem_list.c
+++ b/src/app/main/subsystem_list.c
@@ -26,6 +26,7 @@
#include "lib/thread/thread_sys.h"
#include "lib/time/time_sys.h"
#include "lib/tls/tortls_sys.h"
+#include "lib/trace/trace_sys.h"
#include "lib/wallclock/wallclock_sys.h"
#include "lib/evloop/evloop_sys.h"
@@ -47,6 +48,8 @@ const subsys_fns_t *tor_subsystems[] = {
&sys_logging,
&sys_threads,
+ &sys_tracing,
+
&sys_time,
&sys_crypto,
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..1d53e077d1 100644
--- a/src/core/mainloop/connection.c
+++ b/src/core/mainloop/connection.c
@@ -105,7 +105,9 @@
#include "feature/relay/routermode.h"
#include "feature/rend/rendclient.h"
#include "feature/rend/rendcommon.h"
+#include "feature/stats/connstats.h"
#include "feature/stats/rephist.h"
+#include "feature/stats/bwhist.h"
#include "lib/crypt_ops/crypto_util.h"
#include "lib/geoip/geoip.h"
@@ -3344,9 +3346,9 @@ record_num_bytes_transferred_impl(connection_t *conn,
/* Count bytes of answering direct and tunneled directory requests */
if (conn->type == CONN_TYPE_DIR && conn->purpose == DIR_PURPOSE_SERVER) {
if (num_read > 0)
- rep_hist_note_dir_bytes_read(num_read, now);
+ bwhist_note_dir_bytes_read(num_read, now);
if (num_written > 0)
- rep_hist_note_dir_bytes_written(num_written, now);
+ bwhist_note_dir_bytes_written(num_written, now);
}
/* Linked connections and internal IPs aren't counted for statistics or
@@ -3361,15 +3363,16 @@ record_num_bytes_transferred_impl(connection_t *conn,
if (!connection_is_rate_limited(conn))
return;
+ const bool is_ipv6 = (conn->socket_family == AF_INET6);
if (conn->type == CONN_TYPE_OR)
- rep_hist_note_or_conn_bytes(conn->global_identifier, num_read,
- num_written, now);
+ conn_stats_note_or_conn_bytes(conn->global_identifier, num_read,
+ num_written, now, is_ipv6);
if (num_read > 0) {
- rep_hist_note_bytes_read(num_read, now);
+ bwhist_note_bytes_read(num_read, now, is_ipv6);
}
if (num_written > 0) {
- rep_hist_note_bytes_written(num_written, now);
+ bwhist_note_bytes_written(num_written, now, is_ipv6);
}
if (conn->type == CONN_TYPE_EXIT)
rep_hist_note_exit_bytes(conn->port, num_written, num_read);
@@ -4871,7 +4874,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/mainloop/mainloop.c b/src/core/mainloop/mainloop.c
index e4e17f6b76..3bf9be566b 100644
--- a/src/core/mainloop/mainloop.c
+++ b/src/core/mainloop/mainloop.c
@@ -95,6 +95,7 @@
#include "feature/rend/rendservice.h"
#include "feature/stats/geoip_stats.h"
#include "feature/stats/predict_ports.h"
+#include "feature/stats/connstats.h"
#include "feature/stats/rephist.h"
#include "lib/buf/buffers.h"
#include "lib/crypt_ops/crypto_rand.h"
@@ -1950,7 +1951,7 @@ write_stats_file_callback(time_t now, const or_options_t *options)
next_time_to_write_stats_files = next_write;
}
if (options->ConnDirectionStatistics) {
- time_t next_write = rep_hist_conn_stats_write(now);
+ time_t next_write = conn_stats_save(now);
if (next_write && next_write < next_time_to_write_stats_files)
next_time_to_write_stats_files = next_write;
}
diff --git a/src/core/or/channel.c b/src/core/or/channel.c
index a05554472f..20ccf41306 100644
--- a/src/core/or/channel.c
+++ b/src/core/or/channel.c
@@ -83,13 +83,6 @@
#include "core/or/cell_queue_st.h"
-/* Static function prototypes */
-
-static bool channel_matches_target_addr_for_extend(
- channel_t *chan,
- const tor_addr_t *target_ipv4_addr,
- const tor_addr_t *target_ipv6_addr);
-
/* Global lists of channels */
/* All channel_t instances */
@@ -2849,7 +2842,7 @@ channel_get_canonical_remote_descr,(channel_t *chan))
* doesn't let us do this.
*/
MOCK_IMPL(int,
-channel_get_addr_if_possible,(channel_t *chan, tor_addr_t *addr_out))
+channel_get_addr_if_possible,(const channel_t *chan, tor_addr_t *addr_out))
{
tor_assert(chan);
tor_assert(addr_out);
@@ -3317,7 +3310,7 @@ channel_matches_extend_info(channel_t *chan, extend_info_t *extend_info)
* This function calls into the lower layer and asks if this channel thinks
* it matches the target addresses for circuit extension purposes.
*/
-static bool
+STATIC bool
channel_matches_target_addr_for_extend(channel_t *chan,
const tor_addr_t *target_ipv4_addr,
const tor_addr_t *target_ipv6_addr)
diff --git a/src/core/or/channel.h b/src/core/or/channel.h
index 4968c8714a..5fe1fb9cc4 100644
--- a/src/core/or/channel.h
+++ b/src/core/or/channel.h
@@ -335,7 +335,7 @@ struct channel_t {
* provided tor_addr_t *, and return 1 if successful or 0 if no address
* available.
*/
- int (*get_remote_addr)(channel_t *, tor_addr_t *);
+ int (*get_remote_addr)(const channel_t *, tor_addr_t *);
int (*get_transport_name)(channel_t *chan, char **transport_out);
#define GRD_FLAG_ORIGINAL 1
@@ -562,7 +562,10 @@ void channel_listener_dumpstats(int severity);
#ifdef CHANNEL_FILE_PRIVATE
STATIC void channel_add_to_digest_map(channel_t *chan);
-
+STATIC bool channel_matches_target_addr_for_extend(
+ channel_t *chan,
+ const tor_addr_t *target_ipv4_addr,
+ const tor_addr_t *target_ipv6_addr);
#endif /* defined(CHANNEL_FILE_PRIVATE) */
/* Channel operations for subclasses and internal use only */
@@ -723,7 +726,7 @@ MOCK_DECL(void, channel_dump_statistics, (channel_t *chan, int severity));
void channel_dump_transport_statistics(channel_t *chan, int severity);
const char * channel_get_actual_remote_descr(channel_t *chan);
const char * channel_get_actual_remote_address(channel_t *chan);
-MOCK_DECL(int, channel_get_addr_if_possible, (channel_t *chan,
+MOCK_DECL(int, channel_get_addr_if_possible, (const channel_t *chan,
tor_addr_t *addr_out));
MOCK_DECL(const char *, channel_get_canonical_remote_descr,(channel_t *chan));
int channel_has_queued_writes(channel_t *chan);
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..ff4505acfa 100644
--- a/src/core/or/channeltls.c
+++ b/src/core/or/channeltls.c
@@ -63,15 +63,16 @@
#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"
#include "feature/nodelist/routerinfo_st.h"
#include "core/or/var_cell_st.h"
+#include "src/feature/relay/relay_find_addr.h"
#include "lib/tls/tortls.h"
#include "lib/tls/x509.h"
@@ -103,7 +104,8 @@ static const char * channel_tls_describe_transport_method(channel_t *chan);
static void channel_tls_free_method(channel_t *chan);
static double channel_tls_get_overhead_estimate_method(channel_t *chan);
static int
-channel_tls_get_remote_addr_method(channel_t *chan, tor_addr_t *addr_out);
+channel_tls_get_remote_addr_method(const channel_t *chan,
+ tor_addr_t *addr_out);
static int
channel_tls_get_transport_name_method(channel_t *chan, char **transport_out);
static const char *
@@ -203,7 +205,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 +342,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);
@@ -514,10 +516,10 @@ channel_tls_get_overhead_estimate_method(channel_t *chan)
* succeeds for this transport).
*/
static int
-channel_tls_get_remote_addr_method(channel_t *chan, tor_addr_t *addr_out)
+channel_tls_get_remote_addr_method(const channel_t *chan, tor_addr_t *addr_out)
{
int rv = 0;
- channel_tls_t *tlschan = BASE_CHAN_TO_TLS(chan);
+ const channel_tls_t *tlschan = BASE_CHAN_TO_TLS((channel_t*) chan);
tor_assert(tlschan);
tor_assert(addr_out);
@@ -702,9 +704,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 +1355,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",
@@ -1688,6 +1690,85 @@ time_abs(time_t val)
return (val < 0) ? -val : val;
}
+/** Return true iff the channel can process a NETINFO cell. For this to return
+ * true, these channel conditions apply:
+ *
+ * 1. Link protocol is version 2 or higher (tor-spec.txt, NETINFO cells
+ * section).
+ *
+ * 2. Underlying OR connection of the channel is either in v2 or v3
+ * handshaking state.
+ */
+static bool
+can_process_netinfo_cell(const channel_tls_t *chan)
+{
+ /* NETINFO cells can only be negotiated on link protocol 2 or higher. */
+ if (chan->conn->link_proto < 2) {
+ log_fn(LOG_PROTOCOL_WARN, LD_OR,
+ "Received a NETINFO cell on %s connection; dropping.",
+ chan->conn->link_proto == 0 ? "non-versioned" : "a v1");
+ return false;
+ }
+
+ /* Can't process a NETINFO cell if the connection is not handshaking. */
+ if (chan->conn->base_.state != OR_CONN_STATE_OR_HANDSHAKING_V2 &&
+ chan->conn->base_.state != OR_CONN_STATE_OR_HANDSHAKING_V3) {
+ log_fn(LOG_PROTOCOL_WARN, LD_OR,
+ "Received a NETINFO cell on non-handshaking connection; dropping.");
+ return false;
+ }
+
+ /* Make sure we do have handshake state. */
+ tor_assert(chan->conn->handshake_state);
+ tor_assert(chan->conn->handshake_state->received_versions);
+
+ return true;
+}
+
+/** Mark the given channel endpoint as a client (which means either a tor
+ * client or a tor bridge).
+ *
+ * This MUST be done on an _unauthenticated_ channel. It is a mistake to mark
+ * an authenticated channel as a client.
+ *
+ * The following is done on the channel:
+ *
+ * 1. Marked as a client.
+ * 2. Type of circuit ID type is set.
+ * 3. The underlying OR connection is initialized with the address of the
+ * endpoint.
+ */
+static void
+mark_channel_tls_endpoint_as_client(channel_tls_t *chan)
+{
+ /* Ending up here for an authenticated link is a mistake. */
+ if (BUG(chan->conn->handshake_state->authenticated)) {
+ return;
+ }
+
+ tor_assert(tor_digest_is_zero(
+ (const char*)(chan->conn->handshake_state->
+ authenticated_rsa_peer_id)));
+ tor_assert(fast_mem_is_zero(
+ (const char*)(chan->conn->handshake_state->
+ authenticated_ed25519_peer_id.pubkey), 32));
+ /* If the client never authenticated, it's a tor client or bridge
+ * relay, and we must not use it for EXTEND requests (nor could we, as
+ * there are no authenticated peer IDs) */
+ channel_mark_client(TLS_CHAN_TO_BASE(chan));
+ channel_set_circid_type(TLS_CHAN_TO_BASE(chan), NULL,
+ chan->conn->link_proto < MIN_LINK_PROTO_FOR_WIDE_CIRC_IDS);
+
+ connection_or_init_conn_from_address(chan->conn,
+ &(chan->conn->base_.addr),
+ chan->conn->base_.port,
+ /* zero, checked above */
+ (const char*)(chan->conn->handshake_state->
+ authenticated_rsa_peer_id),
+ NULL, /* Ed25519 ID: Also checked as zero */
+ 0);
+}
+
/**
* Process a 'netinfo' cell
*
@@ -1713,20 +1794,12 @@ channel_tls_process_netinfo_cell(cell_t *cell, channel_tls_t *chan)
tor_assert(chan);
tor_assert(chan->conn);
- if (chan->conn->link_proto < 2) {
- log_fn(LOG_PROTOCOL_WARN, LD_OR,
- "Received a NETINFO cell on %s connection; dropping.",
- chan->conn->link_proto == 0 ? "non-versioned" : "a v1");
+ /* Make sure we can process a NETINFO cell. Link protocol and state
+ * validation is done to make sure of it. */
+ if (!can_process_netinfo_cell(chan)) {
return;
}
- if (chan->conn->base_.state != OR_CONN_STATE_OR_HANDSHAKING_V2 &&
- chan->conn->base_.state != OR_CONN_STATE_OR_HANDSHAKING_V3) {
- log_fn(LOG_PROTOCOL_WARN, LD_OR,
- "Received a NETINFO cell on non-handshaking connection; dropping.");
- return;
- }
- tor_assert(chan->conn->handshake_state &&
- chan->conn->handshake_state->received_versions);
+
started_here = connection_or_nonopen_was_started_here(chan->conn);
identity_digest = chan->conn->identity_digest;
@@ -1741,30 +1814,13 @@ channel_tls_process_netinfo_cell(cell_t *cell, channel_tls_t *chan)
return;
}
} else {
- /* we're the server. If the client never authenticated, we have
- some housekeeping to do.*/
+ /* We're the server. If the client never authenticated, we have some
+ * housekeeping to do.
+ *
+ * It's a tor client or bridge relay, and we must not use it for EXTEND
+ * requests (nor could we, as there are no authenticated peer IDs) */
if (!(chan->conn->handshake_state->authenticated)) {
- tor_assert(tor_digest_is_zero(
- (const char*)(chan->conn->handshake_state->
- authenticated_rsa_peer_id)));
- tor_assert(fast_mem_is_zero(
- (const char*)(chan->conn->handshake_state->
- authenticated_ed25519_peer_id.pubkey), 32));
- /* If the client never authenticated, it's a tor client or bridge
- * relay, and we must not use it for EXTEND requests (nor could we, as
- * there are no authenticated peer IDs) */
- channel_mark_client(TLS_CHAN_TO_BASE(chan));
- channel_set_circid_type(TLS_CHAN_TO_BASE(chan), NULL,
- chan->conn->link_proto < MIN_LINK_PROTO_FOR_WIDE_CIRC_IDS);
-
- connection_or_init_conn_from_address(chan->conn,
- &(chan->conn->base_.addr),
- chan->conn->base_.port,
- /* zero, checked above */
- (const char*)(chan->conn->handshake_state->
- authenticated_rsa_peer_id),
- NULL, /* Ed25519 ID: Also checked as zero */
- 0);
+ mark_channel_tls_endpoint_as_client(chan);
}
}
}
@@ -1875,8 +1931,12 @@ channel_tls_process_netinfo_cell(cell_t *cell, channel_tls_t *chan)
"NETINFO cell", "OR");
}
- /* XXX maybe act on my_apparent_addr, if the source is sufficiently
- * trustworthy. */
+ /* Consider our apparent address as a possible suggestion for our address if
+ * we were unable to resolve it previously. The endpoint address is passed
+ * in order to make sure to never consider an address that is the same as
+ * our endpoint. */
+ relay_address_new_suggestion(&my_apparent_addr, &chan->conn->real_addr,
+ identity_digest);
if (! chan->conn->handshake_state->sent_netinfo) {
/* If we were prepared to authenticate, but we never got an AUTH_CHALLENGE
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..24543d3ac0 100644
--- a/src/core/or/circuitbuild.c
+++ b/src/core/or/circuitbuild.c
@@ -45,10 +45,12 @@
#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"
#include "core/or/relay.h"
+#include "core/or/trace_probes_circuit.h"
#include "core/or/crypt_path.h"
#include "feature/client/bridges.h"
#include "feature/client/circpathbias.h"
@@ -70,6 +72,7 @@
#include "feature/rend/rendcommon.h"
#include "feature/stats/predict_ports.h"
#include "lib/crypt_ops/crypto_rand.h"
+#include "lib/trace/events.h"
#include "core/or/cell_st.h"
#include "core/or/cpath_build_state_st.h"
@@ -78,9 +81,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 +96,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 +443,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 +460,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.
@@ -491,6 +499,8 @@ circuit_establish_circuit(uint8_t purpose, extend_info_t *exit_ei, int flags)
circuit_mark_for_close(TO_CIRCUIT(circ), -err_reason);
return NULL;
}
+
+ tor_trace(TR_SUBSYS(circuit), TR_EV(establish), circ);
return circ;
}
@@ -546,7 +556,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 +565,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 +585,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 +603,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;
@@ -980,6 +983,7 @@ circuit_send_first_onion_skin(origin_circuit_t *circ)
if (circuit_deliver_create_cell(TO_CIRCUIT(circ), &cc, 0) < 0)
return - END_CIRC_REASON_RESOURCELIMIT;
+ tor_trace(TR_SUBSYS(circuit), TR_EV(first_onion_skin), circ, circ->cpath);
circ->cpath->state = CPATH_STATE_AWAITING_KEYS;
circuit_set_state(TO_CIRCUIT(circ), CIRCUIT_STATE_BUILDING);
@@ -1050,8 +1054,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 +1079,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. */
@@ -1126,6 +1147,7 @@ circuit_send_intermediate_onion_skin(origin_circuit_t *circ,
return 0; /* circuit is closed */
}
hop->state = CPATH_STATE_AWAITING_KEYS;
+ tor_trace(TR_SUBSYS(circuit), TR_EV(intermediate_onion_skin), circ, hop);
return 0;
}
@@ -1539,7 +1561,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 +1610,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 +1627,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 +1783,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 +1963,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 +2033,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 +2101,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 +2315,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 +2392,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 +2461,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 +2496,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 +2530,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..2455aa8779 100644
--- a/src/core/or/circuitlist.c
+++ b/src/core/or/circuitlist.c
@@ -64,6 +64,8 @@
#include "core/or/circuitstats.h"
#include "core/or/circuitpadding.h"
#include "core/or/crypt_path.h"
+#include "core/or/extendinfo.h"
+#include "core/or/trace_probes_circuit.h"
#include "core/mainloop/connection.h"
#include "app/config/config.h"
#include "core/or/connection_edge.h"
@@ -89,6 +91,7 @@
#include "feature/rend/rendclient.h"
#include "feature/rend/rendcommon.h"
#include "feature/stats/predict_ports.h"
+#include "feature/stats/bwhist.h"
#include "feature/stats/rephist.h"
#include "feature/nodelist/routerlist.h"
#include "feature/nodelist/routerset.h"
@@ -564,6 +567,8 @@ circuit_set_state(circuit_t *circ, uint8_t state)
}
if (state == CIRCUIT_STATE_GUARD_WAIT || state == CIRCUIT_STATE_OPEN)
tor_assert(!circ->n_chan_create_cell);
+
+ tor_trace(TR_SUBSYS(circuit), TR_EV(change_state), circ, circ->state, state);
circ->state = state;
if (CIRCUIT_IS_ORIGIN(circ))
circuit_state_publish(circ);
@@ -1078,6 +1083,7 @@ origin_circuit_new(void)
prediction_time_remaining);
}
+ tor_trace(TR_SUBSYS(circuit), TR_EV(new_origin), circ);
return circ;
}
@@ -1100,6 +1106,7 @@ or_circuit_new(circid_t p_circ_id, channel_t *p_chan)
init_circuit_base(TO_CIRCUIT(circ));
+ tor_trace(TR_SUBSYS(circuit), TR_EV(new_or), circ);
return circ;
}
@@ -1252,6 +1259,10 @@ circuit_free_(circuit_t *circ)
/* Clear all dangling handle references. */
circuit_handles_clear(circ);
+ /* Tracepoint. Data within the circuit object is recorded so do this before
+ * the actual memory free. */
+ tor_trace(TR_SUBSYS(circuit), TR_EV(free), circ);
+
if (should_free) {
memwipe(mem, 0xAA, memlen); /* poison memory */
tor_free(mem);
@@ -1944,7 +1955,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;
}
@@ -2165,6 +2176,12 @@ circuit_synchronize_written_or_bandwidth(const circuit_t *c,
else
cell_size = CELL_MAX_NETWORK_SIZE;
+ /* If we know the channel, find out if it's IPv6. */
+ tor_addr_t remote_addr;
+ bool is_ipv6 = chan &&
+ channel_get_addr_if_possible(chan, &remote_addr) &&
+ tor_addr_family(&remote_addr) == AF_INET6;
+
/* The missing written bytes are the cell counts times their cell
* size plus TLS per cell overhead */
written_sync = cells*(cell_size+TLS_PER_CELL_OVERHEAD);
@@ -2172,7 +2189,7 @@ circuit_synchronize_written_or_bandwidth(const circuit_t *c,
/* Report the missing bytes as written, to avoid asymmetry.
* We must use time() for consistency with rephist, even though on
* some very old rare platforms, approx_time() may be faster. */
- rep_hist_note_bytes_written(written_sync, time(NULL));
+ bwhist_note_bytes_written(written_sync, time(NULL), is_ipv6);
}
/** Mark <b>circ</b> to be closed next time we call
@@ -2274,6 +2291,7 @@ circuit_mark_for_close_, (circuit_t *circ, int reason, int line,
CIRCUIT_IS_ORIGIN(circ) ?
TO_ORIGIN_CIRCUIT(circ)->global_identifier : 0,
file, line, orig_reason, reason);
+ tor_trace(TR_SUBSYS(circuit), TR_EV(mark_for_close), circ);
}
/** Called immediately before freeing a marked circuit <b>circ</b> from
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 5875627b93..51bd9e1208 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..d2bdf77d8d 100644
--- a/src/core/or/circuituse.c
+++ b/src/core/or/circuituse.c
@@ -37,7 +37,9 @@
#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 "core/or/trace_probes_circuit.h"
#include "feature/client/addressmap.h"
#include "feature/client/bridges.h"
#include "feature/client/circpathbias.h"
@@ -62,6 +64,7 @@
#include "feature/stats/predict_ports.h"
#include "lib/math/fp.h"
#include "lib/time/tvdiff.h"
+#include "lib/trace/events.h"
#include "core/or/cpath_build_state_st.h"
#include "feature/dircommon/dir_connection_st.h"
@@ -202,8 +205,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;
}
}
@@ -837,6 +840,7 @@ circuit_expire_building(void)
-1);
circuit_log_path(LOG_INFO,LD_CIRC,TO_ORIGIN_CIRCUIT(victim));
+ tor_trace(TR_SUBSYS(circuit), TR_EV(timeout), TO_ORIGIN_CIRCUIT(victim));
if (victim->purpose == CIRCUIT_PURPOSE_C_MEASURE_TIMEOUT)
circuit_mark_for_close(victim, END_CIRC_REASON_MEASUREMENT_EXPIRED);
else
@@ -1500,8 +1504,11 @@ circuit_expire_old_circuits_clientside(void)
circ->purpose);
/* Don't do this magic for testing circuits. Their death is governed
* by circuit_expire_building */
- if (circ->purpose != CIRCUIT_PURPOSE_PATH_BIAS_TESTING)
+ if (circ->purpose != CIRCUIT_PURPOSE_PATH_BIAS_TESTING) {
+ tor_trace(TR_SUBSYS(circuit), TR_EV(idle_timeout),
+ TO_ORIGIN_CIRCUIT(circ));
circuit_mark_for_close(circ, END_CIRC_REASON_FINISHED);
+ }
} else if (!circ->timestamp_dirty && circ->state == CIRCUIT_STATE_OPEN) {
if (timercmp(&circ->timestamp_began, &cutoff, OP_LT)) {
if (circ->purpose == CIRCUIT_PURPOSE_C_GENERAL ||
@@ -1520,6 +1527,8 @@ circuit_expire_old_circuits_clientside(void)
" that has been unused for %ld msec.",
TO_ORIGIN_CIRCUIT(circ)->global_identifier,
tv_mdiff(&circ->timestamp_began, &now));
+ tor_trace(TR_SUBSYS(circuit), TR_EV(idle_timeout),
+ TO_ORIGIN_CIRCUIT(circ));
circuit_mark_for_close(circ, END_CIRC_REASON_FINISHED);
} else if (!TO_ORIGIN_CIRCUIT(circ)->is_ancient) {
/* Server-side rend joined circuits can end up really old, because
@@ -1642,7 +1651,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 +1669,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,
@@ -1681,6 +1691,7 @@ circuit_testing_failed(origin_circuit_t *circ, int at_last_hop)
void
circuit_has_opened(origin_circuit_t *circ)
{
+ tor_trace(TR_SUBSYS(circuit), TR_EV(opened), circ);
circuit_event_status(circ, CIRC_EVENT_BUILT, 0);
/* Remember that this circuit has finished building. Now if we start
@@ -2092,11 +2103,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,
@@ -2195,6 +2213,8 @@ circuit_launch_by_extend_info(uint8_t purpose,
tor_fragile_assert();
return NULL;
}
+
+ tor_trace(TR_SUBSYS(circuit), TR_EV(cannibalized), circ);
return circ;
}
}
@@ -3126,6 +3146,8 @@ circuit_change_purpose(circuit_t *circ, uint8_t new_purpose)
old_purpose = circ->purpose;
circ->purpose = new_purpose;
+ tor_trace(TR_SUBSYS(circuit), TR_EV(change_purpose), circ, old_purpose,
+ new_purpose);
if (CIRCUIT_IS_ORIGIN(circ)) {
control_event_circuit_purpose_changed(TO_ORIGIN_CIRCUIT(circ),
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..9ff92adbde 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 \
@@ -94,3 +96,10 @@ noinst_HEADERS += \
src/core/or/tor_version_st.h \
src/core/or/var_cell_st.h \
src/core/or/versions.h
+
+if USE_TRACING_INSTRUMENTATION_LTTNG
+LIBTOR_APP_A_SOURCES += \
+ src/core/or/trace_probes_circuit.c
+noinst_HEADERS += \
+ src/core/or/trace_probes_circuit.h
+endif
diff --git a/src/core/or/lttng_circuit.inc b/src/core/or/lttng_circuit.inc
new file mode 100644
index 0000000000..fc3e175c8a
--- /dev/null
+++ b/src/core/or/lttng_circuit.inc
@@ -0,0 +1,322 @@
+/* Copyright (c) 2020, The Tor Project, Inc. */
+/* See LICENSE for licensing information */
+
+/**
+ * \file lttng_circuit.inc
+ * \brief LTTng tracing probe declaration for the circuit subsystem. It is in
+* this .inc file due to the non C standard syntax and the way we guard
+* the header with the LTTng specific TRACEPOINT_HEADER_MULTI_READ.
+ **/
+
+#include "orconfig.h"
+
+/* We only build the following if LTTng instrumentation has been enabled. */
+#ifdef USE_TRACING_INSTRUMENTATION_LTTNG
+
+/* The following defines are LTTng-UST specific. */
+#undef TRACEPOINT_PROVIDER
+#define TRACEPOINT_PROVIDER tor_circuit
+
+#undef TRACEPOINT_INCLUDE
+#define TRACEPOINT_INCLUDE "./src/core/or/lttng_circuit.inc"
+
+#if !defined(LTTNG_CIRCUIT_INC) || defined(TRACEPOINT_HEADER_MULTI_READ)
+#define LTTNG_CIRCUIT_INC
+
+#include <lttng/tracepoint.h>
+
+/*
+ * Circuit Purposes
+ *
+ * The following defines an enumeration of all possible circuit purpose so
+ * they appear in the trace with the define name (first parameter of
+ * ctf_enum_value) instead of the numerical value.
+ */
+TRACEPOINT_ENUM(tor_circuit, purpose,
+ TP_ENUM_VALUES(
+ /* Initializing. */
+ ctf_enum_value("<UNSET>", 0)
+
+ /* OR Side. */
+ ctf_enum_value("OR", CIRCUIT_PURPOSE_OR)
+ ctf_enum_value("OR_INTRO_POINT", CIRCUIT_PURPOSE_INTRO_POINT)
+ ctf_enum_value("OR_REND_POINT_WAITING",
+ CIRCUIT_PURPOSE_REND_POINT_WAITING)
+ ctf_enum_value("OR_REND_ESTABLISHED", CIRCUIT_PURPOSE_REND_ESTABLISHED)
+
+ /* Client Side. */
+ ctf_enum_value("C_GENERAL", CIRCUIT_PURPOSE_C_GENERAL)
+ ctf_enum_value("C_INTRODUCING", CIRCUIT_PURPOSE_C_INTRODUCING)
+ ctf_enum_value("C_INTRODUCE_ACK_WAIT",
+ CIRCUIT_PURPOSE_C_INTRODUCE_ACK_WAIT)
+ ctf_enum_value("C_INTRODUCE_ACKED", CIRCUIT_PURPOSE_C_INTRODUCE_ACKED)
+ ctf_enum_value("C_ESTABLISH_REND", CIRCUIT_PURPOSE_C_ESTABLISH_REND)
+ ctf_enum_value("C_REND_READY", CIRCUIT_PURPOSE_C_REND_READY)
+ ctf_enum_value("C_REND_READY_INTRO_ACKED",
+ CIRCUIT_PURPOSE_C_REND_READY_INTRO_ACKED)
+ ctf_enum_value("C_REND_JOINED", CIRCUIT_PURPOSE_C_REND_JOINED)
+ ctf_enum_value("C_HSDIR_GET", CIRCUIT_PURPOSE_C_HSDIR_GET)
+
+ /* CBT and Padding. */
+ ctf_enum_value("C_MEASURE_TIMEOUT", CIRCUIT_PURPOSE_C_MEASURE_TIMEOUT)
+ ctf_enum_value("C_CIRCUIT_PADDING", CIRCUIT_PURPOSE_C_CIRCUIT_PADDING)
+
+ /* Service Side. */
+ ctf_enum_value("S_ESTABLISH_INTRO", CIRCUIT_PURPOSE_S_ESTABLISH_INTRO)
+ ctf_enum_value("S_INTRO", CIRCUIT_PURPOSE_S_INTRO)
+ ctf_enum_value("S_CONNECT_REND", CIRCUIT_PURPOSE_S_CONNECT_REND)
+ ctf_enum_value("S_REND_JOINED", CIRCUIT_PURPOSE_S_REND_JOINED)
+ ctf_enum_value("S_HSDIR_POST", CIRCUIT_PURPOSE_S_HSDIR_POST)
+
+ /* Misc. */
+ ctf_enum_value("TESTING", CIRCUIT_PURPOSE_TESTING)
+ ctf_enum_value("CONTROLER", CIRCUIT_PURPOSE_CONTROLLER)
+ ctf_enum_value("PATH_BIAS_TESTING", CIRCUIT_PURPOSE_PATH_BIAS_TESTING)
+
+ /* VanGuard */
+ ctf_enum_value("HS_VANGUARDS", CIRCUIT_PURPOSE_HS_VANGUARDS)
+ )
+)
+
+/*
+ * Circuit End Reasons
+ *
+ * The following defines an enumeration of all possible circuit end reasons so
+ * they appear in the trace with the define name (first parameter of
+ * ctf_enum_value) instead of the numerical value.
+ */
+TRACEPOINT_ENUM(tor_circuit, end_reason,
+ TP_ENUM_VALUES(
+ /* Local reasons. */
+ ctf_enum_value("IP_NOW_REDUNDANT", END_CIRC_REASON_IP_NOW_REDUNDANT)
+ ctf_enum_value("MEASUREMENT_EXPIRED", END_CIRC_REASON_MEASUREMENT_EXPIRED)
+ ctf_enum_value("REASON_NOPATH", END_CIRC_REASON_NOPATH)
+ ctf_enum_value("AT_ORIGIN", END_CIRC_AT_ORIGIN)
+ ctf_enum_value("NONE", END_CIRC_REASON_NONE)
+ ctf_enum_value("TORPROTOCOL", END_CIRC_REASON_TORPROTOCOL)
+ ctf_enum_value("INTERNAL", END_CIRC_REASON_INTERNAL)
+ ctf_enum_value("REQUESTED", END_CIRC_REASON_REQUESTED)
+ ctf_enum_value("HIBERNATING", END_CIRC_REASON_HIBERNATING)
+ ctf_enum_value("RESOURCELIMIT", END_CIRC_REASON_RESOURCELIMIT)
+ ctf_enum_value("CONNECTFAILED", END_CIRC_REASON_CONNECTFAILED)
+ ctf_enum_value("OR_IDENTITY", END_CIRC_REASON_OR_IDENTITY)
+ ctf_enum_value("CHANNEL_CLOSED", END_CIRC_REASON_CHANNEL_CLOSED)
+ ctf_enum_value("FINISHED", END_CIRC_REASON_FINISHED)
+ ctf_enum_value("TIMEOUT", END_CIRC_REASON_TIMEOUT)
+ ctf_enum_value("DESTROYED", END_CIRC_REASON_DESTROYED)
+ ctf_enum_value("NOSUCHSERVICE", END_CIRC_REASON_NOSUCHSERVICE)
+
+ /* Remote reasons. */
+ ctf_enum_value("FLAG_REMOTE", END_CIRC_REASON_FLAG_REMOTE)
+ ctf_enum_value("REMOTE_TORPROTOCOL",
+ END_CIRC_REASON_FLAG_REMOTE | END_CIRC_REASON_TORPROTOCOL)
+ ctf_enum_value("REMOTE_INTERNAL",
+ END_CIRC_REASON_FLAG_REMOTE | END_CIRC_REASON_INTERNAL)
+ ctf_enum_value("REMOTE_REQUESTED",
+ END_CIRC_REASON_FLAG_REMOTE | END_CIRC_REASON_REQUESTED)
+ ctf_enum_value("REMOTE_HIBERNATING",
+ END_CIRC_REASON_FLAG_REMOTE | END_CIRC_REASON_HIBERNATING)
+ ctf_enum_value("REMOTE_RESOURCELIMIT",
+ END_CIRC_REASON_FLAG_REMOTE | END_CIRC_REASON_RESOURCELIMIT)
+ ctf_enum_value("REMOTE_CONNECTFAILED",
+ END_CIRC_REASON_FLAG_REMOTE | END_CIRC_REASON_CONNECTFAILED)
+ ctf_enum_value("REMOTE_OR_IDENTITY",
+ END_CIRC_REASON_FLAG_REMOTE | END_CIRC_REASON_OR_IDENTITY)
+ ctf_enum_value("REMOTE_CHANNEL_CLOSED",
+ END_CIRC_REASON_FLAG_REMOTE | END_CIRC_REASON_CHANNEL_CLOSED)
+ ctf_enum_value("REMOTE_FINISHED",
+ END_CIRC_REASON_FLAG_REMOTE | END_CIRC_REASON_FINISHED)
+ ctf_enum_value("REMOTE_TIMEOUT",
+ END_CIRC_REASON_FLAG_REMOTE | END_CIRC_REASON_TIMEOUT)
+ ctf_enum_value("REMOTE_DESTROYED",
+ END_CIRC_REASON_FLAG_REMOTE | END_CIRC_REASON_DESTROYED)
+ ctf_enum_value("REMOTE_NOSUCHSERVICE",
+ END_CIRC_REASON_FLAG_REMOTE | END_CIRC_REASON_NOSUCHSERVICE)
+ )
+)
+
+/*
+ * Circuit State
+ *
+ * The following defines an enumeration of all possible circuit state so they
+ * appear in the trace with the define name (first parameter of
+ * ctf_enum_value) instead of the numerical value.
+ */
+TRACEPOINT_ENUM(tor_circuit, state,
+ TP_ENUM_VALUES(
+ ctf_enum_value("BUILDING", CIRCUIT_STATE_BUILDING)
+ ctf_enum_value("ONIONSKIN_PENDING", CIRCUIT_STATE_ONIONSKIN_PENDING)
+ ctf_enum_value("CHAN_WAIT", CIRCUIT_STATE_CHAN_WAIT)
+ ctf_enum_value("GUARD_WAIT", CIRCUIT_STATE_GUARD_WAIT)
+ ctf_enum_value("OPEN", CIRCUIT_STATE_OPEN)
+ )
+)
+
+/*
+ * Event Class
+ *
+ * A tracepoint class is a class of tracepoints which share the same output
+ * event field definitions. They are then used by the
+ * TRACEPOINT_EVENT_INSTANCE() macro as a base field definition.
+ */
+
+/* Class for origin circuit. */
+TRACEPOINT_EVENT_CLASS(tor_circuit, origin_circuit_t_class,
+ TP_ARGS(const origin_circuit_t *, circ),
+ TP_FIELDS(
+ ctf_integer(uint32_t, circ_id, circ->global_identifier)
+ ctf_enum(tor_circuit, purpose, int, purpose, TO_CIRCUIT(circ)->purpose)
+ ctf_enum(tor_circuit, state, int, state, TO_CIRCUIT(circ)->state)
+ )
+)
+
+/* Class for or circuit. */
+TRACEPOINT_EVENT_CLASS(tor_circuit, or_circuit_t_class,
+ TP_ARGS(const or_circuit_t *, circ),
+ TP_FIELDS(
+ ctf_enum(tor_circuit, purpose, int, purpose, TO_CIRCUIT(circ)->purpose)
+ ctf_enum(tor_circuit, state, int, state, TO_CIRCUIT(circ)->state)
+ )
+)
+
+/*
+ * Origin circuit events.
+ *
+ * Tracepoint use the origin_circuit_t object.
+ */
+
+/* Tracepoint emitted when a new origin circuit has been created. */
+TRACEPOINT_EVENT_INSTANCE(tor_circuit, origin_circuit_t_class, new_origin,
+ TP_ARGS(const origin_circuit_t *, circ)
+)
+
+/* Tracepoint emitted when an origin circuit has opened. */
+TRACEPOINT_EVENT_INSTANCE(tor_circuit, origin_circuit_t_class, opened,
+ TP_ARGS(const origin_circuit_t *, circ)
+)
+
+/* Tracepoint emitted when an origin circuit has established. */
+TRACEPOINT_EVENT_INSTANCE(tor_circuit, origin_circuit_t_class, establish,
+ TP_ARGS(const origin_circuit_t *, circ)
+)
+
+/* Tracepoint emitted when an origin circuit has been cannibalized. */
+TRACEPOINT_EVENT_INSTANCE(tor_circuit, origin_circuit_t_class, cannibalized,
+ TP_ARGS(const origin_circuit_t *, circ)
+)
+
+/* Tracepoint emitted when an origin circuit has timed out. This is called
+ * when circuit_expire_building() as selected the circuit and is about to
+ * close it for timeout. */
+TRACEPOINT_EVENT_INSTANCE(tor_circuit, origin_circuit_t_class, timeout,
+ TP_ARGS(const origin_circuit_t *, circ)
+)
+
+/* Tracepoint emitted when an origin circuit has timed out due to idleness.
+ * This is when the circuit is closed after MaxCircuitDirtiness. */
+TRACEPOINT_EVENT_INSTANCE(tor_circuit, origin_circuit_t_class, idle_timeout,
+ TP_ARGS(const origin_circuit_t *, circ)
+)
+
+/* Tracepoint emitted when an origin circuit sends out its first onion skin. */
+TRACEPOINT_EVENT(tor_circuit, first_onion_skin,
+ TP_ARGS(const origin_circuit_t *, circ, const crypt_path_t *, hop),
+ TP_FIELDS(
+ ctf_integer(uint32_t, circ_id, circ->global_identifier)
+ ctf_enum(tor_circuit, purpose, int, purpose, TO_CIRCUIT(circ)->purpose)
+ ctf_enum(tor_circuit, state, int, state, TO_CIRCUIT(circ)->state)
+ ctf_array_hex(char, fingerprint, hop->extend_info->identity_digest,
+ DIGEST_LEN)
+ )
+)
+
+/* Tracepoint emitted when an origin circuit sends out an intermediate onion
+ * skin. */
+TRACEPOINT_EVENT(tor_circuit, intermediate_onion_skin,
+ TP_ARGS(const origin_circuit_t *, circ, const crypt_path_t *, hop),
+ TP_FIELDS(
+ ctf_integer(uint32_t, circ_id, circ->global_identifier)
+ ctf_enum(tor_circuit, purpose, int, purpose, TO_CIRCUIT(circ)->purpose)
+ ctf_enum(tor_circuit, state, int, state, TO_CIRCUIT(circ)->state)
+ ctf_array_hex(char, fingerprint, hop->extend_info->identity_digest,
+ DIGEST_LEN)
+ )
+)
+
+/*
+ * OR circuit events.
+ *
+ * Tracepoint use the or_circuit_t object.
+ */
+
+/* Tracepoint emitted when a new or circuit has been created. */
+TRACEPOINT_EVENT_INSTANCE(tor_circuit, or_circuit_t_class, new_or,
+ TP_ARGS(const or_circuit_t *, circ)
+)
+
+/*
+ * General circuit events.
+ *
+ * Tracepoint use the circuit_t object.
+ */
+
+/* Tracepoint emitted when a circuit is freed. */
+TRACEPOINT_EVENT(tor_circuit, free,
+ TP_ARGS(const circuit_t *, circ),
+ TP_FIELDS(
+ ctf_integer(uint32_t, circ_id,
+ (CIRCUIT_IS_ORIGIN(circ) ?
+ TO_ORIGIN_CIRCUIT(circ)->global_identifier : 0))
+ ctf_enum(tor_circuit, purpose, int, purpose, circ->purpose)
+ ctf_enum(tor_circuit, state, int, state, circ->state)
+ )
+)
+
+/* Tracepoint emitted when a circuit is marked for close. */
+TRACEPOINT_EVENT(tor_circuit, mark_for_close,
+ TP_ARGS(const circuit_t *, circ),
+ TP_FIELDS(
+ ctf_integer(uint32_t, circ_id,
+ (CIRCUIT_IS_ORIGIN(circ) ?
+ TO_ORIGIN_CIRCUIT(circ)->global_identifier : 0))
+ ctf_enum(tor_circuit, purpose, int, purpose, circ->purpose)
+ ctf_enum(tor_circuit, state, int, state, circ->state)
+ ctf_enum(tor_circuit, end_reason, int, close_reason,
+ circ->marked_for_close_reason)
+ ctf_enum(tor_circuit, end_reason, int, orig_close_reason,
+ circ->marked_for_close_orig_reason)
+ )
+)
+
+/* Tracepoint emitted when a circuit changes purpose. */
+TRACEPOINT_EVENT(tor_circuit, change_purpose,
+ TP_ARGS(const circuit_t *, circ, int, old_purpose, int, new_purpose),
+ TP_FIELDS(
+ ctf_integer(uint32_t, circ_id,
+ (CIRCUIT_IS_ORIGIN(circ) ?
+ TO_ORIGIN_CIRCUIT(circ)->global_identifier : 0))
+ ctf_enum(tor_circuit, state, int, state, circ->state)
+ ctf_enum(tor_circuit, purpose, int, purpose, old_purpose)
+ ctf_enum(tor_circuit, purpose, int, new, new_purpose)
+ )
+)
+
+/* Tracepoint emitted when a circuit changes state. */
+TRACEPOINT_EVENT(tor_circuit, change_state,
+ TP_ARGS(const circuit_t *, circ, int, old_state, int, new_state),
+ TP_FIELDS(
+ ctf_integer(uint32_t, circ_id,
+ (CIRCUIT_IS_ORIGIN(circ) ?
+ TO_ORIGIN_CIRCUIT(circ)->global_identifier : 0))
+ ctf_enum(tor_circuit, purpose, int, purpose, circ->purpose)
+ ctf_enum(tor_circuit, state, int, old, old_state)
+ ctf_enum(tor_circuit, state, int, new, new_state)
+ )
+)
+
+#endif /* LTTNG_CIRCUIT_INC || TRACEPOINT_HEADER_MULTI_READ */
+
+/* Must be included after the probes declaration. */
+#include <lttng/tracepoint-event.h>
+
+#endif /* USE_TRACING_INSTRUMENTATION_LTTNG */
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..1ac264925c 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,
@@ -387,6 +393,11 @@ protocol_list_supports_protocol_or_later(const char *list,
const char *
protover_get_supported_protocols(void)
{
+ /* WARNING!
+ *
+ * Remember to edit the SUPPORTED_PROTOCOLS list in protover.rs if you
+ * are editing this list.
+ */
return
"Cons=1-2 "
"Desc=1-2 "
@@ -403,7 +414,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 +751,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/trace_probes_circuit.c b/src/core/or/trace_probes_circuit.c
new file mode 100644
index 0000000000..b186ffda7f
--- /dev/null
+++ b/src/core/or/trace_probes_circuit.c
@@ -0,0 +1,30 @@
+/* Copyright (c) 2020, The Tor Project, Inc. */
+/* See LICENSE for licensing information */
+
+/**
+ * \file trace_probes_circuit.c
+ * \brief Tracepoint provider source file for the circuit subsystem. Probes
+ * are generated within this C file for LTTng-UST
+ **/
+
+#include "orconfig.h"
+
+/*
+ * Following section is specific to LTTng-UST.
+ */
+#ifdef USE_TRACING_INSTRUMENTATION_LTTNG
+
+/* Header files that the probes need. */
+#include "core/or/circuitlist.h"
+#include "core/or/crypt_path_st.h"
+#include "core/or/extend_info_st.h"
+#include "core/or/or.h"
+#include "core/or/or_circuit_st.h"
+#include "core/or/origin_circuit_st.h"
+
+#define TRACEPOINT_DEFINE
+#define TRACEPOINT_CREATE_PROBES
+
+#include "trace_probes_circuit.h"
+
+#endif /* USE_TRACING_INSTRUMENTATION_LTTNG */
diff --git a/src/core/or/trace_probes_circuit.h b/src/core/or/trace_probes_circuit.h
new file mode 100644
index 0000000000..59f53c324a
--- /dev/null
+++ b/src/core/or/trace_probes_circuit.h
@@ -0,0 +1,22 @@
+/* Copyright (c) 2020, The Tor Project, Inc. */
+/* See LICENSE for licensing information */
+
+/**
+ * \file trace_probes_circuit.c
+ * \brief The tracing probes for the circuit subsystem. Currently, only
+ * LTTng-UST probes are available.
+ **/
+
+#ifndef TOR_TRACE_PROBES_CIRCUIT_H
+#define TOR_TRACE_PROBES_CIRCUIT_H
+
+#include "lib/trace/events.h"
+
+/* We only build the following if LTTng instrumentation has been enabled. */
+#ifdef USE_TRACING_INSTRUMENTATION_LTTNG
+
+#include "core/or/lttng_circuit.inc"
+
+#endif /* USE_TRACING_INSTRUMENTATION_LTTNG */
+
+#endif /* TOR_TRACE_PROBES_CIRCUIT_H */
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..c1864faedf 100644
--- a/src/feature/nodelist/dirlist.c
+++ b/src/feature/nodelist/dirlist.c
@@ -250,6 +250,34 @@ router_digest_is_trusted_dir_type(const char *digest, dirinfo_type_t type)
return 0;
}
+/** Return true iff the given address matches a trusted directory that matches
+ * at least one bit of type.
+ *
+ * If type is NO_DIRINFO or ALL_DIRINFO, any authority is matched. */
+bool
+router_addr_is_trusted_dir_type(const tor_addr_t *addr, dirinfo_type_t type)
+{
+ int family = tor_addr_family(addr);
+
+ if (!trusted_dir_servers) {
+ return false;
+ }
+
+ SMARTLIST_FOREACH_BEGIN(trusted_dir_servers, dir_server_t *, ent) {
+ /* Ignore entries that don't match the given type. */
+ if (type != NO_DIRINFO && (type & ent->type) == 0) {
+ continue;
+ }
+ /* Match IPv4 or IPv6 address. */
+ if ((family == AF_INET && tor_addr_eq_ipv4h(addr, ent->addr)) ||
+ (family == AF_INET6 && tor_addr_eq(addr, &ent->ipv6_addr))) {
+ return true;
+ }
+ } SMARTLIST_FOREACH_END(ent);
+
+ return false;
+}
+
/** Create a directory server at <b>address</b>:<b>port</b>, with OR identity
* key <b>digest</b> which has DIGEST_LEN bytes. If <b>address</b> is NULL,
* add ourself. If <b>is_authority</b>, this is a directory authority. Return
@@ -294,7 +322,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 +371,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 +397,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/dirlist.h b/src/feature/nodelist/dirlist.h
index 9201e76a9c..c9310ff357 100644
--- a/src/feature/nodelist/dirlist.h
+++ b/src/feature/nodelist/dirlist.h
@@ -25,6 +25,11 @@ int router_digest_is_fallback_dir(const char *digest);
MOCK_DECL(dir_server_t *, trusteddirserver_get_by_v3_auth_digest,
(const char *d));
+bool router_addr_is_trusted_dir_type(const tor_addr_t *addr,
+ dirinfo_type_t type);
+#define router_addr_is_trusted_dir(d) \
+ router_addr_is_trusted_dir_type((d), NO_DIRINFO)
+
int router_digest_is_trusted_dir_type(const char *digest,
dirinfo_type_t type);
#define router_digest_is_trusted_dir(d) \
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..7cb7f2ccfd 100644
--- a/src/feature/relay/relay_config.c
+++ b/src/feature/relay/relay_config.c
@@ -36,6 +36,7 @@
#include "feature/nodelist/nickname.h"
#include "feature/stats/geoip_stats.h"
#include "feature/stats/predict_ports.h"
+#include "feature/stats/connstats.h"
#include "feature/stats/rephist.h"
#include "feature/dirauth/authmode.h"
@@ -1029,7 +1030,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 +1115,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();
}
@@ -1309,7 +1308,7 @@ options_act_relay_stats(const or_options_t *old_options,
}
if ((!old_options || !old_options->ConnDirectionStatistics) &&
options->ConnDirectionStatistics) {
- rep_hist_conn_stats_init(now);
+ conn_stats_init(now);
}
if ((!old_options || !old_options->HiddenServiceStatistics) &&
options->HiddenServiceStatistics) {
@@ -1339,7 +1338,7 @@ options_act_relay_stats(const or_options_t *old_options,
rep_hist_exit_stats_term();
if (old_options && old_options->ConnDirectionStatistics &&
!options->ConnDirectionStatistics)
- rep_hist_conn_stats_term();
+ conn_stats_terminate();
return 0;
}
diff --git a/src/feature/relay/relay_find_addr.c b/src/feature/relay/relay_find_addr.c
index 86cd799d42..16d0a4733b 100644
--- a/src/feature/relay/relay_find_addr.c
+++ b/src/feature/relay/relay_find_addr.c
@@ -15,6 +15,7 @@
#include "feature/control/control_events.h"
#include "feature/dircommon/dir_connection_st.h"
+#include "feature/nodelist/dirlist.h"
#include "feature/relay/relay_find_addr.h"
#include "feature/relay/router.h"
#include "feature/relay/routermode.h"
@@ -37,6 +38,63 @@ router_guess_address_from_dir_headers(uint32_t *guess)
return -1;
}
+/** Consider the address suggestion suggested_addr as a possible one to use as
+ * our address.
+ *
+ * This is called when a valid NETINFO cell is recevied containing a candidate
+ * for our address.
+ *
+ * The suggested address is ignored if it does NOT come from a trusted source.
+ * At the moment, we only look a trusted directory authorities.
+ *
+ * The suggested address is ignored if it is internal or it is the same as the
+ * given peer_addr which is the address from the endpoint that sent the
+ * NETINFO cell.
+ *
+ * The suggested address is set in our suggested address cache if everything
+ * passes. */
+void
+relay_address_new_suggestion(const tor_addr_t *suggested_addr,
+ const tor_addr_t *peer_addr,
+ const char *identity_digest)
+{
+ const or_options_t *options = get_options();
+
+ tor_assert(suggested_addr);
+ tor_assert(peer_addr);
+ tor_assert(identity_digest);
+
+ /* Non server should just ignore this suggestion. Clients don't need to
+ * learn their address let alone cache it. */
+ if (!server_mode(options)) {
+ return;
+ }
+
+ /* Is the peer a trusted source? Ignore anything coming from non trusted
+ * source. In this case, we only look at trusted directory authorities. */
+ if (!router_addr_is_trusted_dir(peer_addr) ||
+ !router_digest_is_trusted_dir(identity_digest)) {
+ return;
+ }
+
+ /* Ignore a suggestion that is an internal address or the same as the one
+ * the peer address. */
+ if (tor_addr_is_internal(suggested_addr, 0)) {
+ /* Do not believe anyone who says our address is internal. */
+ return;
+ }
+ if (tor_addr_eq(suggested_addr, peer_addr)) {
+ /* Do not believe anyone who says our address is their address. */
+ log_fn(LOG_PROTOCOL_WARN, LD_PROTOCOL,
+ "A relay endpoint %s is telling us that their address is ours.",
+ fmt_addr(peer_addr));
+ return;
+ }
+
+ /* Save the suggestion in our cache. */
+ resolved_addr_set_suggested(suggested_addr);
+}
+
/** A directory server <b>d_conn</b> told us our IP address is
* <b>suggestion</b>.
* If this address is different from the one we think we are now, and
@@ -45,8 +103,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 +121,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 +176,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_find_addr.h b/src/feature/relay/relay_find_addr.h
index ac51a977e6..6f298e6c79 100644
--- a/src/feature/relay/relay_find_addr.h
+++ b/src/feature/relay/relay_find_addr.h
@@ -15,6 +15,10 @@ MOCK_DECL(int, router_pick_published_address,
void router_new_address_suggestion(const char *suggestion,
const dir_connection_t *d_conn);
+void relay_address_new_suggestion(const tor_addr_t *suggested_addr,
+ const tor_addr_t *peer_addr,
+ const char *identity_digest);
+
#ifdef RELAY_FIND_ADDR_PRIVATE
#endif /* RELAY_FIND_ADDR_PRIVATE */
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..b63950ea13 100644
--- a/src/feature/relay/router.c
+++ b/src/feature/relay/router.c
@@ -44,6 +44,7 @@
#include "feature/relay/selftest.h"
#include "lib/geoip/geoip.h"
#include "feature/stats/geoip_stats.h"
+#include "feature/stats/bwhist.h"
#include "feature/stats/rephist.h"
#include "lib/crypt_ops/crypto_ed25519.h"
#include "lib/crypt_ops/crypto_format.h"
@@ -831,30 +832,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 +873,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 +1119,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 +1149,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 +1352,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 +1391,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 +1539,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))
{
@@ -2046,7 +2099,7 @@ router_build_fresh_unsigned_routerinfo,(routerinfo_t **ri_out))
ri->bandwidthburst = relay_get_effective_bwburst(options);
/* Report bandwidth, unless we're hibernating or shutting down */
- ri->bandwidthcapacity = hibernating ? 0 : rep_hist_bandwidth_assess();
+ ri->bandwidthcapacity = hibernating ? 0 : bwhist_bandwidth_assess();
if (dns_seems_to_be_broken() || has_dns_init_failed()) {
/* DNS is screwed up; don't claim to be an exit. */
@@ -2373,6 +2426,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)
@@ -2474,7 +2545,7 @@ check_descriptor_bandwidth_changed(time_t now)
/* Consider ourselves to have zero bandwidth if we're hibernating or
* shutting down. */
- cur = hibernating ? 0 : rep_hist_bandwidth_assess();
+ cur = hibernating ? 0 : bwhist_bandwidth_assess();
if ((prev != cur && (!prev || !cur)) ||
cur > (prev * BANDWIDTH_CHANGE_FACTOR) ||
@@ -2525,6 +2596,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 +2609,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;
@@ -3135,7 +3209,7 @@ extrainfo_dump_to_string_stats_helper(smartlist_t *chunks,
log_info(LD_GENERAL, "Adding stats to extra-info descriptor.");
/* Bandwidth usage stats don't have their own option */
{
- contents = rep_hist_get_bandwidth_lines();
+ contents = bwhist_get_bandwidth_lines();
smartlist_add(chunks, contents);
}
/* geoip hashes aren't useful unless we are publishing other stats */
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/bwhist.c b/src/feature/stats/bwhist.c
new file mode 100644
index 0000000000..e74a2881f5
--- /dev/null
+++ b/src/feature/stats/bwhist.c
@@ -0,0 +1,592 @@
+/* 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 bwhist.c
+ * @brief Tracking for relay bandwidth history
+ *
+ * This module handles bandwidth usage history, used by relays to
+ * self-report how much bandwidth they've used for different
+ * purposes over last day or so, in order to generate the
+ * {dirreq-,}{read,write}-history lines in that they publish.
+ **/
+
+#define BWHIST_PRIVATE
+#include "orconfig.h"
+#include "core/or/or.h"
+#include "feature/stats/bwhist.h"
+
+#include "app/config/config.h"
+#include "app/config/statefile.h"
+#include "feature/relay/routermode.h"
+
+#include "app/config/or_state_st.h"
+#include "app/config/or_options_st.h"
+
+/** For how many seconds do we keep track of individual per-second bandwidth
+ * totals? */
+#define NUM_SECS_ROLLING_MEASURE 10
+/** How large are the intervals for which we track and report bandwidth use? */
+#define NUM_SECS_BW_SUM_INTERVAL (24*60*60)
+/** How far in the past do we remember and publish bandwidth use? */
+#define NUM_SECS_BW_SUM_IS_VALID (5*24*60*60)
+/** How many bandwidth usage intervals do we remember? (derived) */
+#define NUM_TOTALS (NUM_SECS_BW_SUM_IS_VALID/NUM_SECS_BW_SUM_INTERVAL)
+
+/** Structure to track bandwidth use, and remember the maxima for a given
+ * time period.
+ */
+struct bw_array_t {
+ /** Observation array: Total number of bytes transferred in each of the last
+ * NUM_SECS_ROLLING_MEASURE seconds. This is used as a circular array. */
+ uint64_t obs[NUM_SECS_ROLLING_MEASURE];
+ int cur_obs_idx; /**< Current position in obs. */
+ time_t cur_obs_time; /**< Time represented in obs[cur_obs_idx] */
+ uint64_t total_obs; /**< Total for all members of obs except
+ * obs[cur_obs_idx] */
+ uint64_t max_total; /**< Largest value that total_obs has taken on in the
+ * current period. */
+ uint64_t total_in_period; /**< Total bytes transferred in the current
+ * period. */
+
+ /** When does the next period begin? */
+ time_t next_period;
+ /** Where in 'maxima' should the maximum bandwidth usage for the current
+ * period be stored? */
+ int next_max_idx;
+ /** How many values in maxima/totals have been set ever? */
+ int num_maxes_set;
+ /** Circular array of the maximum
+ * bandwidth-per-NUM_SECS_ROLLING_MEASURE usage for the last
+ * NUM_TOTALS periods */
+ uint64_t maxima[NUM_TOTALS];
+ /** Circular array of the total bandwidth usage for the last NUM_TOTALS
+ * periods */
+ uint64_t totals[NUM_TOTALS];
+};
+
+/** Shift the current period of b forward by one. */
+STATIC void
+commit_max(bw_array_t *b)
+{
+ /* Store total from current period. */
+ b->totals[b->next_max_idx] = b->total_in_period;
+ /* Store maximum from current period. */
+ b->maxima[b->next_max_idx++] = b->max_total;
+ /* Advance next_period and next_max_idx */
+ b->next_period += NUM_SECS_BW_SUM_INTERVAL;
+ if (b->next_max_idx == NUM_TOTALS)
+ b->next_max_idx = 0;
+ if (b->num_maxes_set < NUM_TOTALS)
+ ++b->num_maxes_set;
+ /* Reset max_total. */
+ b->max_total = 0;
+ /* Reset total_in_period. */
+ b->total_in_period = 0;
+}
+
+/** Shift the current observation time of <b>b</b> forward by one second. */
+STATIC void
+advance_obs(bw_array_t *b)
+{
+ int nextidx;
+ uint64_t total;
+
+ /* Calculate the total bandwidth for the last NUM_SECS_ROLLING_MEASURE
+ * seconds; adjust max_total as needed.*/
+ total = b->total_obs + b->obs[b->cur_obs_idx];
+ if (total > b->max_total)
+ b->max_total = total;
+
+ nextidx = b->cur_obs_idx+1;
+ if (nextidx == NUM_SECS_ROLLING_MEASURE)
+ nextidx = 0;
+
+ b->total_obs = total - b->obs[nextidx];
+ b->obs[nextidx]=0;
+ b->cur_obs_idx = nextidx;
+
+ if (++b->cur_obs_time >= b->next_period)
+ commit_max(b);
+}
+
+/** Add <b>n</b> bytes to the number of bytes in <b>b</b> for second
+ * <b>when</b>. */
+static inline void
+add_obs(bw_array_t *b, time_t when, uint64_t n)
+{
+ if (when < b->cur_obs_time)
+ return; /* Don't record data in the past. */
+
+ /* If we're currently adding observations for an earlier second than
+ * 'when', advance b->cur_obs_time and b->cur_obs_idx by an
+ * appropriate number of seconds, and do all the other housekeeping. */
+ while (when > b->cur_obs_time) {
+ /* Doing this one second at a time is potentially inefficient, if we start
+ with a state file that is very old. Fortunately, it doesn't seem to
+ show up in profiles, so we can just ignore it for now. */
+ advance_obs(b);
+ }
+
+ b->obs[b->cur_obs_idx] += n;
+ b->total_in_period += n;
+}
+
+/** Allocate, initialize, and return a new bw_array. */
+static bw_array_t *
+bw_array_new(void)
+{
+ bw_array_t *b;
+ time_t start;
+ b = tor_malloc_zero(sizeof(bw_array_t));
+ start = time(NULL);
+ b->cur_obs_time = start;
+ b->next_period = start + NUM_SECS_BW_SUM_INTERVAL;
+ return b;
+}
+
+#define bw_array_free(val) \
+ FREE_AND_NULL(bw_array_t, bw_array_free_, (val))
+
+/** Free storage held by bandwidth array <b>b</b>. */
+static void
+bw_array_free_(bw_array_t *b)
+{
+ if (!b) {
+ return;
+ }
+
+ tor_free(b);
+}
+
+/** Recent history of bandwidth observations for (all) read operations. */
+static bw_array_t *read_array = NULL;
+/** Recent history of bandwidth observations for IPv6 read operations. */
+static bw_array_t *read_array_ipv6 = NULL;
+/** Recent history of bandwidth observations for (all) write operations. */
+STATIC bw_array_t *write_array = NULL;
+/** Recent history of bandwidth observations for IPv6 write operations. */
+static bw_array_t *write_array_ipv6 = NULL;
+/** Recent history of bandwidth observations for read operations for the
+ directory protocol. */
+static bw_array_t *dir_read_array = NULL;
+/** Recent history of bandwidth observations for write operations for the
+ directory protocol. */
+static bw_array_t *dir_write_array = NULL;
+
+/** Set up structures for bandwidth history, clearing them if they already
+ * exist. */
+void
+bwhist_init(void)
+{
+ bw_array_free(read_array);
+ bw_array_free(read_array_ipv6);
+ bw_array_free(write_array);
+ bw_array_free(write_array_ipv6);
+ bw_array_free(dir_read_array);
+ bw_array_free(dir_write_array);
+
+ read_array = bw_array_new();
+ read_array_ipv6 = bw_array_new();
+ write_array = bw_array_new();
+ write_array_ipv6 = bw_array_new();
+ dir_read_array = bw_array_new();
+ dir_write_array = bw_array_new();
+}
+
+/** Remember that we read <b>num_bytes</b> bytes in second <b>when</b>.
+ *
+ * Add num_bytes to the current running total for <b>when</b>.
+ *
+ * <b>when</b> can go back to time, but it's safe to ignore calls
+ * earlier than the latest <b>when</b> you've heard of.
+ */
+void
+bwhist_note_bytes_written(uint64_t num_bytes, time_t when, bool ipv6)
+{
+/* Maybe a circular array for recent seconds, and step to a new point
+ * every time a new second shows up. Or simpler is to just to have
+ * a normal array and push down each item every second; it's short.
+ */
+/* When a new second has rolled over, compute the sum of the bytes we've
+ * seen over when-1 to when-1-NUM_SECS_ROLLING_MEASURE, and stick it
+ * somewhere. See bwhist_bandwidth_assess() below.
+ */
+ add_obs(write_array, when, num_bytes);
+ if (ipv6)
+ add_obs(write_array_ipv6, when, num_bytes);
+}
+
+/** Remember that we wrote <b>num_bytes</b> bytes in second <b>when</b>.
+ * (like bwhist_note_bytes_written() above)
+ */
+void
+bwhist_note_bytes_read(uint64_t num_bytes, time_t when, bool ipv6)
+{
+/* if we're smart, we can make this func and the one above share code */
+ add_obs(read_array, when, num_bytes);
+ if (ipv6)
+ add_obs(read_array_ipv6, when, num_bytes);
+}
+
+/** Remember that we wrote <b>num_bytes</b> directory bytes in second
+ * <b>when</b>. (like bwhist_note_bytes_written() above)
+ */
+void
+bwhist_note_dir_bytes_written(uint64_t num_bytes, time_t when)
+{
+ add_obs(dir_write_array, when, num_bytes);
+}
+
+/** Remember that we read <b>num_bytes</b> directory bytes in second
+ * <b>when</b>. (like bwhist_note_bytes_written() above)
+ */
+void
+bwhist_note_dir_bytes_read(uint64_t num_bytes, time_t when)
+{
+ add_obs(dir_read_array, when, num_bytes);
+}
+
+/** Helper: Return the largest value in b->maxima. (This is equal to the
+ * most bandwidth used in any NUM_SECS_ROLLING_MEASURE period for the last
+ * NUM_SECS_BW_SUM_IS_VALID seconds.)
+ */
+STATIC uint64_t
+find_largest_max(bw_array_t *b)
+{
+ int i;
+ uint64_t max;
+ max=0;
+ for (i=0; i<NUM_TOTALS; ++i) {
+ if (b->maxima[i]>max)
+ max = b->maxima[i];
+ }
+ return max;
+}
+
+/** Find the largest sums in the past NUM_SECS_BW_SUM_IS_VALID (roughly)
+ * seconds. Find one sum for reading and one for writing. They don't have
+ * to be at the same time.
+ *
+ * Return the smaller of these sums, divided by NUM_SECS_ROLLING_MEASURE.
+ */
+MOCK_IMPL(int,
+bwhist_bandwidth_assess,(void))
+{
+ uint64_t w,r;
+ r = find_largest_max(read_array);
+ w = find_largest_max(write_array);
+ if (r>w)
+ return (int)(((double)w)/NUM_SECS_ROLLING_MEASURE);
+ else
+ return (int)(((double)r)/NUM_SECS_ROLLING_MEASURE);
+}
+
+/** Print the bandwidth history of b (either [dir-]read_array or
+ * [dir-]write_array) into the buffer pointed to by buf. The format is
+ * simply comma separated numbers, from oldest to newest.
+ *
+ * It returns the number of bytes written.
+ */
+static size_t
+bwhist_fill_bandwidth_history(char *buf, size_t len, const bw_array_t *b)
+{
+ char *cp = buf;
+ int i, n;
+ const or_options_t *options = get_options();
+ uint64_t cutoff;
+
+ if (b->num_maxes_set <= b->next_max_idx) {
+ /* We haven't been through the circular array yet; time starts at i=0.*/
+ i = 0;
+ } else {
+ /* We've been around the array at least once. The next i to be
+ overwritten is the oldest. */
+ i = b->next_max_idx;
+ }
+
+ if (options->RelayBandwidthRate) {
+ /* We don't want to report that we used more bandwidth than the max we're
+ * willing to relay; otherwise everybody will know how much traffic
+ * we used ourself. */
+ cutoff = options->RelayBandwidthRate * NUM_SECS_BW_SUM_INTERVAL;
+ } else {
+ cutoff = UINT64_MAX;
+ }
+
+ for (n=0; n<b->num_maxes_set; ++n,++i) {
+ uint64_t total;
+ if (i >= NUM_TOTALS)
+ i -= NUM_TOTALS;
+ tor_assert(i < NUM_TOTALS);
+ /* Round the bandwidth used down to the nearest 1k. */
+ total = b->totals[i] & ~0x3ff;
+ if (total > cutoff)
+ total = cutoff;
+
+ if (n==(b->num_maxes_set-1))
+ tor_snprintf(cp, len-(cp-buf), "%"PRIu64, (total));
+ else
+ tor_snprintf(cp, len-(cp-buf), "%"PRIu64",", (total));
+ cp += strlen(cp);
+ }
+ return cp-buf;
+}
+
+/** Encode a single bandwidth history line into <b>buf</b>. */
+static void
+bwhist_get_one_bandwidth_line(buf_t *buf, const char *desc,
+ const bw_array_t *b)
+{
+ /* [dirreq-](read|write)-history yyyy-mm-dd HH:MM:SS (n s) n,n,n... */
+ /* The n,n,n part above. Largest representation of a uint64_t is 20 chars
+ * long, plus the comma. */
+#define MAX_HIST_VALUE_LEN (21*NUM_TOTALS)
+
+ char tmp[MAX_HIST_VALUE_LEN];
+ char end[ISO_TIME_LEN+1];
+
+ size_t slen = bwhist_fill_bandwidth_history(tmp, MAX_HIST_VALUE_LEN, b);
+ /* If we don't have anything to write, skip to the next entry. */
+ if (slen == 0)
+ return;
+
+ format_iso_time(end, b->next_period-NUM_SECS_BW_SUM_INTERVAL);
+ buf_add_printf(buf, "%s %s (%d s) %s\n",
+ desc, end, NUM_SECS_BW_SUM_INTERVAL, tmp);
+}
+
+/** Allocate and return lines for representing this server's bandwidth
+ * history in its descriptor. We publish these lines in our extra-info
+ * descriptor.
+ */
+char *
+bwhist_get_bandwidth_lines(void)
+{
+ buf_t *buf = buf_new();
+
+ bwhist_get_one_bandwidth_line(buf, "write-history", write_array);
+ bwhist_get_one_bandwidth_line(buf, "read-history", read_array);
+ bwhist_get_one_bandwidth_line(buf, "ipv6-write-history", write_array_ipv6);
+ bwhist_get_one_bandwidth_line(buf, "ipv6-read-history", read_array_ipv6);
+ bwhist_get_one_bandwidth_line(buf, "dirreq-write-history", dir_write_array);
+ bwhist_get_one_bandwidth_line(buf, "dirreq-read-history", dir_read_array);
+
+ char *result = buf_extract(buf, NULL);
+ buf_free(buf);
+ return result;
+}
+
+/** Write a single bw_array_t into the Values, Ends, Interval, and Maximum
+ * entries of an or_state_t. Done before writing out a new state file. */
+static void
+bwhist_update_bwhist_state_section(or_state_t *state,
+ const bw_array_t *b,
+ smartlist_t **s_values,
+ smartlist_t **s_maxima,
+ time_t *s_begins,
+ int *s_interval)
+{
+ int i,j;
+ uint64_t maxval;
+
+ if (*s_values) {
+ SMARTLIST_FOREACH(*s_values, char *, val, tor_free(val));
+ smartlist_free(*s_values);
+ }
+ if (*s_maxima) {
+ SMARTLIST_FOREACH(*s_maxima, char *, val, tor_free(val));
+ smartlist_free(*s_maxima);
+ }
+ if (! server_mode(get_options())) {
+ /* Clients don't need to store bandwidth history persistently;
+ * force these values to the defaults. */
+ /* FFFF we should pull the default out of config.c's state table,
+ * so we don't have two defaults. */
+ if (*s_begins != 0 || *s_interval != 900) {
+ time_t now = time(NULL);
+ time_t save_at = get_options()->AvoidDiskWrites ? now+3600 : now+600;
+ or_state_mark_dirty(state, save_at);
+ }
+ *s_begins = 0;
+ *s_interval = 900;
+ *s_values = smartlist_new();
+ *s_maxima = smartlist_new();
+ return;
+ }
+ *s_begins = b->next_period;
+ *s_interval = NUM_SECS_BW_SUM_INTERVAL;
+
+ *s_values = smartlist_new();
+ *s_maxima = smartlist_new();
+ /* Set i to first position in circular array */
+ i = (b->num_maxes_set <= b->next_max_idx) ? 0 : b->next_max_idx;
+ for (j=0; j < b->num_maxes_set; ++j,++i) {
+ if (i >= NUM_TOTALS)
+ i = 0;
+ smartlist_add_asprintf(*s_values, "%"PRIu64,
+ (b->totals[i] & ~0x3ff));
+ maxval = b->maxima[i] / NUM_SECS_ROLLING_MEASURE;
+ smartlist_add_asprintf(*s_maxima, "%"PRIu64,
+ (maxval & ~0x3ff));
+ }
+ smartlist_add_asprintf(*s_values, "%"PRIu64,
+ (b->total_in_period & ~0x3ff));
+ maxval = b->max_total / NUM_SECS_ROLLING_MEASURE;
+ smartlist_add_asprintf(*s_maxima, "%"PRIu64,
+ (maxval & ~0x3ff));
+}
+
+/** Update <b>state</b> with the newest bandwidth history. Done before
+ * writing out a new state file. */
+void
+bwhist_update_state(or_state_t *state)
+{
+#define UPDATE(arrname,st) \
+ bwhist_update_bwhist_state_section(state,\
+ (arrname),\
+ &state->BWHistory ## st ## Values, \
+ &state->BWHistory ## st ## Maxima, \
+ &state->BWHistory ## st ## Ends, \
+ &state->BWHistory ## st ## Interval)
+
+ UPDATE(write_array, Write);
+ UPDATE(read_array, Read);
+ UPDATE(write_array_ipv6, IPv6Write);
+ UPDATE(read_array_ipv6, IPv6Read);
+ UPDATE(dir_write_array, DirWrite);
+ UPDATE(dir_read_array, DirRead);
+
+ if (server_mode(get_options())) {
+ or_state_mark_dirty(state, time(NULL)+(2*3600));
+ }
+#undef UPDATE
+}
+
+/** Load a single bw_array_t from its Values, Ends, Maxima, and Interval
+ * entries in an or_state_t. Done while reading the state file. */
+static int
+bwhist_load_bwhist_state_section(bw_array_t *b,
+ const smartlist_t *s_values,
+ const smartlist_t *s_maxima,
+ const time_t s_begins,
+ const int s_interval)
+{
+ time_t now = time(NULL);
+ int retval = 0;
+ time_t start;
+
+ uint64_t v, mv;
+ int i,ok,ok_m = 0;
+ int have_maxima = s_maxima && s_values &&
+ (smartlist_len(s_values) == smartlist_len(s_maxima));
+
+ if (s_values && s_begins >= now - NUM_SECS_BW_SUM_INTERVAL*NUM_TOTALS) {
+ start = s_begins - s_interval*(smartlist_len(s_values));
+ if (start > now)
+ return 0;
+ b->cur_obs_time = start;
+ b->next_period = start + NUM_SECS_BW_SUM_INTERVAL;
+ SMARTLIST_FOREACH_BEGIN(s_values, const char *, cp) {
+ const char *maxstr = NULL;
+ v = tor_parse_uint64(cp, 10, 0, UINT64_MAX, &ok, NULL);
+ if (have_maxima) {
+ maxstr = smartlist_get(s_maxima, cp_sl_idx);
+ mv = tor_parse_uint64(maxstr, 10, 0, UINT64_MAX, &ok_m, NULL);
+ mv *= NUM_SECS_ROLLING_MEASURE;
+ } else {
+ /* No maxima known; guess average rate to be conservative. */
+ mv = (v / s_interval) * NUM_SECS_ROLLING_MEASURE;
+ }
+ if (!ok) {
+ retval = -1;
+ log_notice(LD_HIST, "Could not parse value '%s' into a number.'",cp);
+ }
+ if (maxstr && !ok_m) {
+ retval = -1;
+ log_notice(LD_HIST, "Could not parse maximum '%s' into a number.'",
+ maxstr);
+ }
+
+ if (start < now) {
+ time_t cur_start = start;
+ time_t actual_interval_len = s_interval;
+ uint64_t cur_val = 0;
+ /* Calculate the average per second. This is the best we can do
+ * because our state file doesn't have per-second resolution. */
+ if (start + s_interval > now)
+ actual_interval_len = now - start;
+ cur_val = v / actual_interval_len;
+ /* This is potentially inefficient, but since we don't do it very
+ * often it should be ok. */
+ while (cur_start < start + actual_interval_len) {
+ add_obs(b, cur_start, cur_val);
+ ++cur_start;
+ }
+ b->max_total = mv;
+ /* This will result in some fairly choppy history if s_interval
+ * is not the same as NUM_SECS_BW_SUM_INTERVAL. XXXX */
+ start += actual_interval_len;
+ }
+ } SMARTLIST_FOREACH_END(cp);
+ }
+
+ /* Clean up maxima and observed */
+ for (i=0; i<NUM_SECS_ROLLING_MEASURE; ++i) {
+ b->obs[i] = 0;
+ }
+ b->total_obs = 0;
+
+ return retval;
+}
+
+/** Set bandwidth history from the state file we just loaded. */
+int
+bwhist_load_state(or_state_t *state, char **err)
+{
+ int all_ok = 1;
+
+ /* Assert they already have been malloced */
+ tor_assert(read_array && write_array);
+ tor_assert(read_array_ipv6 && write_array_ipv6);
+ tor_assert(dir_read_array && dir_write_array);
+
+#define LOAD(arrname,st) \
+ if (bwhist_load_bwhist_state_section( \
+ (arrname), \
+ state->BWHistory ## st ## Values, \
+ state->BWHistory ## st ## Maxima, \
+ state->BWHistory ## st ## Ends, \
+ state->BWHistory ## st ## Interval)<0) \
+ all_ok = 0
+
+ LOAD(write_array, Write);
+ LOAD(read_array, Read);
+ LOAD(write_array_ipv6, IPv6Write);
+ LOAD(read_array_ipv6, IPv6Read);
+ LOAD(dir_write_array, DirWrite);
+ LOAD(dir_read_array, DirRead);
+
+#undef LOAD
+ if (!all_ok) {
+ *err = tor_strdup("Parsing of bandwidth history values failed");
+ /* and create fresh arrays */
+ bwhist_init();
+ return -1;
+ }
+ return 0;
+}
+
+void
+bwhist_free_all(void)
+{
+ bw_array_free(read_array);
+ bw_array_free(read_array_ipv6);
+ bw_array_free(write_array);
+ bw_array_free(write_array_ipv6);
+ bw_array_free(dir_read_array);
+ bw_array_free(dir_write_array);
+}
diff --git a/src/feature/stats/bwhist.h b/src/feature/stats/bwhist.h
new file mode 100644
index 0000000000..d556f5a026
--- /dev/null
+++ b/src/feature/stats/bwhist.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 bwhist.h
+ * @brief Header for feature/stats/bwhist.c
+ **/
+
+#ifndef TOR_FEATURE_STATS_BWHIST_H
+#define TOR_FEATURE_STATS_BWHIST_H
+
+void bwhist_init(void);
+void bwhist_free_all(void);
+
+void bwhist_note_bytes_read(uint64_t num_bytes, time_t when, bool ipv6);
+void bwhist_note_bytes_written(uint64_t num_bytes, time_t when, bool ipv6);
+void bwhist_note_dir_bytes_read(uint64_t num_bytes, time_t when);
+void bwhist_note_dir_bytes_written(uint64_t num_bytes, time_t when);
+
+MOCK_DECL(int, bwhist_bandwidth_assess, (void));
+char *bwhist_get_bandwidth_lines(void);
+struct or_state_t;
+void bwhist_update_state(struct or_state_t *state);
+int bwhist_load_state(struct or_state_t *state, char **err);
+
+#ifdef BWHIST_PRIVATE
+typedef struct bw_array_t bw_array_t;
+STATIC uint64_t find_largest_max(bw_array_t *b);
+STATIC void commit_max(bw_array_t *b);
+STATIC void advance_obs(bw_array_t *b);
+#endif /* defined(REPHIST_PRIVATE) */
+
+#ifdef TOR_UNIT_TESTS
+extern struct bw_array_t *write_array;
+#endif
+
+#endif /* !defined(TOR_FEATURE_STATS_BWHIST_H) */
diff --git a/src/feature/stats/connstats.c b/src/feature/stats/connstats.c
new file mode 100644
index 0000000000..f0c786efb3
--- /dev/null
+++ b/src/feature/stats/connstats.c
@@ -0,0 +1,283 @@
+/* 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 connstats.c
+ * @brief Count bidirectional vs one-way connections.
+ *
+ * Connection statistics, use to track one-way and bidirectional connections.
+ *
+ * Note that this code counts concurrent connections in each
+ * BIDI_INTERVAL-second interval, not total connections. It can tell you what
+ * fraction of connections are bidirectional at each time, not necessarily
+ * what number are bidirectional.
+ **/
+
+#include "orconfig.h"
+#include "core/or/or.h"
+#include "feature/stats/connstats.h"
+#include "app/config/config.h"
+
+/** Start of the current connection stats interval or 0 if we're not
+ * collecting connection statistics. */
+static time_t start_of_conn_stats_interval;
+
+/** Initialize connection stats. */
+void
+conn_stats_init(time_t now)
+{
+ start_of_conn_stats_interval = now;
+}
+
+/** Count connections on which we read and wrote less than this many bytes
+ * as "below threshold." */
+#define BIDI_THRESHOLD 20480
+
+/** Count connections that we read or wrote at least this factor as many
+ * bytes from/to than we wrote or read to/from as mostly reading or
+ * writing. */
+#define BIDI_FACTOR 10
+
+/** Interval length in seconds for considering read and written bytes for
+ * connection stats. */
+#define BIDI_INTERVAL 10
+
+/** Start of next BIDI_INTERVAL second interval. */
+static time_t bidi_next_interval = 0;
+
+/** A single grouped set of connection type counts. */
+typedef struct conn_counts_t {
+ /** Number of connections that we read and wrote less than BIDI_THRESHOLD
+ * bytes from/to in BIDI_INTERVAL seconds. */
+ uint32_t below_threshold;
+
+ /** Number of connections that we read at least BIDI_FACTOR times more
+ * bytes from than we wrote to in BIDI_INTERVAL seconds. */
+ uint32_t mostly_read;
+
+ /** Number of connections that we wrote at least BIDI_FACTOR times more
+ * bytes to than we read from in BIDI_INTERVAL seconds. */
+ uint32_t mostly_written;
+
+ /** Number of connections that we read and wrote at least BIDI_THRESHOLD
+ * bytes from/to, but not BIDI_FACTOR times more in either direction in
+ * BIDI_INTERVAL seconds. */
+ uint32_t both_read_and_written;
+} conn_counts_t ;
+
+/** A collection of connection counts, over all OR connections. */
+static conn_counts_t counts;
+/** A collection of connection counts, over IPv6 OR connections only. */
+static conn_counts_t counts_ipv6;
+
+/** Entry in a map from connection ID to the number of read and written
+ * bytes on this connection in a BIDI_INTERVAL second interval. */
+typedef struct bidi_map_entry_t {
+ HT_ENTRY(bidi_map_entry_t) node;
+ uint64_t conn_id; /**< Connection ID */
+ size_t read; /**< Number of read bytes */
+ size_t written; /**< Number of written bytes */
+ bool is_ipv6; /**< True if this is an IPv6 connection */
+} bidi_map_entry_t;
+
+/** Map of OR connections together with the number of read and written
+ * bytes in the current BIDI_INTERVAL second interval. */
+static HT_HEAD(bidimap, bidi_map_entry_t) bidi_map =
+ HT_INITIALIZER();
+
+/** Hashtable helper: return true if @a a and @a b have the same key. */
+static int
+bidi_map_ent_eq(const bidi_map_entry_t *a, const bidi_map_entry_t *b)
+{
+ return a->conn_id == b->conn_id;
+}
+
+/** Hashtable helper: compute a digest for the key of @a entry. */
+static unsigned
+bidi_map_ent_hash(const bidi_map_entry_t *entry)
+{
+ return (unsigned) entry->conn_id;
+}
+
+HT_PROTOTYPE(bidimap, bidi_map_entry_t, node, bidi_map_ent_hash,
+ bidi_map_ent_eq);
+HT_GENERATE2(bidimap, bidi_map_entry_t, node, bidi_map_ent_hash,
+ bidi_map_ent_eq, 0.6, tor_reallocarray_, tor_free_);
+
+/** Release all storage held in connstats.c */
+void
+conn_stats_free_all(void)
+{
+ bidi_map_entry_t **ptr, **next, *ent;
+ for (ptr = HT_START(bidimap, &bidi_map); ptr; ptr = next) {
+ ent = *ptr;
+ next = HT_NEXT_RMV(bidimap, &bidi_map, ptr);
+ tor_free(ent);
+ }
+ HT_CLEAR(bidimap, &bidi_map);
+}
+
+/** Reset counters for conn statistics. */
+void
+conn_stats_reset(time_t now)
+{
+ start_of_conn_stats_interval = now;
+ memset(&counts, 0, sizeof(counts));
+ memset(&counts_ipv6, 0, sizeof(counts_ipv6));
+ conn_stats_free_all();
+}
+
+/** Stop collecting connection stats in a way that we can re-start doing
+ * so in conn_stats_init(). */
+void
+conn_stats_terminate(void)
+{
+ conn_stats_reset(0);
+}
+
+/**
+ * Record a single entry @a ent in the counts structure @cnt.
+ */
+static void
+add_entry_to_count(conn_counts_t *cnt, const bidi_map_entry_t *ent)
+{
+ if (ent->read + ent->written < BIDI_THRESHOLD)
+ cnt->below_threshold++;
+ else if (ent->read >= ent->written * BIDI_FACTOR)
+ cnt->mostly_read++;
+ else if (ent->written >= ent->read * BIDI_FACTOR)
+ cnt->mostly_written++;
+ else
+ cnt->both_read_and_written++;
+}
+
+/**
+ * Count all the connection information we've received during the current
+ * period in 'bidimap', and store that information in the appropriate count
+ * structures.
+ **/
+static void
+collect_period_statistics(void)
+{
+ bidi_map_entry_t **ptr, **next, *ent;
+ for (ptr = HT_START(bidimap, &bidi_map); ptr; ptr = next) {
+ ent = *ptr;
+ add_entry_to_count(&counts, ent);
+ if (ent->is_ipv6)
+ add_entry_to_count(&counts_ipv6, ent);
+ next = HT_NEXT_RMV(bidimap, &bidi_map, ptr);
+ tor_free(ent);
+ }
+ log_info(LD_GENERAL, "%d below threshold, %d mostly read, "
+ "%d mostly written, %d both read and written.",
+ counts.below_threshold, counts.mostly_read, counts.mostly_written,
+ counts.both_read_and_written);
+}
+
+/** We read <b>num_read</b> bytes and wrote <b>num_written</b> from/to OR
+ * connection <b>conn_id</b> in second <b>when</b>. If this is the first
+ * observation in a new interval, sum up the last observations. Add bytes
+ * for this connection. */
+void
+conn_stats_note_or_conn_bytes(uint64_t conn_id, size_t num_read,
+ size_t num_written, time_t when,
+ bool is_ipv6)
+{
+ if (!start_of_conn_stats_interval)
+ return;
+ /* Initialize */
+ if (bidi_next_interval == 0)
+ bidi_next_interval = when + BIDI_INTERVAL;
+ /* Sum up last period's statistics */
+ if (when >= bidi_next_interval) {
+ collect_period_statistics();
+ while (when >= bidi_next_interval)
+ bidi_next_interval += BIDI_INTERVAL;
+ }
+ /* Add this connection's bytes. */
+ if (num_read > 0 || num_written > 0) {
+ bidi_map_entry_t *entry, lookup;
+ lookup.conn_id = conn_id;
+ entry = HT_FIND(bidimap, &bidi_map, &lookup);
+ if (entry) {
+ entry->written += num_written;
+ entry->read += num_read;
+ entry->is_ipv6 |= is_ipv6;
+ } else {
+ entry = tor_malloc_zero(sizeof(bidi_map_entry_t));
+ entry->conn_id = conn_id;
+ entry->written = num_written;
+ entry->read = num_read;
+ entry->is_ipv6 = is_ipv6;
+ HT_INSERT(bidimap, &bidi_map, entry);
+ }
+ }
+}
+
+/** Return a newly allocated string containing the connection statistics
+ * until <b>now</b>, or NULL if we're not collecting conn stats. Caller must
+ * ensure start_of_conn_stats_interval is in the past. */
+char *
+conn_stats_format(time_t now)
+{
+ char *result, written_at[ISO_TIME_LEN+1];
+
+ if (!start_of_conn_stats_interval)
+ return NULL; /* Not initialized. */
+
+ tor_assert(now >= start_of_conn_stats_interval);
+
+ format_iso_time(written_at, now);
+ tor_asprintf(&result,
+ "conn-bi-direct %s (%d s) "
+ "%"PRIu32",%"PRIu32",%"PRIu32",%"PRIu32"\n"
+ "ipv6-conn-bi-direct %s (%d s) "
+ "%"PRIu32",%"PRIu32",%"PRIu32",%"PRIu32"\n",
+ written_at,
+ (unsigned) (now - start_of_conn_stats_interval),
+ counts.below_threshold,
+ counts.mostly_read,
+ counts.mostly_written,
+ counts.both_read_and_written,
+ written_at,
+ (unsigned) (now - start_of_conn_stats_interval),
+ counts_ipv6.below_threshold,
+ counts_ipv6.mostly_read,
+ counts_ipv6.mostly_written,
+ counts_ipv6.both_read_and_written);
+
+ return result;
+}
+
+/** If 24 hours have passed since the beginning of the current conn stats
+ * period, write conn stats to $DATADIR/stats/conn-stats (possibly
+ * overwriting an existing file) and reset counters. Return when we would
+ * next want to write conn stats or 0 if we never want to write. */
+time_t
+conn_stats_save(time_t now)
+{
+ char *str = NULL;
+
+ if (!start_of_conn_stats_interval)
+ return 0; /* Not initialized. */
+ if (start_of_conn_stats_interval + WRITE_STATS_INTERVAL > now)
+ goto done; /* Not ready to write */
+
+ /* Generate history string. */
+ str = conn_stats_format(now);
+
+ /* Reset counters. */
+ conn_stats_reset(now);
+
+ /* Try to write to disk. */
+ if (!check_or_create_data_subdir("stats")) {
+ write_to_data_subdir("stats", "conn-stats", str, "connection statistics");
+ }
+
+ done:
+ tor_free(str);
+ return start_of_conn_stats_interval + WRITE_STATS_INTERVAL;
+}
diff --git a/src/feature/stats/connstats.h b/src/feature/stats/connstats.h
new file mode 100644
index 0000000000..1a03d0748b
--- /dev/null
+++ b/src/feature/stats/connstats.h
@@ -0,0 +1,25 @@
+/* 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 connstats.h
+ * @brief Header for feature/stats/connstats.c
+ **/
+
+#ifndef TOR_FEATURE_STATS_CONNSTATS_H
+#define TOR_FEATURE_STATS_CONNSTATS_H
+
+void conn_stats_init(time_t now);
+void conn_stats_note_or_conn_bytes(uint64_t conn_id, size_t num_read,
+ size_t num_written, time_t when,
+ bool is_ipv6);
+void conn_stats_reset(time_t now);
+char *conn_stats_format(time_t now);
+time_t conn_stats_save(time_t now);
+void conn_stats_terminate(void);
+void conn_stats_free_all(void);
+
+#endif /* !defined(TOR_FEATURE_STATS_CONNSTATS_H) */
diff --git a/src/feature/stats/include.am b/src/feature/stats/include.am
index 8789bc3d96..bc13882f4b 100644
--- a/src/feature/stats/include.am
+++ b/src/feature/stats/include.am
@@ -1,12 +1,16 @@
# ADD_C_FILE: INSERT SOURCES HERE.
LIBTOR_APP_A_SOURCES += \
+ src/feature/stats/bwhist.c \
+ src/feature/stats/connstats.c \
src/feature/stats/geoip_stats.c \
src/feature/stats/rephist.c \
src/feature/stats/predict_ports.c
# ADD_C_FILE: INSERT HEADERS HERE.
noinst_HEADERS += \
+ src/feature/stats/bwhist.h \
+ src/feature/stats/connstats.h \
src/feature/stats/geoip_stats.h \
src/feature/stats/rephist.h \
src/feature/stats/predict_ports.h
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..b6730e1226 100644
--- a/src/feature/stats/rephist.c
+++ b/src/feature/stats/rephist.c
@@ -18,11 +18,6 @@
* stability information about various relays, including "uptime",
* "weighted fractional uptime" and "mean time between failures".
*
- * <li>Bandwidth usage history, used by relays to self-report how much
- * bandwidth they've used for different purposes over last day or so,
- * in order to generate the {dirreq-,}{read,write}-history lines in
- * that they publish.
- *
* <li>Predicted ports, used by clients to remember how long it's been
* since they opened an exit connection to each given target
* port. Clients use this information in order to try to keep circuits
@@ -48,9 +43,6 @@
* <li>Descriptor serving statistics, used by directory caches to track
* how many descriptors they've served.
*
- * <li>Connection statistics, used by relays to track one-way and
- * bidirectional connections.
- *
* <li>Onion handshake statistics, used by relays to count how many
* TAP and ntor handshakes they've handled.
*
@@ -77,14 +69,13 @@
#define REPHIST_PRIVATE
#include "core/or/or.h"
#include "app/config/config.h"
-#include "app/config/statefile.h"
#include "core/or/circuitlist.h"
#include "core/or/connection_or.h"
#include "feature/dirauth/authmode.h"
#include "feature/nodelist/networkstatus.h"
#include "feature/nodelist/nodelist.h"
-#include "feature/relay/routermode.h"
#include "feature/stats/predict_ports.h"
+#include "feature/stats/connstats.h"
#include "feature/stats/rephist.h"
#include "lib/container/order.h"
#include "lib/crypt_ops/crypto_rand.h"
@@ -92,14 +83,11 @@
#include "feature/nodelist/networkstatus_st.h"
#include "core/or/or_circuit_st.h"
-#include "app/config/or_state_st.h"
#ifdef HAVE_FCNTL_H
#include <fcntl.h>
#endif
-static void bw_arrays_init(void);
-
/** Total number of bytes currently allocated in fields used by rephist.c. */
uint64_t rephist_total_alloc=0;
/** Number of or_history_t objects currently allocated. */
@@ -232,7 +220,6 @@ void
rep_hist_init(void)
{
history_map = digestmap_new();
- bw_arrays_init();
}
/** We have just decided that this router with identity digest <b>id</b> is
@@ -973,560 +960,6 @@ rep_hist_load_mtbf_data(time_t now)
return r;
}
-/** For how many seconds do we keep track of individual per-second bandwidth
- * totals? */
-#define NUM_SECS_ROLLING_MEASURE 10
-/** How large are the intervals for which we track and report bandwidth use? */
-#define NUM_SECS_BW_SUM_INTERVAL (24*60*60)
-/** How far in the past do we remember and publish bandwidth use? */
-#define NUM_SECS_BW_SUM_IS_VALID (5*24*60*60)
-/** How many bandwidth usage intervals do we remember? (derived) */
-#define NUM_TOTALS (NUM_SECS_BW_SUM_IS_VALID/NUM_SECS_BW_SUM_INTERVAL)
-
-/** Structure to track bandwidth use, and remember the maxima for a given
- * time period.
- */
-struct bw_array_t {
- /** Observation array: Total number of bytes transferred in each of the last
- * NUM_SECS_ROLLING_MEASURE seconds. This is used as a circular array. */
- uint64_t obs[NUM_SECS_ROLLING_MEASURE];
- int cur_obs_idx; /**< Current position in obs. */
- time_t cur_obs_time; /**< Time represented in obs[cur_obs_idx] */
- uint64_t total_obs; /**< Total for all members of obs except
- * obs[cur_obs_idx] */
- uint64_t max_total; /**< Largest value that total_obs has taken on in the
- * current period. */
- uint64_t total_in_period; /**< Total bytes transferred in the current
- * period. */
-
- /** When does the next period begin? */
- time_t next_period;
- /** Where in 'maxima' should the maximum bandwidth usage for the current
- * period be stored? */
- int next_max_idx;
- /** How many values in maxima/totals have been set ever? */
- int num_maxes_set;
- /** Circular array of the maximum
- * bandwidth-per-NUM_SECS_ROLLING_MEASURE usage for the last
- * NUM_TOTALS periods */
- uint64_t maxima[NUM_TOTALS];
- /** Circular array of the total bandwidth usage for the last NUM_TOTALS
- * periods */
- uint64_t totals[NUM_TOTALS];
-};
-
-/** Shift the current period of b forward by one. */
-STATIC void
-commit_max(bw_array_t *b)
-{
- /* Store total from current period. */
- b->totals[b->next_max_idx] = b->total_in_period;
- /* Store maximum from current period. */
- b->maxima[b->next_max_idx++] = b->max_total;
- /* Advance next_period and next_max_idx */
- b->next_period += NUM_SECS_BW_SUM_INTERVAL;
- if (b->next_max_idx == NUM_TOTALS)
- b->next_max_idx = 0;
- if (b->num_maxes_set < NUM_TOTALS)
- ++b->num_maxes_set;
- /* Reset max_total. */
- b->max_total = 0;
- /* Reset total_in_period. */
- b->total_in_period = 0;
-}
-
-/** Shift the current observation time of <b>b</b> forward by one second. */
-STATIC void
-advance_obs(bw_array_t *b)
-{
- int nextidx;
- uint64_t total;
-
- /* Calculate the total bandwidth for the last NUM_SECS_ROLLING_MEASURE
- * seconds; adjust max_total as needed.*/
- total = b->total_obs + b->obs[b->cur_obs_idx];
- if (total > b->max_total)
- b->max_total = total;
-
- nextidx = b->cur_obs_idx+1;
- if (nextidx == NUM_SECS_ROLLING_MEASURE)
- nextidx = 0;
-
- b->total_obs = total - b->obs[nextidx];
- b->obs[nextidx]=0;
- b->cur_obs_idx = nextidx;
-
- if (++b->cur_obs_time >= b->next_period)
- commit_max(b);
-}
-
-/** Add <b>n</b> bytes to the number of bytes in <b>b</b> for second
- * <b>when</b>. */
-static inline void
-add_obs(bw_array_t *b, time_t when, uint64_t n)
-{
- if (when < b->cur_obs_time)
- return; /* Don't record data in the past. */
-
- /* If we're currently adding observations for an earlier second than
- * 'when', advance b->cur_obs_time and b->cur_obs_idx by an
- * appropriate number of seconds, and do all the other housekeeping. */
- while (when > b->cur_obs_time) {
- /* Doing this one second at a time is potentially inefficient, if we start
- with a state file that is very old. Fortunately, it doesn't seem to
- show up in profiles, so we can just ignore it for now. */
- advance_obs(b);
- }
-
- b->obs[b->cur_obs_idx] += n;
- b->total_in_period += n;
-}
-
-/** Allocate, initialize, and return a new bw_array. */
-static bw_array_t *
-bw_array_new(void)
-{
- bw_array_t *b;
- time_t start;
- b = tor_malloc_zero(sizeof(bw_array_t));
- rephist_total_alloc += sizeof(bw_array_t);
- start = time(NULL);
- b->cur_obs_time = start;
- b->next_period = start + NUM_SECS_BW_SUM_INTERVAL;
- return b;
-}
-
-#define bw_array_free(val) \
- FREE_AND_NULL(bw_array_t, bw_array_free_, (val))
-
-/** Free storage held by bandwidth array <b>b</b>. */
-static void
-bw_array_free_(bw_array_t *b)
-{
- if (!b) {
- return;
- }
-
- rephist_total_alloc -= sizeof(bw_array_t);
- tor_free(b);
-}
-
-/** Recent history of bandwidth observations for read operations. */
-static bw_array_t *read_array = NULL;
-/** Recent history of bandwidth observations for write operations. */
-STATIC bw_array_t *write_array = NULL;
-/** Recent history of bandwidth observations for read operations for the
- directory protocol. */
-static bw_array_t *dir_read_array = NULL;
-/** Recent history of bandwidth observations for write operations for the
- directory protocol. */
-static bw_array_t *dir_write_array = NULL;
-
-/** Set up [dir_]read_array and [dir_]write_array, freeing them if they
- * already exist. */
-static void
-bw_arrays_init(void)
-{
- bw_array_free(read_array);
- bw_array_free(write_array);
- bw_array_free(dir_read_array);
- bw_array_free(dir_write_array);
-
- read_array = bw_array_new();
- write_array = bw_array_new();
- dir_read_array = bw_array_new();
- dir_write_array = bw_array_new();
-}
-
-/** Remember that we read <b>num_bytes</b> bytes in second <b>when</b>.
- *
- * Add num_bytes to the current running total for <b>when</b>.
- *
- * <b>when</b> can go back to time, but it's safe to ignore calls
- * earlier than the latest <b>when</b> you've heard of.
- */
-void
-rep_hist_note_bytes_written(uint64_t num_bytes, time_t when)
-{
-/* Maybe a circular array for recent seconds, and step to a new point
- * every time a new second shows up. Or simpler is to just to have
- * a normal array and push down each item every second; it's short.
- */
-/* When a new second has rolled over, compute the sum of the bytes we've
- * seen over when-1 to when-1-NUM_SECS_ROLLING_MEASURE, and stick it
- * somewhere. See rep_hist_bandwidth_assess() below.
- */
- add_obs(write_array, when, num_bytes);
-}
-
-/** Remember that we wrote <b>num_bytes</b> bytes in second <b>when</b>.
- * (like rep_hist_note_bytes_written() above)
- */
-void
-rep_hist_note_bytes_read(uint64_t num_bytes, time_t when)
-{
-/* if we're smart, we can make this func and the one above share code */
- add_obs(read_array, when, num_bytes);
-}
-
-/** Remember that we wrote <b>num_bytes</b> directory bytes in second
- * <b>when</b>. (like rep_hist_note_bytes_written() above)
- */
-void
-rep_hist_note_dir_bytes_written(uint64_t num_bytes, time_t when)
-{
- add_obs(dir_write_array, when, num_bytes);
-}
-
-/** Remember that we read <b>num_bytes</b> directory bytes in second
- * <b>when</b>. (like rep_hist_note_bytes_written() above)
- */
-void
-rep_hist_note_dir_bytes_read(uint64_t num_bytes, time_t when)
-{
- add_obs(dir_read_array, when, num_bytes);
-}
-
-/** Helper: Return the largest value in b->maxima. (This is equal to the
- * most bandwidth used in any NUM_SECS_ROLLING_MEASURE period for the last
- * NUM_SECS_BW_SUM_IS_VALID seconds.)
- */
-STATIC uint64_t
-find_largest_max(bw_array_t *b)
-{
- int i;
- uint64_t max;
- max=0;
- for (i=0; i<NUM_TOTALS; ++i) {
- if (b->maxima[i]>max)
- max = b->maxima[i];
- }
- return max;
-}
-
-/** Find the largest sums in the past NUM_SECS_BW_SUM_IS_VALID (roughly)
- * seconds. Find one sum for reading and one for writing. They don't have
- * to be at the same time.
- *
- * Return the smaller of these sums, divided by NUM_SECS_ROLLING_MEASURE.
- */
-MOCK_IMPL(int,
-rep_hist_bandwidth_assess,(void))
-{
- uint64_t w,r;
- r = find_largest_max(read_array);
- w = find_largest_max(write_array);
- if (r>w)
- return (int)(((double)w)/NUM_SECS_ROLLING_MEASURE);
- else
- return (int)(((double)r)/NUM_SECS_ROLLING_MEASURE);
-}
-
-/** Print the bandwidth history of b (either [dir-]read_array or
- * [dir-]write_array) into the buffer pointed to by buf. The format is
- * simply comma separated numbers, from oldest to newest.
- *
- * It returns the number of bytes written.
- */
-static size_t
-rep_hist_fill_bandwidth_history(char *buf, size_t len, const bw_array_t *b)
-{
- char *cp = buf;
- int i, n;
- const or_options_t *options = get_options();
- uint64_t cutoff;
-
- if (b->num_maxes_set <= b->next_max_idx) {
- /* We haven't been through the circular array yet; time starts at i=0.*/
- i = 0;
- } else {
- /* We've been around the array at least once. The next i to be
- overwritten is the oldest. */
- i = b->next_max_idx;
- }
-
- if (options->RelayBandwidthRate) {
- /* We don't want to report that we used more bandwidth than the max we're
- * willing to relay; otherwise everybody will know how much traffic
- * we used ourself. */
- cutoff = options->RelayBandwidthRate * NUM_SECS_BW_SUM_INTERVAL;
- } else {
- cutoff = UINT64_MAX;
- }
-
- for (n=0; n<b->num_maxes_set; ++n,++i) {
- uint64_t total;
- if (i >= NUM_TOTALS)
- i -= NUM_TOTALS;
- tor_assert(i < NUM_TOTALS);
- /* Round the bandwidth used down to the nearest 1k. */
- total = b->totals[i] & ~0x3ff;
- if (total > cutoff)
- total = cutoff;
-
- if (n==(b->num_maxes_set-1))
- tor_snprintf(cp, len-(cp-buf), "%"PRIu64, (total));
- else
- tor_snprintf(cp, len-(cp-buf), "%"PRIu64",", (total));
- cp += strlen(cp);
- }
- return cp-buf;
-}
-
-/** Allocate and return lines for representing this server's bandwidth
- * history in its descriptor. We publish these lines in our extra-info
- * descriptor.
- */
-char *
-rep_hist_get_bandwidth_lines(void)
-{
- char *buf, *cp;
- char t[ISO_TIME_LEN+1];
- int r;
- bw_array_t *b = NULL;
- const char *desc = NULL;
- size_t len;
-
- /* [dirreq-](read|write)-history yyyy-mm-dd HH:MM:SS (n s) n,n,n... */
-/* The n,n,n part above. Largest representation of a uint64_t is 20 chars
- * long, plus the comma. */
-#define MAX_HIST_VALUE_LEN (21*NUM_TOTALS)
- len = (67+MAX_HIST_VALUE_LEN)*4;
- buf = tor_malloc_zero(len);
- cp = buf;
- for (r=0;r<4;++r) {
- char tmp[MAX_HIST_VALUE_LEN];
- size_t slen;
- switch (r) {
- case 0:
- b = write_array;
- desc = "write-history";
- break;
- case 1:
- b = read_array;
- desc = "read-history";
- break;
- case 2:
- b = dir_write_array;
- desc = "dirreq-write-history";
- break;
- case 3:
- b = dir_read_array;
- desc = "dirreq-read-history";
- break;
- }
- tor_assert(b);
- slen = rep_hist_fill_bandwidth_history(tmp, MAX_HIST_VALUE_LEN, b);
- /* If we don't have anything to write, skip to the next entry. */
- if (slen == 0)
- continue;
- format_iso_time(t, b->next_period-NUM_SECS_BW_SUM_INTERVAL);
- tor_snprintf(cp, len-(cp-buf), "%s %s (%d s) ",
- desc, t, NUM_SECS_BW_SUM_INTERVAL);
- cp += strlen(cp);
- strlcat(cp, tmp, len-(cp-buf));
- cp += slen;
- strlcat(cp, "\n", len-(cp-buf));
- ++cp;
- }
- return buf;
-}
-
-/** Write a single bw_array_t into the Values, Ends, Interval, and Maximum
- * entries of an or_state_t. Done before writing out a new state file. */
-static void
-rep_hist_update_bwhist_state_section(or_state_t *state,
- const bw_array_t *b,
- smartlist_t **s_values,
- smartlist_t **s_maxima,
- time_t *s_begins,
- int *s_interval)
-{
- int i,j;
- uint64_t maxval;
-
- if (*s_values) {
- SMARTLIST_FOREACH(*s_values, char *, val, tor_free(val));
- smartlist_free(*s_values);
- }
- if (*s_maxima) {
- SMARTLIST_FOREACH(*s_maxima, char *, val, tor_free(val));
- smartlist_free(*s_maxima);
- }
- if (! server_mode(get_options())) {
- /* Clients don't need to store bandwidth history persistently;
- * force these values to the defaults. */
- /* FFFF we should pull the default out of config.c's state table,
- * so we don't have two defaults. */
- if (*s_begins != 0 || *s_interval != 900) {
- time_t now = time(NULL);
- time_t save_at = get_options()->AvoidDiskWrites ? now+3600 : now+600;
- or_state_mark_dirty(state, save_at);
- }
- *s_begins = 0;
- *s_interval = 900;
- *s_values = smartlist_new();
- *s_maxima = smartlist_new();
- return;
- }
- *s_begins = b->next_period;
- *s_interval = NUM_SECS_BW_SUM_INTERVAL;
-
- *s_values = smartlist_new();
- *s_maxima = smartlist_new();
- /* Set i to first position in circular array */
- i = (b->num_maxes_set <= b->next_max_idx) ? 0 : b->next_max_idx;
- for (j=0; j < b->num_maxes_set; ++j,++i) {
- if (i >= NUM_TOTALS)
- i = 0;
- smartlist_add_asprintf(*s_values, "%"PRIu64,
- (b->totals[i] & ~0x3ff));
- maxval = b->maxima[i] / NUM_SECS_ROLLING_MEASURE;
- smartlist_add_asprintf(*s_maxima, "%"PRIu64,
- (maxval & ~0x3ff));
- }
- smartlist_add_asprintf(*s_values, "%"PRIu64,
- (b->total_in_period & ~0x3ff));
- maxval = b->max_total / NUM_SECS_ROLLING_MEASURE;
- smartlist_add_asprintf(*s_maxima, "%"PRIu64,
- (maxval & ~0x3ff));
-}
-
-/** Update <b>state</b> with the newest bandwidth history. Done before
- * writing out a new state file. */
-void
-rep_hist_update_state(or_state_t *state)
-{
-#define UPDATE(arrname,st) \
- rep_hist_update_bwhist_state_section(state,\
- (arrname),\
- &state->BWHistory ## st ## Values, \
- &state->BWHistory ## st ## Maxima, \
- &state->BWHistory ## st ## Ends, \
- &state->BWHistory ## st ## Interval)
-
- UPDATE(write_array, Write);
- UPDATE(read_array, Read);
- UPDATE(dir_write_array, DirWrite);
- UPDATE(dir_read_array, DirRead);
-
- if (server_mode(get_options())) {
- or_state_mark_dirty(state, time(NULL)+(2*3600));
- }
-#undef UPDATE
-}
-
-/** Load a single bw_array_t from its Values, Ends, Maxima, and Interval
- * entries in an or_state_t. Done while reading the state file. */
-static int
-rep_hist_load_bwhist_state_section(bw_array_t *b,
- const smartlist_t *s_values,
- const smartlist_t *s_maxima,
- const time_t s_begins,
- const int s_interval)
-{
- time_t now = time(NULL);
- int retval = 0;
- time_t start;
-
- uint64_t v, mv;
- int i,ok,ok_m = 0;
- int have_maxima = s_maxima && s_values &&
- (smartlist_len(s_values) == smartlist_len(s_maxima));
-
- if (s_values && s_begins >= now - NUM_SECS_BW_SUM_INTERVAL*NUM_TOTALS) {
- start = s_begins - s_interval*(smartlist_len(s_values));
- if (start > now)
- return 0;
- b->cur_obs_time = start;
- b->next_period = start + NUM_SECS_BW_SUM_INTERVAL;
- SMARTLIST_FOREACH_BEGIN(s_values, const char *, cp) {
- const char *maxstr = NULL;
- v = tor_parse_uint64(cp, 10, 0, UINT64_MAX, &ok, NULL);
- if (have_maxima) {
- maxstr = smartlist_get(s_maxima, cp_sl_idx);
- mv = tor_parse_uint64(maxstr, 10, 0, UINT64_MAX, &ok_m, NULL);
- mv *= NUM_SECS_ROLLING_MEASURE;
- } else {
- /* No maxima known; guess average rate to be conservative. */
- mv = (v / s_interval) * NUM_SECS_ROLLING_MEASURE;
- }
- if (!ok) {
- retval = -1;
- log_notice(LD_HIST, "Could not parse value '%s' into a number.'",cp);
- }
- if (maxstr && !ok_m) {
- retval = -1;
- log_notice(LD_HIST, "Could not parse maximum '%s' into a number.'",
- maxstr);
- }
-
- if (start < now) {
- time_t cur_start = start;
- time_t actual_interval_len = s_interval;
- uint64_t cur_val = 0;
- /* Calculate the average per second. This is the best we can do
- * because our state file doesn't have per-second resolution. */
- if (start + s_interval > now)
- actual_interval_len = now - start;
- cur_val = v / actual_interval_len;
- /* This is potentially inefficient, but since we don't do it very
- * often it should be ok. */
- while (cur_start < start + actual_interval_len) {
- add_obs(b, cur_start, cur_val);
- ++cur_start;
- }
- b->max_total = mv;
- /* This will result in some fairly choppy history if s_interval
- * is not the same as NUM_SECS_BW_SUM_INTERVAL. XXXX */
- start += actual_interval_len;
- }
- } SMARTLIST_FOREACH_END(cp);
- }
-
- /* Clean up maxima and observed */
- for (i=0; i<NUM_SECS_ROLLING_MEASURE; ++i) {
- b->obs[i] = 0;
- }
- b->total_obs = 0;
-
- return retval;
-}
-
-/** Set bandwidth history from the state file we just loaded. */
-int
-rep_hist_load_state(or_state_t *state, char **err)
-{
- int all_ok = 1;
-
- /* Assert they already have been malloced */
- tor_assert(read_array && write_array);
- tor_assert(dir_read_array && dir_write_array);
-
-#define LOAD(arrname,st) \
- if (rep_hist_load_bwhist_state_section( \
- (arrname), \
- state->BWHistory ## st ## Values, \
- state->BWHistory ## st ## Maxima, \
- state->BWHistory ## st ## Ends, \
- state->BWHistory ## st ## Interval)<0) \
- all_ok = 0
-
- LOAD(write_array, Write);
- LOAD(read_array, Read);
- LOAD(dir_write_array, DirWrite);
- LOAD(dir_read_array, DirRead);
-
-#undef LOAD
- if (!all_ok) {
- *err = tor_strdup("Parsing of bandwidth history values failed");
- /* and create fresh arrays */
- bw_arrays_init();
- return -1;
- }
- return 0;
-}
-
/*** Exit port statistics ***/
/* Some constants */
@@ -2213,223 +1646,6 @@ rep_hist_note_desc_served(const char * desc)
/*** Connection statistics ***/
-/** Start of the current connection stats interval or 0 if we're not
- * collecting connection statistics. */
-static time_t start_of_conn_stats_interval;
-
-/** Initialize connection stats. */
-void
-rep_hist_conn_stats_init(time_t now)
-{
- start_of_conn_stats_interval = now;
-}
-
-/* Count connections that we read and wrote less than these many bytes
- * from/to as below threshold. */
-#define BIDI_THRESHOLD 20480
-
-/* Count connections that we read or wrote at least this factor as many
- * bytes from/to than we wrote or read to/from as mostly reading or
- * writing. */
-#define BIDI_FACTOR 10
-
-/* Interval length in seconds for considering read and written bytes for
- * connection stats. */
-#define BIDI_INTERVAL 10
-
-/** Start of next BIDI_INTERVAL second interval. */
-static time_t bidi_next_interval = 0;
-
-/** Number of connections that we read and wrote less than BIDI_THRESHOLD
- * bytes from/to in BIDI_INTERVAL seconds. */
-static uint32_t below_threshold = 0;
-
-/** Number of connections that we read at least BIDI_FACTOR times more
- * bytes from than we wrote to in BIDI_INTERVAL seconds. */
-static uint32_t mostly_read = 0;
-
-/** Number of connections that we wrote at least BIDI_FACTOR times more
- * bytes to than we read from in BIDI_INTERVAL seconds. */
-static uint32_t mostly_written = 0;
-
-/** Number of connections that we read and wrote at least BIDI_THRESHOLD
- * bytes from/to, but not BIDI_FACTOR times more in either direction in
- * BIDI_INTERVAL seconds. */
-static uint32_t both_read_and_written = 0;
-
-/** Entry in a map from connection ID to the number of read and written
- * bytes on this connection in a BIDI_INTERVAL second interval. */
-typedef struct bidi_map_entry_t {
- HT_ENTRY(bidi_map_entry_t) node;
- uint64_t conn_id; /**< Connection ID */
- size_t read; /**< Number of read bytes */
- size_t written; /**< Number of written bytes */
-} bidi_map_entry_t;
-
-/** Map of OR connections together with the number of read and written
- * bytes in the current BIDI_INTERVAL second interval. */
-static HT_HEAD(bidimap, bidi_map_entry_t) bidi_map =
- HT_INITIALIZER();
-
-static int
-bidi_map_ent_eq(const bidi_map_entry_t *a, const bidi_map_entry_t *b)
-{
- return a->conn_id == b->conn_id;
-}
-
-/* DOCDOC bidi_map_ent_hash */
-static unsigned
-bidi_map_ent_hash(const bidi_map_entry_t *entry)
-{
- return (unsigned) entry->conn_id;
-}
-
-HT_PROTOTYPE(bidimap, bidi_map_entry_t, node, bidi_map_ent_hash,
- bidi_map_ent_eq);
-HT_GENERATE2(bidimap, bidi_map_entry_t, node, bidi_map_ent_hash,
- bidi_map_ent_eq, 0.6, tor_reallocarray_, tor_free_);
-
-/* DOCDOC bidi_map_free */
-static void
-bidi_map_free_all(void)
-{
- bidi_map_entry_t **ptr, **next, *ent;
- for (ptr = HT_START(bidimap, &bidi_map); ptr; ptr = next) {
- ent = *ptr;
- next = HT_NEXT_RMV(bidimap, &bidi_map, ptr);
- tor_free(ent);
- }
- HT_CLEAR(bidimap, &bidi_map);
-}
-
-/** Reset counters for conn statistics. */
-void
-rep_hist_reset_conn_stats(time_t now)
-{
- start_of_conn_stats_interval = now;
- below_threshold = 0;
- mostly_read = 0;
- mostly_written = 0;
- both_read_and_written = 0;
- bidi_map_free_all();
-}
-
-/** Stop collecting connection stats in a way that we can re-start doing
- * so in rep_hist_conn_stats_init(). */
-void
-rep_hist_conn_stats_term(void)
-{
- rep_hist_reset_conn_stats(0);
-}
-
-/** We read <b>num_read</b> bytes and wrote <b>num_written</b> from/to OR
- * connection <b>conn_id</b> in second <b>when</b>. If this is the first
- * observation in a new interval, sum up the last observations. Add bytes
- * for this connection. */
-void
-rep_hist_note_or_conn_bytes(uint64_t conn_id, size_t num_read,
- size_t num_written, time_t when)
-{
- if (!start_of_conn_stats_interval)
- return;
- /* Initialize */
- if (bidi_next_interval == 0)
- bidi_next_interval = when + BIDI_INTERVAL;
- /* Sum up last period's statistics */
- if (when >= bidi_next_interval) {
- bidi_map_entry_t **ptr, **next, *ent;
- for (ptr = HT_START(bidimap, &bidi_map); ptr; ptr = next) {
- ent = *ptr;
- if (ent->read + ent->written < BIDI_THRESHOLD)
- below_threshold++;
- else if (ent->read >= ent->written * BIDI_FACTOR)
- mostly_read++;
- else if (ent->written >= ent->read * BIDI_FACTOR)
- mostly_written++;
- else
- both_read_and_written++;
- next = HT_NEXT_RMV(bidimap, &bidi_map, ptr);
- tor_free(ent);
- }
- while (when >= bidi_next_interval)
- bidi_next_interval += BIDI_INTERVAL;
- log_info(LD_GENERAL, "%d below threshold, %d mostly read, "
- "%d mostly written, %d both read and written.",
- below_threshold, mostly_read, mostly_written,
- both_read_and_written);
- }
- /* Add this connection's bytes. */
- if (num_read > 0 || num_written > 0) {
- bidi_map_entry_t *entry, lookup;
- lookup.conn_id = conn_id;
- entry = HT_FIND(bidimap, &bidi_map, &lookup);
- if (entry) {
- entry->written += num_written;
- entry->read += num_read;
- } else {
- entry = tor_malloc_zero(sizeof(bidi_map_entry_t));
- entry->conn_id = conn_id;
- entry->written = num_written;
- entry->read = num_read;
- HT_INSERT(bidimap, &bidi_map, entry);
- }
- }
-}
-
-/** Return a newly allocated string containing the connection statistics
- * until <b>now</b>, or NULL if we're not collecting conn stats. Caller must
- * ensure start_of_conn_stats_interval is in the past. */
-char *
-rep_hist_format_conn_stats(time_t now)
-{
- char *result, written[ISO_TIME_LEN+1];
-
- if (!start_of_conn_stats_interval)
- return NULL; /* Not initialized. */
-
- tor_assert(now >= start_of_conn_stats_interval);
-
- format_iso_time(written, now);
- tor_asprintf(&result, "conn-bi-direct %s (%d s) %d,%d,%d,%d\n",
- written,
- (unsigned) (now - start_of_conn_stats_interval),
- below_threshold,
- mostly_read,
- mostly_written,
- both_read_and_written);
- return result;
-}
-
-/** If 24 hours have passed since the beginning of the current conn stats
- * period, write conn stats to $DATADIR/stats/conn-stats (possibly
- * overwriting an existing file) and reset counters. Return when we would
- * next want to write conn stats or 0 if we never want to write. */
-time_t
-rep_hist_conn_stats_write(time_t now)
-{
- char *str = NULL;
-
- if (!start_of_conn_stats_interval)
- return 0; /* Not initialized. */
- if (start_of_conn_stats_interval + WRITE_STATS_INTERVAL > now)
- goto done; /* Not ready to write */
-
- /* Generate history string. */
- str = rep_hist_format_conn_stats(now);
-
- /* Reset counters. */
- rep_hist_reset_conn_stats(now);
-
- /* Try to write to disk. */
- if (!check_or_create_data_subdir("stats")) {
- write_to_data_subdir("stats", "conn-stats", str, "connection statistics");
- }
-
- done:
- tor_free(str);
- return start_of_conn_stats_interval + WRITE_STATS_INTERVAL;
-}
-
/** Internal statistics to track how many requests of each type of
* handshake we've received, and how many we've assigned to cpuworkers.
* Useful for seeing trends in cpu load.
@@ -2455,6 +1671,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)
@@ -2901,23 +2137,11 @@ rep_hist_free_all(void)
hs_stats_free(hs_stats);
digestmap_free(history_map, free_or_history);
- bw_array_free(read_array);
- read_array = NULL;
-
- bw_array_free(write_array);
- write_array = NULL;
-
- bw_array_free(dir_read_array);
- dir_read_array = NULL;
-
- bw_array_free(dir_write_array);
- dir_write_array = NULL;
-
tor_free(exit_bytes_read);
tor_free(exit_bytes_written);
tor_free(exit_streams);
predicted_ports_free_all();
- bidi_map_free_all();
+ conn_stats_free_all();
if (circuits_for_buffer_stats) {
SMARTLIST_FOREACH(circuits_for_buffer_stats, circ_buffer_stats_t *, s,
diff --git a/src/feature/stats/rephist.h b/src/feature/stats/rephist.h
index 92c3d2a5a5..c9ebc5c328 100644
--- a/src/feature/stats/rephist.h
+++ b/src/feature/stats/rephist.h
@@ -14,18 +14,9 @@
void rep_hist_init(void);
void rep_hist_dump_stats(time_t now, int severity);
-void rep_hist_note_bytes_read(uint64_t num_bytes, time_t when);
-void rep_hist_note_bytes_written(uint64_t num_bytes, time_t when);
void rep_hist_make_router_pessimal(const char *id, time_t when);
-void rep_hist_note_dir_bytes_read(uint64_t num_bytes, time_t when);
-void rep_hist_note_dir_bytes_written(uint64_t num_bytes, time_t when);
-
-MOCK_DECL(int, rep_hist_bandwidth_assess, (void));
-char *rep_hist_get_bandwidth_lines(void);
-void rep_hist_update_state(or_state_t *state);
-int rep_hist_load_state(or_state_t *state, char **err);
void rep_history_clean(time_t before);
void rep_hist_note_router_reachable(const char *id, const tor_addr_t *at_addr,
@@ -65,18 +56,13 @@ void rep_hist_note_desc_served(const char * desc);
void rep_hist_desc_stats_term(void);
time_t rep_hist_desc_stats_write(time_t now);
-void rep_hist_conn_stats_init(time_t now);
-void rep_hist_note_or_conn_bytes(uint64_t conn_id, size_t num_read,
- size_t num_written, time_t when);
-void rep_hist_reset_conn_stats(time_t now);
-char *rep_hist_format_conn_stats(time_t now);
-time_t rep_hist_conn_stats_write(time_t now);
-void rep_hist_conn_stats_term(void);
-
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);
@@ -95,16 +81,8 @@ extern uint32_t rephist_total_num;
#ifdef TOR_UNIT_TESTS
extern int onion_handshakes_requested[MAX_ONION_HANDSHAKE_TYPE+1];
extern int onion_handshakes_assigned[MAX_ONION_HANDSHAKE_TYPE+1];
-extern struct bw_array_t *write_array;
#endif
-#ifdef REPHIST_PRIVATE
-typedef struct bw_array_t bw_array_t;
-STATIC uint64_t find_largest_max(bw_array_t *b);
-STATIC void commit_max(bw_array_t *b);
-STATIC void advance_obs(bw_array_t *b);
-#endif /* defined(REPHIST_PRIVATE) */
-
/**
* Represents the type of a cell for padding accounting
*/
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/lib/trace/.may_include b/src/lib/trace/.may_include
index 45cd13676b..1ed533cc7a 100644
--- a/src/lib/trace/.may_include
+++ b/src/lib/trace/.may_include
@@ -1,3 +1,4 @@
orconfig.h
lib/log/*.h
lib/trace/*.h
+lib/subsys/*.h
diff --git a/src/lib/trace/debug.h b/src/lib/trace/debug.h
index 87b3074e0b..84a2867a6d 100644
--- a/src/lib/trace/debug.h
+++ b/src/lib/trace/debug.h
@@ -6,8 +6,10 @@
* \brief Macros for debugging our event-trace support.
**/
-#ifndef TOR_TRACE_LOG_DEBUG_H
-#define TOR_TRACE_LOG_DEBUG_H
+#ifndef TOR_TRACE_DEBUG_H
+#define TOR_TRACE_DEBUG_H
+
+#ifdef USE_TRACING_INSTRUMENTATION_LOG_DEBUG
#include "lib/log/log.h"
@@ -17,14 +19,20 @@
/* Send every event to a debug log level. This is useful to debug new trace
* events without implementing them for a specific event tracing framework.
- * Note that the arguments are ignored since at this step we do not know the
- * types and amount there is. */
+ *
+ * NOTE: arguments can't be used becaue there is no easy generic ways to learn
+ * their type and amount. It is probably doable with massive C pre-processor
+ * trickery but this is meant to be simple. */
+
+#define TOR_TRACE_LOG_DEBUG(subsystem, event_name, ...) \
+ log_debug(LD_GENERAL, "Tracepoint \"" XSTR(event_name) "\" from " \
+ "subsystem \"" XSTR(subsystem) "\" hit.")
+
+#else /* defined(USE_TRACING_INSTRUMENTATION_LOG_DEBUG) */
+
+/* NOP the debug event. */
+#define TOR_TRACE_LOG_DEBUG(subsystem, name, ...)
-/* Example on how to map a tracepoint to log_debug(). */
-#undef tor_trace
-#define tor_trace(subsystem, name, args...) \
- log_debug(LD_GENERAL, "Trace event \"" XSTR(name) "\" from " \
- "\"" XSTR(subsystem) "\" hit. " \
- "(line "XSTR(__LINE__) ")")
+#endif /* defined(USE_TRACING_INSTRUMENTATION_LOG_DEBUG) */
-#endif /* !defined(TOR_TRACE_LOG_DEBUG_H) */
+#endif /* !defined(TOR_TRACE_DEBUG_H) */
diff --git a/src/lib/trace/events.h b/src/lib/trace/events.h
index 368f85dd02..ce1604de22 100644
--- a/src/lib/trace/events.h
+++ b/src/lib/trace/events.h
@@ -3,43 +3,75 @@
/**
* \file events.h
- * \brief Header file for Tor event tracing.
+ * \brief Header file for Tor tracing instrumentation definition.
**/
-#ifndef TOR_TRACE_EVENTS_H
-#define TOR_TRACE_EVENTS_H
+#ifndef TOR_LIB_TRACE_EVENTS_H
+#define TOR_LIB_TRACE_EVENTS_H
+
+#include "orconfig.h"
/*
- * The following defines a generic event tracing function name that has to be
- * used to trace events in the code base.
+ * A tracepoint signature is defined as follow:
+ *
+ * tor_trace(<subsystem>, <event_name>, <args>...)
+ *
+ * If tracing is enabled, the tor_trace() macro is mapped to all possible
+ * instrumentations (defined below). Each instrumentation type MUST define a
+ * top level macro (TOR_TRACE_<type>) so it can be inserted into each
+ * tracepoint.
+ *
+ * In case no tracing is enabled (HAVE_TRACING), tracepoints are NOP and thus
+ * have no execution cost.
*
- * That generic function is then defined by a event tracing framework. For
- * instance, the "log debug" framework sends all trace events to log_debug()
- * which is defined in src/trace/debug.h which can only be enabled at compile
- * time (--enable-event-tracing-debug).
+ * Currently, three types of instrumentation are supported:
*
- * By default, every trace events in the code base are replaced by a NOP. See
- * doc/HACKING/Tracing.md for more information on how to use event tracing or
- * add events.
+ * log-debug: Every tracepoints is mapped to a log_debug() statement.
+ *
+ * User Statically-Defined Tracing (USDT): Probes that can be used with perf,
+ * dtrace, SystemTap, DTrace and BPF Compiler Collection (BCC).
+ *
+ * LTTng-UST: Probes for the LTTng Userspace Tracer. If USDT interface
+ * (sdt.h) is available, the USDT probes are also generated by LTTng thus
+ * enabling this instrumentation provides both probes.
*/
-#ifdef TOR_EVENT_TRACING_ENABLED
-/* Map every trace event to a per subsystem macro. */
-#define tor_trace(subsystem, name, ...) \
- tor_trace_##subsystem(name, __VA_ARGS__)
+/** Helper to disambiguate these identifiers in the code base. They should
+ * only be used with tor_trace() like so:
+ *
+ * tor_trace(TR_SUBSYS(circuit), TR_EV(opened), ...);
+ */
+
+#define TR_SUBSYS(name) tor_ ## name
+#define TR_EV(name) name
+
+#ifdef HAVE_TRACING
-/* Enable event tracing for the debug framework where all trace events are
- * mapped to a log_debug(). */
-#ifdef USE_EVENT_TRACING_DEBUG
+#define tor_trace(subsystem, event_name, ...) \
+ do { \
+ TOR_TRACE_LOG_DEBUG(subsystem, event_name); \
+ TOR_TRACE_USDT(subsystem, event_name, ## __VA_ARGS__); \
+ TOR_TRACE_LTTNG(subsystem, event_name, ## __VA_ARGS__); \
+ } while (0)
+
+/* This corresponds to the --enable-tracing-instrumentation-log-debug
+ * configure option which maps all tracepoints to a log_debug() statement. */
#include "lib/trace/debug.h"
-#endif
-#else /* !defined(TOR_EVENT_TRACING_ENABLED) */
+/* This corresponds to the --enable-tracing-instrumentation-usdt configure
+ * option which will generate USDT probes for each tracepoints. */
+#include "lib/trace/usdt/usdt.h"
+
+/* This corresponds to the --enable-tracing-instrumentation-lttng configure
+ * option which will generate LTTng probes for each tracepoints. */
+#include "lib/trace/lttng/lttng.h"
+
+#else /* !defined(HAVE_TRACING) */
-/* Reaching this point, we NOP every event declaration because event tracing
- * is not been enabled at compile time. */
-#define tor_trace(subsystem, name, args...)
+/* Reaching this point, tracing is disabled thus we NOP every tracepoints
+ * declaration so we have no execution cost at runtime. */
+#define tor_trace(subsystem, name, ...)
-#endif /* defined(TOR_EVENT_TRACING_ENABLED) */
+#endif /* defined(HAVE_TRACING) */
-#endif /* !defined(TOR_TRACE_EVENTS_H) */
+#endif /* !defined(TOR_LIB_TRACE_EVENTS_H) */
diff --git a/src/lib/trace/include.am b/src/lib/trace/include.am
index 98098c87f4..6fe1365652 100644
--- a/src/lib/trace/include.am
+++ b/src/lib/trace/include.am
@@ -2,18 +2,34 @@
noinst_LIBRARIES += \
src/lib/libtor-trace.a
+# ADD_C_FILE: INSERT SOURCES HERE.
+LIBTOR_TRACE_A_SOURCES = \
+ src/lib/trace/trace.c \
+ src/lib/trace/trace_sys.c
+
# ADD_C_FILE: INSERT HEADERS HERE.
TRACEHEADERS = \
- src/lib/trace/trace.h \
+ src/lib/trace/trace.h \
+ src/lib/trace/trace_sys.h \
src/lib/trace/events.h
-if USE_EVENT_TRACING_DEBUG
+if USE_TRACING_INSTRUMENTATION_LOG_DEBUG
TRACEHEADERS += \
src/lib/trace/debug.h
endif
-# ADD_C_FILE: INSERT SOURCES HERE.
-src_lib_libtor_trace_a_SOURCES = \
- src/lib/trace/trace.c
+if USE_TRACING_INSTRUMENTATION_USDT
+include src/lib/trace/usdt/include.am
+endif
+
+if USE_TRACING_INSTRUMENTATION_LTTNG
+include src/lib/trace/lttng/include.am
+endif
+
+if USE_TRACING
+src_lib_libtor_trace_a_SOURCES = $(LIBTOR_TRACE_A_SOURCES)
+else
+src_lib_libtor_trace_a_SOURCES = src/lib/trace/trace_stub.c
+endif
noinst_HEADERS+= $(TRACEHEADERS)
diff --git a/src/lib/trace/lttng/include.am b/src/lib/trace/lttng/include.am
new file mode 100644
index 0000000000..4495ce0900
--- /dev/null
+++ b/src/lib/trace/lttng/include.am
@@ -0,0 +1,3 @@
+# ADD_C_FILE: INSERT HEADERS HERE.
+TRACEHEADERS += \
+ src/lib/trace/lttng/lttng.h
diff --git a/src/lib/trace/lttng/lttng.h b/src/lib/trace/lttng/lttng.h
new file mode 100644
index 0000000000..8ede98bb02
--- /dev/null
+++ b/src/lib/trace/lttng/lttng.h
@@ -0,0 +1,28 @@
+/* Copyright (c) 2020, The Tor Project, Inc. */
+/* See LICENSE for licensing information */
+
+/**
+ * \file lttng.h
+ * \brief Header file for lttng.c.
+ **/
+
+#ifndef TOR_TRACE_LTTNG_LTTNG_H
+#define TOR_TRACE_LTTNG_LTTNG_H
+
+#ifdef USE_TRACING_INSTRUMENTATION_LTTNG
+
+#include <lttng/tracepoint.h>
+
+/* Map event to an LTTng tracepoint. */
+#define TOR_TRACE_LTTNG(subsystem, event_name, ...) \
+ tracepoint(subsystem, event_name, ## __VA_ARGS__)
+
+#else /* !defined(USE_TRACING_INSTRUMENTATION_LTTNG) */
+
+/* NOP event. */
+#define TOR_TRACE_LTTNG(subsystem, event_name, ...)
+
+#endif /* !defined(USE_TRACING_INSTRUMENTATION_LTTNG) */
+
+#endif /* TOR_TRACE_LTTNG_LTTNG_H */
+
diff --git a/src/lib/trace/trace.c b/src/lib/trace/trace.c
index 4e5c66b4c6..10d11c17c5 100644
--- a/src/lib/trace/trace.c
+++ b/src/lib/trace/trace.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2017-2020, The Tor Project, Inc. */
+/* Copyright (c) 2020, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
@@ -15,3 +15,9 @@ void
tor_trace_init(void)
{
}
+
+/** Free all the tracing library. */
+void
+tor_trace_free_all(void)
+{
+}
diff --git a/src/lib/trace/trace.h b/src/lib/trace/trace.h
index 5e24678c3c..22589dbe94 100644
--- a/src/lib/trace/trace.h
+++ b/src/lib/trace/trace.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2017-2020, The Tor Project, Inc. */
+/* Copyright (c) 2020, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
@@ -6,9 +6,31 @@
* \brief Header for trace.c
**/
-#ifndef TOR_TRACE_TRACE_H
-#define TOR_TRACE_TRACE_H
+#ifndef TOR_LIB_TRACE_TRACE_H
+#define TOR_LIB_TRACE_TRACE_H
+
+#include "orconfig.h"
void tor_trace_init(void);
+void tor_trace_free_all(void);
+
+#ifdef HAVE_TRACING
+
+#include "lib/log/log.h"
+
+static inline void
+tracing_log_warning(void)
+{
+ log_warn(LD_GENERAL,
+ "Tracing capabilities have been built in. If this is NOT on "
+ "purpose, your tor is NOT safe to run.");
+}
+
+#else
+
+/* NOP it. */
+#define tracing_log_warning()
+
+#endif /* defined(HAVE_TRACING) */
-#endif /* !defined(TOR_TRACE_TRACE_H) */
+#endif /* !defined(TOR_LIB_TRACE_TRACE_H) */
diff --git a/src/lib/trace/trace_stub.c b/src/lib/trace/trace_stub.c
new file mode 100644
index 0000000000..9043efe360
--- /dev/null
+++ b/src/lib/trace/trace_stub.c
@@ -0,0 +1,19 @@
+/* Copyright (c) 2020, The Tor Project, Inc. */
+/* See LICENSE for licensing information */
+
+/**
+ * \file trace_stub.c
+ * \brief Stub declaratinos for use when trace library is disabled.
+ **/
+
+#include "lib/subsys/subsys.h"
+
+#include "lib/trace/trace_sys.h"
+
+const subsys_fns_t sys_tracing = {
+ SUBSYS_DECLARE_LOCATION(),
+
+ .name = "tracing",
+ .supported = false,
+ .level = TRACE_SUBSYS_LEVEL,
+};
diff --git a/src/lib/trace/trace_sys.c b/src/lib/trace/trace_sys.c
new file mode 100644
index 0000000000..2ba0258407
--- /dev/null
+++ b/src/lib/trace/trace_sys.c
@@ -0,0 +1,36 @@
+/* Copyright (c) 2018-2019, The Tor Project, Inc. */
+/* See LICENSE for licensing information */
+
+/**
+ * \file log_sys.c
+ * \brief Setup and tear down the tracing module.
+ **/
+
+#include "lib/subsys/subsys.h"
+
+#include "lib/trace/trace.h"
+#include "lib/trace/trace_sys.h"
+
+static int
+subsys_tracing_initialize(void)
+{
+ tor_trace_init();
+ return 0;
+}
+
+static void
+subsys_tracing_shutdown(void)
+{
+ tor_trace_free_all();
+}
+
+const subsys_fns_t sys_tracing = {
+ SUBSYS_DECLARE_LOCATION(),
+
+ .name = "tracing",
+ .supported = true,
+ .level = TRACE_SUBSYS_LEVEL,
+
+ .initialize = subsys_tracing_initialize,
+ .shutdown = subsys_tracing_shutdown,
+};
diff --git a/src/lib/trace/trace_sys.h b/src/lib/trace/trace_sys.h
new file mode 100644
index 0000000000..d4da5a9701
--- /dev/null
+++ b/src/lib/trace/trace_sys.h
@@ -0,0 +1,22 @@
+/* Copyright (c) 2018-2019, The Tor Project, Inc. */
+/* See LICENSE for licensing information */
+
+/**
+ * \file log_sys.h
+ * \brief Declare subsystem object for the logging module.
+ **/
+
+#ifndef TOR_TRACE_SYS_H
+#define TOR_TRACE_SYS_H
+
+extern const struct subsys_fns_t sys_tracing;
+
+/**
+ * Subsystem level for the tracing system.
+ *
+ * Defined here so that it can be shared between the real and stub
+ * definitions.
+ **/
+#define TRACE_SUBSYS_LEVEL (-85)
+
+#endif /* !defined(TOR_TRACE_SYS_H) */
diff --git a/src/lib/trace/usdt/include.am b/src/lib/trace/usdt/include.am
new file mode 100644
index 0000000000..4e7e04c326
--- /dev/null
+++ b/src/lib/trace/usdt/include.am
@@ -0,0 +1,3 @@
+# ADD_C_FILE: INSERT HEADERS HERE.
+TRACEHEADERS += \
+ src/lib/trace/usdt/usdt.h
diff --git a/src/lib/trace/usdt/usdt.h b/src/lib/trace/usdt/usdt.h
new file mode 100644
index 0000000000..0b5fd6c444
--- /dev/null
+++ b/src/lib/trace/usdt/usdt.h
@@ -0,0 +1,33 @@
+/* Copyright (c) 2020, The Tor Project, Inc. */
+/* See LICENSE for licensing information */
+
+/**
+ * \file trace.h
+ * \brief Header for usdt.h
+ **/
+
+#ifndef TOR_TRACE_USDT_USDT_H
+#define TOR_TRACE_USDT_USDT_H
+
+#ifdef USE_TRACING_INSTRUMENTATION_USDT
+
+#ifdef HAVE_SYS_SDT_H
+#define SDT_USE_VARIADIC
+#include <sys/sdt.h>
+#define TOR_STAP_PROBEV STAP_PROBEV
+#else /* defined(HAVE_SYS_SDT_H) */
+#define TOR_STAP_PROBEV(...)
+#endif
+
+/* Map events to an USDT probe. */
+#define TOR_TRACE_USDT(subsystem, event_name, ...) \
+ TOR_STAP_PROBEV(subsystem, event_name, ## __VA_ARGS__);
+
+#else /* !defined(USE_TRACING_INSTRUMENTATION_USDT) */
+
+/* NOP event. */
+#define TOR_TRACE_USDT(subsystem, event_name, ...)
+
+#endif /* !defined(USE_TRACING_INSTRUMENTATION_USDT) */
+
+#endif /* !defined(TOR_TRACE_USDT_USDT_H) */
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/fuzz/include.am b/src/test/fuzz/include.am
index d0711f05d6..f3f7202ce2 100644
--- a/src/test/fuzz/include.am
+++ b/src/test/fuzz/include.am
@@ -14,7 +14,7 @@ FUZZING_LIBS = \
@TOR_LIB_WS32@ @TOR_LIB_IPHLPAPI@ @TOR_LIB_GDI@ @TOR_LIB_USERENV@ @CURVE25519_LIBS@ \
@TOR_SYSTEMD_LIBS@ \
@TOR_LZMA_LIBS@ \
- @TOR_ZSTD_LIBS@
+ @TOR_ZSTD_LIBS@ @TOR_TRACE_LIBS@
oss-fuzz-prereqs: \
$(TOR_INTERNAL_TESTING_LIBS)
diff --git a/src/test/include.am b/src/test/include.am
index e7647260c5..d7be1a5f77 100644
--- a/src/test/include.am
+++ b/src/test/include.am
@@ -297,7 +297,7 @@ src_test_test_switch_id_LDADD = \
$(rust_ldadd) \
@TOR_ZLIB_LIBS@ @TOR_LIB_MATH@ \
@TOR_LIB_WS32@ @TOR_LIB_IPHLPAPI@ @TOR_LIB_USERENV@ \
- @TOR_LZMA_LIBS@ @TOR_ZSTD_LIBS@
+ @TOR_LZMA_LIBS@ @TOR_ZSTD_LIBS@ @TOR_TRACE_LIBS@
src_test_test_LDFLAGS = @TOR_LDFLAGS_zlib@ $(TOR_LDFLAGS_CRYPTLIB) \
@TOR_LDFLAGS_libevent@
@@ -307,7 +307,7 @@ src_test_test_LDADD = \
@TOR_ZLIB_LIBS@ @TOR_LIB_MATH@ @TOR_LIBEVENT_LIBS@ \
$(TOR_LIBS_CRYPTLIB) @TOR_LIB_WS32@ @TOR_LIB_IPHLPAPI@ @TOR_LIB_GDI@ @TOR_LIB_USERENV@ \
@CURVE25519_LIBS@ \
- @TOR_SYSTEMD_LIBS@ @TOR_LZMA_LIBS@ @TOR_ZSTD_LIBS@
+ @TOR_SYSTEMD_LIBS@ @TOR_LZMA_LIBS@ @TOR_ZSTD_LIBS@ @TOR_TRACE_LIBS@
src_test_test_slow_CPPFLAGS = $(src_test_test_CPPFLAGS)
src_test_test_slow_CFLAGS = $(src_test_test_CFLAGS)
@@ -336,7 +336,7 @@ src_test_bench_LDADD = \
@TOR_ZLIB_LIBS@ @TOR_LIB_MATH@ @TOR_LIBEVENT_LIBS@ \
$(TOR_LIBS_CRYPTLIB) @TOR_LIB_WS32@ @TOR_LIB_IPHLPAPI@ @TOR_LIB_GDI@ @TOR_LIB_USERENV@ \
@CURVE25519_LIBS@ \
- @TOR_SYSTEMD_LIBS@ @TOR_LZMA_LIBS@ @TOR_ZSTD_LIBS@
+ @TOR_SYSTEMD_LIBS@ @TOR_LZMA_LIBS@ @TOR_ZSTD_LIBS@ @TOR_TRACE_LIBS@
src_test_test_workqueue_LDFLAGS = @TOR_LDFLAGS_zlib@ $(TOR_LDFLAGS_CRYPTLIB) \
@TOR_LDFLAGS_libevent@
@@ -346,7 +346,7 @@ src_test_test_workqueue_LDADD = \
@TOR_ZLIB_LIBS@ @TOR_LIB_MATH@ @TOR_LIBEVENT_LIBS@ \
$(TOR_LIBS_CRYPTLIB) @TOR_LIB_WS32@ @TOR_LIB_IPHLPAPI@ @TOR_LIB_GDI@ @TOR_LIB_USERENV@ \
@CURVE25519_LIBS@ \
- @TOR_LZMA_LIBS@ @TOR_ZSTD_LIBS@
+ @TOR_LZMA_LIBS@ @TOR_ZSTD_LIBS@ @TOR_TRACE_LIBS@
src_test_test_timers_CPPFLAGS = $(src_test_test_CPPFLAGS)
src_test_test_timers_CFLAGS = $(src_test_test_CFLAGS)
@@ -358,7 +358,7 @@ src_test_test_timers_LDADD = \
@TOR_ZLIB_LIBS@ @TOR_LIB_MATH@ @TOR_LIBEVENT_LIBS@ \
$(TOR_LIBS_CRYPTLIB) @TOR_LIB_WS32@ @TOR_LIB_IPHLPAPI@ @TOR_LIB_GDI@ @TOR_LIB_USERENV@ \
@CURVE25519_LIBS@ \
- @TOR_LZMA_LIBS@
+ @TOR_LZMA_LIBS@ @TOR_TRACE_LIBS@
src_test_test_timers_LDFLAGS = $(src_test_test_LDFLAGS)
# ADD_C_FILE: INSERT HEADERS HERE.
@@ -394,7 +394,7 @@ src_test_test_ntor_cl_LDADD = \
$(rust_ldadd) \
@TOR_ZLIB_LIBS@ @TOR_LIB_MATH@ \
$(TOR_LIBS_CRYPTLIB) @TOR_LIB_WS32@ @TOR_LIB_IPHLPAPI@ @TOR_LIB_GDI@ @TOR_LIB_USERENV@ \
- @CURVE25519_LIBS@ @TOR_LZMA_LIBS@
+ @CURVE25519_LIBS@ @TOR_LZMA_LIBS@ @TOR_TRACE_LIBS@
src_test_test_ntor_cl_AM_CPPFLAGS = \
$(AM_CPPFLAGS)
@@ -403,7 +403,8 @@ src_test_test_hs_ntor_cl_LDFLAGS = @TOR_LDFLAGS_zlib@ $(TOR_LDFLAGS_CRYPTLIB)
src_test_test_hs_ntor_cl_LDADD = \
$(TOR_INTERNAL_LIBS) \
@TOR_ZLIB_LIBS@ @TOR_LIB_MATH@ \
- $(TOR_LIBS_CRYPTLIB) @TOR_LIB_WS32@ @TOR_LIB_IPHLPAPI@ @TOR_LIB_GDI@ @CURVE25519_LIBS@
+ $(TOR_LIBS_CRYPTLIB) @TOR_LIB_WS32@ @TOR_LIB_IPHLPAPI@ @TOR_LIB_GDI@ \
+ @CURVE25519_LIBS@ @TOR_TRACE_LIBS@
src_test_test_hs_ntor_cl_AM_CPPFLAGS = \
$(AM_CPPFLAGS)
@@ -415,7 +416,8 @@ src_test_test_bt_cl_LDADD = \
$(TOR_UTIL_TESTING_LIBS) \
$(rust_ldadd) \
@TOR_LIB_MATH@ \
- @TOR_LIB_WS32@ @TOR_LIB_IPHLPAPI@ @TOR_LIB_GDI@ @TOR_LIB_USERENV@
+ @TOR_LIB_WS32@ @TOR_LIB_IPHLPAPI@ @TOR_LIB_GDI@ @TOR_LIB_USERENV@ \
+ @TOR_TRACE_LIBS@
src_test_test_bt_cl_CFLAGS = $(AM_CFLAGS) $(TEST_CFLAGS)
src_test_test_bt_cl_CPPFLAGS= $(src_test_AM_CPPFLAGS) $(TEST_CPPFLAGS)
endif
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_addr.c b/src/test/test_addr.c
index cf5aad7e71..dbc581288d 100644
--- a/src/test/test_addr.c
+++ b/src/test/test_addr.c
@@ -341,6 +341,7 @@ test_addr_ip6_helpers(void *arg)
test_pton6_bad("0XYXXY");
test_pton6_bad("0x");
test_pton6_bad("0X");
+ test_pton6_bad("2000::1a00::1000:fc098");
/* test internal checking */
test_external_ip("fbff:ffff::2:7", 0);
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_channel.c b/src/test/test_channel.c
index 849cc497fc..2b723b4a8d 100644
--- a/src/test/test_channel.c
+++ b/src/test/test_channel.c
@@ -16,6 +16,10 @@
/* For packed_cell stuff */
#define RELAY_PRIVATE
#include "core/or/relay.h"
+/* For channel_tls_t object and private functions. */
+#define CHANNEL_OBJECT_PRIVATE
+#define CHANNELTLS_PRIVATE
+#include "core/or/channeltls.h"
/* For init/free stuff */
#include "core/or/scheduler.h"
#include "feature/nodelist/networkstatus.h"
@@ -25,6 +29,8 @@
#include "core/or/origin_circuit_st.h"
#include "feature/nodelist/routerstatus_st.h"
#include "core/or/var_cell_st.h"
+#include "core/or/or_connection_st.h"
+#include "lib/net/inaddr.h"
/* Test suite stuff */
#include "test/log_test_helpers.h"
@@ -1537,6 +1543,54 @@ test_channel_listener(void *arg)
channel_free_all();
}
+#define TEST_SETUP_MATCHES_ADDR(orcon, addr, src, rv) STMT_BEGIN \
+ rv = tor_inet_pton(addr.family, src, &addr.addr); \
+ tt_int_op(rv, OP_EQ, 1); \
+ orcon->real_addr = addr; \
+ STMT_END;
+
+#define TEST_MATCHES_ADDR(chan, addr4, addr6, rv, exp) STMT_BEGIN \
+ rv = channel_matches_target_addr_for_extend(chan, addr4, addr6); \
+ tt_int_op(rv, OP_EQ, exp); \
+ STMT_END;
+
+static void
+test_channel_matches_target_addr_for_extend(void *arg)
+{
+ (void) arg;
+
+ channel_tls_t *tlschan = tor_malloc_zero(sizeof(*tlschan));
+ or_connection_t *orcon = tor_malloc_zero(sizeof(*orcon));
+ channel_t *chan = &(tlschan->base_);
+ tor_addr_t addr;
+ int rv;
+
+ tlschan->conn = orcon;
+ channel_tls_common_init(tlschan);
+
+ /* Test for IPv4 addresses. */
+ addr.family = AF_INET;
+ TEST_SETUP_MATCHES_ADDR(orcon, addr, "1.2.3.4", rv);
+ TEST_MATCHES_ADDR(chan, &addr, NULL, rv, 1);
+
+ tor_inet_pton(addr.family, "2.5.3.4", &addr.addr);
+ TEST_MATCHES_ADDR(chan, &addr, NULL, rv, 0);
+
+ /* Test for IPv6 addresses. */
+ addr.family = AF_INET6;
+ TEST_SETUP_MATCHES_ADDR(orcon, addr, "3:4:7:1:9:8:09:10", rv);
+ TEST_MATCHES_ADDR(chan, NULL, &addr, rv, 1);
+
+ tor_inet_pton(addr.family, "::", &addr.addr);
+ TEST_MATCHES_ADDR(chan, NULL, &addr, rv, 0);
+
+ done:
+ circuitmux_clear_policy(chan->cmux);
+ circuitmux_free(chan->cmux);
+ tor_free(orcon);
+ tor_free(tlschan);
+}
+
struct testcase_t channel_tests[] = {
{ "inbound_cell", test_channel_inbound_cell, TT_FORK,
NULL, NULL },
@@ -1558,5 +1612,7 @@ struct testcase_t channel_tests[] = {
NULL, NULL },
{ "listener", test_channel_listener, TT_FORK,
NULL, NULL },
+ { "matches_target", test_channel_matches_target_addr_for_extend, TT_FORK,
+ NULL, NULL },
END_OF_TESTCASES
};
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_dos.c b/src/test/test_dos.c
index 527e5bbe7f..3be09047d5 100644
--- a/src/test/test_dos.c
+++ b/src/test/test_dos.c
@@ -108,7 +108,7 @@ test_dos_conn_creation(void *arg)
/** Helper mock: Place a fake IP addr for this channel in <b>addr_out</b> */
static int
-mock_channel_get_addr_if_possible(channel_t *chan, tor_addr_t *addr_out)
+mock_channel_get_addr_if_possible(const channel_t *chan, tor_addr_t *addr_out)
{
(void)chan;
tt_int_op(AF_INET,OP_EQ, tor_addr_parse(addr_out, "18.0.0.1"));
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_relay.c b/src/test/test_relay.c
index 066aeaa7b3..060ca1b75d 100644
--- a/src/test/test_relay.c
+++ b/src/test/test_relay.c
@@ -3,12 +3,12 @@
#define CIRCUITBUILD_PRIVATE
#define RELAY_PRIVATE
-#define REPHIST_PRIVATE
+#define BWHIST_PRIVATE
#include "core/or/or.h"
#include "core/or/circuitbuild.h"
#include "core/or/circuitlist.h"
#include "core/or/channeltls.h"
-#include "feature/stats/rephist.h"
+#include "feature/stats/bwhist.h"
#include "core/or/relay.h"
#include "lib/container/order.h"
/* For init/free stuff */
diff --git a/src/test/test_router.c b/src/test/test_router.c
index cf0c2b3dd1..010289397a 100644
--- a/src/test/test_router.c
+++ b/src/test/test_router.c
@@ -24,7 +24,7 @@
#include "feature/nodelist/routerlist.h"
#include "feature/nodelist/routerstatus_st.h"
#include "feature/relay/router.h"
-#include "feature/stats/rephist.h"
+#include "feature/stats/bwhist.h"
#include "lib/crypt_ops/crypto_curve25519.h"
#include "lib/crypt_ops/crypto_ed25519.h"
#include "lib/encoding/confline.h"
@@ -226,13 +226,13 @@ test_router_check_descriptor_bandwidth_changed(void *arg)
/* When uptime is less than 24h and bandwidthcapacity does not change
* Uptime: 10800, last_changed: x, Previous bw: 10000, Current bw: 20001 */
- MOCK(rep_hist_bandwidth_assess, mock_rep_hist_bandwidth_assess);
+ MOCK(bwhist_bandwidth_assess, mock_rep_hist_bandwidth_assess);
setup_full_capture_of_logs(LOG_INFO);
check_descriptor_bandwidth_changed(time(NULL) + 6*60*60 + 1);
expect_log_msg_containing(
"Measured bandwidth has changed; rebuilding descriptor.");
UNMOCK(get_uptime);
- UNMOCK(rep_hist_bandwidth_assess);
+ UNMOCK(bwhist_bandwidth_assess);
teardown_capture_of_logs();
/* When uptime is more than 24h */
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/test/test_stats.c b/src/test/test_stats.c
index 291473ebc9..f0715c2e45 100644
--- a/src/test/test_stats.c
+++ b/src/test/test_stats.c
@@ -39,6 +39,7 @@
#include "test/test.h"
#include "core/mainloop/mainloop.h"
#include "lib/memarea/memarea.h"
+#include "feature/stats/connstats.h"
#include "feature/stats/rephist.h"
#include "app/config/statefile.h"
@@ -111,37 +112,41 @@ test_stats(void *arg)
/* Continue with testing connection statistics; we shouldn't collect
* conn stats without initializing them. */
- rep_hist_note_or_conn_bytes(1, 20, 400, now);
- s = rep_hist_format_conn_stats(now + 86400);
+ conn_stats_note_or_conn_bytes(1, 20, 400, now, false);
+ s = conn_stats_format(now + 86400);
tt_ptr_op(s, OP_EQ, NULL);
/* Initialize stats, note bytes, and generate history string. */
- rep_hist_conn_stats_init(now);
- rep_hist_note_or_conn_bytes(1, 30000, 400000, now);
- rep_hist_note_or_conn_bytes(1, 30000, 400000, now + 5);
- rep_hist_note_or_conn_bytes(2, 400000, 30000, now + 10);
- rep_hist_note_or_conn_bytes(2, 400000, 30000, now + 15);
- s = rep_hist_format_conn_stats(now + 86400);
- tt_str_op("conn-bi-direct 2010-08-12 13:27:30 (86400 s) 0,0,1,0\n",OP_EQ, s);
+ conn_stats_init(now);
+ conn_stats_note_or_conn_bytes(1, 30000, 400000, now, false);
+ conn_stats_note_or_conn_bytes(1, 30000, 400000, now + 5, false);
+ conn_stats_note_or_conn_bytes(2, 400000, 30000, now + 10, true);
+ conn_stats_note_or_conn_bytes(2, 400000, 30000, now + 15, true);
+ s = conn_stats_format(now + 86400);
+ tt_str_op("conn-bi-direct 2010-08-12 13:27:30 (86400 s) 0,0,1,0\n"
+ "ipv6-conn-bi-direct 2010-08-12 13:27:30 (86400 s) 0,0,0,0\n",
+ OP_EQ, s);
tor_free(s);
/* Stop collecting stats, add some bytes, and ensure we don't generate
* a history string. */
- rep_hist_conn_stats_term();
- rep_hist_note_or_conn_bytes(2, 400000, 30000, now + 15);
- s = rep_hist_format_conn_stats(now + 86400);
+ conn_stats_terminate();
+ conn_stats_note_or_conn_bytes(2, 400000, 30000, now + 15, true);
+ s = conn_stats_format(now + 86400);
tt_ptr_op(s, OP_EQ, NULL);
/* Re-start stats, add some bytes, reset stats, and see what history we
* get when observing no bytes at all. */
- rep_hist_conn_stats_init(now);
- rep_hist_note_or_conn_bytes(1, 30000, 400000, now);
- rep_hist_note_or_conn_bytes(1, 30000, 400000, now + 5);
- rep_hist_note_or_conn_bytes(2, 400000, 30000, now + 10);
- rep_hist_note_or_conn_bytes(2, 400000, 30000, now + 15);
- rep_hist_reset_conn_stats(now);
- s = rep_hist_format_conn_stats(now + 86400);
- tt_str_op("conn-bi-direct 2010-08-12 13:27:30 (86400 s) 0,0,0,0\n",OP_EQ, s);
+ conn_stats_init(now);
+ conn_stats_note_or_conn_bytes(1, 30000, 400000, now, false);
+ conn_stats_note_or_conn_bytes(1, 30000, 400000, now + 5, false);
+ conn_stats_note_or_conn_bytes(2, 400000, 30000, now + 10, true);
+ conn_stats_note_or_conn_bytes(2, 400000, 30000, now + 15, true);
+ conn_stats_reset(now);
+ s = conn_stats_format(now + 86400);
+ tt_str_op("conn-bi-direct 2010-08-12 13:27:30 (86400 s) 0,0,0,0\n"
+ "ipv6-conn-bi-direct 2010-08-12 13:27:30 (86400 s) 0,0,0,0\n",
+ OP_EQ, s);
tor_free(s);
/* Continue with testing buffer statistics; we shouldn't collect buffer
diff --git a/src/test/testing_common.c b/src/test/testing_common.c
index b3337f24b0..cd93055dfb 100644
--- a/src/test/testing_common.c
+++ b/src/test/testing_common.c
@@ -18,6 +18,7 @@
#include "lib/crypt_ops/crypto_ed25519.h"
#include "lib/crypt_ops/crypto_rand.h"
#include "feature/stats/predict_ports.h"
+#include "feature/stats/bwhist.h"
#include "feature/stats/rephist.h"
#include "lib/err/backtrace.h"
#include "test/test.h"
@@ -333,6 +334,7 @@ main(int c, const char **v)
return 1;
}
rep_hist_init();
+ bwhist_init();
setup_directory();
initialize_mainloop_events();
options_init(options);
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 a06dac67c2..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-dev"
+#define VERSION "0.4.5.0-alpha-dev"
#define HAVE_STRUCT_SOCKADDR_IN6
#define HAVE_STRUCT_IN6_ADDR