aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.travis.yml5
-rw-r--r--ChangeLog573
-rw-r--r--ReleaseNotes399
-rw-r--r--changes/bug229073
-rw-r--r--changes/bug236965
-rw-r--r--changes/bug23826-2382814
-rw-r--r--changes/bug239533
-rw-r--r--changes/bug241194
-rw-r--r--changes/bug242304
-rw-r--r--changes/bug242623
-rw-r--r--changes/bug243183
-rw-r--r--changes/bug244803
-rw-r--r--changes/cargo-build-problem3
-rw-r--r--changes/ticket200204
-rw-r--r--changes/ticket2069914
-rw-r--r--changes/ticket237604
-rw-r--r--changes/ticket243632
-rw-r--r--changes/ticket244673
-rw-r--r--changes/ticket245003
-rw-r--r--changes/ticket245184
-rw-r--r--configure.ac11
-rw-r--r--doc/HACKING/GettingStartedRust.md32
-rw-r--r--doc/HACKING/android/Simpleperf.md98
-rw-r--r--doc/tor.1.txt67
-rw-r--r--src/common/compat_threads.c19
-rw-r--r--src/common/compat_threads.h68
-rw-r--r--src/common/crypto.c29
-rw-r--r--src/common/sandbox.c86
-rw-r--r--src/common/storagedir.c25
-rw-r--r--src/or/channel.c70
-rw-r--r--src/or/circuitbuild.c8
-rw-r--r--src/or/circuitstats.c11
-rw-r--r--src/or/circuituse.c18
-rw-r--r--src/or/config.c6
-rw-r--r--src/or/confparse.h6
-rw-r--r--src/or/connection.c4
-rw-r--r--src/or/connection_or.c43
-rw-r--r--src/or/connection_or.h3
-rw-r--r--src/or/conscache.c17
-rw-r--r--src/or/consdiffmgr.c13
-rw-r--r--src/or/control.c539
-rw-r--r--src/or/control.h65
-rw-r--r--src/or/directory.c139
-rw-r--r--src/or/directory.h44
-rw-r--r--src/or/dirserv.c19
-rw-r--r--src/or/dirserv.h1
-rw-r--r--src/or/dirvote.c27
-rw-r--r--src/or/dirvote.h14
-rw-r--r--src/or/dns.c5
-rw-r--r--src/or/entrynodes.c124
-rw-r--r--src/or/entrynodes.h35
-rw-r--r--src/or/git_revision.h2
-rw-r--r--src/or/hs_cache.c18
-rw-r--r--src/or/hs_cache.h2
-rw-r--r--src/or/hs_circuit.c11
-rw-r--r--src/or/hs_circuit.h2
-rw-r--r--src/or/hs_client.c5
-rw-r--r--src/or/hs_common.h11
-rw-r--r--src/or/hs_control.c256
-rw-r--r--src/or/hs_control.h52
-rw-r--r--src/or/hs_service.c245
-rw-r--r--src/or/hs_service.h15
-rw-r--r--src/or/include.am4
-rw-r--r--src/or/main.c2
-rw-r--r--src/or/microdesc.c101
-rw-r--r--src/or/microdesc.h4
-rw-r--r--src/or/networkstatus.c7
-rw-r--r--src/or/protover.c7
-rw-r--r--src/or/protover.h2
-rw-r--r--src/or/protover_rust.c2
-rw-r--r--src/or/rendclient.c10
-rw-r--r--src/or/rendservice.c16
-rw-r--r--src/or/rendservice.h11
-rw-r--r--src/or/rephist.c4
-rw-r--r--src/or/router.c2
-rw-r--r--src/or/routerlist.c20
-rw-r--r--src/or/scheduler.c25
-rw-r--r--src/or/scheduler_kist.c8
-rw-r--r--src/or/tor_api_internal.h2
-rw-r--r--src/rust/tor_rust/include.am14
-rw-r--r--src/test/include.am1
-rw-r--r--src/test/test.c1
-rw-r--r--src/test/test.h1
-rw-r--r--src/test/test_config.c11
-rw-r--r--src/test/test_controller.c168
-rw-r--r--src/test/test_entrynodes.c148
-rw-r--r--src/test/test_hs.c15
-rw-r--r--src/test/test_hs_control.c199
-rwxr-xr-xsrc/test/test_rust.sh8
89 files changed, 3572 insertions, 542 deletions
diff --git a/.travis.yml b/.travis.yml
index 8cc210827a..d3918875dd 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -56,6 +56,7 @@ env:
- MAKEFLAGS="-j 2"
matrix:
- RUST_OPTIONS="--enable-rust --enable-cargo-online-mode"
+ - RUST_OPTIONS="--enable-rust" TOR_RUST_DEPENDENCIES=true
- RUST_OPTIONS=""
matrix:
@@ -87,6 +88,10 @@ install:
- if [[ "$RUST_OPTIONS" != "" ]]; then which cargo; fi
- if [[ "$RUST_OPTIONS" != "" ]]; then rustc --version; fi
- if [[ "$RUST_OPTIONS" != "" ]]; then cargo --version; fi
+ ## If we're testing rust builds in offline-mode, then set up our vendored dependencies
+ - if [[ "$RUST_OPTIONS" == "--enable-rust" ]]; then git submodule init ; fi
+ - if [[ "$RUST_OPTIONS" == "--enable-rust" ]]; then git submodule update; fi
+ - if [[ "$TOR_RUST_DEPENDENCIES" == "true" ]]; then export TOR_RUST_DEPENDENCIES=$PWD/src/ext/rust/crates; fi
script:
- ./autogen.sh
diff --git a/ChangeLog b/ChangeLog
index 3d6e9f5222..381cc60c42 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,576 @@
+Changes in version 0.3.2.6-alpha - 2017-12-01
+ This version of Tor is the latest in the 0.3.2 alpha series. It
+ includes fixes for several important security issues. All Tor users
+ should upgrade to this release, or to one of the other releases coming
+ out today.
+
+ o Major bugfixes (security):
+ - Fix a denial of service bug where an attacker could use a
+ malformed directory object to cause a Tor instance to pause while
+ OpenSSL would try to read a passphrase from the terminal. (Tor
+ instances run without a terminal, which is the case for most Tor
+ packages, are not impacted.) Fixes bug 24246; bugfix on every
+ version of Tor. Also tracked as TROVE-2017-011 and CVE-2017-8821.
+ Found by OSS-Fuzz as testcase 6360145429790720.
+ - Fix a denial of service issue where an attacker could crash a
+ directory authority using a malformed router descriptor. Fixes bug
+ 24245; bugfix on 0.2.9.4-alpha. Also tracked as TROVE-2017-010
+ and CVE-2017-8820.
+ - When checking for replays in the INTRODUCE1 cell data for a
+ (legacy) onion service, correctly detect replays in the RSA-
+ encrypted part of the cell. We were previously checking for
+ replays on the entire cell, but those can be circumvented due to
+ the malleability of Tor's legacy hybrid encryption. This fix helps
+ prevent a traffic confirmation attack. Fixes bug 24244; bugfix on
+ 0.2.4.1-alpha. This issue is also tracked as TROVE-2017-009
+ and CVE-2017-8819.
+
+ o Major bugfixes (security, onion service v2):
+ - Fix a use-after-free error that could crash v2 Tor onion services
+ when they failed to open circuits while expiring introduction
+ points. Fixes bug 24313; bugfix on 0.2.7.2-alpha. This issue is
+ also tracked as TROVE-2017-013 and CVE-2017-8823.
+
+ o Major bugfixes (security, relay):
+ - When running as a relay, make sure that we never build a path
+ through ourselves, even in the case where we have somehow lost the
+ version of our descriptor appearing in the consensus. Fixes part
+ of bug 21534; bugfix on 0.2.0.1-alpha. This issue is also tracked
+ as TROVE-2017-012 and CVE-2017-8822.
+ - When running as a relay, make sure that we never choose ourselves
+ as a guard. Fixes part of bug 21534; bugfix on 0.3.0.1-alpha. This
+ issue is also tracked as TROVE-2017-012 and CVE-2017-8822.
+
+ o Minor feature (relay statistics):
+ - Change relay bandwidth reporting stats interval from 4 hours to 24
+ hours in order to reduce the efficiency of guard discovery
+ attacks. Fixes ticket 23856.
+
+ o Minor features (directory authority):
+ - Add an IPv6 address for the "bastet" directory authority. Closes
+ ticket 24394.
+
+ o Minor bugfixes (client):
+ - By default, do not enable storage of client-side DNS values. These
+ values were unused by default previously, but they should not have
+ been cached at all. Fixes bug 24050; bugfix on 0.2.6.3-alpha.
+
+
+Changes in version 0.3.1.9 - 2017-12-01:
+ Tor 0.3.1.9 backports important security and stability fixes from the
+ 0.3.2 development series. All Tor users should upgrade to this
+ release, or to another of the releases coming out today.
+
+ o Major bugfixes (security, backport from 0.3.2.6-alpha):
+ - Fix a denial of service bug where an attacker could use a
+ malformed directory object to cause a Tor instance to pause while
+ OpenSSL would try to read a passphrase from the terminal. (Tor
+ instances run without a terminal, which is the case for most Tor
+ packages, are not impacted.) Fixes bug 24246; bugfix on every
+ version of Tor. Also tracked as TROVE-2017-011 and CVE-2017-8821.
+ Found by OSS-Fuzz as testcase 6360145429790720.
+ - Fix a denial of service issue where an attacker could crash a
+ directory authority using a malformed router descriptor. Fixes bug
+ 24245; bugfix on 0.2.9.4-alpha. Also tracked as TROVE-2017-010
+ and CVE-2017-8820.
+ - When checking for replays in the INTRODUCE1 cell data for a
+ (legacy) onion service, correctly detect replays in the RSA-
+ encrypted part of the cell. We were previously checking for
+ replays on the entire cell, but those can be circumvented due to
+ the malleability of Tor's legacy hybrid encryption. This fix helps
+ prevent a traffic confirmation attack. Fixes bug 24244; bugfix on
+ 0.2.4.1-alpha. This issue is also tracked as TROVE-2017-009
+ and CVE-2017-8819.
+
+ o Major bugfixes (security, onion service v2, backport from 0.3.2.6-alpha):
+ - Fix a use-after-free error that could crash v2 Tor onion services
+ when they failed to open circuits while expiring introduction
+ points. Fixes bug 24313; bugfix on 0.2.7.2-alpha. This issue is
+ also tracked as TROVE-2017-013 and CVE-2017-8823.
+
+ o Major bugfixes (security, relay, backport from 0.3.2.6-alpha):
+ - When running as a relay, make sure that we never build a path
+ through ourselves, even in the case where we have somehow lost the
+ version of our descriptor appearing in the consensus. Fixes part
+ of bug 21534; bugfix on 0.2.0.1-alpha. This issue is also tracked
+ as TROVE-2017-012 and CVE-2017-8822.
+ - When running as a relay, make sure that we never choose ourselves
+ as a guard. Fixes part of bug 21534; bugfix on 0.3.0.1-alpha. This
+ issue is also tracked as TROVE-2017-012 and CVE-2017-8822.
+
+ o Major bugfixes (exit relays, DNS, backport from 0.3.2.4-alpha):
+ - Fix an issue causing DNS to fail on high-bandwidth exit nodes,
+ making them nearly unusable. Fixes bugs 21394 and 18580; bugfix on
+ 0.1.2.2-alpha, which introduced eventdns. Thanks to Dhalgren for
+ identifying and finding a workaround to this bug and to Moritz,
+ Arthur Edelstein, and Roger for helping to track it down and
+ analyze it.
+
+ o Minor features (bridge):
+ - Bridges now include notice in their descriptors that they are
+ bridges, and notice of their distribution status, based on their
+ publication settings. Implements ticket 18329. For more fine-
+ grained control of how a bridge is distributed, upgrade to 0.3.2.x
+ or later.
+
+ o Minor features (directory authority, backport from 0.3.2.6-alpha):
+ - Add an IPv6 address for the "bastet" directory authority. Closes
+ ticket 24394.
+
+ o Minor features (geoip):
+ - Update geoip and geoip6 to the November 6 2017 Maxmind GeoLite2
+ Country database.
+
+ o Minor bugfix (relay address resolution, backport from 0.3.2.1-alpha):
+ - Avoid unnecessary calls to directory_fetches_from_authorities() on
+ relays, to prevent spurious address resolutions and descriptor
+ rebuilds. This is a mitigation for bug 21789. Fixes bug 23470;
+ bugfix on in 0.2.8.1-alpha.
+
+ o Minor bugfixes (compilation, backport from 0.3.2.1-alpha):
+ - Fix unused variable warnings in donna's Curve25519 SSE2 code.
+ Fixes bug 22895; bugfix on 0.2.7.2-alpha.
+
+ o Minor bugfixes (logging, relay shutdown, annoyance, backport from 0.3.2.2-alpha):
+ - When a circuit is marked for close, do not attempt to package any
+ cells for channels on that circuit. Previously, we would detect
+ this condition lower in the call stack, when we noticed that the
+ circuit had no attached channel, and log an annoying message.
+ Fixes bug 8185; bugfix on 0.2.5.4-alpha.
+
+ o Minor bugfixes (onion service, backport from 0.3.2.5-alpha):
+ - Rename the consensus parameter "hsdir-interval" to "hsdir_interval"
+ so it matches dir-spec.txt. Fixes bug 24262; bugfix
+ on 0.3.1.1-alpha.
+
+ o Minor bugfixes (relay, crash, backport from 0.3.2.4-alpha):
+ - Avoid a crash when transitioning from client mode to bridge mode.
+ Previously, we would launch the worker threads whenever our
+ "public server" mode changed, but not when our "server" mode
+ changed. Fixes bug 23693; bugfix on 0.2.6.3-alpha.
+
+
+Changes in version 0.3.0.13 - 2017-12-01
+ Tor 0.3.0.13 backports important security and stability bugfixes from
+ later Tor releases. All Tor users should upgrade to this release, or
+ to another of the releases coming out today.
+
+ Note: the Tor 0.3.0 series will no longer be supported after 26 Jan
+ 2018. If you need a release with long-term support, please stick with
+ the 0.2.9 series. Otherwise, please upgrade to 0.3.1 or later.
+
+ o Major bugfixes (security, backport from 0.3.2.6-alpha):
+ - Fix a denial of service bug where an attacker could use a
+ malformed directory object to cause a Tor instance to pause while
+ OpenSSL would try to read a passphrase from the terminal. (Tor
+ instances run without a terminal, which is the case for most Tor
+ packages, are not impacted.) Fixes bug 24246; bugfix on every
+ version of Tor. Also tracked as TROVE-2017-011 and CVE-2017-8821.
+ Found by OSS-Fuzz as testcase 6360145429790720.
+ - Fix a denial of service issue where an attacker could crash a
+ directory authority using a malformed router descriptor. Fixes bug
+ 24245; bugfix on 0.2.9.4-alpha. Also tracked as TROVE-2017-010
+ and CVE-2017-8820.
+ - When checking for replays in the INTRODUCE1 cell data for a
+ (legacy) onion service, correctly detect replays in the RSA-
+ encrypted part of the cell. We were previously checking for
+ replays on the entire cell, but those can be circumvented due to
+ the malleability of Tor's legacy hybrid encryption. This fix helps
+ prevent a traffic confirmation attack. Fixes bug 24244; bugfix on
+ 0.2.4.1-alpha. This issue is also tracked as TROVE-2017-009
+ and CVE-2017-8819.
+
+ o Major bugfixes (security, onion service v2, backport from 0.3.2.6-alpha):
+ - Fix a use-after-free error that could crash v2 Tor onion services
+ when they failed to open circuits while expiring introduction
+ points. Fixes bug 24313; bugfix on 0.2.7.2-alpha. This issue is
+ also tracked as TROVE-2017-013 and CVE-2017-8823.
+
+ o Major bugfixes (security, relay, backport from 0.3.2.6-alpha):
+ - When running as a relay, make sure that we never build a path
+ through ourselves, even in the case where we have somehow lost the
+ version of our descriptor appearing in the consensus. Fixes part
+ of bug 21534; bugfix on 0.2.0.1-alpha. This issue is also tracked
+ as TROVE-2017-012 and CVE-2017-8822.
+ - When running as a relay, make sure that we never choose ourselves
+ as a guard. Fixes part of bug 21534; bugfix on 0.3.0.1-alpha. This
+ issue is also tracked as TROVE-2017-012 and CVE-2017-8822.
+
+ o Major bugfixes (exit relays, DNS, backport from 0.3.2.4-alpha):
+ - Fix an issue causing DNS to fail on high-bandwidth exit nodes,
+ making them nearly unusable. Fixes bugs 21394 and 18580; bugfix on
+ 0.1.2.2-alpha, which introduced eventdns. Thanks to Dhalgren for
+ identifying and finding a workaround to this bug and to Moritz,
+ Arthur Edelstein, and Roger for helping to track it down and
+ analyze it.
+
+ o Minor features (security, windows, backport from 0.3.1.1-alpha):
+ - Enable a couple of pieces of Windows hardening: one
+ (HeapEnableTerminationOnCorruption) that has been on-by-default
+ since Windows 8, and unavailable before Windows 7; and one
+ (PROCESS_DEP_DISABLE_ATL_THUNK_EMULATION) which we believe doesn't
+ affect us, but shouldn't do any harm. Closes ticket 21953.
+
+ o Minor features (bridge, backport from 0.3.1.9):
+ - Bridges now include notice in their descriptors that they are
+ bridges, and notice of their distribution status, based on their
+ publication settings. Implements ticket 18329. For more fine-
+ grained control of how a bridge is distributed, upgrade to 0.3.2.x
+ or later.
+
+ o Minor features (directory authority, backport from 0.3.2.6-alpha):
+ - Add an IPv6 address for the "bastet" directory authority. Closes
+ ticket 24394.
+
+ o Minor features (geoip):
+ - Update geoip and geoip6 to the November 6 2017 Maxmind GeoLite2
+ Country database.
+
+ o Minor bugfix (relay address resolution, backport from 0.3.2.1-alpha):
+ - Avoid unnecessary calls to directory_fetches_from_authorities() on
+ relays, to prevent spurious address resolutions and descriptor
+ rebuilds. This is a mitigation for bug 21789. Fixes bug 23470;
+ bugfix on in 0.2.8.1-alpha.
+
+ o Minor bugfixes (compilation, backport from 0.3.2.1-alpha):
+ - Fix unused variable warnings in donna's Curve25519 SSE2 code.
+ Fixes bug 22895; bugfix on 0.2.7.2-alpha.
+
+ o Minor bugfixes (logging, relay shutdown, annoyance, backport from 0.3.2.2-alpha):
+ - When a circuit is marked for close, do not attempt to package any
+ cells for channels on that circuit. Previously, we would detect
+ this condition lower in the call stack, when we noticed that the
+ circuit had no attached channel, and log an annoying message.
+ Fixes bug 8185; bugfix on 0.2.5.4-alpha.
+
+ o Minor bugfixes (relay, crash, backport from 0.3.2.4-alpha):
+ - Avoid a crash when transitioning from client mode to bridge mode.
+ Previously, we would launch the worker threads whenever our
+ "public server" mode changed, but not when our "server" mode
+ changed. Fixes bug 23693; bugfix on 0.2.6.3-alpha.
+
+ o Minor bugfixes (testing, backport from 0.3.1.6-rc):
+ - Fix an undersized buffer in test-memwipe.c. Fixes bug 23291;
+ bugfix on 0.2.7.2-alpha. Found and patched by Ties Stuij.
+
+
+Changes in version 0.2.9.14 - 2017-12-01
+ Tor 0.3.0.13 backports important security and stability bugfixes from
+ later Tor releases. All Tor users should upgrade to this release, or
+ to another of the releases coming out today.
+
+ o Major bugfixes (exit relays, DNS, backport from 0.3.2.4-alpha):
+ - Fix an issue causing DNS to fail on high-bandwidth exit nodes,
+ making them nearly unusable. Fixes bugs 21394 and 18580; bugfix on
+ 0.1.2.2-alpha, which introduced eventdns. Thanks to Dhalgren for
+ identifying and finding a workaround to this bug and to Moritz,
+ Arthur Edelstein, and Roger for helping to track it down and
+ analyze it.
+
+ o Major bugfixes (security, backport from 0.3.2.6-alpha):
+ - Fix a denial of service bug where an attacker could use a
+ malformed directory object to cause a Tor instance to pause while
+ OpenSSL would try to read a passphrase from the terminal. (Tor
+ instances run without a terminal, which is the case for most Tor
+ packages, are not impacted.) Fixes bug 24246; bugfix on every
+ version of Tor. Also tracked as TROVE-2017-011 and CVE-2017-8821.
+ Found by OSS-Fuzz as testcase 6360145429790720.
+ - Fix a denial of service issue where an attacker could crash a
+ directory authority using a malformed router descriptor. Fixes bug
+ 24245; bugfix on 0.2.9.4-alpha. Also tracked as TROVE-2017-010
+ and CVE-2017-8820.
+ - When checking for replays in the INTRODUCE1 cell data for a
+ (legacy) onion service, correctly detect replays in the RSA-
+ encrypted part of the cell. We were previously checking for
+ replays on the entire cell, but those can be circumvented due to
+ the malleability of Tor's legacy hybrid encryption. This fix helps
+ prevent a traffic confirmation attack. Fixes bug 24244; bugfix on
+ 0.2.4.1-alpha. This issue is also tracked as TROVE-2017-009
+ and CVE-2017-8819.
+
+ o Major bugfixes (security, onion service v2, backport from 0.3.2.6-alpha):
+ - Fix a use-after-free error that could crash v2 Tor onion services
+ when they failed to open circuits while expiring introduction
+ points. Fixes bug 24313; bugfix on 0.2.7.2-alpha. This issue is
+ also tracked as TROVE-2017-013 and CVE-2017-8823.
+
+ o Major bugfixes (security, relay, backport from 0.3.2.6-alpha):
+ - When running as a relay, make sure that we never build a path
+ through ourselves, even in the case where we have somehow lost the
+ version of our descriptor appearing in the consensus. Fixes part
+ of bug 21534; bugfix on 0.2.0.1-alpha. This issue is also tracked
+ as TROVE-2017-012 and CVE-2017-8822.
+
+ o Minor features (bridge, backport from 0.3.1.9):
+ - Bridges now include notice in their descriptors that they are
+ bridges, and notice of their distribution status, based on their
+ publication settings. Implements ticket 18329. For more fine-
+ grained control of how a bridge is distributed, upgrade to 0.3.2.x
+ or later.
+
+ o Minor features (directory authority, backport from 0.3.2.6-alpha):
+ - Add an IPv6 address for the "bastet" directory authority. Closes
+ ticket 24394.
+
+ o Minor features (geoip):
+ - Update geoip and geoip6 to the November 6 2017 Maxmind GeoLite2
+ Country database.
+
+ o Minor features (security, windows, backport from 0.3.1.1-alpha):
+ - Enable a couple of pieces of Windows hardening: one
+ (HeapEnableTerminationOnCorruption) that has been on-by-default
+ since Windows 8, and unavailable before Windows 7; and one
+ (PROCESS_DEP_DISABLE_ATL_THUNK_EMULATION) which we believe doesn't
+ affect us, but shouldn't do any harm. Closes ticket 21953.
+
+ o Minor bugfix (relay address resolution, backport from 0.3.2.1-alpha):
+ - Avoid unnecessary calls to directory_fetches_from_authorities() on
+ relays, to prevent spurious address resolutions and descriptor
+ rebuilds. This is a mitigation for bug 21789. Fixes bug 23470;
+ bugfix on in 0.2.8.1-alpha.
+
+ o Minor bugfixes (compilation, backport from 0.3.2.1-alpha):
+ - Fix unused variable warnings in donna's Curve25519 SSE2 code.
+ Fixes bug 22895; bugfix on 0.2.7.2-alpha.
+
+ o Minor bugfixes (logging, relay shutdown, annoyance, backport from 0.3.2.2-alpha):
+ - When a circuit is marked for close, do not attempt to package any
+ cells for channels on that circuit. Previously, we would detect
+ this condition lower in the call stack, when we noticed that the
+ circuit had no attached channel, and log an annoying message.
+ Fixes bug 8185; bugfix on 0.2.5.4-alpha.
+
+ o Minor bugfixes (relay, crash, backport from 0.3.2.4-alpha):
+ - Avoid a crash when transitioning from client mode to bridge mode.
+ Previously, we would launch the worker threads whenever our
+ "public server" mode changed, but not when our "server" mode
+ changed. Fixes bug 23693; bugfix on 0.2.6.3-alpha.
+
+ o Minor bugfixes (testing, backport from 0.3.1.6-rc):
+ - Fix an undersized buffer in test-memwipe.c. Fixes bug 23291;
+ bugfix on 0.2.7.2-alpha. Found and patched by Ties Stuij.
+
+
+Changes in version 0.2.8.17 - 2017-12-01
+ Tor 0.2.8.17 backports important security and stability bugfixes from
+ later Tor releases. All Tor users should upgrade to this release, or
+ to another of the releases coming out today.
+
+ Note: the Tor 0.2.8 series will no longer be supported after 1 Jan
+ 2018. If you need a release with long-term support, please upgrade with
+ the 0.2.9 series. Otherwise, please upgrade to 0.3.1 or later.
+
+ o Major bugfixes (security, backport from 0.3.2.6-alpha):
+ - Fix a denial of service bug where an attacker could use a
+ malformed directory object to cause a Tor instance to pause while
+ OpenSSL would try to read a passphrase from the terminal. (Tor
+ instances run without a terminal, which is the case for most Tor
+ packages, are not impacted.) Fixes bug 24246; bugfix on every
+ version of Tor. Also tracked as TROVE-2017-011 and CVE-2017-8821.
+ Found by OSS-Fuzz as testcase 6360145429790720.
+ - When checking for replays in the INTRODUCE1 cell data for a
+ (legacy) onion service, correctly detect replays in the RSA-
+ encrypted part of the cell. We were previously checking for
+ replays on the entire cell, but those can be circumvented due to
+ the malleability of Tor's legacy hybrid encryption. This fix helps
+ prevent a traffic confirmation attack. Fixes bug 24244; bugfix on
+ 0.2.4.1-alpha. This issue is also tracked as TROVE-2017-009
+ and CVE-2017-8819.
+
+ o Major bugfixes (security, onion service v2, backport from 0.3.2.6-alpha):
+ - Fix a use-after-free error that could crash v2 Tor onion services
+ when they failed to open circuits while expiring introduction
+ points. Fixes bug 24313; bugfix on 0.2.7.2-alpha. This issue is
+ also tracked as TROVE-2017-013 and CVE-2017-8823.
+
+ o Major bugfixes (security, relay, backport from 0.3.2.6-alpha):
+ - When running as a relay, make sure that we never build a path through
+ ourselves, even in the case where we have somehow lost the version of
+ our descriptor appearing in the consensus. Fixes part of bug 21534;
+ bugfix on 0.2.0.1-alpha. This issue is also tracked as TROVE-2017-012
+ and CVE-2017-8822.
+
+ o Minor features (bridge, backport from 0.3.1.9):
+ - Bridges now include notice in their descriptors that they are
+ bridges, and notice of their distribution status, based on their
+ publication settings. Implements ticket 18329. For more fine-
+ grained control of how a bridge is distributed, upgrade to 0.3.2.x
+ or later.
+
+ o Minor features (directory authority, backport from 0.3.2.6-alpha):
+ - Add an IPv6 address for the "bastet" directory authority. Closes
+ ticket 24394.
+
+ o Minor features (geoip):
+ - Update geoip and geoip6 to the November 6 2017 Maxmind GeoLite2
+ Country database.
+
+ o Minor bugfixes (testing, backport from 0.3.1.6-rc):
+ - Fix an undersized buffer in test-memwipe.c. Fixes bug 23291;
+ bugfix on 0.2.7.2-alpha. Found and patched by Ties Stuij.
+
+
+Changes in version 0.2.5.16 - 2017-12-01
+ Tor 0.2.5.13 backports important security and stability bugfixes from
+ later Tor releases. All Tor users should upgrade to this release, or
+ to another of the releases coming out today.
+
+ Note: the Tor 0.2.5 series will no longer be supported after 1 May
+ 2018. If you need a release with long-term support, please upgrade to
+ the 0.2.9 series. Otherwise, please upgrade to 0.3.1 or later.
+
+ o Major bugfixes (security, backport from 0.3.2.6-alpha):
+ - Fix a denial of service bug where an attacker could use a
+ malformed directory object to cause a Tor instance to pause while
+ OpenSSL would try to read a passphrase from the terminal. (Tor
+ instances run without a terminal, which is the case for most Tor
+ packages, are not impacted.) Fixes bug 24246; bugfix on every
+ version of Tor. Also tracked as TROVE-2017-011 and CVE-2017-8821.
+ Found by OSS-Fuzz as testcase 6360145429790720.
+ - When checking for replays in the INTRODUCE1 cell data for a
+ (legacy) onion service, correctly detect replays in the RSA-
+ encrypted part of the cell. We were previously checking for
+ replays on the entire cell, but those can be circumvented due to
+ the malleability of Tor's legacy hybrid encryption. This fix helps
+ prevent a traffic confirmation attack. Fixes bug 24244; bugfix on
+ 0.2.4.1-alpha. This issue is also tracked as TROVE-2017-009
+ and CVE-2017-8819.
+
+ o Major bugfixes (security, relay, backport from 0.3.2.6-alpha):
+ - When running as a relay, make sure that we never build a path
+ through ourselves, even in the case where we have somehow lost the
+ version of our descriptor appearing in the consensus. Fixes part
+ of bug 21534; bugfix on 0.2.0.1-alpha. This issue is also tracked
+ as TROVE-2017-012 and CVE-2017-8822.
+
+ o Minor features (bridge, backport from 0.3.1.9):
+ - Bridges now include notice in their descriptors that they are
+ bridges, and notice of their distribution status, based on their
+ publication settings. Implements ticket 18329. For more fine-
+ grained control of how a bridge is distributed, upgrade to 0.3.2.x
+ or later.
+
+ o Minor features (geoip):
+ - Update geoip and geoip6 to the November 6 2017 Maxmind GeoLite2
+ Country database.
+
+
+Changes in version 0.3.2.5-alpha - 2017-11-22
+ Tor 0.3.2.5-alpha is the fifth alpha release in the 0.3.2.x series. It
+ fixes several stability and reliability bugs, including a fix for
+ intermittent bootstrapping failures that some people have been seeing
+ since the 0.3.0.x series.
+
+ Please test this alpha out -- many of these fixes will soon be
+ backported to stable Tor versions if no additional bugs are found
+ in them.
+
+ o Major bugfixes (bootstrapping):
+ - Fetch descriptors aggressively whenever we lack enough to build
+ circuits, regardless of how many descriptors we are missing.
+ Previously, we would delay launching the fetch when we had fewer
+ than 15 missing descriptors, even if some of those descriptors
+ were blocking circuits from building. Fixes bug 23985; bugfix on
+ 0.1.1.11-alpha. The effects of this bug became worse in
+ 0.3.0.3-alpha, when we began treating missing descriptors from our
+ primary guards as a reason to delay circuits.
+ - Don't try fetching microdescriptors from relays that have failed
+ to deliver them in the past. Fixes bug 23817; bugfix
+ on 0.3.0.1-alpha.
+
+ o Minor features (directory authority):
+ - Make the "Exit" flag assignment only depend on whether the exit
+ policy allows connections to ports 80 and 443. Previously relays
+ would get the Exit flag if they allowed connections to one of
+ these ports and also port 6667. Resolves ticket 23637.
+
+ o Minor features (geoip):
+ - Update geoip and geoip6 to the November 6 2017 Maxmind GeoLite2
+ Country database.
+
+ o Minor features (linux seccomp2 sandbox):
+ - Update the sandbox rules so that they should now work correctly
+ with Glibc 2.26. Closes ticket 24315.
+
+ o Minor features (logging):
+ - Downgrade a pair of log messages that could occur when an exit's
+ resolver gave us an unusual (but not forbidden) response. Closes
+ ticket 24097.
+ - Improve the message we log when re-enabling circuit build timeouts
+ after having received a consensus. Closes ticket 20963.
+
+ o Minor bugfixes (compilation):
+ - Fix a memory leak warning in one of the libevent-related
+ configuration tests that could occur when manually specifying
+ -fsanitize=address. Fixes bug 24279; bugfix on 0.3.0.2-alpha.
+ Found and patched by Alex Xu.
+ - When detecting OpenSSL on Windows from our configure script, make
+ sure to try linking with the ws2_32 library. Fixes bug 23783;
+ bugfix on 0.3.2.2-alpha.
+
+ o Minor bugfixes (control port, linux seccomp2 sandbox):
+ - Avoid a crash when attempting to use the seccomp2 sandbox together
+ with the OwningControllerProcess feature. Fixes bug 24198; bugfix
+ on 0.2.5.1-alpha.
+
+ o Minor bugfixes (control port, onion services):
+ - Report "FAILED" instead of "UPLOAD_FAILED" "FAILED" for the
+ HS_DESC event when a service is not able to upload a descriptor.
+ Fixes bug 24230; bugfix on 0.2.7.1-alpha.
+
+ o Minor bugfixes (directory cache):
+ - Recover better from empty or corrupt files in the consensus cache
+ directory. Fixes bug 24099; bugfix on 0.3.1.1-alpha.
+ - When a consensus diff calculation is only partially successful,
+ only record the successful parts as having succeeded. Partial
+ success can happen if (for example) one compression method fails
+ but the others succeed. Previously we misrecorded all the
+ calculations as having succeeded, which would later cause a
+ nonfatal assertion failure. Fixes bug 24086; bugfix
+ on 0.3.1.1-alpha.
+
+ o Minor bugfixes (logging):
+ - Only log once if we notice that KIST support is gone. Fixes bug
+ 24158; bugfix on 0.3.2.1-alpha.
+ - Suppress a log notice when relay descriptors arrive. We already
+ have a bootstrap progress for this so no need to log notice
+ everytime tor receives relay descriptors. Microdescriptors behave
+ the same. Fixes bug 23861; bugfix on 0.2.8.2-alpha.
+
+ o Minor bugfixes (network layer):
+ - When closing a connection via close_connection_immediately(), we
+ mark it as "not blocked on bandwidth", to prevent later calls from
+ trying to unblock it, and give it permission to read. This fixes a
+ backtrace warning that can happen on relays under various
+ circumstances. Fixes bug 24167; bugfix on 0.1.0.1-rc.
+
+ o Minor bugfixes (onion services):
+ - The introduction circuit was being timed out too quickly while
+ waiting for the rendezvous circuit to complete. Keep the intro
+ circuit around longer instead of timing out and reopening new ones
+ constantly. Fixes bug 23681; bugfix on 0.2.4.8-alpha.
+ - Rename the consensus parameter "hsdir-interval" to "hsdir_interval"
+ so it matches dir-spec.txt. Fixes bug 24262; bugfix
+ on 0.3.1.1-alpha.
+ - Silence a warning about failed v3 onion descriptor uploads that
+ can happen naturally under certain edge cases. Fixes part of bug
+ 23662; bugfix on 0.3.2.1-alpha.
+
+ o Minor bugfixes (tests):
+ - Fix a memory leak in one of the bridge-distribution test cases.
+ Fixes bug 24345; bugfix on 0.3.2.3-alpha.
+ - Fix a bug in our fuzzing mock replacement for crypto_pk_checksig(),
+ to correctly handle cases where a caller gives it an RSA key of
+ under 160 bits. (This is not actually a bug in Tor itself, but
+ rather in our fuzzing code.) Fixes bug 24247; bugfix on
+ 0.3.0.3-alpha. Found by OSS-Fuzz as issue 4177.
+
+ o Documentation:
+ - Add notes in man page regarding OS support for the various
+ scheduler types. Attempt to use less jargon in the scheduler
+ section. Closes ticket 24254.
+
+
Changes in version 0.3.2.4-alpha - 2017-11-08
Tor 0.3.2.4-alpha is the fourth alpha release in the 0.3.2.x series.
It fixes several stability and reliability bugs, especially including
diff --git a/ReleaseNotes b/ReleaseNotes
index 1bdf30b814..e11eebee9e 100644
--- a/ReleaseNotes
+++ b/ReleaseNotes
@@ -2,6 +2,405 @@ This document summarizes new features and bugfixes in each stable release
of Tor. If you want to see more detailed descriptions of the changes in
each development snapshot, see the ChangeLog file.
+Changes in version 0.3.1.9 - 2017-12-01:
+ Tor 0.3.1.9 backports important security and stability fixes from the
+ 0.3.2 development series. All Tor users should upgrade to this
+ release, or to another of the releases coming out today.
+
+ o Major bugfixes (security, backport from 0.3.2.6-alpha):
+ - Fix a denial of service bug where an attacker could use a
+ malformed directory object to cause a Tor instance to pause while
+ OpenSSL would try to read a passphrase from the terminal. (Tor
+ instances run without a terminal, which is the case for most Tor
+ packages, are not impacted.) Fixes bug 24246; bugfix on every
+ version of Tor. Also tracked as TROVE-2017-011 and CVE-2017-8821.
+ Found by OSS-Fuzz as testcase 6360145429790720.
+ - Fix a denial of service issue where an attacker could crash a
+ directory authority using a malformed router descriptor. Fixes bug
+ 24245; bugfix on 0.2.9.4-alpha. Also tracked as TROVE-2017-010
+ and CVE-2017-8820.
+ - When checking for replays in the INTRODUCE1 cell data for a
+ (legacy) onion service, correctly detect replays in the RSA-
+ encrypted part of the cell. We were previously checking for
+ replays on the entire cell, but those can be circumvented due to
+ the malleability of Tor's legacy hybrid encryption. This fix helps
+ prevent a traffic confirmation attack. Fixes bug 24244; bugfix on
+ 0.2.4.1-alpha. This issue is also tracked as TROVE-2017-009
+ and CVE-2017-8819.
+
+ o Major bugfixes (security, onion service v2, backport from 0.3.2.6-alpha):
+ - Fix a use-after-free error that could crash v2 Tor onion services
+ when they failed to open circuits while expiring introduction
+ points. Fixes bug 24313; bugfix on 0.2.7.2-alpha. This issue is
+ also tracked as TROVE-2017-013 and CVE-2017-8823.
+
+ o Major bugfixes (security, relay, backport from 0.3.2.6-alpha):
+ - When running as a relay, make sure that we never build a path
+ through ourselves, even in the case where we have somehow lost the
+ version of our descriptor appearing in the consensus. Fixes part
+ of bug 21534; bugfix on 0.2.0.1-alpha. This issue is also tracked
+ as TROVE-2017-012 and CVE-2017-8822.
+ - When running as a relay, make sure that we never choose ourselves
+ as a guard. Fixes part of bug 21534; bugfix on 0.3.0.1-alpha. This
+ issue is also tracked as TROVE-2017-012 and CVE-2017-8822.
+
+ o Major bugfixes (exit relays, DNS, backport from 0.3.2.4-alpha):
+ - Fix an issue causing DNS to fail on high-bandwidth exit nodes,
+ making them nearly unusable. Fixes bugs 21394 and 18580; bugfix on
+ 0.1.2.2-alpha, which introduced eventdns. Thanks to Dhalgren for
+ identifying and finding a workaround to this bug and to Moritz,
+ Arthur Edelstein, and Roger for helping to track it down and
+ analyze it.
+
+ o Minor features (bridge):
+ - Bridges now include notice in their descriptors that they are
+ bridges, and notice of their distribution status, based on their
+ publication settings. Implements ticket 18329. For more fine-
+ grained control of how a bridge is distributed, upgrade to 0.3.2.x
+ or later.
+
+ o Minor features (directory authority, backport from 0.3.2.6-alpha):
+ - Add an IPv6 address for the "bastet" directory authority. Closes
+ ticket 24394.
+
+ o Minor features (geoip):
+ - Update geoip and geoip6 to the November 6 2017 Maxmind GeoLite2
+ Country database.
+
+ o Minor bugfix (relay address resolution, backport from 0.3.2.1-alpha):
+ - Avoid unnecessary calls to directory_fetches_from_authorities() on
+ relays, to prevent spurious address resolutions and descriptor
+ rebuilds. This is a mitigation for bug 21789. Fixes bug 23470;
+ bugfix on in 0.2.8.1-alpha.
+
+ o Minor bugfixes (compilation, backport from 0.3.2.1-alpha):
+ - Fix unused variable warnings in donna's Curve25519 SSE2 code.
+ Fixes bug 22895; bugfix on 0.2.7.2-alpha.
+
+ o Minor bugfixes (logging, relay shutdown, annoyance, backport from 0.3.2.2-alpha):
+ - When a circuit is marked for close, do not attempt to package any
+ cells for channels on that circuit. Previously, we would detect
+ this condition lower in the call stack, when we noticed that the
+ circuit had no attached channel, and log an annoying message.
+ Fixes bug 8185; bugfix on 0.2.5.4-alpha.
+
+ o Minor bugfixes (onion service, backport from 0.3.2.5-alpha):
+ - Rename the consensus parameter "hsdir-interval" to "hsdir_interval"
+ so it matches dir-spec.txt. Fixes bug 24262; bugfix
+ on 0.3.1.1-alpha.
+
+ o Minor bugfixes (relay, crash, backport from 0.3.2.4-alpha):
+ - Avoid a crash when transitioning from client mode to bridge mode.
+ Previously, we would launch the worker threads whenever our
+ "public server" mode changed, but not when our "server" mode
+ changed. Fixes bug 23693; bugfix on 0.2.6.3-alpha.
+
+
+Changes in version 0.3.0.13 - 2017-12-01
+ Tor 0.3.0.13 backports important security and stability bugfixes from
+ later Tor releases. All Tor users should upgrade to this release, or
+ to another of the releases coming out today.
+
+ Note: the Tor 0.3.0 series will no longer be supported after 26 Jan
+ 2018. If you need a release with long-term support, please stick with
+ the 0.2.9 series. Otherwise, please upgrade to 0.3.1 or later.
+
+ o Major bugfixes (security, backport from 0.3.2.6-alpha):
+ - Fix a denial of service bug where an attacker could use a
+ malformed directory object to cause a Tor instance to pause while
+ OpenSSL would try to read a passphrase from the terminal. (Tor
+ instances run without a terminal, which is the case for most Tor
+ packages, are not impacted.) Fixes bug 24246; bugfix on every
+ version of Tor. Also tracked as TROVE-2017-011 and CVE-2017-8821.
+ Found by OSS-Fuzz as testcase 6360145429790720.
+ - Fix a denial of service issue where an attacker could crash a
+ directory authority using a malformed router descriptor. Fixes bug
+ 24245; bugfix on 0.2.9.4-alpha. Also tracked as TROVE-2017-010
+ and CVE-2017-8820.
+ - When checking for replays in the INTRODUCE1 cell data for a
+ (legacy) onion service, correctly detect replays in the RSA-
+ encrypted part of the cell. We were previously checking for
+ replays on the entire cell, but those can be circumvented due to
+ the malleability of Tor's legacy hybrid encryption. This fix helps
+ prevent a traffic confirmation attack. Fixes bug 24244; bugfix on
+ 0.2.4.1-alpha. This issue is also tracked as TROVE-2017-009
+ and CVE-2017-8819.
+
+ o Major bugfixes (security, onion service v2, backport from 0.3.2.6-alpha):
+ - Fix a use-after-free error that could crash v2 Tor onion services
+ when they failed to open circuits while expiring introduction
+ points. Fixes bug 24313; bugfix on 0.2.7.2-alpha. This issue is
+ also tracked as TROVE-2017-013 and CVE-2017-8823.
+
+ o Major bugfixes (security, relay, backport from 0.3.2.6-alpha):
+ - When running as a relay, make sure that we never build a path
+ through ourselves, even in the case where we have somehow lost the
+ version of our descriptor appearing in the consensus. Fixes part
+ of bug 21534; bugfix on 0.2.0.1-alpha. This issue is also tracked
+ as TROVE-2017-012 and CVE-2017-8822.
+ - When running as a relay, make sure that we never choose ourselves
+ as a guard. Fixes part of bug 21534; bugfix on 0.3.0.1-alpha. This
+ issue is also tracked as TROVE-2017-012 and CVE-2017-8822.
+
+ o Major bugfixes (exit relays, DNS, backport from 0.3.2.4-alpha):
+ - Fix an issue causing DNS to fail on high-bandwidth exit nodes,
+ making them nearly unusable. Fixes bugs 21394 and 18580; bugfix on
+ 0.1.2.2-alpha, which introduced eventdns. Thanks to Dhalgren for
+ identifying and finding a workaround to this bug and to Moritz,
+ Arthur Edelstein, and Roger for helping to track it down and
+ analyze it.
+
+ o Minor features (security, windows, backport from 0.3.1.1-alpha):
+ - Enable a couple of pieces of Windows hardening: one
+ (HeapEnableTerminationOnCorruption) that has been on-by-default
+ since Windows 8, and unavailable before Windows 7; and one
+ (PROCESS_DEP_DISABLE_ATL_THUNK_EMULATION) which we believe doesn't
+ affect us, but shouldn't do any harm. Closes ticket 21953.
+
+ o Minor features (bridge, backport from 0.3.1.9):
+ - Bridges now include notice in their descriptors that they are
+ bridges, and notice of their distribution status, based on their
+ publication settings. Implements ticket 18329. For more fine-
+ grained control of how a bridge is distributed, upgrade to 0.3.2.x
+ or later.
+
+ o Minor features (directory authority, backport from 0.3.2.6-alpha):
+ - Add an IPv6 address for the "bastet" directory authority. Closes
+ ticket 24394.
+
+ o Minor features (geoip):
+ - Update geoip and geoip6 to the November 6 2017 Maxmind GeoLite2
+ Country database.
+
+ o Minor bugfix (relay address resolution, backport from 0.3.2.1-alpha):
+ - Avoid unnecessary calls to directory_fetches_from_authorities() on
+ relays, to prevent spurious address resolutions and descriptor
+ rebuilds. This is a mitigation for bug 21789. Fixes bug 23470;
+ bugfix on in 0.2.8.1-alpha.
+
+ o Minor bugfixes (compilation, backport from 0.3.2.1-alpha):
+ - Fix unused variable warnings in donna's Curve25519 SSE2 code.
+ Fixes bug 22895; bugfix on 0.2.7.2-alpha.
+
+ o Minor bugfixes (logging, relay shutdown, annoyance, backport from 0.3.2.2-alpha):
+ - When a circuit is marked for close, do not attempt to package any
+ cells for channels on that circuit. Previously, we would detect
+ this condition lower in the call stack, when we noticed that the
+ circuit had no attached channel, and log an annoying message.
+ Fixes bug 8185; bugfix on 0.2.5.4-alpha.
+
+ o Minor bugfixes (relay, crash, backport from 0.3.2.4-alpha):
+ - Avoid a crash when transitioning from client mode to bridge mode.
+ Previously, we would launch the worker threads whenever our
+ "public server" mode changed, but not when our "server" mode
+ changed. Fixes bug 23693; bugfix on 0.2.6.3-alpha.
+
+ o Minor bugfixes (testing, backport from 0.3.1.6-rc):
+ - Fix an undersized buffer in test-memwipe.c. Fixes bug 23291;
+ bugfix on 0.2.7.2-alpha. Found and patched by Ties Stuij.
+
+
+Changes in version 0.2.9.14 - 2017-12-01
+ Tor 0.3.0.13 backports important security and stability bugfixes from
+ later Tor releases. All Tor users should upgrade to this release, or
+ to another of the releases coming out today.
+
+ o Major bugfixes (exit relays, DNS, backport from 0.3.2.4-alpha):
+ - Fix an issue causing DNS to fail on high-bandwidth exit nodes,
+ making them nearly unusable. Fixes bugs 21394 and 18580; bugfix on
+ 0.1.2.2-alpha, which introduced eventdns. Thanks to Dhalgren for
+ identifying and finding a workaround to this bug and to Moritz,
+ Arthur Edelstein, and Roger for helping to track it down and
+ analyze it.
+
+ o Major bugfixes (security, backport from 0.3.2.6-alpha):
+ - Fix a denial of service bug where an attacker could use a
+ malformed directory object to cause a Tor instance to pause while
+ OpenSSL would try to read a passphrase from the terminal. (Tor
+ instances run without a terminal, which is the case for most Tor
+ packages, are not impacted.) Fixes bug 24246; bugfix on every
+ version of Tor. Also tracked as TROVE-2017-011 and CVE-2017-8821.
+ Found by OSS-Fuzz as testcase 6360145429790720.
+ - Fix a denial of service issue where an attacker could crash a
+ directory authority using a malformed router descriptor. Fixes bug
+ 24245; bugfix on 0.2.9.4-alpha. Also tracked as TROVE-2017-010
+ and CVE-2017-8820.
+ - When checking for replays in the INTRODUCE1 cell data for a
+ (legacy) onion service, correctly detect replays in the RSA-
+ encrypted part of the cell. We were previously checking for
+ replays on the entire cell, but those can be circumvented due to
+ the malleability of Tor's legacy hybrid encryption. This fix helps
+ prevent a traffic confirmation attack. Fixes bug 24244; bugfix on
+ 0.2.4.1-alpha. This issue is also tracked as TROVE-2017-009
+ and CVE-2017-8819.
+
+ o Major bugfixes (security, onion service v2, backport from 0.3.2.6-alpha):
+ - Fix a use-after-free error that could crash v2 Tor onion services
+ when they failed to open circuits while expiring introduction
+ points. Fixes bug 24313; bugfix on 0.2.7.2-alpha. This issue is
+ also tracked as TROVE-2017-013 and CVE-2017-8823.
+
+ o Major bugfixes (security, relay, backport from 0.3.2.6-alpha):
+ - When running as a relay, make sure that we never build a path
+ through ourselves, even in the case where we have somehow lost the
+ version of our descriptor appearing in the consensus. Fixes part
+ of bug 21534; bugfix on 0.2.0.1-alpha. This issue is also tracked
+ as TROVE-2017-012 and CVE-2017-8822.
+
+ o Minor features (bridge, backport from 0.3.1.9):
+ - Bridges now include notice in their descriptors that they are
+ bridges, and notice of their distribution status, based on their
+ publication settings. Implements ticket 18329. For more fine-
+ grained control of how a bridge is distributed, upgrade to 0.3.2.x
+ or later.
+
+ o Minor features (directory authority, backport from 0.3.2.6-alpha):
+ - Add an IPv6 address for the "bastet" directory authority. Closes
+ ticket 24394.
+
+ o Minor features (geoip):
+ - Update geoip and geoip6 to the November 6 2017 Maxmind GeoLite2
+ Country database.
+
+ o Minor features (security, windows, backport from 0.3.1.1-alpha):
+ - Enable a couple of pieces of Windows hardening: one
+ (HeapEnableTerminationOnCorruption) that has been on-by-default
+ since Windows 8, and unavailable before Windows 7; and one
+ (PROCESS_DEP_DISABLE_ATL_THUNK_EMULATION) which we believe doesn't
+ affect us, but shouldn't do any harm. Closes ticket 21953.
+
+ o Minor bugfix (relay address resolution, backport from 0.3.2.1-alpha):
+ - Avoid unnecessary calls to directory_fetches_from_authorities() on
+ relays, to prevent spurious address resolutions and descriptor
+ rebuilds. This is a mitigation for bug 21789. Fixes bug 23470;
+ bugfix on in 0.2.8.1-alpha.
+
+ o Minor bugfixes (compilation, backport from 0.3.2.1-alpha):
+ - Fix unused variable warnings in donna's Curve25519 SSE2 code.
+ Fixes bug 22895; bugfix on 0.2.7.2-alpha.
+
+ o Minor bugfixes (logging, relay shutdown, annoyance, backport from 0.3.2.2-alpha):
+ - When a circuit is marked for close, do not attempt to package any
+ cells for channels on that circuit. Previously, we would detect
+ this condition lower in the call stack, when we noticed that the
+ circuit had no attached channel, and log an annoying message.
+ Fixes bug 8185; bugfix on 0.2.5.4-alpha.
+
+ o Minor bugfixes (relay, crash, backport from 0.3.2.4-alpha):
+ - Avoid a crash when transitioning from client mode to bridge mode.
+ Previously, we would launch the worker threads whenever our
+ "public server" mode changed, but not when our "server" mode
+ changed. Fixes bug 23693; bugfix on 0.2.6.3-alpha.
+
+ o Minor bugfixes (testing, backport from 0.3.1.6-rc):
+ - Fix an undersized buffer in test-memwipe.c. Fixes bug 23291;
+ bugfix on 0.2.7.2-alpha. Found and patched by Ties Stuij.
+
+
+Changes in version 0.2.8.17 - 2017-12-01
+ Tor 0.2.8.17 backports important security and stability bugfixes from
+ later Tor releases. All Tor users should upgrade to this release, or
+ to another of the releases coming out today.
+
+ Note: the Tor 0.2.8 series will no longer be supported after 1 Jan
+ 2018. If you need a release with long-term support, please upgrade with
+ the 0.2.9 series. Otherwise, please upgrade to 0.3.1 or later.
+
+ o Major bugfixes (security, backport from 0.3.2.6-alpha):
+ - Fix a denial of service bug where an attacker could use a
+ malformed directory object to cause a Tor instance to pause while
+ OpenSSL would try to read a passphrase from the terminal. (Tor
+ instances run without a terminal, which is the case for most Tor
+ packages, are not impacted.) Fixes bug 24246; bugfix on every
+ version of Tor. Also tracked as TROVE-2017-011 and CVE-2017-8821.
+ Found by OSS-Fuzz as testcase 6360145429790720.
+ - When checking for replays in the INTRODUCE1 cell data for a
+ (legacy) onion service, correctly detect replays in the RSA-
+ encrypted part of the cell. We were previously checking for
+ replays on the entire cell, but those can be circumvented due to
+ the malleability of Tor's legacy hybrid encryption. This fix helps
+ prevent a traffic confirmation attack. Fixes bug 24244; bugfix on
+ 0.2.4.1-alpha. This issue is also tracked as TROVE-2017-009
+ and CVE-2017-8819.
+
+ o Major bugfixes (security, onion service v2, backport from 0.3.2.6-alpha):
+ - Fix a use-after-free error that could crash v2 Tor onion services
+ when they failed to open circuits while expiring introduction
+ points. Fixes bug 24313; bugfix on 0.2.7.2-alpha. This issue is
+ also tracked as TROVE-2017-013 and CVE-2017-8823.
+
+ o Major bugfixes (security, relay, backport from 0.3.2.6-alpha):
+ - When running as a relay, make sure that we never build a path through
+ ourselves, even in the case where we have somehow lost the version of
+ our descriptor appearing in the consensus. Fixes part of bug 21534;
+ bugfix on 0.2.0.1-alpha. This issue is also tracked as TROVE-2017-012
+ and CVE-2017-8822.
+
+ o Minor features (bridge, backport from 0.3.1.9):
+ - Bridges now include notice in their descriptors that they are
+ bridges, and notice of their distribution status, based on their
+ publication settings. Implements ticket 18329. For more fine-
+ grained control of how a bridge is distributed, upgrade to 0.3.2.x
+ or later.
+
+ o Minor features (directory authority, backport from 0.3.2.6-alpha):
+ - Add an IPv6 address for the "bastet" directory authority. Closes
+ ticket 24394.
+
+ o Minor features (geoip):
+ - Update geoip and geoip6 to the November 6 2017 Maxmind GeoLite2
+ Country database.
+
+ o Minor bugfixes (testing, backport from 0.3.1.6-rc):
+ - Fix an undersized buffer in test-memwipe.c. Fixes bug 23291;
+ bugfix on 0.2.7.2-alpha. Found and patched by Ties Stuij.
+
+
+Changes in version 0.2.5.16 - 2017-12-01
+ Tor 0.2.5.13 backports important security and stability bugfixes from
+ later Tor releases. All Tor users should upgrade to this release, or
+ to another of the releases coming out today.
+
+ Note: the Tor 0.2.5 series will no longer be supported after 1 May
+ 2018. If you need a release with long-term support, please upgrade to
+ the 0.2.9 series. Otherwise, please upgrade to 0.3.1 or later.
+
+ o Major bugfixes (security, backport from 0.3.2.6-alpha):
+ - Fix a denial of service bug where an attacker could use a
+ malformed directory object to cause a Tor instance to pause while
+ OpenSSL would try to read a passphrase from the terminal. (Tor
+ instances run without a terminal, which is the case for most Tor
+ packages, are not impacted.) Fixes bug 24246; bugfix on every
+ version of Tor. Also tracked as TROVE-2017-011 and CVE-2017-8821.
+ Found by OSS-Fuzz as testcase 6360145429790720.
+ - When checking for replays in the INTRODUCE1 cell data for a
+ (legacy) onion service, correctly detect replays in the RSA-
+ encrypted part of the cell. We were previously checking for
+ replays on the entire cell, but those can be circumvented due to
+ the malleability of Tor's legacy hybrid encryption. This fix helps
+ prevent a traffic confirmation attack. Fixes bug 24244; bugfix on
+ 0.2.4.1-alpha. This issue is also tracked as TROVE-2017-009
+ and CVE-2017-8819.
+
+ o Major bugfixes (security, relay, backport from 0.3.2.6-alpha):
+ - When running as a relay, make sure that we never build a path
+ through ourselves, even in the case where we have somehow lost the
+ version of our descriptor appearing in the consensus. Fixes part
+ of bug 21534; bugfix on 0.2.0.1-alpha. This issue is also tracked
+ as TROVE-2017-012 and CVE-2017-8822.
+
+ o Minor features (bridge, backport from 0.3.1.9):
+ - Bridges now include notice in their descriptors that they are
+ bridges, and notice of their distribution status, based on their
+ publication settings. Implements ticket 18329. For more fine-
+ grained control of how a bridge is distributed, upgrade to 0.3.2.x
+ or later.
+
+ o Minor features (geoip):
+ - Update geoip and geoip6 to the November 6 2017 Maxmind GeoLite2
+ Country database.
+
+
Changes in version 0.2.5.15 - 2017-10-25
Tor 0.2.5.15 backports a collection of bugfixes from later Tor release
series. It also adds a new directory authority, Bastet.
diff --git a/changes/bug22907 b/changes/bug22907
new file mode 100644
index 0000000000..ff6ab8375b
--- /dev/null
+++ b/changes/bug22907
@@ -0,0 +1,3 @@
+ o Documentation:
+ - Add documentation on how to build tor with Rust dependencies without
+ requiring being online. Closes ticket 22907; bugfix on tor-0.3.0.3-alpha.
diff --git a/changes/bug23696 b/changes/bug23696
new file mode 100644
index 0000000000..c5d18583d4
--- /dev/null
+++ b/changes/bug23696
@@ -0,0 +1,5 @@
+ o Minor bugfix (KIST scheduler):
+ - Downgrade a warning to log info when the monotonic time diff is
+ negative. This can happen on platform not supporting monotonic time. The
+ scheduler recovers from this without any problem. Fixes bug 23696;
+ bugfix on 0.3.2.1-alpha.
diff --git a/changes/bug23826-23828 b/changes/bug23826-23828
new file mode 100644
index 0000000000..2b991e5c1b
--- /dev/null
+++ b/changes/bug23826-23828
@@ -0,0 +1,14 @@
+ o Major features (IPv6, directory documents):
+ - Add consensus method 27, which adds IPv6 ORPorts to the microdesc
+ consensus. This makes it easier for IPv6 clients to bootstrap and
+ choose reachable entry guards.
+ Implements 23826.
+ - Add consensus method 28, which removes IPv6 ORPorts from
+ microdescriptors. Now that there are IPv6 ORPorts in the microdesc
+ consensus, they are redundant in microdescs. This change is compatible
+ with tor clients on 0.2.8.x and later. (0.2.8.x introduced client IPv6
+ bootstrap and guard support.)
+ Implements 23828.
+ - Expand the documentation for AuthDirHasIPv6Connectivity when it is set
+ by different numbers of authorities.
+ Fixes 23870 on 0.2.4.1-alpha.
diff --git a/changes/bug23953 b/changes/bug23953
new file mode 100644
index 0000000000..10d41a00d2
--- /dev/null
+++ b/changes/bug23953
@@ -0,0 +1,3 @@
+ o Minor features (performance):
+ - Use stdatomic.h where available, rather than mutexes, to implement
+ atomic_counter_t. Closes ticket 23953.
diff --git a/changes/bug24119 b/changes/bug24119
new file mode 100644
index 0000000000..5014257602
--- /dev/null
+++ b/changes/bug24119
@@ -0,0 +1,4 @@
+ o Code simplification and refactoring:
+ - Rewrite channel_rsa_id_group_set_badness to reduce temporary memory
+ allocations with large numbers of OR connections (e.g. relays). Closes
+ ticket 24119.
diff --git a/changes/bug24230 b/changes/bug24230
deleted file mode 100644
index b08c4cde24..0000000000
--- a/changes/bug24230
+++ /dev/null
@@ -1,4 +0,0 @@
- o Minor bugfixes (control port, hidden service):
- - Control port was reporting the action "UPLOAD_FAILED" instead of
- "FAILED" for the HS_DESC event when a service was not able to upload a
- descriptor. Fixes bug 24230; bugfix on 0.2.7.1-alpha.
diff --git a/changes/bug24262 b/changes/bug24262
deleted file mode 100644
index eee69512e4..0000000000
--- a/changes/bug24262
+++ /dev/null
@@ -1,3 +0,0 @@
- o Minor bugfixes (hidden service):
- - Fix the consensus parameter "hsdir-interval" to "hsdir_interval" so it
- matches the dir-spec.txt. Fixes bug 24262; bugfix on 0.3.1.1-alpha.
diff --git a/changes/bug24318 b/changes/bug24318
new file mode 100644
index 0000000000..c92f7209f1
--- /dev/null
+++ b/changes/bug24318
@@ -0,0 +1,3 @@
+ o Documentation:
+ - Clarify the behavior of RelayBandwidth{Rate,Burst} with client traffic.
+ Closes ticket 24318.
diff --git a/changes/bug24480 b/changes/bug24480
new file mode 100644
index 0000000000..94e5b91a0c
--- /dev/null
+++ b/changes/bug24480
@@ -0,0 +1,3 @@
+ o Minor bugfixes (compilation):
+ - Fix a signed/unsigned comparison warning introduced by our
+ fix to TROVE-2017-009. Fixes bug 24480; bugfix on 0.2.5.16.
diff --git a/changes/cargo-build-problem b/changes/cargo-build-problem
new file mode 100644
index 0000000000..6691b0efca
--- /dev/null
+++ b/changes/cargo-build-problem
@@ -0,0 +1,3 @@
+ o Minor bugfixes (compilation, rust):
+ - Build correctly when building from outside Tor's source tree with the
+ TOR_RUST_DEPENDENCIES option set. Fixes bug 22768; bugfix on 0.3.1.7.
diff --git a/changes/ticket20020 b/changes/ticket20020
new file mode 100644
index 0000000000..737fb95980
--- /dev/null
+++ b/changes/ticket20020
@@ -0,0 +1,4 @@
+ o Minor features (logging):
+ - Improve a warning message that happens when we fail to re-parse
+ an old router because of an expired certificate. Closes ticket
+ 20020.
diff --git a/changes/ticket20699 b/changes/ticket20699
new file mode 100644
index 0000000000..a93236ba40
--- /dev/null
+++ b/changes/ticket20699
@@ -0,0 +1,14 @@
+ o Major features (hidden service v3, control port):
+ - Control port now supports command and events for hidden service v3. See
+ proposal 284 for more information on what has been done exactly. Only
+ the HSFETCH command hasn't been implemented at this stage because of a
+ lack of use case with v3.
+
+ It is now possible to create ephemeral v3 services using the ADD_ONION
+ command. Here is a summary of the events and commands that have been
+ modified to support v3:
+
+ Events: HS_DESC, HS_DESC_CONTENT, CIRC and CIRC_MINOR The
+ Commands: GETINFO, HSPOST, ADD_ONION and DEL_ONION.
+
+ This closes ticket 20699.
diff --git a/changes/ticket23760 b/changes/ticket23760
new file mode 100644
index 0000000000..9213b14627
--- /dev/null
+++ b/changes/ticket23760
@@ -0,0 +1,4 @@
+ o Code simplification and refactoring:
+ - We make extend_info_from_node() use node_get_curve25519_onion_key()
+ introduced in ticket 23577 to access the curve25519 public keys rather
+ than accessing it directly. Closes ticket 23760. Patch by Neel Chauhan.
diff --git a/changes/ticket24363 b/changes/ticket24363
new file mode 100644
index 0000000000..6f90fc066e
--- /dev/null
+++ b/changes/ticket24363
@@ -0,0 +1,2 @@
+ o Code simplification and refactoring:
+ - Remove /usr/athena from search path in configure.ac. Closes ticket 24363.
diff --git a/changes/ticket24467 b/changes/ticket24467
new file mode 100644
index 0000000000..1b1c223f5f
--- /dev/null
+++ b/changes/ticket24467
@@ -0,0 +1,3 @@
+ o Code simplification and refactoring:
+ - Switch -Wnormalized=id to -Wnormalized=nfkc in configure.ac to avoid
+ source code identifier confusion. Closes ticket 24467.
diff --git a/changes/ticket24500 b/changes/ticket24500
new file mode 100644
index 0000000000..b49b7a5551
--- /dev/null
+++ b/changes/ticket24500
@@ -0,0 +1,3 @@
+ o Minor features (logging):
+ - Provide better warnings when the getrandom() syscall fails.
+ Closes ticket 24500.
diff --git a/changes/ticket24518 b/changes/ticket24518
new file mode 100644
index 0000000000..28d40a3f26
--- /dev/null
+++ b/changes/ticket24518
@@ -0,0 +1,4 @@
+ o Minor bugfixes (build, rust):
+ - Don't pass the --quiet option to cargo: it seems to suppress some
+ errors, which is not what we want to do when building.
+ Fixes bug 24518; bugfix on 0.3.1.7.
diff --git a/configure.ac b/configure.ac
index 998bb914b3..0b3e1dda26 100644
--- a/configure.ac
+++ b/configure.ac
@@ -498,6 +498,7 @@ AC_CHECK_FUNCS(
getrlimit \
gettimeofday \
gmtime_r \
+ gnu_get_libc_version \
htonll \
inet_aton \
ioctl \
@@ -625,7 +626,7 @@ struct event_base *event_base_new(void);],
#ifdef _WIN32
{WSADATA d; WSAStartup(0x101,&d); }
#endif
-event_base_new();
+event_base_free(event_base_new());
], [--with-libevent-dir], [/opt/libevent])
dnl Determine the incantation needed to link libevent.
@@ -724,11 +725,11 @@ AC_ARG_WITH(ssl-dir,
])
AC_MSG_NOTICE([Now, we'll look for OpenSSL >= 1.0.1])
-TOR_SEARCH_LIBRARY(openssl, $tryssldir, [-lssl -lcrypto $TOR_LIB_GDI],
+TOR_SEARCH_LIBRARY(openssl, $tryssldir, [-lssl -lcrypto $TOR_LIB_GDI $TOR_LIB_WS32],
[#include <openssl/ssl.h>],
[struct ssl_method_st; const struct ssl_method_st *TLSv1_1_method(void);],
[TLSv1_1_method();], [],
- [/usr/local/opt/openssl /usr/local/openssl /usr/lib/openssl /usr/local/ssl /usr/lib/ssl /usr/local /usr/athena /opt/openssl])
+ [/usr/local/opt/openssl /usr/local/openssl /usr/lib/openssl /usr/local/ssl /usr/lib/ssl /usr/local /opt/openssl])
dnl XXXX check for OPENSSL_VERSION_NUMBER == SSLeay()
@@ -1216,6 +1217,7 @@ AC_CHECK_HEADERS([assert.h \
arpa/inet.h \
crt_externs.h \
execinfo.h \
+ gnu/libc-version.h \
grp.h \
ifaddrs.h \
inttypes.h \
@@ -1231,6 +1233,7 @@ AC_CHECK_HEADERS([assert.h \
pwd.h \
readpassphrase.h \
stdint.h \
+ stdatomic.h \
sys/eventfd.h \
sys/file.h \
sys/ioctl.h \
@@ -2014,7 +2017,7 @@ if test "x$enable_gcc_warnings_advisory" != "xno"; then
-Wnon-literal-null-conversion
-Wnon-pod-varargs
-Wnonportable-cfstrings
- -Wnormalized=id
+ -Wnormalized=nfkc
-Wnull-arithmetic
-Wnull-character
-Wnull-conversion
diff --git a/doc/HACKING/GettingStartedRust.md b/doc/HACKING/GettingStartedRust.md
index 181535122c..3d00388314 100644
--- a/doc/HACKING/GettingStartedRust.md
+++ b/doc/HACKING/GettingStartedRust.md
@@ -60,30 +60,28 @@ or specifying a local directory.
**Using a local dependency cache**
-**NOTE**: local dependency caches which were not *originally* created via
- `--enable-cargo-online-mode` are broken. See https://bugs.torproject.org/22907
+You'll need the following Rust dependencies (as of this writing):
-To specify a local directory:
+ libc==0.2.22
- RUST_DEPENDENCIES='path_to_dependencies_directory' ./configure --enable-rust
+We vendor our Rust dependencies in a separate repo using
+[cargo-vendor](https://github.com/alexcrichton/cargo-vendor). To use them, do:
-(Note that RUST_DEPENDENCIES must be the full path to the directory; it cannot
-be relative.)
+ git submodule init
+ git submodule update
-You'll need the following Rust dependencies (as of this writing):
+To specify the local directory containing the dependencies, (assuming you are in
+the top level of the repository) configure tor with:
- libc==0.2.22
+ TOR_RUST_DEPENDENCIES='path_to_dependencies_directory' ./configure --enable-rust
+
+(Note that RUST_DEPENDENCIES must be the full path to the directory; it cannot
+be relative.)
-To get them, do:
+Assuming you used the above `git submodule` commands and you're in the topmost
+directory of the repository, this would be:
- mkdir path_to_dependencies_directory
- cd path_to_dependencies_directory
- git clone https://github.com/rust-lang/libc
- cd libc
- git checkout 0.2.22
- cargo package
- cd ..
- ln -s libc/target/package/libc-0.2.22 libc-0.2.22
+ TOR_RUST_DEPENDENCIES=`pwd`/src/ext/rust/crates ./configure --enable-rust
Identifying which modules to rewrite
diff --git a/doc/HACKING/android/Simpleperf.md b/doc/HACKING/android/Simpleperf.md
new file mode 100644
index 0000000000..c12558aed4
--- /dev/null
+++ b/doc/HACKING/android/Simpleperf.md
@@ -0,0 +1,98 @@
+# Using `simpleperf` to collect CPU profiling on Android
+
+This document describes how you can use Android's `simpleperf`
+command-line tool to get CPU profiling information from Tor via the
+Orbot application. The tool is particularly useful for Tor development
+because it is able to profile native applications on the platform
+whereas a lot of the normal tooling for the Android platform is only
+able to collect information from Java-based applications.
+
+## Prerequisites
+
+Before using `simpleperf` there is a couple of steps that must be
+followed. You should make sure you have both a recent installation of
+the Android Software Development Kit (SDK) and Native Development Kit
+(NDK) installed. These can be found on the Android Developers website.
+
+1. Follow the build instructions from the `BUILD` file in the Orbot
+ repository and build an Orbot APK (Android Package) file with
+ debugging enabled. Make sure that when you build the native content of
+ the Orbot application that you run the `make -C external` command with
+ an additional `DEBUG=1` as paramter to ensure that the Orbot build
+ process does not strip the debug symbols from the Tor binary.
+
+2. (Optional) Uninstall and clean-up your old Orbot installation that
+ is most likely downloaded from Google's Play Store or via fdroid:
+
+ $ adb shell pm clear org.torproject.android
+ $ adb uninstall org.torproject.android
+
+3. Install the Android Package you generated in step 1:
+
+ $ 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.
+
+## Profiling using `simpleperf`
+
+The `simpleperf` tool can be found in the `simpleperf/` directory in
+the directory where you installed the Android NDK to. In this
+directory there is a set of Python files that will help you deploy the
+tool to a device and collect the measurement data such that you can
+analyze the results on your computer rather than on your phone.
+
+1. Change directory to the location of the `simpleperf` directory.
+2. Open the `app_profiler.config` file and change
+ `app_package_name` to `org.torproject.android`, `apk_file_path` to
+ the path of your Orbot Android Package (APK file).
+3. Optionally change the duration parameter in the `record_options`
+ variable in `app_profiler.config` to the duration which you would like
+ to collect samples in. The value is specified in seconds.
+4. Run the app profiler using `python app_profiler.py`. This helper
+ script will push the `simpleperf` tool to your device, start the
+ profiler, and once it has completed copy the generated `perf.data`
+ file over to your computer with the results.
+
+### Analyzing the results
+
+You can inspect your resulting `perf.data` file via a simple GUI
+program `python report.py` or via the command-line tool `simpleperf
+report`. I've found the GUI tool to be easier to navigate around with
+than the command-line tool.
+
+The `-g` option can be passed to the command line `simpleperf report`
+tool allows you to see the call graph of functions and how much time
+was spend on the call.
+
+## Tips & Tricks
+
+- When you have installed Orbot the first time, you will notice that
+ if you get a shell on the Android device that there is no Tor binary
+ available. This is because Orbot unpacks the Tor binary first time it
+ is executed and places it under the `app_bin/` directory on the
+ device.
+
+ To access binaries, `torrc` files, and other useful information on
+ the device do the following:
+
+ $ 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/`
+ directory.
+
+- You can enable logging in Tor via the syslog (or android) log
+ mechanism with:
+
+ $ 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
+
+ $ adb logcat
+
diff --git a/doc/tor.1.txt b/doc/tor.1.txt
index 17bdaeb0df..1814b8292a 100644
--- a/doc/tor.1.txt
+++ b/doc/tor.1.txt
@@ -231,12 +231,15 @@ GENERAL OPTIONS
usage for \_relayed traffic_ on this node to the specified number of bytes
per second, and the average outgoing bandwidth usage to that same value.
Relayed traffic currently is calculated to include answers to directory
- requests, but that may change in future versions. (Default: 0)
+ requests, but that may change in future versions. They do not include directory
+ fetches by the relay (from authority or other relays), because that is considered
+ "client" activity. (Default: 0)
[[RelayBandwidthBurst]] **RelayBandwidthBurst** __N__ **bytes**|**KBytes**|**MBytes**|**GBytes**|**TBytes**|**KBits**|**MBits**|**GBits**|**TBits**::
If not 0, limit the maximum token bucket size (also known as the burst) for
\_relayed traffic_ to the given number of bytes in each direction.
- (Default: 0)
+ They do not include directory fetches by the relay (from authority
+ or other relays), because that is considered "client" activity. (Default: 0)
[[PerConnBWRate]] **PerConnBWRate** __N__ **bytes**|**KBytes**|**MBytes**|**GBytes**|**TBytes**|**KBits**|**MBits**|**GBits**|**TBits**::
If set, do separate rate limiting for each connection from a non-relay.
@@ -801,27 +804,35 @@ GENERAL OPTIONS
restarting Tor. (Default: 0)
[[Schedulers]] **Schedulers** **KIST**|**KISTLite**|**Vanilla**::
- Specify the scheduler type that tor should use to handle outbound data on
- channels. This is an ordered list by priority which means that the first
- value will be tried first and if unavailable, the second one is tried and
- so on. It is possible to change thse values at runtime.
+ Specify the scheduler type that tor should use. The scheduler is
+ responsible for moving data around within a Tor process. This is an ordered
+ list by priority which means that the first value will be tried first and if
+ unavailable, the second one is tried and so on. It is possible to change
+ these values at runtime. This option mostly effects relays, and most
+ operators should leave it set to its default value.
(Default: KIST,KISTLite,Vanilla)
+
The possible scheduler types are:
+
- **KIST**: Kernel Informed Socket Transport. Tor will use the kernel tcp
- information stack per-socket to make an informed decision on if it should
- send or not the data. (Only available on Linux)
+ **KIST**: Kernel-Informed Socket Transport. Tor will use TCP information
+ from the kernel to make informed decisions regarding how much data to send
+ and when to send it. KIST also handles traffic in batches (see
+ KISTSchedRunInterval) in order to improve traffic prioritization decisions.
+ As implemented, KIST will only work on Linux kernel version 2.6.39 or
+ higher.
+
- **KISTLite**: Same as KIST but without kernel support which means that tor
- will use all the same mecanics as KIST but without the TCP information the
- kernel can provide.
+ **KISTLite**: Same as KIST but without kernel support. Tor will use all
+ the same mechanics as with KIST, including the batching, but its decisions
+ regarding how much data to send will not be as good. KISTLite will work on
+ all kernels and operating systems, and the majority of the benefits of KIST
+ are still realized with KISTLite.
+
- **Vanilla**: The scheduler that tor has always used that is do as much as
- possible or AMAP.
+ **Vanilla**: The scheduler that Tor used before KIST was implemented. It
+ sends as much data as possible, as soon as possible. Vanilla will work on
+ all kernels and operating systems.
[[KISTSchedRunInterval]] **KISTSchedRunInterval** __NUM__ **msec**::
- If KIST or KISTLite is used in Schedulers option, this control at which
+ If KIST or KISTLite is used in the Schedulers option, this controls at which
interval the scheduler tick is. If the value is 0 msec, the value is taken
from the consensus if possible else it will fallback to the default 10
msec. Maximum possible value is 100 msec. (Default: 0 msec)
@@ -2483,9 +2494,29 @@ on the public Tor network.
[[AuthDirHasIPv6Connectivity]] **AuthDirHasIPv6Connectivity** **0**|**1**::
Authoritative directories only. When set to 0, OR ports with an
- IPv6 address are being accepted without reachability testing.
- When set to 1, IPv6 OR ports are being tested just like IPv4 OR
- ports. (Default: 0)
+ IPv6 address are not included in the authority's votes. When set to 1,
+ IPv6 OR ports are tested for reachability like IPv4 OR ports. If the
+ reachability test succeeds, the authority votes for the IPv6 ORPort, and
+ votes Running for the relay. If the reachability test fails, the authority
+ does not vote for the IPv6 ORPort, and does not vote Running (Default: 0) +
++
+ The content of the consensus depends on the number of voting authorities
+ that set AuthDirHasIPv6Connectivity:
+
+ If no authorities set AuthDirHasIPv6Connectivity 1, there will be no
+ IPv6 ORPorts in the consensus.
+
+ If a minority of authorities set AuthDirHasIPv6Connectivity 1,
+ unreachable IPv6 ORPorts will be removed from the consensus. But the
+ majority of IPv4-only authorities will still vote the relay as Running.
+ Reachable IPv6 ORPort lines will be included in the consensus
+
+ If a majority of voting authorities set AuthDirHasIPv6Connectivity 1,
+ relays with unreachable IPv6 ORPorts will not be listed as Running.
+ Reachable IPv6 ORPort lines will be included in the consensus
+ (To ensure that any valid majority will vote relays with unreachable
+ IPv6 ORPorts not Running, 75% of authorities must set
+ AuthDirHasIPv6Connectivity 1.)
[[MinMeasuredBWsForAuthToIgnoreAdvertised]] **MinMeasuredBWsForAuthToIgnoreAdvertised** __N__::
A total value, in abstract bandwidth units, describing how much
diff --git a/src/common/compat_threads.c b/src/common/compat_threads.c
index 208d3138d9..6adcaab956 100644
--- a/src/common/compat_threads.c
+++ b/src/common/compat_threads.c
@@ -352,12 +352,7 @@ alert_sockets_close(alert_sockets_t *socks)
socks->read_fd = socks->write_fd = -1;
}
-/*
- * XXXX We might be smart to move to compiler intrinsics or real atomic
- * XXXX operations at some point. But not yet.
- *
- */
-
+#ifndef HAVE_STDATOMIC_H
/** Initialize a new atomic counter with the value 0 */
void
atomic_counter_init(atomic_counter_t *counter)
@@ -397,4 +392,16 @@ atomic_counter_get(atomic_counter_t *counter)
tor_mutex_release(&counter->mutex);
return val;
}
+/** Replace the value of an atomic counter; return the old one. */
+size_t
+atomic_counter_exchange(atomic_counter_t *counter, size_t newval)
+{
+ size_t oldval;
+ tor_mutex_acquire(&counter->mutex);
+ oldval = counter->val;
+ counter->val = newval;
+ tor_mutex_release(&counter->mutex);
+ return oldval;
+}
+#endif /* !defined(HAVE_STDATOMIC_H) */
diff --git a/src/common/compat_threads.h b/src/common/compat_threads.h
index 42f14eab2a..ce86b15e9d 100644
--- a/src/common/compat_threads.h
+++ b/src/common/compat_threads.h
@@ -14,6 +14,10 @@
#include <pthread.h>
#endif
+#ifdef HAVE_STDATOMIC_H
+#include <stdatomic.h>
+#endif
+
#if defined(_WIN32)
#define USE_WIN32_THREADS
#elif defined(HAVE_PTHREAD_H) && defined(HAVE_PTHREAD_CREATE)
@@ -150,16 +154,68 @@ void tor_threadlocal_set(tor_threadlocal_t *threadlocal, void *value);
/**
* Atomic counter type; holds a size_t value.
*/
+#ifdef HAVE_STDATOMIC_H
+typedef struct atomic_counter_t {
+ atomic_size_t val;
+} atomic_counter_t;
+#define ATOMIC_LINKAGE static
+#else /* !(defined(HAVE_STDATOMIC_H)) */
typedef struct atomic_counter_t {
tor_mutex_t mutex;
size_t val;
} atomic_counter_t;
-
-void atomic_counter_init(atomic_counter_t *counter);
-void atomic_counter_destroy(atomic_counter_t *counter);
-void atomic_counter_add(atomic_counter_t *counter, size_t add);
-void atomic_counter_sub(atomic_counter_t *counter, size_t sub);
-size_t atomic_counter_get(atomic_counter_t *counter);
+#define ATOMIC_LINKAGE
+#endif /* defined(HAVE_STDATOMIC_H) */
+
+ATOMIC_LINKAGE void atomic_counter_init(atomic_counter_t *counter);
+ATOMIC_LINKAGE void atomic_counter_destroy(atomic_counter_t *counter);
+ATOMIC_LINKAGE void atomic_counter_add(atomic_counter_t *counter, size_t add);
+ATOMIC_LINKAGE void atomic_counter_sub(atomic_counter_t *counter, size_t sub);
+ATOMIC_LINKAGE size_t atomic_counter_get(atomic_counter_t *counter);
+ATOMIC_LINKAGE size_t atomic_counter_exchange(atomic_counter_t *counter,
+ size_t newval);
+#undef ATOMIC_LINKAGE
+
+#ifdef HAVE_STDATOMIC_H
+/** Initialize a new atomic counter with the value 0 */
+static inline void
+atomic_counter_init(atomic_counter_t *counter)
+{
+ atomic_init(&counter->val, 0);
+}
+/** Clean up all resources held by an atomic counter. */
+static inline void
+atomic_counter_destroy(atomic_counter_t *counter)
+{
+ (void)counter;
+}
+/** Add a value to an atomic counter. */
+static inline void
+atomic_counter_add(atomic_counter_t *counter, size_t add)
+{
+ (void) atomic_fetch_add(&counter->val, add);
+}
+/** Subtract a value from an atomic counter. */
+static inline void
+atomic_counter_sub(atomic_counter_t *counter, size_t sub)
+{
+ (void) atomic_fetch_sub(&counter->val, sub);
+}
+/** Return the current value of an atomic counter */
+static inline size_t
+atomic_counter_get(atomic_counter_t *counter)
+{
+ return atomic_load(&counter->val);
+}
+/** Replace the value of an atomic counter; return the old one. */
+static inline size_t
+atomic_counter_exchange(atomic_counter_t *counter, size_t newval)
+{
+ return atomic_exchange(&counter->val, newval);
+}
+
+#else /* !(defined(HAVE_STDATOMIC_H)) */
+#endif /* defined(HAVE_STDATOMIC_H) */
#endif /* !defined(TOR_COMPAT_THREADS_H) */
diff --git a/src/common/crypto.c b/src/common/crypto.c
index 6fe3c661c8..380f038f42 100644
--- a/src/common/crypto.c
+++ b/src/common/crypto.c
@@ -645,11 +645,21 @@ crypto_pk_generate_key_with_bits,(crypto_pk_t *env, int bits))
return 0;
}
+/** A PEM callback that always reports a failure to get a password */
+static int
+pem_no_password_cb(char *buf, int size, int rwflag, void *u)
+{
+ (void)buf;
+ (void)size;
+ (void)rwflag;
+ (void)u;
+ return 0;
+}
+
/** Read a PEM-encoded private key from the <b>len</b>-byte string <b>s</b>
* into <b>env</b>. Return 0 on success, -1 on failure. If len is -1,
* the string is nul-terminated.
*/
-/* Used here, and used for testing. */
int
crypto_pk_read_private_key_from_string(crypto_pk_t *env,
const char *s, ssize_t len)
@@ -668,7 +678,7 @@ crypto_pk_read_private_key_from_string(crypto_pk_t *env,
if (env->key)
RSA_free(env->key);
- env->key = PEM_read_bio_RSAPrivateKey(b,NULL,NULL,NULL);
+ env->key = PEM_read_bio_RSAPrivateKey(b,NULL,pem_no_password_cb,NULL);
BIO_free(b);
@@ -800,7 +810,7 @@ crypto_pk_read_public_key_from_string(crypto_pk_t *env, const char *src,
if (env->key)
RSA_free(env->key);
- env->key = PEM_read_bio_RSAPublicKey(b, NULL, NULL, NULL);
+ env->key = PEM_read_bio_RSAPublicKey(b, NULL, pem_no_password_cb, NULL);
BIO_free(b);
if (!env->key) {
crypto_log_errors(LOG_WARN, "reading public key from string");
@@ -2865,8 +2875,17 @@ crypto_strongest_rand_syscall(uint8_t *out, size_t out_len)
tor_assert(errno != EAGAIN);
tor_assert(errno != EINTR);
- /* Probably ENOSYS. */
- log_warn(LD_CRYPTO, "Can't get entropy from getrandom().");
+ /* Useful log message for errno. */
+ if (errno == ENOSYS) {
+ log_warn(LD_CRYPTO, "Can't get entropy from getrandom(). "
+ " You are running a version of Tor built to support"
+ " getrandom(), but the kernel doesn't implement this"
+ " implement this function--probably because it is too old?");
+ } else {
+ log_warn(LD_CRYPTO, "Can't get entropy from getrandom(): %s.",
+ strerror(errno));
+ }
+
getrandom_works = 0; /* Don't bother trying again. */
return -1;
/* LCOV_EXCL_STOP */
diff --git a/src/common/sandbox.c b/src/common/sandbox.c
index 8cb78bd28e..aec9857e94 100644
--- a/src/common/sandbox.c
+++ b/src/common/sandbox.c
@@ -62,6 +62,9 @@
#include <time.h>
#include <poll.h>
+#ifdef HAVE_GNU_LIBC_VERSION_H
+#include <gnu/libc-version.h>
+#endif
#ifdef HAVE_LINUX_NETFILTER_IPV4_H
#include <linux/netfilter_ipv4.h>
#endif
@@ -133,6 +136,9 @@ static int filter_nopar_gen[] = {
SCMP_SYS(clone),
SCMP_SYS(epoll_create),
SCMP_SYS(epoll_wait),
+#ifdef __NR_epoll_pwait
+ SCMP_SYS(epoll_pwait),
+#endif
#ifdef HAVE_EVENTFD
SCMP_SYS(eventfd2),
#endif
@@ -397,6 +403,52 @@ sb_mmap2(scmp_filter_ctx ctx, sandbox_cfg_t *filter)
}
#endif /* defined(__NR_mmap2) */
+#ifdef HAVE_GNU_LIBC_VERSION_H
+#ifdef HAVE_GNU_GET_LIBC_VERSION
+#define CHECK_LIBC_VERSION
+#endif
+#endif
+
+/* Return true if we think we're running with a libc that always uses
+ * openat on linux. */
+static int
+libc_uses_openat_for_everything(void)
+{
+#ifdef CHECK_LIBC_VERSION
+ const char *version = gnu_get_libc_version();
+ if (version == NULL)
+ return 0;
+
+ int major = -1;
+ int minor = -1;
+
+ tor_sscanf(version, "%d.%d", &major, &minor);
+ if (major >= 3)
+ return 1;
+ else if (major == 2 && minor >= 26)
+ return 1;
+ else
+ return 0;
+#else /* !(defined(CHECK_LIBC_VERSION)) */
+ return 0;
+#endif /* defined(CHECK_LIBC_VERSION) */
+}
+
+/** Allow a single file to be opened. If <b>use_openat</b> is true,
+ * we're using a libc that remaps all the opens into openats. */
+static int
+allow_file_open(scmp_filter_ctx ctx, int use_openat, const char *file)
+{
+ if (use_openat) {
+ return seccomp_rule_add_2(ctx, SCMP_ACT_ALLOW, SCMP_SYS(openat),
+ SCMP_CMP_STR(0, SCMP_CMP_EQ, AT_FDCWD),
+ SCMP_CMP_STR(1, SCMP_CMP_EQ, file));
+ } else {
+ return seccomp_rule_add_1(ctx, SCMP_ACT_ALLOW, SCMP_SYS(open),
+ SCMP_CMP_STR(0, SCMP_CMP_EQ, file));
+ }
+}
+
/**
* Function responsible for setting up the open syscall for
* the seccomp filter sandbox.
@@ -407,14 +459,15 @@ sb_open(scmp_filter_ctx ctx, sandbox_cfg_t *filter)
int rc;
sandbox_cfg_t *elem = NULL;
+ int use_openat = libc_uses_openat_for_everything();
+
// for each dynamic parameter filters
for (elem = filter; elem != NULL; elem = elem->next) {
smp_param_t *param = elem->param;
if (param != NULL && param->prot == 1 && param->syscall
== SCMP_SYS(open)) {
- rc = seccomp_rule_add_1(ctx, SCMP_ACT_ALLOW, SCMP_SYS(open),
- SCMP_CMP_STR(0, SCMP_CMP_EQ, param->value));
+ rc = allow_file_open(ctx, use_openat, param->value);
if (rc != 0) {
log_err(LD_BUG,"(Sandbox) failed to add open syscall, received "
"libseccomp error %d", rc);
@@ -432,6 +485,15 @@ sb_open(scmp_filter_ctx ctx, sandbox_cfg_t *filter)
return rc;
}
+ rc = seccomp_rule_add_1(ctx, SCMP_ACT_ERRNO(EACCES), SCMP_SYS(openat),
+ SCMP_CMP_MASKED(2, O_CLOEXEC|O_NONBLOCK|O_NOCTTY|O_NOFOLLOW,
+ O_RDONLY));
+ if (rc != 0) {
+ log_err(LD_BUG,"(Sandbox) failed to add openat syscall, received "
+ "libseccomp error %d", rc);
+ return rc;
+ }
+
return 0;
}
@@ -621,7 +683,7 @@ sb_socket(scmp_filter_ctx ctx, sandbox_cfg_t *filter)
rc = seccomp_rule_add_3(ctx, SCMP_ACT_ALLOW, SCMP_SYS(socket),
SCMP_CMP(0, SCMP_CMP_EQ, PF_NETLINK),
- SCMP_CMP(1, SCMP_CMP_EQ, SOCK_RAW),
+ SCMP_CMP_MASKED(1, SOCK_CLOEXEC, SOCK_RAW),
SCMP_CMP(2, SCMP_CMP_EQ, 0));
if (rc)
return rc;
@@ -1054,6 +1116,19 @@ sb_stat64(scmp_filter_ctx ctx, sandbox_cfg_t *filter)
}
#endif /* defined(__NR_stat64) */
+static int
+sb_kill(scmp_filter_ctx ctx, sandbox_cfg_t *filter)
+{
+ (void) filter;
+#ifdef __NR_kill
+ /* Allow killing anything with signal 0 -- it isn't really a kill. */
+ return seccomp_rule_add_1(ctx, SCMP_ACT_ALLOW, SCMP_SYS(kill),
+ SCMP_CMP(1, SCMP_CMP_EQ, 0));
+#else
+ return 0;
+#endif /* defined(__NR_kill) */
+}
+
/**
* Array of function pointers responsible for filtering different syscalls at
* a parameter level.
@@ -1090,10 +1165,10 @@ static sandbox_filter_func_t filter_func[] = {
sb_setsockopt,
sb_getsockopt,
sb_socketpair,
-
#ifdef HAVE_KIST_SUPPORT
sb_ioctl,
#endif
+ sb_kill
};
const char *
@@ -1601,7 +1676,8 @@ add_param_filter(scmp_filter_ctx ctx, sandbox_cfg_t* cfg)
// function pointer
for (i = 0; i < ARRAY_LENGTH(filter_func); i++) {
- if ((filter_func[i])(ctx, cfg)) {
+ rc = filter_func[i](ctx, cfg);
+ if (rc) {
log_err(LD_BUG,"(Sandbox) failed to add syscall %d, received libseccomp "
"error %d", i, rc);
return rc;
diff --git a/src/common/storagedir.c b/src/common/storagedir.c
index 31933f64c2..c471ea911f 100644
--- a/src/common/storagedir.c
+++ b/src/common/storagedir.c
@@ -187,14 +187,19 @@ storage_dir_get_usage(storage_dir_t *d)
return d->usage;
}
-/** Mmap a specified file within <b>d</b>. */
+/** Mmap a specified file within <b>d</b>.
+ *
+ * On failure, return NULL and set errno as for tor_mmap_file(). */
tor_mmap_t *
storage_dir_map(storage_dir_t *d, const char *fname)
{
char *path = NULL;
tor_asprintf(&path, "%s/%s", d->directory, fname);
tor_mmap_t *result = tor_mmap_file(path);
+ int errval = errno;
tor_free(path);
+ if (result == NULL)
+ errno = errval;
return result;
}
@@ -364,6 +369,10 @@ storage_dir_save_labeled_to_file(storage_dir_t *d,
* the data's size into *<b>sz_out</b>. On success, also return a tor_mmap_t
* object whose contents should not be used -- it needs to be kept around,
* though, for as long as <b>data_out</b> is going to be valid.
+ *
+ * On failure, set errno as for tor_mmap_file() if the file was missing or
+ * empty, and set errno to EINVAL if the file was not in the labeled
+ * format expected.
*/
tor_mmap_t *
storage_dir_map_labeled(storage_dir_t *dir,
@@ -373,13 +382,20 @@ storage_dir_map_labeled(storage_dir_t *dir,
size_t *sz_out)
{
tor_mmap_t *m = storage_dir_map(dir, fname);
- if (! m)
+ int errval;
+ if (! m) {
+ errval = errno;
goto err;
+ }
const char *nulp = memchr(m->data, '\0', m->size);
- if (! nulp)
+ if (! nulp) {
+ errval = EINVAL;
goto err;
- if (labels_out && config_get_lines(m->data, labels_out, 0) < 0)
+ }
+ if (labels_out && config_get_lines(m->data, labels_out, 0) < 0) {
+ errval = EINVAL;
goto err;
+ }
size_t offset = nulp - m->data + 1;
tor_assert(offset <= m->size);
*data_out = (const uint8_t *)(m->data + offset);
@@ -388,6 +404,7 @@ storage_dir_map_labeled(storage_dir_t *dir,
return m;
err:
tor_munmap_file(m);
+ errno = errval;
return NULL;
}
diff --git a/src/or/channel.c b/src/or/channel.c
index 0b5a7fde90..7590ba8a5b 100644
--- a/src/or/channel.c
+++ b/src/or/channel.c
@@ -4726,6 +4726,16 @@ channel_set_circid_type,(channel_t *chan,
}
}
+static int
+channel_sort_by_ed25519_identity(const void **a_, const void **b_)
+{
+ const channel_t *a = *a_,
+ *b = *b_;
+ return fast_memcmp(&a->ed25519_identity.pubkey,
+ &b->ed25519_identity.pubkey,
+ sizeof(a->ed25519_identity.pubkey));
+}
+
/** Helper for channel_update_bad_for_new_circs(): Perform the
* channel_update_bad_for_new_circs operation on all channels in <b>lst</b>,
* all of which MUST have the same RSA ID. (They MAY have different
@@ -4734,44 +4744,52 @@ static void
channel_rsa_id_group_set_badness(struct channel_list_s *lst, int force)
{
/*XXXX This function should really be about channels. 15056 */
- channel_t *chan;
+ channel_t *chan = TOR_LIST_FIRST(lst);
+
+ if (!chan)
+ return;
+
+ /* if there is only one channel, don't bother looping */
+ if (PREDICT_LIKELY(!TOR_LIST_NEXT(chan, next_with_same_id))) {
+ connection_or_single_set_badness_(
+ time(NULL), BASE_CHAN_TO_TLS(chan)->conn, force);
+ return;
+ }
+
+ smartlist_t *channels = smartlist_new();
- /* First, get a minimal list of the ed25519 identites */
- smartlist_t *ed_identities = smartlist_new();
TOR_LIST_FOREACH(chan, lst, next_with_same_id) {
- uint8_t *id_copy =
- tor_memdup(&chan->ed25519_identity.pubkey, DIGEST256_LEN);
- smartlist_add(ed_identities, id_copy);
+ if (BASE_CHAN_TO_TLS(chan)->conn) {
+ smartlist_add(channels, chan);
+ }
}
- smartlist_sort_digests256(ed_identities);
- smartlist_uniq_digests256(ed_identities);
- /* Now, for each Ed identity, build a smartlist and find the best entry on
- * it. */
+ smartlist_sort(channels, channel_sort_by_ed25519_identity);
+
+ const ed25519_public_key_t *common_ed25519_identity = NULL;
+ /* it would be more efficient to do a slice, but this case is rare */
smartlist_t *or_conns = smartlist_new();
- SMARTLIST_FOREACH_BEGIN(ed_identities, const uint8_t *, ed_id) {
- TOR_LIST_FOREACH(chan, lst, next_with_same_id) {
- channel_tls_t *chantls = BASE_CHAN_TO_TLS(chan);
- if (tor_memneq(ed_id, &chan->ed25519_identity.pubkey, DIGEST256_LEN))
- continue;
- or_connection_t *orconn = chantls->conn;
- if (orconn) {
- tor_assert(orconn->chan == chantls);
- smartlist_add(or_conns, orconn);
- }
+ SMARTLIST_FOREACH_BEGIN(channels, channel_t *, channel) {
+ if (!common_ed25519_identity)
+ common_ed25519_identity = &channel->ed25519_identity;
+
+ if (! ed25519_pubkey_eq(&channel->ed25519_identity,
+ common_ed25519_identity)) {
+ connection_or_group_set_badness_(or_conns, force);
+ smartlist_clear(or_conns);
+ common_ed25519_identity = &channel->ed25519_identity;
}
- connection_or_group_set_badness_(or_conns, force);
- smartlist_clear(or_conns);
- } SMARTLIST_FOREACH_END(ed_id);
+ smartlist_add(or_conns, BASE_CHAN_TO_TLS(channel)->conn);
+ } SMARTLIST_FOREACH_END(channel);
+
+ connection_or_group_set_badness_(or_conns, force);
/* XXXX 15056 we may want to do something special with connections that have
* no set Ed25519 identity! */
smartlist_free(or_conns);
-
- SMARTLIST_FOREACH(ed_identities, uint8_t *, ed_id, tor_free(ed_id));
- smartlist_free(ed_identities);
+ smartlist_free(channels);
}
/** Go through all the channels (or if <b>digest</b> is non-NULL, just
diff --git a/src/or/circuitbuild.c b/src/or/circuitbuild.c
index 7f0bcc4150..2e6b63b4d6 100644
--- a/src/or/circuitbuild.c
+++ b/src/or/circuitbuild.c
@@ -2707,12 +2707,16 @@ extend_info_from_node(const node_t *node, int for_direct_connect)
node_describe(node));
}
+ /* Retrieve the curve25519 pubkey. */
+ const curve25519_public_key_t *curve_pubkey =
+ node_get_curve25519_onion_key(node);
+
if (valid_addr && node->ri)
return extend_info_new(node->ri->nickname,
node->identity,
ed_pubkey,
node->ri->onion_pkey,
- node->ri->onion_curve25519_pkey,
+ curve_pubkey,
&ap.addr,
ap.port);
else if (valid_addr && node->rs && node->md)
@@ -2720,7 +2724,7 @@ extend_info_from_node(const node_t *node, int for_direct_connect)
node->identity,
ed_pubkey,
node->md->onion_pkey,
- node->md->onion_curve25519_pkey,
+ curve_pubkey,
&ap.addr,
ap.port);
else
diff --git a/src/or/circuitstats.c b/src/or/circuitstats.c
index 923a6d794f..b8421a3c7e 100644
--- a/src/or/circuitstats.c
+++ b/src/or/circuitstats.c
@@ -431,9 +431,14 @@ circuit_build_times_new_consensus_params(circuit_build_times_t *cbt,
if (num > 0) {
if (num != cbt->liveness.num_recent_circs) {
int8_t *recent_circs;
- log_notice(LD_CIRC, "The Tor Directory Consensus has changed how many "
- "circuits we must track to detect network failures from %d "
- "to %d.", cbt->liveness.num_recent_circs, num);
+ if (cbt->liveness.num_recent_circs > 0) {
+ log_notice(LD_CIRC, "The Tor Directory Consensus has changed how "
+ "many circuits we must track to detect network failures "
+ "from %d to %d.", cbt->liveness.num_recent_circs, num);
+ } else {
+ log_notice(LD_CIRC, "Upon receiving a consensus directory, "
+ "re-enabling circuit-based network failure detection.");
+ }
tor_assert(cbt->liveness.timeouts_after_firsthop ||
cbt->liveness.num_recent_circs == 0);
diff --git a/src/or/circuituse.c b/src/or/circuituse.c
index 62cc865f48..aa0df95652 100644
--- a/src/or/circuituse.c
+++ b/src/or/circuituse.c
@@ -543,8 +543,7 @@ circuit_expire_building(void)
cutoff = begindir_cutoff;
else if (victim->purpose == CIRCUIT_PURPOSE_C_MEASURE_TIMEOUT)
cutoff = close_cutoff;
- else if (victim->purpose == CIRCUIT_PURPOSE_C_INTRODUCING ||
- victim->purpose == CIRCUIT_PURPOSE_C_INTRODUCE_ACK_WAIT)
+ else if (victim->purpose == CIRCUIT_PURPOSE_C_INTRODUCE_ACK_WAIT)
cutoff = c_intro_cutoff;
else if (victim->purpose == CIRCUIT_PURPOSE_S_ESTABLISH_INTRO)
cutoff = s_intro_cutoff;
@@ -661,12 +660,13 @@ circuit_expire_building(void)
TO_ORIGIN_CIRCUIT(victim)->path_state = PATH_STATE_USE_FAILED;
break;
case CIRCUIT_PURPOSE_C_INTRODUCING:
- /* We keep old introducing circuits around for
- * a while in parallel, and they can end up "opened".
- * We decide below if we're going to mark them timed
- * out and eventually close them.
- */
- break;
+ /* That purpose means that the intro point circuit has been opened
+ * succesfully but the INTRODUCE1 cell hasn't been sent yet because
+ * the client is waiting for the rendezvous point circuit to open.
+ * Keep this circuit open while waiting for the rendezvous circuit.
+ * We let the circuit idle timeout take care of cleaning this
+ * circuit if it never used. */
+ continue;
case CIRCUIT_PURPOSE_C_ESTABLISH_REND:
case CIRCUIT_PURPOSE_C_REND_READY_INTRO_ACKED:
case CIRCUIT_PURPOSE_C_INTRODUCE_ACK_WAIT:
@@ -757,8 +757,6 @@ circuit_expire_building(void)
NULL)
break;
/* fallthrough! */
- case CIRCUIT_PURPOSE_C_INTRODUCING:
- /* connection_ap_handshake_attach_circuit() will relaunch for us */
case CIRCUIT_PURPOSE_C_INTRODUCE_ACK_WAIT:
case CIRCUIT_PURPOSE_C_REND_READY_INTRO_ACKED:
/* If we have reached this line, we want to spare the circ for now. */
diff --git a/src/or/config.c b/src/or/config.c
index 16e6445616..d589876785 100644
--- a/src/or/config.c
+++ b/src/or/config.c
@@ -1094,6 +1094,7 @@ static const char *default_authorities[] = {
"199.58.81.140:80 74A9 1064 6BCE EFBC D2E8 74FC 1DC9 9743 0F96 8145",
"bastet orport=443 "
"v3ident=27102BC123E7AF1D4741AE047E160C91ADC76B21 "
+ "ipv6=[2620:13:4000:6000::1000:118]:443 "
"204.13.164.118:80 24E2 F139 121D 4394 C54B 5BCC 368B 3B41 1857 C413",
NULL
};
@@ -1858,7 +1859,7 @@ options_act(const or_options_t *old_options)
"given FD.");
return -1;
}
-#endif
+#endif /* defined(_WIN32) */
}
/* Load state */
@@ -6584,7 +6585,6 @@ port_cfg_new(size_t namelen)
cfg->entry_cfg.ipv6_traffic = 1;
cfg->entry_cfg.dns_request = 1;
cfg->entry_cfg.onion_traffic = 1;
- cfg->entry_cfg.cache_ipv4_answers = 1;
cfg->entry_cfg.prefer_ipv6_virtaddr = 1;
return cfg;
}
@@ -6900,7 +6900,7 @@ parse_port_config(smartlist_t *out,
bind_ipv4_only = 0, bind_ipv6_only = 0,
ipv4_traffic = 1, ipv6_traffic = 1, prefer_ipv6 = 0, dns_request = 1,
onion_traffic = 1,
- cache_ipv4 = 1, use_cached_ipv4 = 0,
+ cache_ipv4 = 0, use_cached_ipv4 = 0,
cache_ipv6 = 0, use_cached_ipv6 = 0,
prefer_ipv6_automap = 1, world_writable = 0, group_writable = 0,
relax_dirmode_check = 0,
diff --git a/src/or/confparse.h b/src/or/confparse.h
index 6f0b3b325c..022886e811 100644
--- a/src/or/confparse.h
+++ b/src/or/confparse.h
@@ -68,7 +68,7 @@ typedef union {
config_line_t **LINELIST_V;
routerset_t **ROUTERSET;
} confparse_dummy_values_t;
-#endif
+#endif /* defined(TOR_UNIT_TESTS) */
/** An abbreviation for a configuration option allowed on the command line. */
typedef struct config_abbrev_t {
@@ -132,13 +132,13 @@ typedef struct config_var_t {
{ NULL, CONFIG_TYPE_OBSOLETE, 0, NULL, { .INT=NULL } }
#define DUMMY_TYPECHECK_INSTANCE(tp) \
static tp tp ## _dummy
-#else
+#else /* !(defined(TOR_UNIT_TESTS)) */
#define CONF_TEST_MEMBERS(tp, conftype, member)
#define END_OF_CONFIG_VARS { NULL, CONFIG_TYPE_OBSOLETE, 0, NULL }
/* Repeatedly declarable incomplete struct to absorb redundant semicolons */
#define DUMMY_TYPECHECK_INSTANCE(tp) \
struct tor_semicolon_eater
-#endif
+#endif /* defined(TOR_UNIT_TESTS) */
/** Type of a callback to validate whether a given configuration is
* well-formed and consistent. See options_trial_assign() for documentation
diff --git a/src/or/connection.c b/src/or/connection.c
index 24f5a64622..92ccd3d5c8 100644
--- a/src/or/connection.c
+++ b/src/or/connection.c
@@ -768,6 +768,10 @@ connection_close_immediate(connection_t *conn)
connection_unregister_events(conn);
+ /* Prevent the event from getting unblocked. */
+ conn->read_blocked_on_bw =
+ conn->write_blocked_on_bw = 0;
+
if (SOCKET_OK(conn->s))
tor_close_socket(conn->s);
conn->s = TOR_INVALID_SOCKET;
diff --git a/src/or/connection_or.c b/src/or/connection_or.c
index 7af1f2b645..fdf1b2ebb1 100644
--- a/src/or/connection_or.c
+++ b/src/or/connection_or.c
@@ -965,6 +965,36 @@ connection_or_mark_bad_for_new_circs(or_connection_t *or_conn)
* too old for new circuits? */
#define TIME_BEFORE_OR_CONN_IS_TOO_OLD (60*60*24*7)
+/** Expire an or_connection if it is too old. Helper for
+ * connection_or_group_set_badness_ and fast path for
+ * channel_rsa_id_group_set_badness.
+ *
+ * Returns 1 if the connection was already expired, else 0.
+ */
+int
+connection_or_single_set_badness_(time_t now,
+ or_connection_t *or_conn,
+ int force)
+{
+ /* XXXX this function should also be about channels? */
+ if (or_conn->base_.marked_for_close ||
+ connection_or_is_bad_for_new_circs(or_conn))
+ return 1;
+
+ if (force ||
+ or_conn->base_.timestamp_created + TIME_BEFORE_OR_CONN_IS_TOO_OLD
+ < now) {
+ log_info(LD_OR,
+ "Marking OR conn to %s:%d as too old for new circuits "
+ "(fd "TOR_SOCKET_T_FORMAT", %d secs old).",
+ or_conn->base_.address, or_conn->base_.port, or_conn->base_.s,
+ (int)(now - or_conn->base_.timestamp_created));
+ connection_or_mark_bad_for_new_circs(or_conn);
+ }
+
+ return 0;
+}
+
/** Given a list of all the or_connections with a given
* identity, set elements of that list as is_bad_for_new_circs as
* appropriate. Helper for connection_or_set_bad_connections().
@@ -995,19 +1025,8 @@ connection_or_group_set_badness_(smartlist_t *group, int force)
/* Pass 1: expire everything that's old, and see what the status of
* everything else is. */
SMARTLIST_FOREACH_BEGIN(group, or_connection_t *, or_conn) {
- if (or_conn->base_.marked_for_close ||
- connection_or_is_bad_for_new_circs(or_conn))
+ if (connection_or_single_set_badness_(now, or_conn, force))
continue;
- if (force ||
- or_conn->base_.timestamp_created + TIME_BEFORE_OR_CONN_IS_TOO_OLD
- < now) {
- log_info(LD_OR,
- "Marking OR conn to %s:%d as too old for new circuits "
- "(fd "TOR_SOCKET_T_FORMAT", %d secs old).",
- or_conn->base_.address, or_conn->base_.port, or_conn->base_.s,
- (int)(now - or_conn->base_.timestamp_created));
- connection_or_mark_bad_for_new_circs(or_conn);
- }
if (connection_or_is_bad_for_new_circs(or_conn)) {
++n_old;
diff --git a/src/or/connection_or.h b/src/or/connection_or.h
index ee66b7c528..644df5c2c9 100644
--- a/src/or/connection_or.h
+++ b/src/or/connection_or.h
@@ -112,6 +112,9 @@ void var_cell_free(var_cell_t *cell);
#define MIN_LINK_PROTO_FOR_CHANNEL_PADDING 5
#define MAX_LINK_PROTO MIN_LINK_PROTO_FOR_CHANNEL_PADDING
+int connection_or_single_set_badness_(time_t now,
+ or_connection_t *or_conn,
+ int force);
void connection_or_group_set_badness_(smartlist_t *group, int force);
#ifdef TOR_UNIT_TESTS
diff --git a/src/or/conscache.c b/src/or/conscache.c
index 1407d0f0b9..9a90ff4dd2 100644
--- a/src/or/conscache.c
+++ b/src/or/conscache.c
@@ -539,9 +539,20 @@ consensus_cache_rescan(consensus_cache_t *cache)
map = storage_dir_map_labeled(cache->dir, fname,
&labels, &body, &bodylen);
if (! map) {
- /* Can't load this; continue */
- log_warn(LD_FS, "Unable to map file %s from consensus cache: %s",
- escaped(fname), strerror(errno));
+ /* The ERANGE error might come from tor_mmap_file() -- it means the file
+ * was empty. EINVAL might come from ..map_labeled() -- it means the
+ * file was misformatted. In both cases, we should just delete it.
+ */
+ if (errno == ERANGE || errno == EINVAL) {
+ log_warn(LD_FS, "Found %s file %s in consensus cache; removing it.",
+ errno == ERANGE ? "empty" : "misformatted",
+ escaped(fname));
+ storage_dir_remove_file(cache->dir, fname);
+ } else {
+ /* Can't load this; continue */
+ log_warn(LD_FS, "Unable to map file %s from consensus cache: %s",
+ escaped(fname), strerror(errno));
+ }
continue;
}
consensus_cache_entry_t *ent =
diff --git a/src/or/consdiffmgr.c b/src/or/consdiffmgr.c
index 1d63d59577..e539b61484 100644
--- a/src/or/consdiffmgr.c
+++ b/src/or/consdiffmgr.c
@@ -283,6 +283,10 @@ cdm_diff_ht_set_status(consensus_flavor_t flav,
int status,
consensus_cache_entry_handle_t *handle)
{
+ if (handle == NULL) {
+ tor_assert_nonfatal(status != CDM_DIFF_PRESENT);
+ }
+
struct cdm_diff_t search, *ent;
memset(&search, 0, sizeof(cdm_diff_t));
search.flavor = flav;
@@ -1589,8 +1593,13 @@ consensus_diff_worker_replyfn(void *work_)
for (u = 0; u < ARRAY_LENGTH(handles); ++u) {
compress_method_t method = compress_diffs_with[u];
if (cache) {
- cdm_diff_ht_set_status(flav, from_sha3, to_sha3, method, status,
- handles[u]);
+ consensus_cache_entry_handle_t *h = handles[u];
+ int this_status = status;
+ if (h == NULL) {
+ this_status = CDM_DIFF_ERROR;
+ }
+ tor_assert_nonfatal(h != NULL || this_status == CDM_DIFF_ERROR);
+ cdm_diff_ht_set_status(flav, from_sha3, to_sha3, method, this_status, h);
} else {
consensus_cache_entry_handle_free(handles[u]);
}
diff --git a/src/or/control.c b/src/or/control.c
index e17e923650..de08b2ee7d 100644
--- a/src/or/control.c
+++ b/src/or/control.c
@@ -58,7 +58,9 @@
#include "entrynodes.h"
#include "geoip.h"
#include "hibernate.h"
+#include "hs_cache.h"
#include "hs_common.h"
+#include "hs_control.h"
#include "main.h"
#include "microdesc.h"
#include "networkstatus.h"
@@ -2014,36 +2016,89 @@ getinfo_helper_dir(control_connection_t *control_conn,
SMARTLIST_FOREACH(sl, char *, c, tor_free(c));
smartlist_free(sl);
} else if (!strcmpstart(question, "hs/client/desc/id/")) {
- rend_cache_entry_t *e = NULL;
+ hostname_type_t addr_type;
question += strlen("hs/client/desc/id/");
- if (strlen(question) != REND_SERVICE_ID_LEN_BASE32) {
+ if (rend_valid_v2_service_id(question)) {
+ addr_type = ONION_V2_HOSTNAME;
+ } else if (hs_address_is_valid(question)) {
+ addr_type = ONION_V3_HOSTNAME;
+ } else {
*errmsg = "Invalid address";
return -1;
}
- if (!rend_cache_lookup_entry(question, -1, &e)) {
- /* Descriptor found in cache */
- *answer = tor_strdup(e->desc);
+ if (addr_type == ONION_V2_HOSTNAME) {
+ rend_cache_entry_t *e = NULL;
+ if (!rend_cache_lookup_entry(question, -1, &e)) {
+ /* Descriptor found in cache */
+ *answer = tor_strdup(e->desc);
+ } else {
+ *errmsg = "Not found in cache";
+ return -1;
+ }
} else {
- *errmsg = "Not found in cache";
- return -1;
+ ed25519_public_key_t service_pk;
+ const char *desc;
+
+ /* The check before this if/else makes sure of this. */
+ tor_assert(addr_type == ONION_V3_HOSTNAME);
+
+ if (hs_parse_address(question, &service_pk, NULL, NULL) < 0) {
+ *errmsg = "Invalid v3 address";
+ return -1;
+ }
+
+ desc = hs_cache_lookup_encoded_as_client(&service_pk);
+ if (desc) {
+ *answer = tor_strdup(desc);
+ } else {
+ *errmsg = "Not found in cache";
+ return -1;
+ }
}
} else if (!strcmpstart(question, "hs/service/desc/id/")) {
- rend_cache_entry_t *e = NULL;
+ hostname_type_t addr_type;
question += strlen("hs/service/desc/id/");
- if (strlen(question) != REND_SERVICE_ID_LEN_BASE32) {
+ if (rend_valid_v2_service_id(question)) {
+ addr_type = ONION_V2_HOSTNAME;
+ } else if (hs_address_is_valid(question)) {
+ addr_type = ONION_V3_HOSTNAME;
+ } else {
*errmsg = "Invalid address";
return -1;
}
+ rend_cache_entry_t *e = NULL;
- if (!rend_cache_lookup_v2_desc_as_service(question, &e)) {
- /* Descriptor found in cache */
- *answer = tor_strdup(e->desc);
+ if (addr_type == ONION_V2_HOSTNAME) {
+ if (!rend_cache_lookup_v2_desc_as_service(question, &e)) {
+ /* Descriptor found in cache */
+ *answer = tor_strdup(e->desc);
+ } else {
+ *errmsg = "Not found in cache";
+ return -1;
+ }
} else {
- *errmsg = "Not found in cache";
- return -1;
+ ed25519_public_key_t service_pk;
+ char *desc;
+
+ /* The check before this if/else makes sure of this. */
+ tor_assert(addr_type == ONION_V3_HOSTNAME);
+
+ if (hs_parse_address(question, &service_pk, NULL, NULL) < 0) {
+ *errmsg = "Invalid v3 address";
+ return -1;
+ }
+
+ desc = hs_service_lookup_current_desc(&service_pk);
+ if (desc) {
+ /* Newly allocated string, we have ownership. */
+ *answer = desc;
+ } else {
+ *errmsg = "Not found in cache";
+ return -1;
+ }
}
} else if (!strcmpstart(question, "md/id/")) {
const node_t *node = node_get_by_hex_id(question+strlen("md/id/"), 0);
@@ -2624,9 +2679,16 @@ circuit_describe_status_for_controller(origin_circuit_t *circ)
}
}
- if (circ->rend_data != NULL) {
- smartlist_add_asprintf(descparts, "REND_QUERY=%s",
- rend_data_get_address(circ->rend_data));
+ if (circ->rend_data != NULL || circ->hs_ident != NULL) {
+ char addr[HS_SERVICE_ADDR_LEN_BASE32 + 1];
+ const char *onion_address;
+ if (circ->rend_data) {
+ onion_address = rend_data_get_address(circ->rend_data);
+ } else {
+ hs_build_address(&circ->hs_ident->identity_pk, HS_VERSION_THREE, addr);
+ onion_address = addr;
+ }
+ smartlist_add_asprintf(descparts, "REND_QUERY=%s", onion_address);
}
{
@@ -4277,9 +4339,11 @@ handle_control_hspost(control_connection_t *conn,
const char *body)
{
static const char *opt_server = "SERVER=";
+ static const char *opt_hsaddress = "HSADDRESS=";
smartlist_t *hs_dirs = NULL;
const char *encoded_desc = body;
size_t encoded_desc_len = len;
+ const char *onion_address = NULL;
char *cp = memchr(body, '\n', len);
if (cp == NULL) {
@@ -4309,15 +4373,16 @@ handle_control_hspost(control_connection_t *conn,
server);
goto done;
}
- if (!node->rs->is_hs_dir) {
- connection_printf_to_buf(conn, "552 Server \"%s\" is not a HSDir"
- "\r\n", server);
- goto done;
- }
/* Valid server, add it to our local list. */
if (!hs_dirs)
hs_dirs = smartlist_new();
smartlist_add(hs_dirs, node->rs);
+ } else if (!strcasecmpstart(arg, opt_hsaddress)) {
+ if (!hs_address_is_valid(arg)) {
+ connection_printf_to_buf(conn, "512 Malformed onion address\r\n");
+ goto done;
+ }
+ onion_address = arg;
} else {
connection_printf_to_buf(conn, "512 Unexpected argument \"%s\"\r\n",
arg);
@@ -4326,6 +4391,19 @@ handle_control_hspost(control_connection_t *conn,
} SMARTLIST_FOREACH_END(arg);
}
+ /* Handle the v3 case. */
+ if (onion_address) {
+ char *desc_str = NULL;
+ read_escaped_data(encoded_desc, encoded_desc_len, &desc_str);
+ if (hs_control_hspost_command(desc_str, onion_address, hs_dirs) < 0) {
+ connection_printf_to_buf(conn, "554 Invalid descriptor\r\n");
+ }
+ tor_free(desc_str);
+ goto done;
+ }
+
+ /* From this point on, it is only v2. */
+
/* Read the dot encoded descriptor, and parse it. */
rend_encoded_v2_service_descriptor_t *desc =
tor_malloc_zero(sizeof(rend_encoded_v2_service_descriptor_t));
@@ -4370,6 +4448,52 @@ handle_control_hspost(control_connection_t *conn,
return 0;
}
+/* Helper function for ADD_ONION that adds an ephemeral service depending on
+ * the given hs_version.
+ *
+ * The secret key in pk depends on the hs_version. The ownership of the key
+ * used in pk is given to the HS subsystem so the caller must stop accessing
+ * it after.
+ *
+ * The port_cfgs is a list of service port. Ownership transfered to service.
+ * The max_streams refers to the MaxStreams= key.
+ * The max_streams_close_circuit refers to the MaxStreamsCloseCircuit key.
+ * The auth_type is the authentication type of the clients in auth_clients.
+ * The ownership of that list is transfered to the service.
+ *
+ * On success (RSAE_OKAY), the address_out points to a newly allocated string
+ * containing the onion address without the .onion part. On error, address_out
+ * is untouched. */
+static hs_service_add_ephemeral_status_t
+add_onion_helper_add_service(int hs_version,
+ add_onion_secret_key_t *pk,
+ smartlist_t *port_cfgs, int max_streams,
+ int max_streams_close_circuit, int auth_type,
+ smartlist_t *auth_clients, char **address_out)
+{
+ hs_service_add_ephemeral_status_t ret;
+
+ tor_assert(pk);
+ tor_assert(port_cfgs);
+ tor_assert(address_out);
+
+ switch (hs_version) {
+ case HS_VERSION_TWO:
+ ret = rend_service_add_ephemeral(pk->v2, port_cfgs, max_streams,
+ max_streams_close_circuit, auth_type,
+ auth_clients, address_out);
+ break;
+ case HS_VERSION_THREE:
+ ret = hs_service_add_ephemeral(pk->v3, port_cfgs, max_streams,
+ max_streams_close_circuit, address_out);
+ break;
+ default:
+ tor_assert_unreached();
+ }
+
+ return ret;
+}
+
/** Called when we get a ADD_ONION command; parse the body, and set up
* the new ephemeral Onion Service. */
static int
@@ -4551,15 +4675,15 @@ handle_control_add_onion(control_connection_t *conn,
}
/* Parse the "keytype:keyblob" argument. */
- crypto_pk_t *pk = NULL;
+ int hs_version = 0;
+ add_onion_secret_key_t pk;
const char *key_new_alg = NULL;
char *key_new_blob = NULL;
char *err_msg = NULL;
- pk = add_onion_helper_keyarg(smartlist_get(args, 0), discard_pk,
- &key_new_alg, &key_new_blob,
- &err_msg);
- if (!pk) {
+ if (add_onion_helper_keyarg(smartlist_get(args, 0), discard_pk,
+ &key_new_alg, &key_new_blob, &pk, &hs_version,
+ &err_msg) < 0) {
if (err_msg) {
connection_write_str_to_buf(err_msg, conn);
tor_free(err_msg);
@@ -4568,16 +4692,23 @@ handle_control_add_onion(control_connection_t *conn,
}
tor_assert(!err_msg);
+ /* Hidden service version 3 don't have client authentication support so if
+ * ClientAuth was given, send back an error. */
+ if (hs_version == HS_VERSION_THREE && auth_clients) {
+ connection_printf_to_buf(conn, "513 ClientAuth not supported\r\n");
+ goto out;
+ }
+
/* Create the HS, using private key pk, client authentication auth_type,
* the list of auth_clients, and port config port_cfg.
* rend_service_add_ephemeral() will take ownership of pk and port_cfg,
* regardless of success/failure.
*/
char *service_id = NULL;
- int ret = rend_service_add_ephemeral(pk, port_cfgs, max_streams,
- max_streams_close_circuit,
- auth_type, auth_clients,
- &service_id);
+ int ret = add_onion_helper_add_service(hs_version, &pk, port_cfgs,
+ max_streams,
+ max_streams_close_circuit, auth_type,
+ auth_clients, &service_id);
port_cfgs = NULL; /* port_cfgs is now owned by the rendservice code. */
auth_clients = NULL; /* so is auth_clients */
switch (ret) {
@@ -4670,9 +4801,10 @@ handle_control_add_onion(control_connection_t *conn,
* Note: The error messages returned are deliberately vague to avoid echoing
* key material.
*/
-STATIC crypto_pk_t *
+STATIC int
add_onion_helper_keyarg(const char *arg, int discard_pk,
const char **key_new_alg_out, char **key_new_blob_out,
+ add_onion_secret_key_t *decoded_key, int *hs_version,
char **err_msg_out)
{
smartlist_t *key_args = smartlist_new();
@@ -4680,7 +4812,7 @@ add_onion_helper_keyarg(const char *arg, int discard_pk,
const char *key_new_alg = NULL;
char *key_new_blob = NULL;
char *err_msg = NULL;
- int ok = 0;
+ int ret = -1;
smartlist_split_string(key_args, arg, ":", SPLIT_IGNORE_BLANK, 0);
if (smartlist_len(key_args) != 2) {
@@ -4692,6 +4824,7 @@ add_onion_helper_keyarg(const char *arg, int discard_pk,
static const char *key_type_new = "NEW";
static const char *key_type_best = "BEST";
static const char *key_type_rsa1024 = "RSA1024";
+ static const char *key_type_ed25519_v3 = "ED25519-V3";
const char *key_type = smartlist_get(key_args, 0);
const char *key_blob = smartlist_get(key_args, 1);
@@ -4704,9 +4837,23 @@ add_onion_helper_keyarg(const char *arg, int discard_pk,
goto err;
}
if (crypto_pk_num_bits(pk) != PK_BYTES*8) {
+ crypto_pk_free(pk);
err_msg = tor_strdup("512 Invalid RSA key size\r\n");
goto err;
}
+ decoded_key->v2 = pk;
+ *hs_version = HS_VERSION_TWO;
+ } else if (!strcasecmp(key_type_ed25519_v3, key_type)) {
+ /* "ED25519-V3:<Base64 Blob>" - Loading a pre-existing ed25519 key. */
+ ed25519_secret_key_t *sk = tor_malloc_zero(sizeof(*sk));
+ if (base64_decode((char *) sk->seckey, sizeof(sk->seckey), key_blob,
+ strlen(key_blob)) != sizeof(sk->seckey)) {
+ tor_free(sk);
+ err_msg = tor_strdup("512 Failed to decode ED25519-V3 key\r\n");
+ goto err;
+ }
+ decoded_key->v3 = sk;
+ *hs_version = HS_VERSION_THREE;
} else if (!strcasecmp(key_type_new, key_type)) {
/* "NEW:<Algorithm>" - Generating a new key, blob as algorithm. */
if (!strcasecmp(key_type_rsa1024, key_blob) ||
@@ -4720,12 +4867,38 @@ add_onion_helper_keyarg(const char *arg, int discard_pk,
}
if (!discard_pk) {
if (crypto_pk_base64_encode(pk, &key_new_blob)) {
+ crypto_pk_free(pk);
tor_asprintf(&err_msg, "551 Failed to encode %s key\r\n",
key_type_rsa1024);
goto err;
}
key_new_alg = key_type_rsa1024;
}
+ decoded_key->v2 = pk;
+ *hs_version = HS_VERSION_TWO;
+ } else if (!strcasecmp(key_type_ed25519_v3, key_blob)) {
+ ed25519_secret_key_t *sk = tor_malloc_zero(sizeof(*sk));
+ if (ed25519_secret_key_generate(sk, 1) < 0) {
+ tor_free(sk);
+ tor_asprintf(&err_msg, "551 Failed to generate %s key\r\n",
+ key_type_ed25519_v3);
+ goto err;
+ }
+ if (!discard_pk) {
+ ssize_t len = base64_encode_size(sizeof(sk->seckey), 0) + 1;
+ key_new_blob = tor_malloc_zero(len);
+ if (base64_encode(key_new_blob, len, (const char *) sk->seckey,
+ sizeof(sk->seckey), 0) != (len - 1)) {
+ tor_free(sk);
+ tor_free(key_new_blob);
+ tor_asprintf(&err_msg, "551 Failed to encode %s key\r\n",
+ key_type_ed25519_v3);
+ goto err;
+ }
+ key_new_alg = key_type_ed25519_v3;
+ }
+ decoded_key->v3 = sk;
+ *hs_version = HS_VERSION_THREE;
} else {
err_msg = tor_strdup("513 Invalid key type\r\n");
goto err;
@@ -4736,8 +4909,7 @@ add_onion_helper_keyarg(const char *arg, int discard_pk,
}
/* Succeded in loading or generating a private key. */
- tor_assert(pk);
- ok = 1;
+ ret = 0;
err:
SMARTLIST_FOREACH(key_args, char *, cp, {
@@ -4746,10 +4918,6 @@ add_onion_helper_keyarg(const char *arg, int discard_pk,
});
smartlist_free(key_args);
- if (!ok) {
- crypto_pk_free(pk);
- pk = NULL;
- }
if (err_msg_out) {
*err_msg_out = err_msg;
} else {
@@ -4758,7 +4926,7 @@ add_onion_helper_keyarg(const char *arg, int discard_pk,
*key_new_alg_out = key_new_alg;
*key_new_blob_out = key_new_blob;
- return pk;
+ return ret;
}
/** Helper function to handle parsing a ClientAuth argument to the
@@ -4827,6 +4995,7 @@ handle_control_del_onion(control_connection_t *conn,
uint32_t len,
const char *body)
{
+ int hs_version = 0;
smartlist_t *args;
(void) len; /* body is nul-terminated; it's safe to ignore the length */
args = getargs_helper("DEL_ONION", conn, body, 1, 1);
@@ -4834,7 +5003,11 @@ handle_control_del_onion(control_connection_t *conn,
return 0;
const char *service_id = smartlist_get(args, 0);
- if (!rend_valid_v2_service_id(service_id)) {
+ if (rend_valid_v2_service_id(service_id)) {
+ hs_version = HS_VERSION_TWO;
+ } else if (hs_address_is_valid(service_id)) {
+ hs_version = HS_VERSION_THREE;
+ } else {
connection_printf_to_buf(conn, "512 Malformed Onion Service id\r\n");
goto out;
}
@@ -4861,8 +5034,20 @@ handle_control_del_onion(control_connection_t *conn,
if (onion_services == NULL) {
connection_printf_to_buf(conn, "552 Unknown Onion Service id\r\n");
} else {
- int ret = rend_service_del_ephemeral(service_id);
- if (ret) {
+ int ret = -1;
+ switch (hs_version) {
+ case HS_VERSION_TWO:
+ ret = rend_service_del_ephemeral(service_id);
+ break;
+ case HS_VERSION_THREE:
+ ret = hs_service_del_ephemeral(service_id);
+ break;
+ default:
+ /* The ret value will be -1 thus hitting the warning below. This should
+ * never happen because of the check at the start of the function. */
+ break;
+ }
+ if (ret < 0) {
/* This should *NEVER* fail, since the service is on either the
* per-control connection list, or the global one.
*/
@@ -4932,9 +5117,16 @@ connection_control_closed(control_connection_t *conn)
* The list and it's contents are scrubbed/freed in connection_free_.
*/
if (conn->ephemeral_onion_services) {
- SMARTLIST_FOREACH(conn->ephemeral_onion_services, char *, cp, {
- rend_service_del_ephemeral(cp);
- });
+ SMARTLIST_FOREACH_BEGIN(conn->ephemeral_onion_services, char *, cp) {
+ if (rend_valid_v2_service_id(cp)) {
+ rend_service_del_ephemeral(cp);
+ } else if (hs_address_is_valid(cp)) {
+ hs_service_del_ephemeral(cp);
+ } else {
+ /* An invalid .onion in our list should NEVER happen */
+ tor_fragile_assert();
+ }
+ } SMARTLIST_FOREACH_END(cp);
}
if (conn->is_owning_control_connection) {
@@ -7012,27 +7204,33 @@ rend_hsaddress_str_or_unknown(const char *onion_address)
* <b>rend_query</b> is used to fetch requested onion address and auth type.
* <b>hs_dir</b> is the description of contacting hs directory.
* <b>desc_id_base32</b> is the ID of requested hs descriptor.
+ * <b>hsdir_index</b> is the HSDir fetch index value for v3, an hex string.
*/
void
-control_event_hs_descriptor_requested(const rend_data_t *rend_query,
+control_event_hs_descriptor_requested(const char *onion_address,
+ rend_auth_type_t auth_type,
const char *id_digest,
- const char *desc_id_base32)
+ const char *desc_id,
+ const char *hsdir_index)
{
- if (!id_digest || !rend_query || !desc_id_base32) {
- log_warn(LD_BUG, "Called with rend_query==%p, "
- "id_digest==%p, desc_id_base32==%p",
- rend_query, id_digest, desc_id_base32);
+ char *hsdir_index_field = NULL;
+
+ if (BUG(!id_digest || !desc_id)) {
return;
}
+ if (hsdir_index) {
+ tor_asprintf(&hsdir_index_field, " HSDIR_INDEX=%s", hsdir_index);
+ }
+
send_control_event(EVENT_HS_DESC,
- "650 HS_DESC REQUESTED %s %s %s %s\r\n",
- rend_hsaddress_str_or_unknown(
- rend_data_get_address(rend_query)),
- rend_auth_type_to_string(
- TO_REND_DATA_V2(rend_query)->auth_type),
+ "650 HS_DESC REQUESTED %s %s %s %s%s\r\n",
+ rend_hsaddress_str_or_unknown(onion_address),
+ rend_auth_type_to_string(auth_type),
node_describe_longname_by_id(id_digest),
- desc_id_base32);
+ desc_id,
+ hsdir_index_field ? hsdir_index_field : "");
+ tor_free(hsdir_index_field);
}
/** For an HS descriptor query <b>rend_data</b>, using the
@@ -7081,89 +7279,87 @@ get_desc_id_from_query(const rend_data_t *rend_data, const char *hsdir_fp)
/** send HS_DESC CREATED event when a local service generates a descriptor.
*
- * <b>service_id</b> is the descriptor onion address.
- * <b>desc_id_base32</b> is the descriptor ID.
- * <b>replica</b> is the the descriptor replica number.
+ * <b>onion_address</b> is service address.
+ * <b>desc_id</b> is the descriptor ID.
+ * <b>replica</b> is the the descriptor replica number. If it is negative, it
+ * is ignored.
*/
void
-control_event_hs_descriptor_created(const char *service_id,
- const char *desc_id_base32,
+control_event_hs_descriptor_created(const char *onion_address,
+ const char *desc_id,
int replica)
{
- if (!service_id || !desc_id_base32) {
- log_warn(LD_BUG, "Called with service_digest==%p, "
- "desc_id_base32==%p", service_id, desc_id_base32);
+ char *replica_field = NULL;
+
+ if (BUG(!onion_address || !desc_id)) {
return;
}
+ if (replica >= 0) {
+ tor_asprintf(&replica_field, " REPLICA=%d", replica);
+ }
+
send_control_event(EVENT_HS_DESC,
- "650 HS_DESC CREATED %s UNKNOWN UNKNOWN %s "
- "REPLICA=%d\r\n",
- service_id,
- desc_id_base32,
- replica);
+ "650 HS_DESC CREATED %s UNKNOWN UNKNOWN %s%s\r\n",
+ onion_address, desc_id,
+ replica_field ? replica_field : "");
+ tor_free(replica_field);
}
/** send HS_DESC upload event.
*
- * <b>service_id</b> is the descriptor onion address.
+ * <b>onion_address</b> is service address.
* <b>hs_dir</b> is the description of contacting hs directory.
- * <b>desc_id_base32</b> is the ID of requested hs descriptor.
+ * <b>desc_id</b> is the ID of requested hs descriptor.
*/
void
-control_event_hs_descriptor_upload(const char *service_id,
+control_event_hs_descriptor_upload(const char *onion_address,
const char *id_digest,
- const char *desc_id_base32)
+ const char *desc_id,
+ const char *hsdir_index)
{
- if (!service_id || !id_digest || !desc_id_base32) {
- log_warn(LD_BUG, "Called with service_digest==%p, "
- "desc_id_base32==%p, id_digest==%p", service_id,
- desc_id_base32, id_digest);
+ char *hsdir_index_field = NULL;
+
+ if (BUG(!onion_address || !id_digest || !desc_id)) {
return;
}
+ if (hsdir_index) {
+ tor_asprintf(&hsdir_index_field, " HSDIR_INDEX=%s", hsdir_index);
+ }
+
send_control_event(EVENT_HS_DESC,
- "650 HS_DESC UPLOAD %s UNKNOWN %s %s\r\n",
- service_id,
+ "650 HS_DESC UPLOAD %s UNKNOWN %s %s%s\r\n",
+ onion_address,
node_describe_longname_by_id(id_digest),
- desc_id_base32);
+ desc_id,
+ hsdir_index_field ? hsdir_index_field : "");
+ tor_free(hsdir_index_field);
}
/** send HS_DESC event after got response from hs directory.
*
* NOTE: this is an internal function used by following functions:
- * control_event_hs_descriptor_received
- * control_event_hs_descriptor_failed
+ * control_event_hsv2_descriptor_received
+ * control_event_hsv2_descriptor_failed
+ * control_event_hsv3_descriptor_failed
*
* So do not call this function directly.
*/
-void
-control_event_hs_descriptor_receive_end(const char *action,
- const char *onion_address,
- const rend_data_t *rend_data,
- const char *id_digest,
- const char *reason)
+static void
+event_hs_descriptor_receive_end(const char *action,
+ const char *onion_address,
+ const char *desc_id,
+ rend_auth_type_t auth_type,
+ const char *hsdir_id_digest,
+ const char *reason)
{
- char *desc_id_field = NULL;
char *reason_field = NULL;
- char desc_id_base32[REND_DESC_ID_V2_LEN_BASE32 + 1];
- const char *desc_id = NULL;
- if (!action || !rend_data || !onion_address) {
- log_warn(LD_BUG, "Called with action==%p, rend_data==%p, "
- "onion_address==%p", action, rend_data, onion_address);
+ if (BUG(!action || !onion_address)) {
return;
}
- desc_id = get_desc_id_from_query(rend_data, id_digest);
- if (desc_id != NULL) {
- /* Set the descriptor ID digest to base32 so we can send it. */
- base32_encode(desc_id_base32, sizeof(desc_id_base32), desc_id,
- DIGEST_LEN);
- /* Extra whitespace is needed before the value. */
- tor_asprintf(&desc_id_field, " %s", desc_id_base32);
- }
-
if (reason) {
tor_asprintf(&reason_field, " REASON=%s", reason);
}
@@ -7172,14 +7368,13 @@ control_event_hs_descriptor_receive_end(const char *action,
"650 HS_DESC %s %s %s %s%s%s\r\n",
action,
rend_hsaddress_str_or_unknown(onion_address),
- rend_auth_type_to_string(
- TO_REND_DATA_V2(rend_data)->auth_type),
- id_digest ?
- node_describe_longname_by_id(id_digest) : "UNKNOWN",
- desc_id_field ? desc_id_field : "",
+ rend_auth_type_to_string(auth_type),
+ hsdir_id_digest ?
+ node_describe_longname_by_id(hsdir_id_digest) :
+ "UNKNOWN",
+ desc_id ? desc_id : "",
reason_field ? reason_field : "");
- tor_free(desc_id_field);
tor_free(reason_field);
}
@@ -7199,9 +7394,7 @@ control_event_hs_descriptor_upload_end(const char *action,
{
char *reason_field = NULL;
- if (!action || !id_digest) {
- log_warn(LD_BUG, "Called with action==%p, id_digest==%p", action,
- id_digest);
+ if (BUG(!action || !id_digest)) {
return;
}
@@ -7224,17 +7417,54 @@ control_event_hs_descriptor_upload_end(const char *action,
* called when we successfully received a hidden service descriptor.
*/
void
-control_event_hs_descriptor_received(const char *onion_address,
- const rend_data_t *rend_data,
- const char *id_digest)
+control_event_hsv2_descriptor_received(const char *onion_address,
+ const rend_data_t *rend_data,
+ const char *hsdir_id_digest)
{
- if (!rend_data || !id_digest || !onion_address) {
- log_warn(LD_BUG, "Called with rend_data==%p, id_digest==%p, "
- "onion_address==%p", rend_data, id_digest, onion_address);
+ char *desc_id_field = NULL;
+ const char *desc_id;
+
+ if (BUG(!rend_data || !hsdir_id_digest || !onion_address)) {
return;
}
- control_event_hs_descriptor_receive_end("RECEIVED", onion_address,
- rend_data, id_digest, NULL);
+
+ desc_id = get_desc_id_from_query(rend_data, hsdir_id_digest);
+ if (desc_id != NULL) {
+ char desc_id_base32[REND_DESC_ID_V2_LEN_BASE32 + 1];
+ /* Set the descriptor ID digest to base32 so we can send it. */
+ base32_encode(desc_id_base32, sizeof(desc_id_base32), desc_id,
+ DIGEST_LEN);
+ /* Extra whitespace is needed before the value. */
+ tor_asprintf(&desc_id_field, " %s", desc_id_base32);
+ }
+
+ event_hs_descriptor_receive_end("RECEIVED", onion_address, desc_id_field,
+ TO_REND_DATA_V2(rend_data)->auth_type,
+ hsdir_id_digest, NULL);
+ tor_free(desc_id_field);
+}
+
+/* Send HS_DESC RECEIVED event
+ *
+ * Called when we successfully received a hidden service descriptor. */
+void
+control_event_hsv3_descriptor_received(const char *onion_address,
+ const char *desc_id,
+ const char *hsdir_id_digest)
+{
+ char *desc_id_field = NULL;
+
+ if (BUG(!onion_address || !desc_id || !hsdir_id_digest)) {
+ return;
+ }
+
+ /* Because DescriptorID is an optional positional value, we need to add a
+ * whitespace before in order to not be next to the HsDir value. */
+ tor_asprintf(&desc_id_field, " %s", desc_id);
+
+ event_hs_descriptor_receive_end("RECEIVED", onion_address, desc_id_field,
+ REND_NO_AUTH, hsdir_id_digest, NULL);
+ tor_free(desc_id_field);
}
/** send HS_DESC UPLOADED event
@@ -7245,9 +7475,7 @@ void
control_event_hs_descriptor_uploaded(const char *id_digest,
const char *onion_address)
{
- if (!id_digest) {
- log_warn(LD_BUG, "Called with id_digest==%p",
- id_digest);
+ if (BUG(!id_digest)) {
return;
}
@@ -7261,17 +7489,58 @@ control_event_hs_descriptor_uploaded(const char *id_digest,
* add it to REASON= field.
*/
void
-control_event_hs_descriptor_failed(const rend_data_t *rend_data,
- const char *id_digest,
- const char *reason)
+control_event_hsv2_descriptor_failed(const rend_data_t *rend_data,
+ const char *hsdir_id_digest,
+ const char *reason)
{
- if (!rend_data) {
- log_warn(LD_BUG, "Called with rend_data==%p", rend_data);
+ char *desc_id_field = NULL;
+ const char *desc_id;
+
+ if (BUG(!rend_data)) {
return;
}
- control_event_hs_descriptor_receive_end("FAILED",
- rend_data_get_address(rend_data),
- rend_data, id_digest, reason);
+
+ desc_id = get_desc_id_from_query(rend_data, hsdir_id_digest);
+ if (desc_id != NULL) {
+ char desc_id_base32[REND_DESC_ID_V2_LEN_BASE32 + 1];
+ /* Set the descriptor ID digest to base32 so we can send it. */
+ base32_encode(desc_id_base32, sizeof(desc_id_base32), desc_id,
+ DIGEST_LEN);
+ /* Extra whitespace is needed before the value. */
+ tor_asprintf(&desc_id_field, " %s", desc_id_base32);
+ }
+
+ event_hs_descriptor_receive_end("FAILED", rend_data_get_address(rend_data),
+ desc_id_field,
+ TO_REND_DATA_V2(rend_data)->auth_type,
+ hsdir_id_digest, reason);
+ tor_free(desc_id_field);
+}
+
+/** Send HS_DESC event to inform controller that the query to
+ * <b>onion_address</b> failed to retrieve hidden service descriptor
+ * <b>desc_id</b> from directory identified by <b>hsdir_id_digest</b>. If
+ * NULL, "UNKNOWN" is used. If <b>reason</b> is not NULL, add it to REASON=
+ * field. */
+void
+control_event_hsv3_descriptor_failed(const char *onion_address,
+ const char *desc_id,
+ const char *hsdir_id_digest,
+ const char *reason)
+{
+ char *desc_id_field = NULL;
+
+ if (BUG(!onion_address || !desc_id || !reason)) {
+ return;
+ }
+
+ /* Because DescriptorID is an optional positional value, we need to add a
+ * whitespace before in order to not be next to the HsDir value. */
+ tor_asprintf(&desc_id_field, " %s", desc_id);
+
+ event_hs_descriptor_receive_end("FAILED", onion_address, desc_id_field,
+ REND_NO_AUTH, hsdir_id_digest, reason);
+ tor_free(desc_id_field);
}
/** Send HS_DESC_CONTENT event after completion of a successful fetch from hs
@@ -7321,9 +7590,7 @@ control_event_hs_descriptor_upload_failed(const char *id_digest,
const char *onion_address,
const char *reason)
{
- if (!id_digest) {
- log_warn(LD_BUG, "Called with id_digest==%p",
- id_digest);
+ if (BUG(!id_digest)) {
return;
}
control_event_hs_descriptor_upload_end("FAILED", onion_address,
diff --git a/src/or/control.h b/src/or/control.h
index 7ec182cb78..28ffeaed86 100644
--- a/src/or/control.h
+++ b/src/or/control.h
@@ -115,32 +115,39 @@ void control_event_transport_launched(const char *mode,
tor_addr_t *addr, uint16_t port);
const char *rend_auth_type_to_string(rend_auth_type_t auth_type);
MOCK_DECL(const char *, node_describe_longname_by_id,(const char *id_digest));
-void control_event_hs_descriptor_requested(const rend_data_t *rend_query,
- const char *desc_id_base32,
- const char *hs_dir);
-void control_event_hs_descriptor_created(const char *service_id,
- const char *desc_id_base32,
+void control_event_hs_descriptor_requested(const char *onion_address,
+ rend_auth_type_t auth_type,
+ const char *id_digest,
+ const char *desc_id,
+ const char *hsdir_index);
+void control_event_hs_descriptor_created(const char *onion_address,
+ const char *desc_id,
int replica);
-void control_event_hs_descriptor_upload(const char *service_id,
- const char *desc_id_base32,
- const char *hs_dir);
-void control_event_hs_descriptor_receive_end(const char *action,
- const char *onion_address,
- const rend_data_t *rend_data,
- const char *id_digest,
- const char *reason);
+void control_event_hs_descriptor_upload(const char *onion_address,
+ const char *desc_id,
+ const char *hs_dir,
+ const char *hsdir_index);
void control_event_hs_descriptor_upload_end(const char *action,
const char *onion_address,
const char *hs_dir,
const char *reason);
-void control_event_hs_descriptor_received(const char *onion_address,
- const rend_data_t *rend_data,
- const char *id_digest);
void control_event_hs_descriptor_uploaded(const char *hs_dir,
const char *onion_address);
-void control_event_hs_descriptor_failed(const rend_data_t *rend_data,
- const char *id_digest,
- const char *reason);
+/* Hidden service v2 HS_DESC specific. */
+void control_event_hsv2_descriptor_failed(const rend_data_t *rend_data,
+ const char *id_digest,
+ const char *reason);
+void control_event_hsv2_descriptor_received(const char *onion_address,
+ const rend_data_t *rend_data,
+ const char *id_digest);
+/* Hidden service v3 HS_DESC specific. */
+void control_event_hsv3_descriptor_failed(const char *onion_address,
+ const char *desc_id,
+ const char *hsdir_id_digest,
+ const char *reason);
+void control_event_hsv3_descriptor_received(const char *onion_address,
+ const char *desc_id,
+ const char *hsdir_id_digest);
void control_event_hs_descriptor_upload_failed(const char *hs_dir,
const char *onion_address,
const char *reason);
@@ -256,10 +263,22 @@ void format_cell_stats(char **event_string, circuit_t *circ,
cell_stats_t *cell_stats);
STATIC char *get_bw_samples(void);
-STATIC crypto_pk_t *add_onion_helper_keyarg(const char *arg, int discard_pk,
- const char **key_new_alg_out,
- char **key_new_blob_out,
- char **err_msg_out);
+/* ADD_ONION secret key to create an ephemeral service. The command supports
+ * multiple versions so this union stores the key and passes it to the HS
+ * subsystem depending on the requested version. */
+typedef union add_onion_secret_key_t {
+ /* Hidden service v2 secret key. */
+ crypto_pk_t *v2;
+ /* Hidden service v3 secret key. */
+ ed25519_secret_key_t *v3;
+} add_onion_secret_key_t;
+
+STATIC int add_onion_helper_keyarg(const char *arg, int discard_pk,
+ const char **key_new_alg_out,
+ char **key_new_blob_out,
+ add_onion_secret_key_t *decoded_key,
+ int *hs_version, char **err_msg_out);
+
STATIC rend_authorized_client_t *
add_onion_helper_clientauth(const char *arg, int *created, char **err_msg_out);
diff --git a/src/or/directory.c b/src/or/directory.c
index e7a5da8139..1a7c016c3e 100644
--- a/src/or/directory.c
+++ b/src/or/directory.c
@@ -25,6 +25,7 @@
#include "geoip.h"
#include "hs_cache.h"
#include "hs_common.h"
+#include "hs_control.h"
#include "hs_client.h"
#include "main.h"
#include "microdesc.h"
@@ -116,7 +117,8 @@ static void dir_routerdesc_download_failed(smartlist_t *failed,
int was_extrainfo,
int was_descriptor_digests);
static void dir_microdesc_download_failed(smartlist_t *failed,
- int status_code);
+ int status_code,
+ const char *dir_id);
static int client_likes_consensus(const struct consensus_cache_entry_t *ent,
const char *want_url);
@@ -469,7 +471,7 @@ directory_pick_generic_dirserver(dirinfo_type_t type, int pds_flags,
log_warn(LD_BUG, "Called when we have UseBridges set.");
if (should_use_directory_guards(options)) {
- const node_t *node = guards_choose_dirguard(guard_state_out);
+ const node_t *node = guards_choose_dirguard(dir_purpose, guard_state_out);
if (node)
rs = node->rs;
} else {
@@ -603,7 +605,7 @@ directory_get_from_dirserver,(
* sort of dir fetch we'll be doing, so it won't return a bridge
* that can't answer our question.
*/
- const node_t *node = guards_choose_dirguard(&guard_state);
+ const node_t *node = guards_choose_dirguard(dir_purpose, &guard_state);
if (node && node->ri) {
/* every bridge has a routerinfo. */
routerinfo_t *ri = node->ri;
@@ -1011,48 +1013,6 @@ directory_must_use_begindir(const or_options_t *options)
return !public_server_mode(options);
}
-struct directory_request_t {
- /**
- * These fields specify which directory we're contacting. Routerstatus,
- * if present, overrides the other fields.
- *
- * @{ */
- tor_addr_port_t or_addr_port;
- tor_addr_port_t dir_addr_port;
- char digest[DIGEST_LEN];
-
- const routerstatus_t *routerstatus;
- /** @} */
- /** One of DIR_PURPOSE_* other than DIR_PURPOSE_SERVER. Describes what
- * kind of operation we'll be doing (upload/download), and of what kind
- * of document. */
- uint8_t dir_purpose;
- /** One of ROUTER_PURPOSE_*; used for uploads and downloads of routerinfo
- * and extrainfo docs. */
- uint8_t router_purpose;
- /** Enum: determines whether to anonymize, and whether to use dirport or
- * orport. */
- dir_indirection_t indirection;
- /** Alias to the variable part of the URL for this request */
- const char *resource;
- /** Alias to the payload to upload (if any) */
- const char *payload;
- /** Number of bytes to upload from payload</b> */
- size_t payload_len;
- /** Value to send in an if-modified-since header, or 0 for none. */
- time_t if_modified_since;
- /** Hidden-service-specific information v2. */
- const rend_data_t *rend_query;
- /** Extra headers to append to the request */
- config_line_t *additional_headers;
- /** Hidden-service-specific information for v3+. */
- const hs_ident_dir_conn_t *hs_ident;
- /** Used internally to directory.c: gets informed when the attempt to
- * connect to the directory succeeds or fails, if that attempt bears on the
- * directory's usability as a directory guard. */
- circuit_guard_state_t *guard_state;
-};
-
/** Evaluate the situation and decide if we should use an encrypted
* "begindir-style" connection for this directory request.
* 0) If there is no DirPort, yes.
@@ -2245,8 +2205,6 @@ static int handle_response_fetch_detached_signatures(dir_connection_t *,
const response_handler_args_t *);
static int handle_response_fetch_desc(dir_connection_t *,
const response_handler_args_t *);
-static int handle_response_fetch_microdesc(dir_connection_t *,
- const response_handler_args_t *);
static int handle_response_upload_dir(dir_connection_t *,
const response_handler_args_t *);
static int handle_response_upload_vote(dir_connection_t *,
@@ -2887,7 +2845,7 @@ handle_response_fetch_desc(dir_connection_t *conn,
conn->router_purpose,
conn->base_.address)) {
time_t now = approx_time();
- directory_info_has_arrived(now, 0, 0);
+ directory_info_has_arrived(now, 0, 1);
}
}
}
@@ -2914,7 +2872,7 @@ handle_response_fetch_desc(dir_connection_t *conn,
* Handler function: processes a response to a request for a group of
* microdescriptors
**/
-static int
+STATIC int
handle_response_fetch_microdesc(dir_connection_t *conn,
const response_handler_args_t *args)
{
@@ -2931,6 +2889,7 @@ handle_response_fetch_microdesc(dir_connection_t *conn,
conn->base_.port);
tor_assert(conn->requested_resource &&
!strcmpstart(conn->requested_resource, "d/"));
+ tor_assert_nonfatal(!tor_mem_is_zero(conn->identity_digest, DIGEST_LEN));
which = smartlist_new();
dir_split_resource_into_fingerprints(conn->requested_resource+2,
which, NULL,
@@ -2941,7 +2900,7 @@ handle_response_fetch_microdesc(dir_connection_t *conn,
"soon.",
status_code, escaped(reason), conn->base_.address,
(int)conn->base_.port, conn->requested_resource);
- dir_microdesc_download_failed(which, status_code);
+ dir_microdesc_download_failed(which, status_code, conn->identity_digest);
SMARTLIST_FOREACH(which, char *, cp, tor_free(cp));
smartlist_free(which);
return 0;
@@ -2953,7 +2912,7 @@ handle_response_fetch_microdesc(dir_connection_t *conn,
now, which);
if (smartlist_len(which)) {
/* Mark remaining ones as failed. */
- dir_microdesc_download_failed(which, status_code);
+ dir_microdesc_download_failed(which, status_code, conn->identity_digest);
}
if (mds && smartlist_len(mds)) {
control_event_bootstrap(BOOTSTRAP_STATUS_LOADING_DESCRIPTORS,
@@ -3132,10 +3091,19 @@ handle_response_fetch_hsdesc_v3(dir_connection_t *conn,
/* We got something: Try storing it in the cache. */
if (hs_cache_store_as_client(body, &conn->hs_ident->identity_pk) < 0) {
log_warn(LD_REND, "Failed to store hidden service descriptor");
+ /* Fire control port FAILED event. */
+ hs_control_desc_event_failed(conn->hs_ident, conn->identity_digest,
+ "BAD_DESC");
+ hs_control_desc_event_content(conn->hs_ident, conn->identity_digest,
+ NULL);
} else {
log_info(LD_REND, "Stored hidden service descriptor successfully.");
TO_CONN(conn)->purpose = DIR_PURPOSE_HAS_FETCHED_HSDESC;
hs_client_desc_has_arrived(conn->hs_ident);
+ /* Fire control port RECEIVED event. */
+ hs_control_desc_event_received(conn->hs_ident, conn->identity_digest);
+ hs_control_desc_event_content(conn->hs_ident, conn->identity_digest,
+ body);
}
break;
case 404:
@@ -3143,13 +3111,22 @@ handle_response_fetch_hsdesc_v3(dir_connection_t *conn,
* tries to clean this conn up. */
log_info(LD_REND, "Fetching hidden service v3 descriptor not found: "
"Retrying at another directory.");
- /* TODO: Inform the control port */
+ /* Fire control port FAILED event. */
+ hs_control_desc_event_failed(conn->hs_ident, conn->identity_digest,
+ "NOT_FOUND");
+ hs_control_desc_event_content(conn->hs_ident, conn->identity_digest,
+ NULL);
break;
case 400:
log_warn(LD_REND, "Fetching v3 hidden service descriptor failed: "
"http status 400 (%s). Dirserver didn't like our "
"query? Retrying at another directory.",
escaped(reason));
+ /* Fire control port FAILED event. */
+ hs_control_desc_event_failed(conn->hs_ident, conn->identity_digest,
+ "QUERY_REJECTED");
+ hs_control_desc_event_content(conn->hs_ident, conn->identity_digest,
+ NULL);
break;
default:
log_warn(LD_REND, "Fetching v3 hidden service descriptor failed: "
@@ -3157,6 +3134,11 @@ handle_response_fetch_hsdesc_v3(dir_connection_t *conn,
"'%s:%d'. Retrying at another directory.",
status_code, escaped(reason), TO_CONN(conn)->address,
TO_CONN(conn)->port);
+ /* Fire control port FAILED event. */
+ hs_control_desc_event_failed(conn->hs_ident, conn->identity_digest,
+ "UNEXPECTED");
+ hs_control_desc_event_content(conn->hs_ident, conn->identity_digest,
+ NULL);
break;
}
@@ -3178,9 +3160,9 @@ handle_response_fetch_renddesc_v2(dir_connection_t *conn,
const size_t body_len = args->body_len;
#define SEND_HS_DESC_FAILED_EVENT(reason) \
- (control_event_hs_descriptor_failed(conn->rend_data, \
- conn->identity_digest, \
- reason))
+ (control_event_hsv2_descriptor_failed(conn->rend_data, \
+ conn->identity_digest, \
+ reason))
#define SEND_HS_DESC_FAILED_CONTENT() \
(control_event_hs_descriptor_content( \
rend_data_get_address(conn->rend_data), \
@@ -3215,9 +3197,9 @@ handle_response_fetch_renddesc_v2(dir_connection_t *conn,
/* success. notify pending connections about this. */
log_info(LD_REND, "Successfully fetched v2 rendezvous "
"descriptor.");
- control_event_hs_descriptor_received(service_id,
- conn->rend_data,
- conn->identity_digest);
+ control_event_hsv2_descriptor_received(service_id,
+ conn->rend_data,
+ conn->identity_digest);
control_event_hs_descriptor_content(service_id,
conn->requested_resource,
conn->identity_digest,
@@ -3334,14 +3316,16 @@ handle_response_upload_hsdesc(dir_connection_t *conn,
case 200:
log_info(LD_REND, "Uploading hidden service descriptor: "
"finished with status 200 (%s)", escaped(reason));
- /* XXX: Trigger control event. */
+ hs_control_desc_event_uploaded(conn->hs_ident, conn->identity_digest);
break;
case 400:
- log_warn(LD_REND, "Uploading hidden service descriptor: http "
- "status 400 (%s) response from dirserver "
- "'%s:%d'. Malformed hidden service descriptor?",
- escaped(reason), conn->base_.address, conn->base_.port);
- /* XXX: Trigger control event. */
+ log_fn(LOG_PROTOCOL_WARN, LD_REND,
+ "Uploading hidden service descriptor: http "
+ "status 400 (%s) response from dirserver "
+ "'%s:%d'. Malformed hidden service descriptor?",
+ escaped(reason), conn->base_.address, conn->base_.port);
+ hs_control_desc_event_failed(conn->hs_ident, conn->identity_digest,
+ "UPLOAD_REJECTED");
break;
default:
log_warn(LD_REND, "Uploading hidden service descriptor: http "
@@ -3349,7 +3333,8 @@ handle_response_upload_hsdesc(dir_connection_t *conn,
"'%s:%d').",
status_code, escaped(reason), conn->base_.address,
conn->base_.port);
- /* XXX: Trigger control event. */
+ hs_control_desc_event_failed(conn->hs_ident, conn->identity_digest,
+ "UNEXPECTED");
break;
}
@@ -5793,13 +5778,14 @@ dir_routerdesc_download_failed(smartlist_t *failed, int status_code,
* every 10 or 60 seconds (FOO_DESCRIPTOR_RETRY_INTERVAL) in main.c. */
}
-/** Called when a connection to download microdescriptors has failed in whole
- * or in part. <b>failed</b> is a list of every microdesc digest we didn't
- * get. <b>status_code</b> is the http status code we received. Reschedule the
- * microdesc downloads as appropriate. */
+/** Called when a connection to download microdescriptors from relay with
+ * <b>dir_id</b> has failed in whole or in part. <b>failed</b> is a list
+ * of every microdesc digest we didn't get. <b>status_code</b> is the http
+ * status code we received. Reschedule the microdesc downloads as
+ * appropriate. */
static void
dir_microdesc_download_failed(smartlist_t *failed,
- int status_code)
+ int status_code, const char *dir_id)
{
networkstatus_t *consensus
= networkstatus_get_latest_consensus_by_flavor(FLAV_MICRODESC);
@@ -5810,17 +5796,26 @@ dir_microdesc_download_failed(smartlist_t *failed,
if (! consensus)
return;
+
+ /* We failed to fetch a microdescriptor from 'dir_id', note it down
+ * so that we don't try the same relay next time... */
+ microdesc_note_outdated_dirserver(dir_id);
+
SMARTLIST_FOREACH_BEGIN(failed, const char *, d) {
rs = router_get_mutable_consensus_status_by_descriptor_digest(consensus,d);
if (!rs)
continue;
dls = &rs->dl_status;
if (dls->n_download_failures >=
- get_options()->TestingMicrodescMaxDownloadTries)
+ get_options()->TestingMicrodescMaxDownloadTries) {
continue;
- {
+ }
+
+ { /* Increment the failure count for this md fetch */
char buf[BASE64_DIGEST256_LEN+1];
digest256_to_base64(buf, d);
+ log_info(LD_DIR, "Failed to download md %s from %s",
+ buf, hex_str(dir_id, DIGEST_LEN));
download_status_increment_failure(dls, status_code, buf,
server, now);
}
diff --git a/src/or/directory.h b/src/or/directory.h
index 904bdfae46..3aef600716 100644
--- a/src/or/directory.h
+++ b/src/or/directory.h
@@ -183,6 +183,48 @@ typedef struct response_handler_args_t {
const char *headers;
} response_handler_args_t;
+struct directory_request_t {
+ /**
+ * These fields specify which directory we're contacting. Routerstatus,
+ * if present, overrides the other fields.
+ *
+ * @{ */
+ tor_addr_port_t or_addr_port;
+ tor_addr_port_t dir_addr_port;
+ char digest[DIGEST_LEN];
+
+ const routerstatus_t *routerstatus;
+ /** @} */
+ /** One of DIR_PURPOSE_* other than DIR_PURPOSE_SERVER. Describes what
+ * kind of operation we'll be doing (upload/download), and of what kind
+ * of document. */
+ uint8_t dir_purpose;
+ /** One of ROUTER_PURPOSE_*; used for uploads and downloads of routerinfo
+ * and extrainfo docs. */
+ uint8_t router_purpose;
+ /** Enum: determines whether to anonymize, and whether to use dirport or
+ * orport. */
+ dir_indirection_t indirection;
+ /** Alias to the variable part of the URL for this request */
+ const char *resource;
+ /** Alias to the payload to upload (if any) */
+ const char *payload;
+ /** Number of bytes to upload from payload</b> */
+ size_t payload_len;
+ /** Value to send in an if-modified-since header, or 0 for none. */
+ time_t if_modified_since;
+ /** Hidden-service-specific information v2. */
+ const rend_data_t *rend_query;
+ /** Extra headers to append to the request */
+ config_line_t *additional_headers;
+ /** Hidden-service-specific information for v3+. */
+ const hs_ident_dir_conn_t *hs_ident;
+ /** Used internally to directory.c: gets informed when the attempt to
+ * connect to the directory succeeds or fails, if that attempt bears on the
+ * directory's usability as a directory guard. */
+ struct circuit_guard_state_t *guard_state;
+};
+
struct get_handler_args_t;
STATIC int handle_get_hs_descriptor_v3(dir_connection_t *conn,
const struct get_handler_args_t *args);
@@ -193,6 +235,8 @@ STATIC void warn_disallowed_anonymous_compression_method(compress_method_t);
STATIC int handle_response_fetch_hsdesc_v3(dir_connection_t *conn,
const response_handler_args_t *args);
+STATIC int handle_response_fetch_microdesc(dir_connection_t *conn,
+ const response_handler_args_t *args);
STATIC int handle_response_fetch_consensus(dir_connection_t *conn,
const response_handler_args_t *args);
diff --git a/src/or/dirserv.c b/src/or/dirserv.c
index 432fe6ae2b..ce737d0b1d 100644
--- a/src/or/dirserv.c
+++ b/src/or/dirserv.c
@@ -1903,21 +1903,28 @@ version_from_platform(const char *platform)
/** Helper: write the router-status information in <b>rs</b> into a newly
* allocated character buffer. Use the same format as in network-status
* documents. If <b>version</b> is non-NULL, add a "v" line for the platform.
+ *
+ * consensus_method is the current consensus method when format is
+ * NS_V3_CONSENSUS or NS_V3_CONSENSUS_MICRODESC. It is ignored for other
+ * formats: pass ROUTERSTATUS_FORMAT_NO_CONSENSUS_METHOD.
+ *
* Return 0 on success, -1 on failure.
*
* The format argument has one of the following values:
* NS_V2 - Output an entry suitable for a V2 NS opinion document
* NS_V3_CONSENSUS - Output the first portion of a V3 NS consensus entry
+ * for consensus_method.
* NS_V3_CONSENSUS_MICRODESC - Output the first portion of a V3 microdesc
- * consensus entry.
+ * consensus entry for consensus_method.
* NS_V3_VOTE - Output a complete V3 NS vote. If <b>vrs</b> is present,
* it contains additional information for the vote.
- * NS_CONTROL_PORT - Output a NS document for the control port
+ * NS_CONTROL_PORT - Output a NS document for the control port.
*/
char *
routerstatus_format_entry(const routerstatus_t *rs, const char *version,
const char *protocols,
routerstatus_format_type_t format,
+ int consensus_method,
const vote_routerstatus_t *vrs)
{
char *summary;
@@ -1948,8 +1955,10 @@ routerstatus_format_entry(const routerstatus_t *rs, const char *version,
* networkstatus_type_t values, with an additional control port value
* added -MP */
- /* V3 microdesc consensuses don't have "a" lines. */
- if (format == NS_V3_CONSENSUS_MICRODESC)
+ /* V3 microdesc consensuses only have "a" lines in later consensus methods
+ */
+ if (format == NS_V3_CONSENSUS_MICRODESC &&
+ consensus_method < MIN_METHOD_FOR_A_LINES_IN_MICRODESC_CONSENSUS)
goto done;
/* Possible "a" line. At most one for now. */
@@ -1958,7 +1967,7 @@ routerstatus_format_entry(const routerstatus_t *rs, const char *version,
fmt_addrport(&rs->ipv6_addr, rs->ipv6_orport));
}
- if (format == NS_V3_CONSENSUS)
+ if (format == NS_V3_CONSENSUS || format == NS_V3_CONSENSUS_MICRODESC)
goto done;
smartlist_add_asprintf(chunks,
diff --git a/src/or/dirserv.h b/src/or/dirserv.h
index 46967a6cb2..9dc239f213 100644
--- a/src/or/dirserv.h
+++ b/src/or/dirserv.h
@@ -150,6 +150,7 @@ char *routerstatus_format_entry(
const char *version,
const char *protocols,
routerstatus_format_type_t format,
+ int consensus_method,
const vote_routerstatus_t *vrs);
void dirserv_free_all(void);
void cached_dir_decref(cached_dir_t *d);
diff --git a/src/or/dirvote.c b/src/or/dirvote.c
index ce82a5ef4a..24a6ed42be 100644
--- a/src/or/dirvote.c
+++ b/src/or/dirvote.c
@@ -278,7 +278,9 @@ format_networkstatus_vote(crypto_pk_t *private_signing_key,
vote_microdesc_hash_t *h;
rsf = routerstatus_format_entry(&vrs->status,
vrs->version, vrs->protocols,
- NS_V3_VOTE, vrs);
+ NS_V3_VOTE,
+ ROUTERSTATUS_FORMAT_NO_CONSENSUS_METHOD,
+ vrs);
if (rsf)
smartlist_add(chunks, rsf);
@@ -519,7 +521,7 @@ compute_routerstatus_consensus(smartlist_t *votes, int consensus_method,
/* compare_vote_rs_() sorts the items by identity digest (all the same),
* then by SD digest. That way, if we have a tie that the published_on
- * date cannot tie, we use the descriptor with the smaller digest.
+ * date cannot break, we use the descriptor with the smaller digest.
*/
smartlist_sort(votes, compare_vote_rs_);
SMARTLIST_FOREACH_BEGIN(votes, vote_routerstatus_t *, rs) {
@@ -795,6 +797,9 @@ dirvote_compute_params(smartlist_t *votes, int method, int total_authorities)
output = smartlist_new();
SMARTLIST_FOREACH_BEGIN(param_list, const char *, param) {
+ /* resolve spurious clang shallow analysis null pointer errors */
+ tor_assert(param);
+
const char *next_param;
int ok=0;
eq = strchr(param, '=');
@@ -807,8 +812,7 @@ dirvote_compute_params(smartlist_t *votes, int method, int total_authorities)
next_param = NULL;
else
next_param = smartlist_get(param_list, param_sl_idx+1);
- /* resolve spurious clang shallow analysis null pointer errors */
- tor_assert(param);
+
if (!next_param || strncmp(next_param, param, cur_param_len)) {
/* We've reached the end of a series. */
/* Make sure enough authorities voted on this param, unless the
@@ -1315,8 +1319,9 @@ compute_nth_protocol_set(int n, int n_voters, const smartlist_t *votes)
/** Given a list of vote networkstatus_t in <b>votes</b>, our public
* authority <b>identity_key</b>, our private authority <b>signing_key</b>,
* and the number of <b>total_authorities</b> that we believe exist in our
- * voting quorum, generate the text of a new v3 consensus vote, and return the
- * value in a newly allocated string.
+ * voting quorum, generate the text of a new v3 consensus or microdescriptor
+ * consensus (depending on <b>flavor</b>), and return the value in a newly
+ * allocated string.
*
* Note: this function DOES NOT check whether the votes are from
* recognized authorities. (dirvote_add_vote does that.)
@@ -2099,7 +2104,8 @@ networkstatus_compute_consensus(smartlist_t *votes,
char *buf;
/* Okay!! Now we can write the descriptor... */
/* First line goes into "buf". */
- buf = routerstatus_format_entry(&rs_out, NULL, NULL, rs_format, NULL);
+ buf = routerstatus_format_entry(&rs_out, NULL, NULL,
+ rs_format, consensus_method, NULL);
if (buf)
smartlist_add(chunks, buf);
}
@@ -3829,7 +3835,10 @@ dirvote_create_microdescriptor(const routerinfo_t *ri, int consensus_method)
smartlist_add_asprintf(chunks, "ntor-onion-key %s", kbuf);
}
+ /* We originally put a lines in the micrdescriptors, but then we worked out
+ * that we needed them in the microdesc consensus. See #20916. */
if (consensus_method >= MIN_METHOD_FOR_A_LINES &&
+ consensus_method < MIN_METHOD_FOR_NO_A_LINES_IN_MICRODESC &&
!tor_addr_is_null(&ri->ipv6_addr) && ri->ipv6_orport)
smartlist_add_asprintf(chunks, "a %s\n",
fmt_addrport(&ri->ipv6_addr, ri->ipv6_orport));
@@ -3938,7 +3947,9 @@ static const struct consensus_method_range_t {
{MIN_METHOD_FOR_P6_LINES, MIN_METHOD_FOR_NTOR_KEY - 1},
{MIN_METHOD_FOR_NTOR_KEY, MIN_METHOD_FOR_ID_HASH_IN_MD - 1},
{MIN_METHOD_FOR_ID_HASH_IN_MD, MIN_METHOD_FOR_ED25519_ID_IN_MD - 1},
- {MIN_METHOD_FOR_ED25519_ID_IN_MD, MAX_SUPPORTED_CONSENSUS_METHOD},
+ {MIN_METHOD_FOR_ED25519_ID_IN_MD,
+ MIN_METHOD_FOR_NO_A_LINES_IN_MICRODESC - 1},
+ {MIN_METHOD_FOR_NO_A_LINES_IN_MICRODESC, MAX_SUPPORTED_CONSENSUS_METHOD},
{-1, -1}
};
diff --git a/src/or/dirvote.h b/src/or/dirvote.h
index 72a35fea6d..c9cb527788 100644
--- a/src/or/dirvote.h
+++ b/src/or/dirvote.h
@@ -51,11 +51,15 @@
#define MIN_VOTE_INTERVAL_TESTING_INITIAL \
((MIN_VOTE_SECONDS_TESTING)+(MIN_DIST_SECONDS_TESTING)+1)
+/* A placeholder for routerstatus_format_entry() when the consensus method
+ * argument is not applicable. */
+#define ROUTERSTATUS_FORMAT_NO_CONSENSUS_METHOD 0
+
/** The lowest consensus method that we currently support. */
#define MIN_SUPPORTED_CONSENSUS_METHOD 13
/** The highest consensus method that we currently support. */
-#define MAX_SUPPORTED_CONSENSUS_METHOD 26
+#define MAX_SUPPORTED_CONSENSUS_METHOD 28
/** Lowest consensus method where microdesc consensuses omit any entry
* with no microdesc. */
@@ -115,6 +119,14 @@
* instead of 0. See #14881 */
#define MIN_METHOD_FOR_INIT_BW_WEIGHTS_ONE 26
+/** Lowest consensus method where the microdesc consensus contains relay IPv6
+ * addresses. See #23826 and #20916. */
+#define MIN_METHOD_FOR_A_LINES_IN_MICRODESC_CONSENSUS 27
+
+/** Lowest consensus method where microdescriptors do not contain relay IPv6
+ * addresses. See #23828 and #20916. */
+#define MIN_METHOD_FOR_NO_A_LINES_IN_MICRODESC 28
+
/** Default bandwidth to clip unmeasured bandwidths to using method >=
* MIN_METHOD_TO_CLIP_UNMEASURED_BW. (This is not a consensus method; do not
* get confused with the above macros.) */
diff --git a/src/or/dns.c b/src/or/dns.c
index c992c8c358..f140051e81 100644
--- a/src/or/dns.c
+++ b/src/or/dns.c
@@ -1578,10 +1578,11 @@ evdns_callback(int result, char type, int count, int ttl, void *addresses,
escaped_safe_str(hostname));
tor_free(escaped_address);
} else if (count) {
- log_warn(LD_EXIT, "eventdns returned only non-IPv4 answers for %s.",
+ log_info(LD_EXIT, "eventdns returned only unrecognized answer types "
+ " for %s.",
escaped_safe_str(string_address));
} else {
- log_warn(LD_BUG, "eventdns returned no addresses or error for %s!",
+ log_info(LD_EXIT, "eventdns returned no addresses or error for %s.",
escaped_safe_str(string_address));
}
}
diff --git a/src/or/entrynodes.c b/src/or/entrynodes.c
index 76a8f591b9..f9438361f0 100644
--- a/src/or/entrynodes.c
+++ b/src/or/entrynodes.c
@@ -740,7 +740,8 @@ node_is_possible_guard(const node_t *node)
node->is_stable &&
node->is_fast &&
node->is_valid &&
- node_is_dir(node));
+ node_is_dir(node) &&
+ !router_digest_is_me(node->identity));
}
/**
@@ -966,7 +967,7 @@ entry_guard_learned_bridge_identity(const tor_addr_port_t *addrport,
* violate it.
*/
STATIC int
-num_reachable_filtered_guards(guard_selection_t *gs,
+num_reachable_filtered_guards(const guard_selection_t *gs,
const entry_guard_restriction_t *rst)
{
int n_reachable_filtered_guards = 0;
@@ -1460,6 +1461,94 @@ guard_in_node_family(const entry_guard_t *guard, const node_t *node)
}
}
+/* Allocate and return a new exit guard restriction (where <b>exit_id</b> is of
+ * size DIGEST_LEN) */
+STATIC entry_guard_restriction_t *
+guard_create_exit_restriction(const uint8_t *exit_id)
+{
+ entry_guard_restriction_t *rst = NULL;
+ rst = tor_malloc_zero(sizeof(entry_guard_restriction_t));
+ rst->type = RST_EXIT_NODE;
+ memcpy(rst->exclude_id, exit_id, DIGEST_LEN);
+ return rst;
+}
+
+/** If we have fewer than this many possible usable guards, don't set
+ * MD-availability-based restrictions: we might blacklist all of them. */
+#define MIN_GUARDS_FOR_MD_RESTRICTION 10
+
+/** Return true if we should set md dirserver restrictions. We might not want
+ * to set those if our guard options are too restricted, since we don't want
+ * to blacklist all of them. */
+static int
+should_set_md_dirserver_restriction(void)
+{
+ const guard_selection_t *gs = get_guard_selection_info();
+ int num_usable_guards = num_reachable_filtered_guards(gs, NULL);
+
+ /* Don't set restriction if too few reachable filtered guards. */
+ if (num_usable_guards < MIN_GUARDS_FOR_MD_RESTRICTION) {
+ log_info(LD_GUARD, "Not setting md restriction: only %d"
+ " usable guards.", num_usable_guards);
+ return 0;
+ }
+
+ /* We have enough usable guards: set MD restriction */
+ return 1;
+}
+
+/** Allocate and return an outdated md guard restriction. Return NULL if no
+ * such restriction is needed. */
+STATIC entry_guard_restriction_t *
+guard_create_dirserver_md_restriction(void)
+{
+ entry_guard_restriction_t *rst = NULL;
+
+ if (!should_set_md_dirserver_restriction()) {
+ log_debug(LD_GUARD, "Not setting md restriction: too few "
+ "filtered guards.");
+ return NULL;
+ }
+
+ rst = tor_malloc_zero(sizeof(entry_guard_restriction_t));
+ rst->type = RST_OUTDATED_MD_DIRSERVER;
+
+ return rst;
+}
+
+/* Return True if <b>guard</b> obeys the exit restriction <b>rst</b>. */
+static int
+guard_obeys_exit_restriction(const entry_guard_t *guard,
+ const entry_guard_restriction_t *rst)
+{
+ tor_assert(rst->type == RST_EXIT_NODE);
+
+ // Exclude the exit ID and all of its family.
+ const node_t *node = node_get_by_id((const char*)rst->exclude_id);
+ if (node && guard_in_node_family(guard, node))
+ return 0;
+
+ return tor_memneq(guard->identity, rst->exclude_id, DIGEST_LEN);
+}
+
+/** Return True if <b>guard</b> should be used as a dirserver for fetching
+ * microdescriptors. */
+static int
+guard_obeys_md_dirserver_restriction(const entry_guard_t *guard)
+{
+ /* If this guard is an outdated dirserver, don't use it. */
+ if (microdesc_relay_is_outdated_dirserver(guard->identity)) {
+ log_info(LD_GENERAL, "Skipping %s dirserver: outdated",
+ hex_str(guard->identity, DIGEST_LEN));
+ return 0;
+ }
+
+ log_debug(LD_GENERAL, "%s dirserver obeys md restrictions",
+ hex_str(guard->identity, DIGEST_LEN));
+
+ return 1;
+}
+
/**
* Return true iff <b>guard</b> obeys the restrictions defined in <b>rst</b>.
* (If <b>rst</b> is NULL, there are no restrictions.)
@@ -1472,13 +1561,14 @@ entry_guard_obeys_restriction(const entry_guard_t *guard,
if (! rst)
return 1; // No restriction? No problem.
- // Only one kind of restriction exists right now: excluding an exit
- // ID and all of its family.
- const node_t *node = node_get_by_id((const char*)rst->exclude_id);
- if (node && guard_in_node_family(guard, node))
- return 0;
+ if (rst->type == RST_EXIT_NODE) {
+ return guard_obeys_exit_restriction(guard, rst);
+ } else if (rst->type == RST_OUTDATED_MD_DIRSERVER) {
+ return guard_obeys_md_dirserver_restriction(guard);
+ }
- return tor_memneq(guard->identity, rst->exclude_id, DIGEST_LEN);
+ tor_assert_nonfatal_unreached();
+ return 0;
}
/**
@@ -2105,7 +2195,7 @@ entry_guard_has_higher_priority(entry_guard_t *a, entry_guard_t *b)
}
/** Release all storage held in <b>restriction</b> */
-static void
+STATIC void
entry_guard_restriction_free(entry_guard_restriction_t *rst)
{
tor_free(rst);
@@ -3358,8 +3448,8 @@ guards_choose_guard(cpath_build_state_t *state,
/* We're building to a targeted exit node, so that node can't be
* chosen as our guard for this circuit. Remember that fact in a
* restriction. */
- rst = tor_malloc_zero(sizeof(entry_guard_restriction_t));
- memcpy(rst->exclude_id, exit_id, DIGEST_LEN);
+ rst = guard_create_exit_restriction(exit_id);
+ tor_assert(rst);
}
if (entry_guard_pick_for_circuit(get_guard_selection_info(),
GUARD_USAGE_TRAFFIC,
@@ -3411,12 +3501,20 @@ remove_all_entry_guards(void)
/** Helper: pick a directory guard, with whatever algorithm is used. */
const node_t *
-guards_choose_dirguard(circuit_guard_state_t **guard_state_out)
+guards_choose_dirguard(uint8_t dir_purpose,
+ circuit_guard_state_t **guard_state_out)
{
const node_t *r = NULL;
+ entry_guard_restriction_t *rst = NULL;
+
+ /* If we are fetching microdescs, don't query outdated dirservers. */
+ if (dir_purpose == DIR_PURPOSE_FETCH_MICRODESC) {
+ rst = guard_create_dirserver_md_restriction();
+ }
+
if (entry_guard_pick_for_circuit(get_guard_selection_info(),
GUARD_USAGE_DIRGUARD,
- NULL,
+ rst,
&r,
guard_state_out) < 0) {
tor_assert(r == NULL);
diff --git a/src/or/entrynodes.h b/src/or/entrynodes.h
index 86f0517df2..9d1293d02a 100644
--- a/src/or/entrynodes.h
+++ b/src/or/entrynodes.h
@@ -272,22 +272,28 @@ struct guard_selection_s {
struct entry_guard_handle_t;
+/** Types of restrictions we impose when picking guard nodes */
+typedef enum guard_restriction_type_t {
+ /* Don't pick the same guard node as our exit node (or its family) */
+ RST_EXIT_NODE = 0,
+ /* Don't pick dirguards that have previously shown to be outdated */
+ RST_OUTDATED_MD_DIRSERVER = 1
+} guard_restriction_type_t;
+
/**
* A restriction to remember which entry guards are off-limits for a given
* circuit.
*
- * Right now, we only use restrictions to block a single guard and its family
- * from being selected; this mechanism is designed to be more extensible in
- * the future, however.
- *
* Note: This mechanism is NOT for recording which guards are never to be
* used: only which guards cannot be used on <em>one particular circuit</em>.
*/
struct entry_guard_restriction_t {
- /**
- * The guard's RSA identity digest must not equal this; and it must not
- * be in the same family as any node with this digest.
- */
+ /* What type of restriction are we imposing? */
+ guard_restriction_type_t type;
+
+ /* In case of restriction type RST_EXIT_NODE, the guard's RSA identity
+ * digest must not equal this; and it must not be in the same family as any
+ * node with this digest. */
uint8_t exclude_id[DIGEST_LEN];
};
@@ -316,7 +322,8 @@ struct circuit_guard_state_t {
int guards_update_all(void);
const node_t *guards_choose_guard(cpath_build_state_t *state,
circuit_guard_state_t **guard_state_out);
-const node_t *guards_choose_dirguard(circuit_guard_state_t **guard_state_out);
+const node_t *guards_choose_dirguard(uint8_t dir_purpose,
+ circuit_guard_state_t **guard_state_out);
#if 1
/* XXXX NM I would prefer that all of this stuff be private to
@@ -518,7 +525,7 @@ STATIC void entry_guard_consider_retry(entry_guard_t *guard);
STATIC void make_guard_confirmed(guard_selection_t *gs, entry_guard_t *guard);
STATIC void entry_guards_update_confirmed(guard_selection_t *gs);
STATIC void entry_guards_update_primary(guard_selection_t *gs);
-STATIC int num_reachable_filtered_guards(guard_selection_t *gs,
+STATIC int num_reachable_filtered_guards(const guard_selection_t *gs,
const entry_guard_restriction_t *rst);
STATIC void sampled_guards_update_from_consensus(guard_selection_t *gs);
/**
@@ -554,6 +561,14 @@ STATIC unsigned entry_guards_note_guard_success(guard_selection_t *gs,
unsigned old_state);
STATIC int entry_guard_has_higher_priority(entry_guard_t *a, entry_guard_t *b);
STATIC char *getinfo_helper_format_single_entry_guard(const entry_guard_t *e);
+
+STATIC entry_guard_restriction_t *guard_create_exit_restriction(
+ const uint8_t *exit_id);
+
+STATIC entry_guard_restriction_t *guard_create_dirserver_md_restriction(void);
+
+STATIC void entry_guard_restriction_free(entry_guard_restriction_t *rst);
+
#endif /* defined(ENTRYNODES_PRIVATE) */
void remove_all_entry_guards_for_guard_selection(guard_selection_t *gs);
diff --git a/src/or/git_revision.h b/src/or/git_revision.h
index 1ceaeedf16..5613cb4335 100644
--- a/src/or/git_revision.h
+++ b/src/or/git_revision.h
@@ -8,5 +8,5 @@
extern const char tor_git_revision[];
-#endif
+#endif /* !defined(TOR_GIT_REVISION_H) */
diff --git a/src/or/hs_cache.c b/src/or/hs_cache.c
index 3ebe13fb4d..b864a0f717 100644
--- a/src/or/hs_cache.c
+++ b/src/or/hs_cache.c
@@ -706,6 +706,24 @@ cache_clean_v3_as_client(time_t now)
}
/** Public API: Given the HS ed25519 identity public key in <b>key</b>, return
+ * its HS encoded descriptor if it's stored in our cache, or NULL if not. */
+const char *
+hs_cache_lookup_encoded_as_client(const ed25519_public_key_t *key)
+{
+ hs_cache_client_descriptor_t *cached_desc = NULL;
+
+ tor_assert(key);
+
+ cached_desc = lookup_v3_desc_as_client(key->pubkey);
+ if (cached_desc) {
+ tor_assert(cached_desc->encoded_desc);
+ return cached_desc->encoded_desc;
+ }
+
+ return NULL;
+}
+
+/** Public API: Given the HS ed25519 identity public key in <b>key</b>, return
* its HS descriptor if it's stored in our cache, or NULL if not. */
const hs_descriptor_t *
hs_cache_lookup_as_client(const ed25519_public_key_t *key)
diff --git a/src/or/hs_cache.h b/src/or/hs_cache.h
index 2dcc518a71..a141634cc4 100644
--- a/src/or/hs_cache.h
+++ b/src/or/hs_cache.h
@@ -81,6 +81,8 @@ int hs_cache_lookup_as_dir(uint32_t version, const char *query,
const hs_descriptor_t *
hs_cache_lookup_as_client(const ed25519_public_key_t *key);
+const char *
+hs_cache_lookup_encoded_as_client(const ed25519_public_key_t *key);
int hs_cache_store_as_client(const char *desc_str,
const ed25519_public_key_t *identity_pk);
void hs_cache_clean_as_client(time_t now);
diff --git a/src/or/hs_circuit.c b/src/or/hs_circuit.c
index 26fe22eb7b..a232a40c80 100644
--- a/src/or/hs_circuit.c
+++ b/src/or/hs_circuit.c
@@ -617,6 +617,7 @@ get_lspecs_from_node(const node_t *node, smartlist_t *lspecs)
link_specifier_set_un_ipv6_port(ls, ap.port);
/* Sixteen bytes IPv6 and two bytes port. */
link_specifier_set_ls_len(ls, addr_len + sizeof(ap.port));
+ smartlist_add(lspecs, ls);
}
}
@@ -1100,9 +1101,19 @@ hs_circ_send_introduce1(origin_circuit_t *intro_circ,
tor_assert(ip);
tor_assert(subcredential);
+ /* It is undefined behavior in hs_cell_introduce1_data_clear() if intro1_data
+ * has been declared on the stack but not initialized. Here, we set it to 0.
+ */
+ memset(&intro1_data, 0, sizeof(hs_cell_introduce1_data_t));
+
/* This takes various objects in order to populate the introduce1 data
* object which is used to build the content of the cell. */
const node_t *exit_node = build_state_get_exit_node(rend_circ->build_state);
+ if (exit_node == NULL) {
+ log_info(LD_REND, "Unable to get rendezvous point for circuit %u. "
+ "Failing.", TO_CIRCUIT(intro_circ)->n_circ_id);
+ goto done;
+ }
setup_introduce1_data(ip, exit_node, subcredential, &intro1_data);
/* If we didn't get any link specifiers, it's because our node was
* bad. */
diff --git a/src/or/hs_circuit.h b/src/or/hs_circuit.h
index 0a1186dbaa..b92fb4e494 100644
--- a/src/or/hs_circuit.h
+++ b/src/or/hs_circuit.h
@@ -67,7 +67,7 @@ create_rp_circuit_identifier(const hs_service_t *service,
const curve25519_public_key_t *server_pk,
const hs_ntor_rend_cell_keys_t *keys);
-#endif
+#endif /* defined(HS_CIRCUIT_PRIVATE) */
#endif /* !defined(TOR_HS_CIRCUIT_H) */
diff --git a/src/or/hs_client.c b/src/or/hs_client.c
index 9ac653c721..666860155c 100644
--- a/src/or/hs_client.c
+++ b/src/or/hs_client.c
@@ -21,6 +21,7 @@
#include "config.h"
#include "directory.h"
#include "hs_client.h"
+#include "hs_control.h"
#include "router.h"
#include "routerset.h"
#include "circuitlist.h"
@@ -349,6 +350,10 @@ directory_launch_v3_desc_fetch(const ed25519_public_key_t *onion_identity_pk,
safe_str_client(base64_blinded_pubkey),
safe_str_client(routerstatus_describe(hsdir)));
+ /* Fire a REQUESTED event on the control port. */
+ hs_control_desc_event_requested(onion_identity_pk, base64_blinded_pubkey,
+ hsdir);
+
/* Cleanup memory. */
memwipe(&blinded_pubkey, 0, sizeof(blinded_pubkey));
memwipe(base64_blinded_pubkey, 0, sizeof(base64_blinded_pubkey));
diff --git a/src/or/hs_common.h b/src/or/hs_common.h
index c95e59a6f8..58fcd1b93c 100644
--- a/src/or/hs_common.h
+++ b/src/or/hs_common.h
@@ -130,6 +130,17 @@ typedef enum {
HS_AUTH_KEY_TYPE_ED25519 = 2,
} hs_auth_key_type_t;
+/* Return value when adding an ephemeral service through the ADD_ONION
+ * control port command. Both v2 and v3 share these. */
+typedef enum {
+ RSAE_BADAUTH = -5, /**< Invalid auth_type/auth_clients */
+ RSAE_BADVIRTPORT = -4, /**< Invalid VIRTPORT/TARGET(s) */
+ RSAE_ADDREXISTS = -3, /**< Onion address collision */
+ RSAE_BADPRIVKEY = -2, /**< Invalid public key */
+ RSAE_INTERNAL = -1, /**< Internal error */
+ RSAE_OKAY = 0 /**< Service added as expected */
+} hs_service_add_ephemeral_status_t;
+
/* Represents the mapping from a virtual port of a rendezvous service to a
* real port on some IP. */
typedef struct rend_service_port_config_t {
diff --git a/src/or/hs_control.c b/src/or/hs_control.c
new file mode 100644
index 0000000000..1b1fe78575
--- /dev/null
+++ b/src/or/hs_control.c
@@ -0,0 +1,256 @@
+/* Copyright (c) 2017, The Tor Project, Inc. */
+/* See LICENSE for licensing information */
+
+/**
+ * \file hs_control.c
+ * \brief Contains control port event related code.
+ **/
+
+#include "or.h"
+#include "control.h"
+#include "hs_common.h"
+#include "hs_control.h"
+#include "hs_descriptor.h"
+#include "hs_service.h"
+#include "nodelist.h"
+
+/* Send on the control port the "HS_DESC REQUESTED [...]" event.
+ *
+ * The onion_pk is the onion service public key, base64_blinded_pk is the
+ * base64 encoded blinded key for the service and hsdir_rs is the routerstatus
+ * object of the HSDir that this request is for. */
+void
+hs_control_desc_event_requested(const ed25519_public_key_t *onion_pk,
+ const char *base64_blinded_pk,
+ const routerstatus_t *hsdir_rs)
+{
+ char onion_address[HS_SERVICE_ADDR_LEN_BASE32 + 1];
+ const uint8_t *hsdir_index;
+ const node_t *hsdir_node;
+
+ tor_assert(onion_pk);
+ tor_assert(base64_blinded_pk);
+ tor_assert(hsdir_rs);
+
+ hs_build_address(onion_pk, HS_VERSION_THREE, onion_address);
+
+ /* Get the node from the routerstatus object to get the HSDir index used for
+ * this request. We can't have a routerstatus entry without a node and we
+ * can't pick a node without an hsdir_index. */
+ hsdir_node = node_get_by_id(hsdir_rs->identity_digest);
+ tor_assert(hsdir_node);
+ tor_assert(hsdir_node->hsdir_index);
+ /* This is a fetch event. */
+ hsdir_index = hsdir_node->hsdir_index->fetch;
+
+ /* Trigger the event. */
+ control_event_hs_descriptor_requested(onion_address, REND_NO_AUTH,
+ hsdir_rs->identity_digest,
+ base64_blinded_pk,
+ hex_str((const char *) hsdir_index,
+ DIGEST256_LEN));
+ memwipe(onion_address, 0, sizeof(onion_address));
+}
+
+/* Send on the control port the "HS_DESC FAILED [...]" event.
+ *
+ * Using a directory connection identifier, the HSDir identity digest and a
+ * reason for the failure. None can be NULL. */
+void
+hs_control_desc_event_failed(const hs_ident_dir_conn_t *ident,
+ const char *hsdir_id_digest,
+ const char *reason)
+{
+ char onion_address[HS_SERVICE_ADDR_LEN_BASE32 + 1];
+ char base64_blinded_pk[ED25519_BASE64_LEN + 1];
+
+ tor_assert(ident);
+ tor_assert(hsdir_id_digest);
+ tor_assert(reason);
+
+ /* Build onion address and encoded blinded key. */
+ IF_BUG_ONCE(ed25519_public_to_base64(base64_blinded_pk,
+ &ident->blinded_pk) < 0) {
+ return;
+ }
+ hs_build_address(&ident->identity_pk, HS_VERSION_THREE, onion_address);
+
+ control_event_hsv3_descriptor_failed(onion_address, base64_blinded_pk,
+ hsdir_id_digest, reason);
+}
+
+/* Send on the control port the "HS_DESC RECEIVED [...]" event.
+ *
+ * Using a directory connection identifier and the HSDir identity digest.
+ * None can be NULL. */
+void
+hs_control_desc_event_received(const hs_ident_dir_conn_t *ident,
+ const char *hsdir_id_digest)
+{
+ char onion_address[HS_SERVICE_ADDR_LEN_BASE32 + 1];
+ char base64_blinded_pk[ED25519_BASE64_LEN + 1];
+
+ tor_assert(ident);
+ tor_assert(hsdir_id_digest);
+
+ /* Build onion address and encoded blinded key. */
+ IF_BUG_ONCE(ed25519_public_to_base64(base64_blinded_pk,
+ &ident->blinded_pk) < 0) {
+ return;
+ }
+ hs_build_address(&ident->identity_pk, HS_VERSION_THREE, onion_address);
+
+ control_event_hsv3_descriptor_received(onion_address, base64_blinded_pk,
+ hsdir_id_digest);
+}
+
+/* Send on the control port the "HS_DESC CREATED [...]" event.
+ *
+ * Using the onion address of the descriptor's service and the blinded public
+ * key of the descriptor as a descriptor ID. None can be NULL. */
+void
+hs_control_desc_event_created(const char *onion_address,
+ const ed25519_public_key_t *blinded_pk)
+{
+ char base64_blinded_pk[ED25519_BASE64_LEN + 1];
+
+ tor_assert(onion_address);
+ tor_assert(blinded_pk);
+
+ /* Build base64 encoded blinded key. */
+ IF_BUG_ONCE(ed25519_public_to_base64(base64_blinded_pk, blinded_pk) < 0) {
+ return;
+ }
+
+ /* Version 3 doesn't use the replica number in its descriptor ID computation
+ * so we pass negative value so the control port subsystem can ignore it. */
+ control_event_hs_descriptor_created(onion_address, base64_blinded_pk, -1);
+}
+
+/* Send on the control port the "HS_DESC UPLOAD [...]" event.
+ *
+ * Using the onion address of the descriptor's service, the HSDir identity
+ * digest, the blinded public key of the descriptor as a descriptor ID and the
+ * HSDir index for this particular request. None can be NULL. */
+void
+hs_control_desc_event_upload(const char *onion_address,
+ const char *hsdir_id_digest,
+ const ed25519_public_key_t *blinded_pk,
+ const uint8_t *hsdir_index)
+{
+ char base64_blinded_pk[ED25519_BASE64_LEN + 1];
+
+ tor_assert(onion_address);
+ tor_assert(hsdir_id_digest);
+ tor_assert(blinded_pk);
+ tor_assert(hsdir_index);
+
+ /* Build base64 encoded blinded key. */
+ IF_BUG_ONCE(ed25519_public_to_base64(base64_blinded_pk, blinded_pk) < 0) {
+ return;
+ }
+
+ control_event_hs_descriptor_upload(onion_address, hsdir_id_digest,
+ base64_blinded_pk,
+ hex_str((const char *) hsdir_index,
+ DIGEST256_LEN));
+}
+
+/* Send on the control port the "HS_DESC UPLOADED [...]" event.
+ *
+ * Using the directory connection identifier and the HSDir identity digest.
+ * None can be NULL. */
+void
+hs_control_desc_event_uploaded(const hs_ident_dir_conn_t *ident,
+ const char *hsdir_id_digest)
+{
+ char onion_address[HS_SERVICE_ADDR_LEN_BASE32 + 1];
+
+ tor_assert(ident);
+ tor_assert(hsdir_id_digest);
+
+ hs_build_address(&ident->identity_pk, HS_VERSION_THREE, onion_address);
+
+ control_event_hs_descriptor_uploaded(hsdir_id_digest, onion_address);
+}
+
+/* Send on the control port the "HS_DESC_CONTENT [...]" event.
+ *
+ * Using the directory connection identifier, the HSDir identity digest and
+ * the body of the descriptor (as it was received from the directory). None
+ * can be NULL. */
+void
+hs_control_desc_event_content(const hs_ident_dir_conn_t *ident,
+ const char *hsdir_id_digest,
+ const char *body)
+{
+ char onion_address[HS_SERVICE_ADDR_LEN_BASE32 + 1];
+ char base64_blinded_pk[ED25519_BASE64_LEN + 1];
+
+ tor_assert(ident);
+ tor_assert(hsdir_id_digest);
+
+ /* Build onion address and encoded blinded key. */
+ IF_BUG_ONCE(ed25519_public_to_base64(base64_blinded_pk,
+ &ident->blinded_pk) < 0) {
+ return;
+ }
+ hs_build_address(&ident->identity_pk, HS_VERSION_THREE, onion_address);
+
+ control_event_hs_descriptor_content(onion_address, base64_blinded_pk,
+ hsdir_id_digest, body);
+}
+
+/* Handle the "HSPOST [...]" command. The body is an encoded descriptor for
+ * the given onion_address. The descriptor will be uploaded to each directory
+ * in hsdirs_rs. If NULL, the responsible directories for the current time
+ * period will be selected.
+ *
+ * Return -1 on if the descriptor plaintext section is not decodable. Else, 0
+ * on success. */
+int
+hs_control_hspost_command(const char *body, const char *onion_address,
+ const smartlist_t *hsdirs_rs)
+{
+ int ret = -1;
+ ed25519_public_key_t identity_pk;
+ hs_desc_plaintext_data_t plaintext;
+ smartlist_t *hsdirs = NULL;
+
+ tor_assert(body);
+ tor_assert(onion_address);
+
+ /* This can't fail because we require the caller to pass us a valid onion
+ * address that has passed hs_address_is_valid(). */
+ hs_parse_address(onion_address, &identity_pk, NULL, NULL);
+
+ /* Only decode the plaintext part which is what the directory will do to
+ * validate before caching. */
+ if (hs_desc_decode_plaintext(body, &plaintext) < 0) {
+ goto done;
+ }
+
+ /* No HSDir(s) given, we'll compute what the current ones should be. */
+ if (hsdirs_rs == NULL) {
+ hsdirs = smartlist_new();
+ hs_get_responsible_hsdirs(&plaintext.blinded_pubkey,
+ hs_get_time_period_num(0),
+ 0, /* Always the current descriptor which uses
+ * the first hsdir index. */
+ 0, /* It is for storing on a directory. */
+ hsdirs);
+ hsdirs_rs = hsdirs;
+ }
+
+ SMARTLIST_FOREACH_BEGIN(hsdirs_rs, const routerstatus_t *, rs) {
+ hs_service_upload_desc_to_dir(body, plaintext.version, &identity_pk,
+ &plaintext.blinded_pubkey, rs);
+ } SMARTLIST_FOREACH_END(rs);
+ ret = 0;
+
+ done:
+ /* We don't have ownership of the objects in this list. */
+ smartlist_free(hsdirs);
+ return ret;
+}
+
diff --git a/src/or/hs_control.h b/src/or/hs_control.h
new file mode 100644
index 0000000000..95c46e655e
--- /dev/null
+++ b/src/or/hs_control.h
@@ -0,0 +1,52 @@
+/* Copyright (c) 2017, The Tor Project, Inc. */
+/* See LICENSE for licensing information */
+
+/**
+ * \file hs_control.h
+ * \brief Header file containing control port event related code.
+ **/
+
+#ifndef TOR_HS_CONTROL_H
+#define TOR_HS_CONTROL_H
+
+#include "hs_ident.h"
+
+/* Event "HS_DESC REQUESTED [...]" */
+void hs_control_desc_event_requested(const ed25519_public_key_t *onion_pk,
+ const char *base64_blinded_pk,
+ const routerstatus_t *hsdir_rs);
+
+/* Event "HS_DESC FAILED [...]" */
+void hs_control_desc_event_failed(const hs_ident_dir_conn_t *ident,
+ const char *hsdir_id_digest,
+ const char *reason);
+
+/* Event "HS_DESC RECEIVED [...]" */
+void hs_control_desc_event_received(const hs_ident_dir_conn_t *ident,
+ const char *hsdir_id_digest);
+
+/* Event "HS_DESC CREATED [...]" */
+void hs_control_desc_event_created(const char *onion_address,
+ const ed25519_public_key_t *blinded_pk);
+
+/* Event "HS_DESC UPLOAD [...]" */
+void hs_control_desc_event_upload(const char *onion_address,
+ const char *hsdir_id_digest,
+ const ed25519_public_key_t *blinded_pk,
+ const uint8_t *hsdir_index);
+
+/* Event "HS_DESC UPLOADED [...]" */
+void hs_control_desc_event_uploaded(const hs_ident_dir_conn_t *ident,
+ const char *hsdir_id_digest);
+
+/* Event "HS_DESC_CONTENT [...]" */
+void hs_control_desc_event_content(const hs_ident_dir_conn_t *ident,
+ const char *hsdir_id_digest,
+ const char *body);
+
+/* Command "HSPOST [...]" */
+int hs_control_hspost_command(const char *body, const char *onion_address,
+ const smartlist_t *hsdirs_rs);
+
+#endif /* !defined(TOR_HS_CONTROL_H) */
+
diff --git a/src/or/hs_service.c b/src/or/hs_service.c
index 8e2f52dcf0..f65b59ae1c 100644
--- a/src/or/hs_service.c
+++ b/src/or/hs_service.c
@@ -30,6 +30,7 @@
#include "hs_circuit.h"
#include "hs_common.h"
#include "hs_config.h"
+#include "hs_control.h"
#include "hs_circuit.h"
#include "hs_descriptor.h"
#include "hs_ident.h"
@@ -1431,6 +1432,9 @@ build_service_descriptor(hs_service_t *service, time_t now,
/* Assign newly built descriptor to the next slot. */
*desc_out = desc;
+ /* Fire a CREATED control port event. */
+ hs_control_desc_event_created(service->onion_address,
+ &desc->blinded_kp.pubkey);
return;
err:
@@ -2199,16 +2203,12 @@ static void
upload_descriptor_to_hsdir(const hs_service_t *service,
hs_service_descriptor_t *desc, const node_t *hsdir)
{
- char version_str[4] = {0}, *encoded_desc = NULL;
- directory_request_t *dir_req;
- hs_ident_dir_conn_t ident;
+ char *encoded_desc = NULL;
tor_assert(service);
tor_assert(desc);
tor_assert(hsdir);
- memset(&ident, 0, sizeof(ident));
-
/* Let's avoid doing that if tor is configured to not publish. */
if (!get_options()->PublishHidServDescriptors) {
log_info(LD_REND, "Service %s not publishing descriptor. "
@@ -2224,29 +2224,10 @@ upload_descriptor_to_hsdir(const hs_service_t *service,
goto end;
}
- /* Setup the connection identifier. */
- hs_ident_dir_conn_init(&service->keys.identity_pk, &desc->blinded_kp.pubkey,
- &ident);
-
- /* This is our resource when uploading which is used to construct the URL
- * with the version number: "/tor/hs/<version>/publish". */
- tor_snprintf(version_str, sizeof(version_str), "%u",
- service->config.version);
-
- /* Build the directory request for this HSDir. */
- dir_req = directory_request_new(DIR_PURPOSE_UPLOAD_HSDESC);
- directory_request_set_routerstatus(dir_req, hsdir->rs);
- directory_request_set_indirection(dir_req, DIRIND_ANONYMOUS);
- directory_request_set_resource(dir_req, version_str);
- directory_request_set_payload(dir_req, encoded_desc,
- strlen(encoded_desc));
- /* The ident object is copied over the directory connection object once
- * the directory request is initiated. */
- directory_request_upload_set_hs_ident(dir_req, &ident);
-
- /* Initiate the directory request to the hsdir.*/
- directory_initiate_request(dir_req);
- directory_request_free(dir_req);
+ /* Time to upload the descriptor to the directory. */
+ hs_service_upload_desc_to_dir(encoded_desc, service->config.version,
+ &service->keys.identity_pk,
+ &desc->blinded_kp.pubkey, hsdir->rs);
/* Add this node to previous_hsdirs list */
service_desc_note_upload(desc, hsdir);
@@ -2263,9 +2244,12 @@ upload_descriptor_to_hsdir(const hs_service_t *service,
desc->desc->plaintext_data.revision_counter,
safe_str_client(node_describe(hsdir)),
safe_str_client(hex_str((const char *) index, 32)));
+
+ /* Fire a UPLOAD control port event. */
+ hs_control_desc_event_upload(service->onion_address, hsdir->identity,
+ &desc->blinded_kp.pubkey, index);
}
- /* XXX: Inform control port of the upload event (#20699). */
end:
tor_free(encoded_desc);
return;
@@ -2900,6 +2884,205 @@ service_add_fnames_to_list(const hs_service_t *service, smartlist_t *list)
/* Public API */
/* ========== */
+/* Upload an encoded descriptor in encoded_desc of the given version. This
+ * descriptor is for the service identity_pk and blinded_pk used to setup the
+ * directory connection identifier. It is uploaded to the directory hsdir_rs
+ * routerstatus_t object.
+ *
+ * NOTE: This function does NOT check for PublishHidServDescriptors because it
+ * is only used by the control port command HSPOST outside of this subsystem.
+ * Inside this code, upload_descriptor_to_hsdir() should be used. */
+void
+hs_service_upload_desc_to_dir(const char *encoded_desc,
+ const uint8_t version,
+ const ed25519_public_key_t *identity_pk,
+ const ed25519_public_key_t *blinded_pk,
+ const routerstatus_t *hsdir_rs)
+{
+ char version_str[4] = {0};
+ directory_request_t *dir_req;
+ hs_ident_dir_conn_t ident;
+
+ tor_assert(encoded_desc);
+ tor_assert(identity_pk);
+ tor_assert(blinded_pk);
+ tor_assert(hsdir_rs);
+
+ /* Setup the connection identifier. */
+ memset(&ident, 0, sizeof(ident));
+ hs_ident_dir_conn_init(identity_pk, blinded_pk, &ident);
+
+ /* This is our resource when uploading which is used to construct the URL
+ * with the version number: "/tor/hs/<version>/publish". */
+ tor_snprintf(version_str, sizeof(version_str), "%u", version);
+
+ /* Build the directory request for this HSDir. */
+ dir_req = directory_request_new(DIR_PURPOSE_UPLOAD_HSDESC);
+ directory_request_set_routerstatus(dir_req, hsdir_rs);
+ directory_request_set_indirection(dir_req, DIRIND_ANONYMOUS);
+ directory_request_set_resource(dir_req, version_str);
+ directory_request_set_payload(dir_req, encoded_desc,
+ strlen(encoded_desc));
+ /* The ident object is copied over the directory connection object once
+ * the directory request is initiated. */
+ directory_request_upload_set_hs_ident(dir_req, &ident);
+
+ /* Initiate the directory request to the hsdir.*/
+ directory_initiate_request(dir_req);
+ directory_request_free(dir_req);
+}
+
+/* Add the ephemeral service using the secret key sk and ports. Both max
+ * streams parameter will be set in the newly created service.
+ *
+ * Ownership of sk and ports is passed to this routine. Regardless of
+ * success/failure, callers should not touch these values after calling this
+ * routine, and may assume that correct cleanup has been done on failure.
+ *
+ * Return an appropriate hs_service_add_ephemeral_status_t. */
+hs_service_add_ephemeral_status_t
+hs_service_add_ephemeral(ed25519_secret_key_t *sk, smartlist_t *ports,
+ int max_streams_per_rdv_circuit,
+ int max_streams_close_circuit, char **address_out)
+{
+ hs_service_add_ephemeral_status_t ret;
+ hs_service_t *service = NULL;
+
+ tor_assert(sk);
+ tor_assert(ports);
+ tor_assert(address_out);
+
+ service = hs_service_new(get_options());
+
+ /* Setup the service configuration with specifics. A default service is
+ * HS_VERSION_TWO so explicitely set it. */
+ service->config.version = HS_VERSION_THREE;
+ service->config.max_streams_per_rdv_circuit = max_streams_per_rdv_circuit;
+ service->config.max_streams_close_circuit = !!max_streams_close_circuit;
+ service->config.is_ephemeral = 1;
+ smartlist_free(service->config.ports);
+ service->config.ports = ports;
+
+ /* Handle the keys. */
+ memcpy(&service->keys.identity_sk, sk, sizeof(service->keys.identity_sk));
+ if (ed25519_public_key_generate(&service->keys.identity_pk,
+ &service->keys.identity_sk) < 0) {
+ log_warn(LD_CONFIG, "Unable to generate ed25519 public key"
+ "for v3 service.");
+ ret = RSAE_BADPRIVKEY;
+ goto err;
+ }
+
+ /* Make sure we have at least one port. */
+ if (smartlist_len(service->config.ports) == 0) {
+ log_warn(LD_CONFIG, "At least one VIRTPORT/TARGET must be specified "
+ "for v3 service.");
+ ret = RSAE_BADVIRTPORT;
+ goto err;
+ }
+
+ /* The only way the registration can fail is if the service public key
+ * already exists. */
+ if (BUG(register_service(hs_service_map, service) < 0)) {
+ log_warn(LD_CONFIG, "Onion Service private key collides with an "
+ "existing v3 service.");
+ ret = RSAE_ADDREXISTS;
+ goto err;
+ }
+
+ /* Last step is to build the onion address. */
+ hs_build_address(&service->keys.identity_pk,
+ (uint8_t) service->config.version,
+ service->onion_address);
+ *address_out = tor_strdup(service->onion_address);
+
+ log_info(LD_CONFIG, "Added ephemeral v3 onion service: %s",
+ safe_str_client(service->onion_address));
+ ret = RSAE_OKAY;
+ goto end;
+
+ err:
+ hs_service_free(service);
+
+ end:
+ memwipe(sk, 0, sizeof(ed25519_secret_key_t));
+ tor_free(sk);
+ return ret;
+}
+
+/* For the given onion address, delete the ephemeral service. Return 0 on
+ * success else -1 on error. */
+int
+hs_service_del_ephemeral(const char *address)
+{
+ uint8_t version;
+ ed25519_public_key_t pk;
+ hs_service_t *service = NULL;
+
+ tor_assert(address);
+
+ if (hs_parse_address(address, &pk, NULL, &version) < 0) {
+ log_warn(LD_CONFIG, "Requested malformed v3 onion address for removal.");
+ goto err;
+ }
+
+ if (version != HS_VERSION_THREE) {
+ log_warn(LD_CONFIG, "Requested version of onion address for removal "
+ "is not supported.");
+ goto err;
+ }
+
+ service = find_service(hs_service_map, &pk);
+ if (service == NULL) {
+ log_warn(LD_CONFIG, "Requested non-existent v3 hidden service for "
+ "removal.");
+ goto err;
+ }
+
+ if (!service->config.is_ephemeral) {
+ log_warn(LD_CONFIG, "Requested non-ephemeral v3 hidden service for "
+ "removal.");
+ goto err;
+ }
+
+ /* Close circuits, remove from map and finally free. */
+ close_service_circuits(service);
+ remove_service(hs_service_map, service);
+ hs_service_free(service);
+
+ log_info(LD_CONFIG, "Removed ephemeral v3 hidden service: %s",
+ safe_str_client(address));
+ return 0;
+
+ err:
+ return -1;
+}
+
+/* Using the ed25519 public key pk, find a service for that key and return the
+ * current encoded descriptor as a newly allocated string or NULL if not
+ * found. This is used by the control port subsystem. */
+char *
+hs_service_lookup_current_desc(const ed25519_public_key_t *pk)
+{
+ const hs_service_t *service;
+
+ tor_assert(pk);
+
+ service = find_service(hs_service_map, pk);
+ if (service && service->desc_current) {
+ char *encoded_desc = NULL;
+ /* No matter what is the result (which should never be a failure), return
+ * the encoded variable, if success it will contain the right thing else
+ * it will be NULL. */
+ hs_desc_encode_descriptor(service->desc_current->desc,
+ &service->desc_current->signing_kp,
+ &encoded_desc);
+ return encoded_desc;
+ }
+
+ return NULL;
+}
+
/* Return the number of service we have configured and usable. */
unsigned int
hs_service_get_num_services(void)
@@ -2928,7 +3111,9 @@ hs_service_intro_circ_has_closed(origin_circuit_t *circ)
get_objects_from_ident(circ->hs_ident, &service, &ip, &desc);
if (service == NULL) {
- log_warn(LD_REND, "Unable to find any hidden service associated "
+ /* This is possible if the circuits are closed and the service is
+ * immediately deleted. */
+ log_info(LD_REND, "Unable to find any hidden service associated "
"identity key %s on intro circuit %u.",
ed25519_fmt(&circ->hs_ident->identity_pk),
TO_CIRCUIT(circ)->n_circ_id);
diff --git a/src/or/hs_service.h b/src/or/hs_service.h
index ed1053d850..678f24b0a2 100644
--- a/src/or/hs_service.h
+++ b/src/or/hs_service.h
@@ -271,6 +271,21 @@ int hs_service_receive_introduce2(origin_circuit_t *circ,
void hs_service_intro_circ_has_closed(origin_circuit_t *circ);
+char *hs_service_lookup_current_desc(const ed25519_public_key_t *pk);
+
+hs_service_add_ephemeral_status_t
+hs_service_add_ephemeral(ed25519_secret_key_t *sk, smartlist_t *ports,
+ int max_streams_per_rdv_circuit,
+ int max_streams_close_circuit, char **address_out);
+int hs_service_del_ephemeral(const char *address);
+
+/* Used outside of the HS subsystem by the control port command HSPOST. */
+void hs_service_upload_desc_to_dir(const char *encoded_desc,
+ const uint8_t version,
+ const ed25519_public_key_t *identity_pk,
+ const ed25519_public_key_t *blinded_pk,
+ const routerstatus_t *hsdir_rs);
+
#ifdef HS_SERVICE_PRIVATE
#ifdef TOR_UNIT_TESTS
diff --git a/src/or/include.am b/src/or/include.am
index b783f4855a..1c66cd2de3 100644
--- a/src/or/include.am
+++ b/src/or/include.am
@@ -60,6 +60,7 @@ LIBTOR_A_SOURCES = \
src/or/hs_client.c \
src/or/hs_common.c \
src/or/hs_config.c \
+ src/or/hs_control.c \
src/or/hs_descriptor.c \
src/or/hs_ident.c \
src/or/hs_intropoint.c \
@@ -196,11 +197,12 @@ ORHEADERS = \
src/or/hibernate.h \
src/or/hs_cache.h \
src/or/hs_cell.h \
- src/or/hs_config.h \
src/or/hs_circuit.h \
src/or/hs_circuitmap.h \
src/or/hs_client.h \
src/or/hs_common.h \
+ src/or/hs_config.h \
+ src/or/hs_control.h \
src/or/hs_descriptor.h \
src/or/hs_ident.h \
src/or/hs_intropoint.h \
diff --git a/src/or/main.c b/src/or/main.c
index b70f47abeb..aae98dd8ab 100644
--- a/src/or/main.c
+++ b/src/or/main.c
@@ -3207,7 +3207,7 @@ tor_init(int argc, char *argv[])
log_notice(LD_GENERAL, "%s", rust_str);
}
tor_free(rust_str);
-#endif
+#endif /* defined(HAVE_RUST) */
if (network_init()<0) {
log_err(LD_BUG,"Error initializing network; exiting.");
diff --git a/src/or/microdesc.c b/src/or/microdesc.c
index 3fe5e933d0..d8a4660af1 100644
--- a/src/or/microdesc.c
+++ b/src/or/microdesc.c
@@ -74,6 +74,102 @@ HT_GENERATE2(microdesc_map, microdesc_t, node,
microdesc_hash_, microdesc_eq_, 0.6,
tor_reallocarray_, tor_free_)
+/************************* md fetch fail cache *****************************/
+
+/* If we end up with too many outdated dirservers, something probably went
+ * wrong so clean up the list. */
+#define TOO_MANY_OUTDATED_DIRSERVERS 30
+
+/** List of dirservers with outdated microdesc information. The smartlist is
+ * filled with the hex digests of outdated dirservers. */
+static smartlist_t *outdated_dirserver_list = NULL;
+
+/** Note that we failed to fetch a microdescriptor from the relay with
+ * <b>relay_digest</b> (of size DIGEST_LEN). */
+void
+microdesc_note_outdated_dirserver(const char *relay_digest)
+{
+ char relay_hexdigest[HEX_DIGEST_LEN+1];
+
+ /* Don't register outdated dirservers if we don't have a live consensus,
+ * since we might be trying to fetch microdescriptors that are not even
+ * currently active. */
+ if (!networkstatus_get_live_consensus(approx_time())) {
+ return;
+ }
+
+ if (!outdated_dirserver_list) {
+ outdated_dirserver_list = smartlist_new();
+ }
+
+ tor_assert(outdated_dirserver_list);
+
+ /* If the list grows too big, clean it up */
+ if (BUG(smartlist_len(outdated_dirserver_list) >
+ TOO_MANY_OUTDATED_DIRSERVERS)) {
+ microdesc_reset_outdated_dirservers_list();
+ }
+
+ /* Turn the binary relay digest to a hex since smartlists have better support
+ * for strings than digests. */
+ base16_encode(relay_hexdigest,sizeof(relay_hexdigest),
+ relay_digest, DIGEST_LEN);
+
+ /* Make sure we don't add a dirauth as an outdated dirserver */
+ if (router_get_trusteddirserver_by_digest(relay_digest)) {
+ log_info(LD_GENERAL, "Auth %s gave us outdated dirinfo.", relay_hexdigest);
+ return;
+ }
+
+ /* Don't double-add outdated dirservers */
+ if (smartlist_contains_string(outdated_dirserver_list, relay_hexdigest)) {
+ return;
+ }
+
+ /* Add it to the list of outdated dirservers */
+ smartlist_add_strdup(outdated_dirserver_list, relay_hexdigest);
+
+ log_info(LD_GENERAL, "Noted %s as outdated md dirserver", relay_hexdigest);
+}
+
+/** Return True if the relay with <b>relay_digest</b> (size DIGEST_LEN) is an
+ * outdated dirserver */
+int
+microdesc_relay_is_outdated_dirserver(const char *relay_digest)
+{
+ char relay_hexdigest[HEX_DIGEST_LEN+1];
+
+ if (!outdated_dirserver_list) {
+ return 0;
+ }
+
+ /* Convert identity digest to hex digest */
+ base16_encode(relay_hexdigest, sizeof(relay_hexdigest),
+ relay_digest, DIGEST_LEN);
+
+ /* Last time we tried to fetch microdescs, was this directory mirror missing
+ * any mds we asked for? */
+ if (smartlist_contains_string(outdated_dirserver_list, relay_hexdigest)) {
+ return 1;
+ }
+
+ return 0;
+}
+
+/** Reset the list of outdated dirservers. */
+void
+microdesc_reset_outdated_dirservers_list(void)
+{
+ if (!outdated_dirserver_list) {
+ return;
+ }
+
+ SMARTLIST_FOREACH(outdated_dirserver_list, char *, cp, tor_free(cp));
+ smartlist_clear(outdated_dirserver_list);
+}
+
+/****************************************************************************/
+
/** Write the body of <b>md</b> into <b>f</b>, with appropriate annotations.
* On success, return the total number of bytes written, and set
* *<b>annotation_len_out</b> to the number of bytes written as
@@ -789,6 +885,11 @@ microdesc_free_all(void)
tor_free(the_microdesc_cache->journal_fname);
tor_free(the_microdesc_cache);
}
+
+ if (outdated_dirserver_list) {
+ SMARTLIST_FOREACH(outdated_dirserver_list, char *, cp, tor_free(cp));
+ smartlist_free(outdated_dirserver_list);
+ }
}
/** If there is a microdescriptor in <b>cache</b> whose sha256 digest is
diff --git a/src/or/microdesc.h b/src/or/microdesc.h
index b40d66b3e3..1be12156a4 100644
--- a/src/or/microdesc.h
+++ b/src/or/microdesc.h
@@ -50,5 +50,9 @@ int we_fetch_microdescriptors(const or_options_t *options);
int we_fetch_router_descriptors(const or_options_t *options);
int we_use_microdescriptors_for_circuits(const or_options_t *options);
+void microdesc_note_outdated_dirserver(const char *relay_digest);
+int microdesc_relay_is_outdated_dirserver(const char *relay_digest);
+void microdesc_reset_outdated_dirservers_list(void);
+
#endif /* !defined(TOR_MICRODESC_H) */
diff --git a/src/or/networkstatus.c b/src/or/networkstatus.c
index d382cc8033..d426d4858e 100644
--- a/src/or/networkstatus.c
+++ b/src/or/networkstatus.c
@@ -2023,6 +2023,9 @@ networkstatus_set_current_consensus(const char *consensus,
tor_free(flavormsg);
}
+ /* We got a new consesus. Reset our md fetch fail cache */
+ microdesc_reset_outdated_dirservers_list();
+
router_dir_info_changed();
result = 0;
@@ -2206,7 +2209,9 @@ signed_descs_update_status_from_consensus_networkstatus(smartlist_t *descs)
char *
networkstatus_getinfo_helper_single(const routerstatus_t *rs)
{
- return routerstatus_format_entry(rs, NULL, NULL, NS_CONTROL_PORT, NULL);
+ return routerstatus_format_entry(rs, NULL, NULL, NS_CONTROL_PORT,
+ ROUTERSTATUS_FORMAT_NO_CONSENSUS_METHOD,
+ NULL);
}
/** Alloc and return a string describing routerstatuses for the most
diff --git a/src/or/protover.c b/src/or/protover.c
index ae955296e6..748c0c2f50 100644
--- a/src/or/protover.c
+++ b/src/or/protover.c
@@ -737,6 +737,11 @@ protocol_list_contains(const smartlist_t *protos,
const char *
protover_compute_for_old_tor(const char *version)
{
+ if (version == NULL) {
+ /* No known version; guess the oldest series that is still supported. */
+ version = "0.2.5.15";
+ }
+
if (tor_version_as_new_as(version,
FIRST_TOR_VERSION_TO_ADVERTISE_PROTOCOLS)) {
return "";
@@ -778,5 +783,5 @@ protover_free_all(void)
}
}
-#endif
+#endif /* !defined(HAVE_RUST) */
diff --git a/src/or/protover.h b/src/or/protover.h
index a4dbc8bfc2..83a728e626 100644
--- a/src/or/protover.h
+++ b/src/or/protover.h
@@ -84,7 +84,7 @@ STATIC const char *protocol_type_to_str(protocol_type_t pr);
STATIC int str_to_protocol_type(const char *s, protocol_type_t *pr_out);
STATIC void proto_entry_free(proto_entry_t *entry);
-#endif
+#endif /* !defined(HAVE_RUST) && defined(TOR_UNIT_TESTS) */
#endif /* defined(PROTOVER_PRIVATE) */
diff --git a/src/or/protover_rust.c b/src/or/protover_rust.c
index 0c409b1681..26e21cc1c5 100644
--- a/src/or/protover_rust.c
+++ b/src/or/protover_rust.c
@@ -15,5 +15,5 @@
/* Define for compatibility, used in main.c */
void protover_free_all(void) {}
-#endif
+#endif /* defined(HAVE_RUST) */
diff --git a/src/or/rendclient.c b/src/or/rendclient.c
index 3274819241..8291e5abfb 100644
--- a/src/or/rendclient.c
+++ b/src/or/rendclient.c
@@ -459,7 +459,8 @@ directory_get_from_hs_dir(const char *desc_id,
hs_dir = hs_pick_hsdir(responsible_dirs, desc_id_base32);
if (!hs_dir) {
/* No suitable hs dir can be found, stop right now. */
- control_event_hs_descriptor_failed(rend_query, NULL, "QUERY_NO_HSDIR");
+ control_event_hsv2_descriptor_failed(rend_query, NULL,
+ "QUERY_NO_HSDIR");
control_event_hs_descriptor_content(rend_data_get_address(rend_query),
desc_id_base32, NULL, NULL);
return 0;
@@ -482,7 +483,7 @@ directory_get_from_hs_dir(const char *desc_id,
REND_DESC_COOKIE_LEN,
0)<0) {
log_warn(LD_BUG, "Could not base64-encode descriptor cookie.");
- control_event_hs_descriptor_failed(rend_query, hsdir_fp, "BAD_DESC");
+ control_event_hsv2_descriptor_failed(rend_query, hsdir_fp, "BAD_DESC");
control_event_hs_descriptor_content(rend_data_get_address(rend_query),
desc_id_base32, hsdir_fp, NULL);
return 0;
@@ -515,9 +516,10 @@ directory_get_from_hs_dir(const char *desc_id,
(rend_data->auth_type == REND_NO_AUTH ? "[none]" :
escaped_safe_str_client(descriptor_cookie_base64)),
routerstatus_describe(hs_dir));
- control_event_hs_descriptor_requested(rend_query,
+ control_event_hs_descriptor_requested(rend_data->onion_address,
+ rend_data->auth_type,
hs_dir->identity_digest,
- desc_id_base32);
+ desc_id_base32, NULL);
return 1;
}
diff --git a/src/or/rendservice.c b/src/or/rendservice.c
index 60234a5c1f..15a0017d66 100644
--- a/src/or/rendservice.c
+++ b/src/or/rendservice.c
@@ -847,9 +847,9 @@ rend_config_service(const config_line_t *line_,
* after calling this routine, and may assume that correct cleanup has
* been done on failure.
*
- * Return an appropriate rend_service_add_ephemeral_status_t.
+ * Return an appropriate hs_service_add_ephemeral_status_t.
*/
-rend_service_add_ephemeral_status_t
+hs_service_add_ephemeral_status_t
rend_service_add_ephemeral(crypto_pk_t *pk,
smartlist_t *ports,
int max_streams_per_circuit,
@@ -1829,6 +1829,7 @@ rend_service_receive_introduction(origin_circuit_t *circuit,
time_t now = time(NULL);
time_t elapsed;
int replay;
+ ssize_t keylen;
/* Do some initial validation and logging before we parse the cell */
if (circuit->base_.purpose != CIRCUIT_PURPOSE_S_INTRO) {
@@ -1903,9 +1904,10 @@ rend_service_receive_introduction(origin_circuit_t *circuit,
}
/* check for replay of PK-encrypted portion. */
+ keylen = crypto_pk_keysize(intro_key);
replay = replaycache_add_test_and_elapsed(
intro_point->accepted_intro_rsa_parts,
- parsed_req->ciphertext, parsed_req->ciphertext_len,
+ parsed_req->ciphertext, MIN(parsed_req->ciphertext_len, keylen),
&elapsed);
if (replay) {
@@ -3574,7 +3576,7 @@ directory_post_to_hs_dir(rend_service_descriptor_t *renddesc,
"directories to post descriptors to.");
control_event_hs_descriptor_upload(service_id,
"UNKNOWN",
- "UNKNOWN");
+ "UNKNOWN", NULL);
goto done;
}
}
@@ -3629,7 +3631,7 @@ directory_post_to_hs_dir(rend_service_descriptor_t *renddesc,
hs_dir->or_port);
control_event_hs_descriptor_upload(service_id,
hs_dir->identity_digest,
- desc_id_base32);
+ desc_id_base32, NULL);
tor_free(hs_dir_ip);
/* Remember successful upload to this router for next time. */
if (!smartlist_contains_digest(successful_uploads,
@@ -3912,6 +3914,10 @@ remove_invalid_intro_points(rend_service_t *service,
log_info(LD_REND, "Expiring %s as intro point for %s.",
safe_str_client(extend_info_describe(intro->extend_info)),
safe_str_client(service->service_id));
+ /* We might have put it in the retry list if so, undo. */
+ if (retry_nodes) {
+ smartlist_remove(retry_nodes, intro);
+ }
smartlist_add(service->expiring_nodes, intro);
SMARTLIST_DEL_CURRENT(service->intro_nodes, intro);
/* Intro point is expired, we need a new one thus don't consider it
diff --git a/src/or/rendservice.h b/src/or/rendservice.h
index 5946e31861..15badce6ab 100644
--- a/src/or/rendservice.h
+++ b/src/or/rendservice.h
@@ -187,16 +187,7 @@ void rend_service_port_config_free(rend_service_port_config_t *p);
void rend_authorized_client_free(rend_authorized_client_t *client);
-/** Return value from rend_service_add_ephemeral. */
-typedef enum {
- RSAE_BADAUTH = -5, /**< Invalid auth_type/auth_clients */
- RSAE_BADVIRTPORT = -4, /**< Invalid VIRTPORT/TARGET(s) */
- RSAE_ADDREXISTS = -3, /**< Onion address collision */
- RSAE_BADPRIVKEY = -2, /**< Invalid public key */
- RSAE_INTERNAL = -1, /**< Internal error */
- RSAE_OKAY = 0 /**< Service added as expected */
-} rend_service_add_ephemeral_status_t;
-rend_service_add_ephemeral_status_t rend_service_add_ephemeral(crypto_pk_t *pk,
+hs_service_add_ephemeral_status_t rend_service_add_ephemeral(crypto_pk_t *pk,
smartlist_t *ports,
int max_streams_per_circuit,
int max_streams_close_circuit,
diff --git a/src/or/rephist.c b/src/or/rephist.c
index 51e800bc31..87b5a93713 100644
--- a/src/or/rephist.c
+++ b/src/or/rephist.c
@@ -1239,9 +1239,9 @@ rep_hist_load_mtbf_data(time_t now)
* 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 (4*60*60)
+#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 (24*60*60)
+#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)
diff --git a/src/or/router.c b/src/or/router.c
index 64bd9fdfcd..cd1848ee7b 100644
--- a/src/or/router.c
+++ b/src/or/router.c
@@ -2500,7 +2500,7 @@ mark_my_descriptor_dirty(const char *reason)
/** How frequently will we republish our descriptor because of large (factor
* of 2) shifts in estimated bandwidth? Note: We don't use this constant
* if our previous bandwidth estimate was exactly 0. */
-#define MAX_BANDWIDTH_CHANGE_FREQ (20*60)
+#define MAX_BANDWIDTH_CHANGE_FREQ (3*60*60)
/** Check whether bandwidth has changed a lot since the last time we announced
* bandwidth. If so, mark our descriptor dirty. */
diff --git a/src/or/routerlist.c b/src/or/routerlist.c
index bd200a783d..93c75ef583 100644
--- a/src/or/routerlist.c
+++ b/src/or/routerlist.c
@@ -2839,7 +2839,10 @@ router_choose_random_node(smartlist_t *excludedsmartlist,
}
} SMARTLIST_FOREACH_END(node);
- if ((r = routerlist_find_my_routerinfo()))
+ /* 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
+ * this is fine to at least try with our routerinfo_t object. */
+ if ((r = router_get_my_routerinfo()))
routerlist_add_node_and_family(excludednodes, r);
router_add_running_nodes_to_smartlist(sl, need_uptime, need_capacity,
@@ -5197,10 +5200,23 @@ update_consensus_router_descriptor_downloads(time_t now, int is_vote,
log_warn(LD_BUG, "Failed to re-parse a router.");
continue;
}
+ /* need to compute this now, since add_to_routerlist may free. */
+ char time_cert_expires[ISO_TIME_LEN+1];
+ format_iso_time(time_cert_expires, ri->cert_expiration_time);
+
r = router_add_to_routerlist(ri, &msg, 1, 0);
if (WRA_WAS_OUTDATED(r)) {
- log_warn(LD_DIR, "Couldn't add re-parsed router: %s",
+ log_warn(LD_DIR, "Couldn't add re-parsed router: %s. This isn't "
+ "usually a big deal, but you should make sure that your "
+ "clock and timezone are set correctly.",
msg?msg:"???");
+ if (r == ROUTER_CERTS_EXPIRED) {
+ char time_cons[ISO_TIME_LEN+1];
+ format_iso_time(time_cons, consensus->valid_after);
+ log_warn(LD_DIR, " (I'm looking at a consensus from %s; This "
+ "router's certificates began expiring at %s.)",
+ time_cons, time_cert_expires);
+ }
}
} SMARTLIST_FOREACH_END(sd);
routerlist_assert_ok(rl);
diff --git a/src/or/scheduler.c b/src/or/scheduler.c
index 510c16b217..cd047d5a75 100644
--- a/src/or/scheduler.c
+++ b/src/or/scheduler.c
@@ -171,6 +171,8 @@ STATIC smartlist_t *channels_pending = NULL;
*/
STATIC struct event *run_sched_ev = NULL;
+static int have_logged_kist_suddenly_disabled = 0;
+
/*****************************************************************************
* Scheduling system static function definitions
*
@@ -252,13 +254,32 @@ select_scheduler(void)
case SCHEDULER_KIST:
if (!scheduler_can_use_kist()) {
#ifdef HAVE_KIST_SUPPORT
- log_notice(LD_SCHED, "Scheduler type KIST has been disabled by "
- "the consensus or no kernel support.");
+ if (!have_logged_kist_suddenly_disabled) {
+ /* We should only log this once in most cases. If it was the kernel
+ * losing support for kist that caused scheduler_can_use_kist() to
+ * return false, then this flag makes sure we only log this message
+ * once. If it was the consensus that switched from "yes use kist"
+ * to "no don't use kist", then we still set the flag so we log
+ * once, but we unset the flag elsewhere if we ever can_use_kist()
+ * again.
+ */
+ have_logged_kist_suddenly_disabled = 1;
+ log_notice(LD_SCHED, "Scheduler type KIST has been disabled by "
+ "the consensus or no kernel support.");
+ }
#else /* !(defined(HAVE_KIST_SUPPORT)) */
log_info(LD_SCHED, "Scheduler type KIST not built in");
#endif /* defined(HAVE_KIST_SUPPORT) */
continue;
}
+ /* This flag will only get set in one of two cases:
+ * 1 - the kernel lost support for kist. In that case, we don't expect to
+ * ever end up here
+ * 2 - the consensus went from "yes use kist" to "no don't use kist".
+ * We might end up here if the consensus changes back to "yes", in which
+ * case we might want to warn the user again if it goes back to "no"
+ * yet again. Thus we unset the flag */
+ have_logged_kist_suddenly_disabled = 0;
new_scheduler = get_kist_scheduler();
scheduler_kist_set_full_mode();
goto end;
diff --git a/src/or/scheduler_kist.c b/src/or/scheduler_kist.c
index d1726ba345..fea92705d4 100644
--- a/src/or/scheduler_kist.c
+++ b/src/or/scheduler_kist.c
@@ -525,9 +525,13 @@ kist_scheduler_schedule(void)
monotime_get(&now);
/* If time is really monotonic, we can never have now being smaller than the
- * last scheduler run. The scheduler_last_run at first is set to 0. */
+ * last scheduler run. The scheduler_last_run at first is set to 0.
+ * Unfortunately, not all platforms guarantee monotonic time so we log at
+ * info level but don't make it more noisy. */
diff = monotime_diff_msec(&scheduler_last_run, &now);
- IF_BUG_ONCE(diff < 0) {
+ if (diff < 0) {
+ log_info(LD_SCHED, "Monotonic time between now and last run of scheduler "
+ "is negative: %" PRId64 ". Setting diff to 0.", diff);
diff = 0;
}
if (diff < sched_run_interval) {
diff --git a/src/or/tor_api_internal.h b/src/or/tor_api_internal.h
index a69ba76420..10b6278b7b 100644
--- a/src/or/tor_api_internal.h
+++ b/src/or/tor_api_internal.h
@@ -16,5 +16,5 @@ struct tor_main_configuration_t {
char **argv;
};
-#endif
+#endif /* !defined(TOR_API_INTERNAL_H) */
diff --git a/src/rust/tor_rust/include.am b/src/rust/tor_rust/include.am
index 90f37a9f1b..c02324cb77 100644
--- a/src/rust/tor_rust/include.am
+++ b/src/rust/tor_rust/include.am
@@ -2,17 +2,23 @@ EXTRA_DIST +=\
src/rust/tor_rust/Cargo.toml \
src/rust/tor_rust/lib.rs
+EXTRA_CARGO_OPTIONS=
+
src/rust/target/release/@TOR_RUST_STATIC_NAME@: FORCE
- ( cd "$(abs_top_srcdir)/src/rust/tor_rust" ; \
+ ( cd "$(abs_top_builddir)/src/rust" ; \
CARGO_TARGET_DIR="$(abs_top_builddir)/src/rust/target" \
CARGO_HOME="$(abs_top_builddir)/src/rust" \
- $(CARGO) build --release --quiet $(CARGO_ONLINE) )
+ $(CARGO) build --release $(EXTRA_CARGO_OPTIONS) \
+ $(CARGO_ONLINE) \
+ --manifest-path "$(abs_top_srcdir)/src/rust/tor_rust/Cargo.toml" )
distclean-rust:
- ( cd "$(abs_top_srcdir)/src/rust/tor_rust" ; \
+ ( cd "$(abs_top_builddir)/src/rust" ; \
CARGO_TARGET_DIR="$(abs_top_builddir)/src/rust/target" \
CARGO_HOME="$(abs_top_builddir)/src/rust" \
- $(CARGO) clean --quiet $(CARGO_ONLINE) )
+ $(CARGO) clean $(EXTRA_CARGO_OPTIONS) \
+ $(CARGO_ONLINE) \
+ --manifest-path "$(abs_top_srcdir)/src/rust/tor_rust/Cargo.toml" )
rm -rf "$(abs_top_builddir)/src/rust/registry"
if USE_RUST
diff --git a/src/test/include.am b/src/test/include.am
index bbf8a370e2..b5c5dd24f7 100644
--- a/src/test/include.am
+++ b/src/test/include.am
@@ -125,6 +125,7 @@ src_test_test_SOURCES = \
src/test/test_hs_service.c \
src/test/test_hs_client.c \
src/test/test_hs_intropoint.c \
+ src/test/test_hs_control.c \
src/test/test_handles.c \
src/test/test_hs_cache.c \
src/test/test_hs_descriptor.c \
diff --git a/src/test/test.c b/src/test/test.c
index 00857c2386..432df35c34 100644
--- a/src/test/test.c
+++ b/src/test/test.c
@@ -1201,6 +1201,7 @@ struct testgroup_t testgroups[] = {
{ "hs_cell/", hs_cell_tests },
{ "hs_common/", hs_common_tests },
{ "hs_config/", hs_config_tests },
+ { "hs_control/", hs_control_tests },
{ "hs_descriptor/", hs_descriptor },
{ "hs_ntor/", hs_ntor_tests },
{ "hs_service/", hs_service_tests },
diff --git a/src/test/test.h b/src/test/test.h
index b1a3366a80..b37fe25b33 100644
--- a/src/test/test.h
+++ b/src/test/test.h
@@ -210,6 +210,7 @@ extern struct testcase_t hs_cache[];
extern struct testcase_t hs_cell_tests[];
extern struct testcase_t hs_common_tests[];
extern struct testcase_t hs_config_tests[];
+extern struct testcase_t hs_control_tests[];
extern struct testcase_t hs_descriptor[];
extern struct testcase_t hs_ntor_tests[];
extern struct testcase_t hs_service_tests[];
diff --git a/src/test/test_config.c b/src/test/test_config.c
index 79f72fca1f..4290d0dc6d 100644
--- a/src/test/test_config.c
+++ b/src/test/test_config.c
@@ -4003,7 +4003,7 @@ test_config_parse_port_config__ports__ports_given(void *data)
tt_int_op(port_cfg->entry_cfg.dns_request, OP_EQ, 1);
tt_int_op(port_cfg->entry_cfg.ipv4_traffic, OP_EQ, 1);
tt_int_op(port_cfg->entry_cfg.onion_traffic, OP_EQ, 1);
- tt_int_op(port_cfg->entry_cfg.cache_ipv4_answers, OP_EQ, 1);
+ tt_int_op(port_cfg->entry_cfg.cache_ipv4_answers, OP_EQ, 0);
tt_int_op(port_cfg->entry_cfg.prefer_ipv6_virtaddr, OP_EQ, 1);
#endif /* defined(_WIN32) */
@@ -4346,7 +4346,7 @@ test_config_parse_port_config__ports__ports_given(void *data)
tt_int_op(ret, OP_EQ, 0);
tt_int_op(smartlist_len(slout), OP_EQ, 1);
port_cfg = (port_cfg_t *)smartlist_get(slout, 0);
- tt_int_op(port_cfg->entry_cfg.cache_ipv4_answers, OP_EQ, 1);
+ tt_int_op(port_cfg->entry_cfg.cache_ipv4_answers, OP_EQ, 0);
tt_int_op(port_cfg->entry_cfg.cache_ipv6_answers, OP_EQ, 1);
// Test success with no cache ipv4 DNS
@@ -5455,7 +5455,7 @@ test_config_check_bridge_distribution_setting_not_a_bridge(void *arg)
or_options_t* options = get_options_mutable();
or_options_t* old_options = options;
or_options_t* default_options = options;
- char* message = (char*)("");
+ char* message = NULL;
int ret;
(void)arg;
@@ -5466,8 +5466,11 @@ test_config_check_bridge_distribution_setting_not_a_bridge(void *arg)
ret = options_validate(old_options, options, default_options, 0, &message);
tt_int_op(ret, OP_EQ, -1);
+ tt_str_op(message, OP_EQ, "You set BridgeDistribution, but you "
+ "didn't set BridgeRelay!");
done:
- return;
+ tor_free(message);
+ options->BridgeDistribution = NULL;
}
/* If the BridgeDistribution setting was valid, 0 should be returned. */
diff --git a/src/test/test_controller.c b/src/test/test_controller.c
index 472fcb8c53..af19f63f6c 100644
--- a/src/test/test_controller.c
+++ b/src/test/test_controller.c
@@ -6,6 +6,7 @@
#include "bridges.h"
#include "control.h"
#include "entrynodes.h"
+#include "hs_common.h"
#include "networkstatus.h"
#include "rendservice.h"
#include "routerlist.h"
@@ -13,10 +14,87 @@
#include "test_helpers.h"
static void
-test_add_onion_helper_keyarg(void *arg)
+test_add_onion_helper_keyarg_v3(void *arg)
{
- crypto_pk_t *pk = NULL;
- crypto_pk_t *pk2 = NULL;
+ int ret, hs_version;
+ add_onion_secret_key_t pk;
+ char *key_new_blob = NULL;
+ char *err_msg = NULL;
+ const char *key_new_alg = NULL;
+
+ (void) arg;
+
+ memset(&pk, 0, sizeof(pk));
+
+ /* Test explicit ED25519-V3 key generation. */
+ ret = add_onion_helper_keyarg("NEW:ED25519-V3", 0, &key_new_alg,
+ &key_new_blob, &pk, &hs_version,
+ &err_msg);
+ tt_int_op(ret, OP_EQ, 0);
+ tt_int_op(hs_version, OP_EQ, HS_VERSION_THREE);
+ tt_assert(pk.v3);
+ tt_str_op(key_new_alg, OP_EQ, "ED25519-V3");
+ tt_assert(key_new_blob);
+ tt_ptr_op(err_msg, OP_EQ, NULL);
+ tor_free(pk.v3); pk.v3 = NULL;
+ tor_free(key_new_blob);
+
+ /* Test discarding the private key. */
+ ret = add_onion_helper_keyarg("NEW:ED25519-V3", 1, &key_new_alg,
+ &key_new_blob, &pk, &hs_version,
+ &err_msg);
+ tt_int_op(ret, OP_EQ, 0);
+ tt_int_op(hs_version, OP_EQ, HS_VERSION_THREE);
+ tt_assert(pk.v3);
+ tt_ptr_op(key_new_alg, OP_EQ, NULL);
+ tt_ptr_op(key_new_blob, OP_EQ, NULL);
+ tt_ptr_op(err_msg, OP_EQ, NULL);
+ tor_free(pk.v3); pk.v3 = NULL;
+ tor_free(key_new_blob);
+
+ /* Test passing a key blob. */
+ {
+ /* The base64 key and hex key are the same. Hex key is 64 bytes long. The
+ * sk has been generated randomly using python3. */
+ const char *base64_sk =
+ "a9bT19PqGC9Y+BmOo1IQvCGjjwxMiaaxEXZ+FKMxpEQW"
+ "6AmSV5roThUGMRCaqQSCnR2jI1vL2QxHORzI4RxMmw==";
+ const char *hex_sk =
+ "\x6b\xd6\xd3\xd7\xd3\xea\x18\x2f\x58\xf8\x19\x8e\xa3\x52\x10\xbc"
+ "\x21\xa3\x8f\x0c\x4c\x89\xa6\xb1\x11\x76\x7e\x14\xa3\x31\xa4\x44"
+ "\x16\xe8\x09\x92\x57\x9a\xe8\x4e\x15\x06\x31\x10\x9a\xa9\x04\x82"
+ "\x9d\x1d\xa3\x23\x5b\xcb\xd9\x0c\x47\x39\x1c\xc8\xe1\x1c\x4c\x9b";
+ char *key_blob = NULL;
+
+ tor_asprintf(&key_blob, "ED25519-V3:%s", base64_sk);
+ tt_assert(key_blob);
+ ret = add_onion_helper_keyarg(key_blob, 1, &key_new_alg,
+ &key_new_blob, &pk, &hs_version,
+ &err_msg);
+ tor_free(key_blob);
+ tt_int_op(ret, OP_EQ, 0);
+ tt_int_op(hs_version, OP_EQ, HS_VERSION_THREE);
+ tt_assert(pk.v3);
+ tt_mem_op(pk.v3, OP_EQ, hex_sk, 64);
+ tt_ptr_op(key_new_alg, OP_EQ, NULL);
+ tt_ptr_op(key_new_blob, OP_EQ, NULL);
+ tt_ptr_op(err_msg, OP_EQ, NULL);
+ tor_free(pk.v3); pk.v3 = NULL;
+ tor_free(key_new_blob);
+ }
+
+ done:
+ tor_free(pk.v3);
+ tor_free(key_new_blob);
+ tor_free(err_msg);
+}
+
+static void
+test_add_onion_helper_keyarg_v2(void *arg)
+{
+ int ret, hs_version;
+ add_onion_secret_key_t pk;
+ crypto_pk_t *pk1 = NULL;
const char *key_new_alg = NULL;
char *key_new_blob = NULL;
char *err_msg = NULL;
@@ -25,83 +103,100 @@ test_add_onion_helper_keyarg(void *arg)
(void) arg;
+ memset(&pk, 0, sizeof(pk));
+
/* Test explicit RSA1024 key generation. */
- pk = add_onion_helper_keyarg("NEW:RSA1024", 0, &key_new_alg, &key_new_blob,
- &err_msg);
- tt_assert(pk);
+ ret = add_onion_helper_keyarg("NEW:RSA1024", 0, &key_new_alg, &key_new_blob,
+ &pk, &hs_version, &err_msg);
+ tt_int_op(ret, OP_EQ, 0);
+ tt_int_op(hs_version, OP_EQ, HS_VERSION_TWO);
+ tt_assert(pk.v2);
tt_str_op(key_new_alg, OP_EQ, "RSA1024");
tt_assert(key_new_blob);
tt_ptr_op(err_msg, OP_EQ, NULL);
/* Test "BEST" key generation (Assumes BEST = RSA1024). */
- crypto_pk_free(pk);
+ crypto_pk_free(pk.v2); pk.v2 = NULL;
tor_free(key_new_blob);
- pk = add_onion_helper_keyarg("NEW:BEST", 0, &key_new_alg, &key_new_blob,
- &err_msg);
- tt_assert(pk);
+ ret = add_onion_helper_keyarg("NEW:BEST", 0, &key_new_alg, &key_new_blob,
+ &pk, &hs_version, &err_msg);
+ tt_int_op(ret, OP_EQ, 0);
+ tt_int_op(hs_version, OP_EQ, HS_VERSION_TWO);
+ tt_assert(pk.v2);
tt_str_op(key_new_alg, OP_EQ, "RSA1024");
tt_assert(key_new_blob);
tt_ptr_op(err_msg, OP_EQ, NULL);
/* Test discarding the private key. */
- crypto_pk_free(pk);
+ crypto_pk_free(pk.v2); pk.v2 = NULL;
tor_free(key_new_blob);
- pk = add_onion_helper_keyarg("NEW:BEST", 1, &key_new_alg, &key_new_blob,
- &err_msg);
- tt_assert(pk);
+ ret = add_onion_helper_keyarg("NEW:BEST", 1, &key_new_alg, &key_new_blob,
+ &pk, &hs_version, &err_msg);
+ tt_int_op(ret, OP_EQ, 0);
+ tt_int_op(hs_version, OP_EQ, HS_VERSION_TWO);
+ tt_assert(pk.v2);
tt_ptr_op(key_new_alg, OP_EQ, NULL);
tt_ptr_op(key_new_blob, OP_EQ, NULL);
tt_ptr_op(err_msg, OP_EQ, NULL);
/* Test generating a invalid key type. */
- crypto_pk_free(pk);
- pk = add_onion_helper_keyarg("NEW:RSA512", 0, &key_new_alg, &key_new_blob,
- &err_msg);
- tt_ptr_op(pk, OP_EQ, NULL);
+ crypto_pk_free(pk.v2); pk.v2 = NULL;
+ ret = add_onion_helper_keyarg("NEW:RSA512", 0, &key_new_alg, &key_new_blob,
+ &pk, &hs_version, &err_msg);
+ tt_int_op(ret, OP_EQ, -1);
+ tt_int_op(hs_version, OP_EQ, HS_VERSION_TWO);
+ tt_assert(!pk.v2);
tt_ptr_op(key_new_alg, OP_EQ, NULL);
tt_ptr_op(key_new_blob, OP_EQ, NULL);
tt_assert(err_msg);
/* Test loading a RSA1024 key. */
tor_free(err_msg);
- pk = pk_generate(0);
- tt_int_op(0, OP_EQ, crypto_pk_base64_encode(pk, &encoded));
+ pk1 = pk_generate(0);
+ tt_int_op(0, OP_EQ, crypto_pk_base64_encode(pk1, &encoded));
tor_asprintf(&arg_str, "RSA1024:%s", encoded);
- pk2 = add_onion_helper_keyarg(arg_str, 0, &key_new_alg, &key_new_blob,
- &err_msg);
- tt_assert(pk2);
+ ret = add_onion_helper_keyarg(arg_str, 0, &key_new_alg, &key_new_blob,
+ &pk, &hs_version, &err_msg);
+ tt_int_op(ret, OP_EQ, 0);
+ tt_int_op(hs_version, OP_EQ, HS_VERSION_TWO);
+ tt_assert(pk.v2);
tt_ptr_op(key_new_alg, OP_EQ, NULL);
tt_ptr_op(key_new_blob, OP_EQ, NULL);
tt_ptr_op(err_msg, OP_EQ, NULL);
- tt_int_op(crypto_pk_cmp_keys(pk, pk2), OP_EQ, 0);
+ tt_int_op(crypto_pk_cmp_keys(pk1, pk.v2), OP_EQ, 0);
/* Test loading a invalid key type. */
tor_free(arg_str);
- crypto_pk_free(pk); pk = NULL;
+ crypto_pk_free(pk1); pk1 = NULL;
+ crypto_pk_free(pk.v2); pk.v2 = NULL;
tor_asprintf(&arg_str, "RSA512:%s", encoded);
- pk = add_onion_helper_keyarg(arg_str, 0, &key_new_alg, &key_new_blob,
- &err_msg);
- tt_ptr_op(pk, OP_EQ, NULL);
+ ret = add_onion_helper_keyarg(arg_str, 0, &key_new_alg, &key_new_blob,
+ &pk, &hs_version, &err_msg);
+ tt_int_op(ret, OP_EQ, -1);
+ tt_int_op(hs_version, OP_EQ, HS_VERSION_TWO);
+ tt_assert(!pk.v2);
tt_ptr_op(key_new_alg, OP_EQ, NULL);
tt_ptr_op(key_new_blob, OP_EQ, NULL);
tt_assert(err_msg);
/* Test loading a invalid key. */
tor_free(arg_str);
- crypto_pk_free(pk); pk = NULL;
+ crypto_pk_free(pk.v2); pk.v2 = NULL;
tor_free(err_msg);
encoded[strlen(encoded)/2] = '\0';
tor_asprintf(&arg_str, "RSA1024:%s", encoded);
- pk = add_onion_helper_keyarg(arg_str, 0, &key_new_alg, &key_new_blob,
- &err_msg);
- tt_ptr_op(pk, OP_EQ, NULL);
+ ret = add_onion_helper_keyarg(arg_str, 0, &key_new_alg, &key_new_blob,
+ &pk, &hs_version, &err_msg);
+ tt_int_op(ret, OP_EQ, -1);
+ tt_int_op(hs_version, OP_EQ, HS_VERSION_TWO);
+ tt_assert(!pk.v2);
tt_ptr_op(key_new_alg, OP_EQ, NULL);
tt_ptr_op(key_new_blob, OP_EQ, NULL);
tt_assert(err_msg);
done:
- crypto_pk_free(pk);
- crypto_pk_free(pk2);
+ crypto_pk_free(pk1);
+ crypto_pk_free(pk.v2);
tor_free(key_new_blob);
tor_free(err_msg);
tor_free(encoded);
@@ -1370,7 +1465,10 @@ test_download_status_bridge(void *arg)
}
struct testcase_t controller_tests[] = {
- { "add_onion_helper_keyarg", test_add_onion_helper_keyarg, 0, NULL, NULL },
+ { "add_onion_helper_keyarg_v2", test_add_onion_helper_keyarg_v2, 0,
+ NULL, NULL },
+ { "add_onion_helper_keyarg_v3", test_add_onion_helper_keyarg_v3, 0,
+ NULL, NULL },
{ "getinfo_helper_onion", test_getinfo_helper_onion, 0, NULL, NULL },
{ "rend_service_parse_port_config", test_rend_service_parse_port_config, 0,
NULL, NULL },
diff --git a/src/test/test_entrynodes.c b/src/test/test_entrynodes.c
index f9d981953d..80ebebe3f8 100644
--- a/src/test/test_entrynodes.c
+++ b/src/test/test_entrynodes.c
@@ -7,6 +7,7 @@
#define STATEFILE_PRIVATE
#define ENTRYNODES_PRIVATE
#define ROUTERLIST_PRIVATE
+#define DIRECTORY_PRIVATE
#include "or.h"
#include "test.h"
@@ -15,6 +16,7 @@
#include "circuitlist.h"
#include "config.h"
#include "confparse.h"
+#include "directory.h"
#include "entrynodes.h"
#include "nodelist.h"
#include "networkstatus.h"
@@ -129,6 +131,14 @@ big_fake_network_setup(const struct testcase_t *testcase)
n->rs->has_bandwidth = 1;
n->rs->bandwidth_kb = 30;
+ /* Make a random nickname for each node */
+ {
+ char nickname_binary[8];
+ crypto_rand(nickname_binary, sizeof(nickname_binary));
+ base64_encode(n->rs->nickname, sizeof(n->rs->nickname),
+ nickname_binary, sizeof(nickname_binary), 0);
+ }
+
/* Call half of the nodes a possible guard. */
if (i % 2 == 0) {
n->is_possible_guard = 1;
@@ -1719,6 +1729,7 @@ test_entry_guard_select_for_circuit_no_confirmed(void *arg)
/* Simpler cases: no gaurds are confirmed yet. */
(void)arg;
guard_selection_t *gs = guard_selection_new("default", GS_TYPE_NORMAL);
+ entry_guard_restriction_t *rst = NULL;
/* simple starting configuration */
entry_guards_update_primary(gs);
@@ -1800,14 +1811,13 @@ test_entry_guard_select_for_circuit_no_confirmed(void *arg)
tt_ptr_op(g2, OP_EQ, g);
/* But if we impose a restriction, we don't get the same guard */
- entry_guard_restriction_t rst;
- memset(&rst, 0, sizeof(rst));
- memcpy(rst.exclude_id, g->identity, DIGEST_LEN);
- g2 = select_entry_guard_for_circuit(gs, GUARD_USAGE_TRAFFIC, &rst, &state);
+ rst = guard_create_exit_restriction((uint8_t*)g->identity);
+ g2 = select_entry_guard_for_circuit(gs, GUARD_USAGE_TRAFFIC, rst, &state);
tt_ptr_op(g2, OP_NE, g);
done:
guard_selection_free(gs);
+ entry_guard_restriction_free(rst);
}
static void
@@ -1817,6 +1827,7 @@ test_entry_guard_select_for_circuit_confirmed(void *arg)
guards, we use a confirmed guard. */
(void)arg;
int i;
+ entry_guard_restriction_t *rst = NULL;
guard_selection_t *gs = guard_selection_new("default", GS_TYPE_NORMAL);
const int N_CONFIRMED = 10;
@@ -1877,10 +1888,8 @@ test_entry_guard_select_for_circuit_confirmed(void *arg)
get_options_mutable()->EnforceDistinctSubnets = 0;
g = smartlist_get(gs->confirmed_entry_guards,
smartlist_len(gs->primary_entry_guards)+2);
- entry_guard_restriction_t rst;
- memset(&rst, 0, sizeof(rst));
- memcpy(rst.exclude_id, g->identity, DIGEST_LEN);
- g2 = select_entry_guard_for_circuit(gs, GUARD_USAGE_TRAFFIC, &rst, &state);
+ rst = guard_create_exit_restriction((uint8_t*)g->identity);
+ g2 = select_entry_guard_for_circuit(gs, GUARD_USAGE_TRAFFIC, rst, &state);
tt_ptr_op(g2, OP_NE, NULL);
tt_ptr_op(g2, OP_NE, g);
tt_int_op(g2->confirmed_idx, OP_EQ,
@@ -1906,13 +1915,13 @@ test_entry_guard_select_for_circuit_confirmed(void *arg)
// Regression test for bug 22753/TROVE-2017-006.
get_options_mutable()->EnforceDistinctSubnets = 1;
g = smartlist_get(gs->confirmed_entry_guards, 0);
- memset(&rst, 0, sizeof(rst));
- memcpy(rst.exclude_id, g->identity, DIGEST_LEN);
- g2 = select_entry_guard_for_circuit(gs, GUARD_USAGE_TRAFFIC, &rst, &state);
+ memcpy(rst->exclude_id, g->identity, DIGEST_LEN);
+ g2 = select_entry_guard_for_circuit(gs, GUARD_USAGE_TRAFFIC, rst, &state);
tt_ptr_op(g2, OP_EQ, NULL);
done:
guard_selection_free(gs);
+ entry_guard_restriction_free(rst);
}
static void
@@ -2493,9 +2502,7 @@ test_entry_guard_upgrade_not_blocked_by_restricted_circ_complete(void *arg)
/* Once more, let circ1 become complete. But this time, we'll claim
* that circ2 was restricted to not use the same guard as circ1. */
data->guard2_state->restrictions =
- tor_malloc_zero(sizeof(entry_guard_restriction_t));
- memcpy(data->guard2_state->restrictions->exclude_id,
- data->guard1->identity, DIGEST_LEN);
+ guard_create_exit_restriction((uint8_t*)data->guard1->identity);
smartlist_t *result = smartlist_new();
int r;
@@ -2604,9 +2611,7 @@ test_entry_guard_upgrade_not_blocked_by_restricted_circ_pending(void *arg)
}
data->guard2_state->restrictions =
- tor_malloc_zero(sizeof(entry_guard_restriction_t));
- memcpy(data->guard2_state->restrictions->exclude_id,
- data->guard1->identity, DIGEST_LEN);
+ guard_create_exit_restriction((uint8_t*)data->guard1->identity);
smartlist_t *result = smartlist_new();
int r;
@@ -2674,6 +2679,114 @@ test_enty_guard_should_expire_waiting(void *arg)
tor_free(fake_state);
}
+static void
+mock_directory_initiate_request(directory_request_t *req)
+{
+ if (req->guard_state) {
+ circuit_guard_state_free(req->guard_state);
+ }
+}
+
+static networkstatus_t *mock_ns_val = NULL;
+static networkstatus_t *
+mock_ns_get_by_flavor(consensus_flavor_t f)
+{
+ (void)f;
+ return mock_ns_val;
+}
+
+/** Test that when we fetch microdescriptors we skip guards that have
+ * previously failed to serve us needed microdescriptors. */
+static void
+test_entry_guard_outdated_dirserver_exclusion(void *arg)
+{
+ int retval;
+ response_handler_args_t *args = NULL;
+ dir_connection_t *conn = NULL;
+ (void) arg;
+
+ /* Test prep: Make a new guard selection */
+ guard_selection_t *gs = get_guard_selection_by_name("default",
+ GS_TYPE_NORMAL, 1);
+
+ /* ... we want to use entry guards */
+ or_options_t *options = get_options_mutable();
+ options->UseEntryGuards = 1;
+ options->UseBridges = 0;
+
+ /* ... prepare some md digests we want to download in the future */
+ smartlist_t *digests = smartlist_new();
+ const char *prose = "unhurried and wise, we perceive.";
+ for (int i = 0; i < 20; i++) {
+ smartlist_add(digests, (char*)prose);
+ }
+
+ tt_int_op(smartlist_len(digests), OP_EQ, 20);
+
+ /* ... now mock some functions */
+ mock_ns_val = tor_malloc_zero(sizeof(networkstatus_t));
+ MOCK(networkstatus_get_latest_consensus_by_flavor, mock_ns_get_by_flavor);
+ MOCK(directory_initiate_request, mock_directory_initiate_request);
+
+ /* Test logic:
+ * 0. Create a proper guard set and primary guard list.
+ * 1. Pretend to fail microdescriptor fetches from all the primary guards.
+ * 2. Order another microdescriptor fetch and make sure that primary guards
+ * get skipped since they failed previous fetches.
+ */
+
+ { /* Setup primary guard list */
+ int i;
+ entry_guards_update_primary(gs);
+ for (i = 0; i < DFLT_N_PRIMARY_GUARDS; ++i) {
+ entry_guard_t *guard = smartlist_get(gs->sampled_entry_guards, i);
+ make_guard_confirmed(gs, guard);
+ }
+ entry_guards_update_primary(gs);
+ }
+
+ {
+ /* Fail microdesc fetches with all the primary guards */
+ args = tor_malloc_zero(sizeof(response_handler_args_t));
+ args->status_code = 404;
+ args->reason = NULL;
+ args->body = NULL;
+ args->body_len = 0;
+
+ conn = tor_malloc_zero(sizeof(dir_connection_t));
+ conn->requested_resource = tor_strdup("d/jlinblackorigami");
+ conn->base_.purpose = DIR_PURPOSE_FETCH_MICRODESC;
+
+ /* Pretend to fail fetches with all primary guards */
+ SMARTLIST_FOREACH_BEGIN(gs->primary_entry_guards,const entry_guard_t *,g) {
+ memcpy(conn->identity_digest, g->identity, DIGEST_LEN);
+
+ retval = handle_response_fetch_microdesc(conn, args);
+ tt_int_op(retval, OP_EQ, 0);
+ } SMARTLIST_FOREACH_END(g);
+ }
+
+ {
+ /* Now order the final md download */
+ setup_full_capture_of_logs(LOG_INFO);
+ initiate_descriptor_downloads(NULL, DIR_PURPOSE_FETCH_MICRODESC,
+ digests, 3, 7, 0);
+
+ /* ... and check that because we failed to fetch microdescs from all our
+ * primaries, we didnt end up selecting a primary for fetching dir info */
+ expect_log_msg_containing("No primary or confirmed guards available.");
+ teardown_capture_of_logs();
+ }
+
+ done:
+ smartlist_free(digests);
+ tor_free(args);
+ if (conn) {
+ tor_free(conn->requested_resource);
+ tor_free(conn);
+ }
+}
+
static const struct testcase_setup_t big_fake_network = {
big_fake_network_setup, big_fake_network_cleanup
};
@@ -2734,6 +2847,7 @@ struct testcase_t entrynodes_tests[] = {
BFN_TEST(select_for_circuit_highlevel_primary_retry),
BFN_TEST(select_and_cancel),
BFN_TEST(drop_guards),
+ BFN_TEST(outdated_dirserver_exclusion),
UPGRADE_TEST(upgrade_a_circuit, "c1-done c2-done"),
UPGRADE_TEST(upgrade_blocked_by_live_primary_guards, "c1-done c2-done"),
diff --git a/src/test/test_hs.c b/src/test/test_hs.c
index 7737499f50..55c6218dd1 100644
--- a/src/test/test_hs.c
+++ b/src/test/test_hs.c
@@ -258,8 +258,9 @@ test_hs_desc_event(void *arg)
sizeof(desc_id_base32));
/* test request event */
- control_event_hs_descriptor_requested(&rend_query.base_, HSDIR_EXIST_ID,
- STR_DESC_ID_BASE32);
+ control_event_hs_descriptor_requested(rend_query.onion_address,
+ rend_query.auth_type, HSDIR_EXIST_ID,
+ STR_DESC_ID_BASE32, NULL);
expected_msg = "650 HS_DESC REQUESTED "STR_HS_ADDR" NO_AUTH "\
STR_HSDIR_EXIST_LONGNAME " " STR_DESC_ID_BASE32 "\r\n";
tt_assert(received_msg);
@@ -268,8 +269,8 @@ test_hs_desc_event(void *arg)
/* test received event */
rend_query.auth_type = REND_BASIC_AUTH;
- control_event_hs_descriptor_received(rend_query.onion_address,
- &rend_query.base_, HSDIR_EXIST_ID);
+ control_event_hsv2_descriptor_received(rend_query.onion_address,
+ &rend_query.base_, HSDIR_EXIST_ID);
expected_msg = "650 HS_DESC RECEIVED "STR_HS_ADDR" BASIC_AUTH "\
STR_HSDIR_EXIST_LONGNAME " " STR_DESC_ID_BASE32"\r\n";
tt_assert(received_msg);
@@ -278,7 +279,7 @@ test_hs_desc_event(void *arg)
/* test failed event */
rend_query.auth_type = REND_STEALTH_AUTH;
- control_event_hs_descriptor_failed(&rend_query.base_,
+ control_event_hsv2_descriptor_failed(&rend_query.base_,
HSDIR_NONE_EXIST_ID,
"QUERY_REJECTED");
expected_msg = "650 HS_DESC FAILED "STR_HS_ADDR" STEALTH_AUTH "\
@@ -289,7 +290,7 @@ test_hs_desc_event(void *arg)
/* test invalid auth type */
rend_query.auth_type = 999;
- control_event_hs_descriptor_failed(&rend_query.base_,
+ control_event_hsv2_descriptor_failed(&rend_query.base_,
HSDIR_EXIST_ID,
"QUERY_REJECTED");
expected_msg = "650 HS_DESC FAILED "STR_HS_ADDR" UNKNOWN "\
@@ -301,7 +302,7 @@ test_hs_desc_event(void *arg)
/* test no HSDir fingerprint type */
rend_query.auth_type = REND_NO_AUTH;
- control_event_hs_descriptor_failed(&rend_query.base_, NULL,
+ control_event_hsv2_descriptor_failed(&rend_query.base_, NULL,
"QUERY_NO_HSDIR");
expected_msg = "650 HS_DESC FAILED "STR_HS_ADDR" NO_AUTH " \
"UNKNOWN REASON=QUERY_NO_HSDIR\r\n";
diff --git a/src/test/test_hs_control.c b/src/test/test_hs_control.c
new file mode 100644
index 0000000000..207a55de6d
--- /dev/null
+++ b/src/test/test_hs_control.c
@@ -0,0 +1,199 @@
+/* Copyright (c) 2017, The Tor Project, Inc. */
+/* See LICENSE for licensing information */
+
+/**
+ * \file test_hs_control.c
+ * \brief Unit tests for hidden service control port event and command.
+ **/
+
+#define CONTROL_PRIVATE
+#define CIRCUITBUILD_PRIVATE
+#define RENDCOMMON_PRIVATE
+#define RENDSERVICE_PRIVATE
+#define HS_SERVICE_PRIVATE
+
+#include "or.h"
+#include "test.h"
+#include "control.h"
+#include "config.h"
+#include "hs_common.h"
+#include "hs_control.h"
+#include "nodelist.h"
+//#include "rendcommon.h"
+//#include "rendservice.h"
+//#include "routerset.h"
+//#include "circuitbuild.h"
+#include "test_helpers.h"
+
+/* mock ID digest and longname for node that's in nodelist */
+#define HSDIR_EXIST_ID \
+ "\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA" \
+ "\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA"
+#define STR_HSDIR_EXIST_LONGNAME \
+ "$AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=TestDir"
+#define STR_HSDIR_NONE_EXIST_LONGNAME \
+ "$BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB"
+
+/* Helper global variable for hidden service descriptor event test.
+ * It's used as a pointer to dynamically created message buffer in
+ * send_control_event_string_replacement function, which mocks
+ * send_control_event_string function.
+ *
+ * Always free it after use! */
+static char *received_msg = NULL;
+
+/** Mock function for send_control_event_string
+ */
+static void
+queue_control_event_string_replacement(uint16_t event, char *msg)
+{
+ (void) event;
+ tor_free(received_msg);
+ received_msg = msg;
+}
+
+/** Mock function for node_describe_longname_by_id, it returns either
+ * STR_HSDIR_EXIST_LONGNAME or STR_HSDIR_NONE_EXIST_LONGNAME
+ */
+static const char *
+node_describe_longname_by_id_replacement(const char *id_digest)
+{
+ if (!strcmp(id_digest, HSDIR_EXIST_ID)) {
+ return STR_HSDIR_EXIST_LONGNAME;
+ } else {
+ return STR_HSDIR_NONE_EXIST_LONGNAME;
+ }
+}
+
+/* HSDir fetch index is a series of 'D' */
+#define HSDIR_INDEX_FETCH_HEX \
+ "4343434343434343434343434343434343434343434343434343434343434343"
+#define HSDIR_INDEX_STORE_HEX \
+ "4444444444444444444444444444444444444444444444444444444444444444"
+
+static const node_t *
+mock_node_get_by_id(const char *digest)
+{
+ static node_t node;
+ memcpy(node.identity, digest, DIGEST_LEN);
+ node.hsdir_index = tor_malloc_zero(sizeof(hsdir_index_t));
+ memset(node.hsdir_index->fetch, 'C', DIGEST256_LEN);
+ memset(node.hsdir_index->store_first, 'D', DIGEST256_LEN);
+ return &node;
+}
+
+static void
+test_hs_desc_event(void *arg)
+{
+ int ret;
+ char *expected_msg = NULL;
+ char onion_address[HS_SERVICE_ADDR_LEN_BASE32 + 1];
+ ed25519_keypair_t identity_kp;
+ ed25519_public_key_t blinded_pk;
+ char base64_blinded_pk[ED25519_BASE64_LEN + 1];
+ routerstatus_t hsdir_rs;
+ hs_ident_dir_conn_t ident;
+
+ (void) arg;
+ MOCK(queue_control_event_string,
+ queue_control_event_string_replacement);
+ MOCK(node_describe_longname_by_id,
+ node_describe_longname_by_id_replacement);
+ MOCK(node_get_by_id, mock_node_get_by_id);
+
+ /* Setup what we need for this test. */
+ ed25519_keypair_generate(&identity_kp, 0);
+ hs_build_address(&identity_kp.pubkey, HS_VERSION_THREE, onion_address);
+ ret = hs_address_is_valid(onion_address);
+ tt_int_op(ret, OP_EQ, 1);
+ memset(&blinded_pk, 'B', sizeof(blinded_pk));
+ memset(&hsdir_rs, 0, sizeof(hsdir_rs));
+ memcpy(hsdir_rs.identity_digest, HSDIR_EXIST_ID, DIGEST_LEN);
+ ret = ed25519_public_to_base64(base64_blinded_pk, &blinded_pk);
+ tt_int_op(ret, OP_EQ, 0);
+ memcpy(&ident.identity_pk, &identity_kp.pubkey,
+ sizeof(ed25519_public_key_t));
+ memcpy(&ident.blinded_pk, &blinded_pk, sizeof(blinded_pk));
+
+ /* HS_DESC REQUESTED ... */
+ hs_control_desc_event_requested(&identity_kp.pubkey, base64_blinded_pk,
+ &hsdir_rs);
+ tor_asprintf(&expected_msg, "650 HS_DESC REQUESTED %s NO_AUTH "
+ STR_HSDIR_EXIST_LONGNAME " %s HSDIR_INDEX="
+ HSDIR_INDEX_FETCH_HEX "\r\n",
+ onion_address, base64_blinded_pk);
+ tt_assert(received_msg);
+ tt_str_op(received_msg, OP_EQ, expected_msg);
+ tor_free(received_msg);
+ tor_free(expected_msg);
+
+ /* HS_DESC CREATED... */
+ hs_control_desc_event_created(onion_address, &blinded_pk);
+ tor_asprintf(&expected_msg, "650 HS_DESC CREATED %s UNKNOWN "
+ "UNKNOWN %s\r\n",
+ onion_address, base64_blinded_pk);
+ tt_assert(received_msg);
+ tt_str_op(received_msg, OP_EQ, expected_msg);
+ tor_free(received_msg);
+ tor_free(expected_msg);
+
+ /* HS_DESC UPLOAD... */
+ uint8_t hsdir_index_store[DIGEST256_LEN];
+ memset(hsdir_index_store, 'D', sizeof(hsdir_index_store));
+ hs_control_desc_event_upload(onion_address, HSDIR_EXIST_ID,
+ &blinded_pk, hsdir_index_store);
+ tor_asprintf(&expected_msg, "650 HS_DESC UPLOAD %s UNKNOWN "
+ STR_HSDIR_EXIST_LONGNAME " %s "
+ "HSDIR_INDEX=" HSDIR_INDEX_STORE_HEX "\r\n",
+ onion_address, base64_blinded_pk);
+ tt_assert(received_msg);
+ tt_str_op(received_msg, OP_EQ, expected_msg);
+ tor_free(received_msg);
+ tor_free(expected_msg);
+
+ /* HS_DESC FAILED... */
+ hs_control_desc_event_failed(&ident, HSDIR_EXIST_ID, "BAD_DESC");
+ tor_asprintf(&expected_msg, "650 HS_DESC FAILED %s NO_AUTH "
+ STR_HSDIR_EXIST_LONGNAME " %s "
+ "REASON=BAD_DESC\r\n",
+ onion_address, base64_blinded_pk);
+ tt_assert(received_msg);
+ tt_str_op(received_msg, OP_EQ, expected_msg);
+ tor_free(received_msg);
+ tor_free(expected_msg);
+
+ /* HS_DESC RECEIVED... */
+ hs_control_desc_event_received(&ident, HSDIR_EXIST_ID);
+ tor_asprintf(&expected_msg, "650 HS_DESC RECEIVED %s NO_AUTH "
+ STR_HSDIR_EXIST_LONGNAME " %s\r\n",
+ onion_address, base64_blinded_pk);
+ tt_assert(received_msg);
+ tt_str_op(received_msg, OP_EQ, expected_msg);
+ tor_free(received_msg);
+ tor_free(expected_msg);
+
+ /* HS_DESC UPLOADED... */
+ hs_control_desc_event_uploaded(&ident, HSDIR_EXIST_ID);
+ tor_asprintf(&expected_msg, "650 HS_DESC UPLOADED %s UNKNOWN "
+ STR_HSDIR_EXIST_LONGNAME "\r\n",
+ onion_address);
+ tt_assert(received_msg);
+ tt_str_op(received_msg, OP_EQ, expected_msg);
+ tor_free(received_msg);
+ tor_free(expected_msg);
+
+ done:
+ UNMOCK(queue_control_event_string);
+ UNMOCK(node_describe_longname_by_id);
+ UNMOCK(node_get_by_id);
+ tor_free(received_msg);
+ tor_free(expected_msg);
+}
+
+struct testcase_t hs_control_tests[] = {
+ { "hs_desc_event", test_hs_desc_event, TT_FORK,
+ NULL, NULL },
+
+ END_OF_TESTCASES
+};
+
diff --git a/src/test/test_rust.sh b/src/test/test_rust.sh
index 8d7900e1df..133f2bb940 100755
--- a/src/test/test_rust.sh
+++ b/src/test/test_rust.sh
@@ -8,8 +8,12 @@ exitcode=0
set -e
for crate in $crates; do
- cd "${abs_top_srcdir:-.}/src/rust/${crate}"
- CARGO_TARGET_DIR="${abs_top_builddir:-../../..}/src/rust/target" CARGO_HOME="${abs_top_builddir:-../../..}/src/rust" "${CARGO:-cargo}" test ${CARGO_ONLINE-"--frozen"} || exitcode=1
+ cd "${abs_top_builddir:-../../..}/src/rust"
+ CARGO_TARGET_DIR="${abs_top_builddir:-../../..}/src/rust/target" \
+ CARGO_HOME="${abs_top_builddir:-../../..}/src/rust" \
+ "${CARGO:-cargo}" test ${CARGO_ONLINE-"--frozen"} \
+ --manifest-path "${abs_top_srcdir:-.}/src/rust/${crate}/Cargo.toml" \
+ || exitcode=1
cd -
done