summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.gitignore1
-rw-r--r--ChangeLog441
-rw-r--r--Makefile.am7
-rw-r--r--ReleaseNotes241
-rw-r--r--changes/bug1206216
-rw-r--r--changes/bug205324
-rw-r--r--changes/bug213949
-rw-r--r--changes/bug215093
-rw-r--r--changes/bug226055
-rw-r--r--changes/bug2331811
-rw-r--r--changes/bug235713
-rw-r--r--changes/bug236234
-rw-r--r--changes/bug236537
-rw-r--r--changes/bug236703
-rw-r--r--changes/bug236787
-rw-r--r--changes/bug236936
-rw-r--r--changes/bug237393
-rw-r--r--changes/bug237414
-rw-r--r--changes/bug237485
-rw-r--r--changes/bug237516
-rw-r--r--changes/bug237534
-rw-r--r--changes/bug237554
-rw-r--r--changes/bug237574
-rw-r--r--changes/bug237584
-rw-r--r--changes/bug237624
-rw-r--r--changes/bug237744
-rw-r--r--changes/bug237906
-rw-r--r--changes/bug238166
-rw-r--r--changes/bug238205
-rw-r--r--changes/bug238488
-rw-r--r--changes/bug238625
-rw-r--r--changes/bug238743
-rw-r--r--changes/bug239524
-rw-r--r--changes/bug239859
-rw-r--r--changes/bug240025
-rw-r--r--changes/bug240255
-rw-r--r--changes/bug240823
-rw-r--r--changes/bug241154
-rw-r--r--changes/bug241373
-rw-r--r--changes/bug241504
-rw-r--r--changes/bug241703
-rw-r--r--changes/bug242476
-rw-r--r--changes/feature183299
-rw-r--r--changes/geoip-2017-11-064
-rw-r--r--changes/geoip-october20174
-rw-r--r--changes/hsdescv3_fuzz_more3
-rw-r--r--changes/longclaw_235923
-rw-r--r--changes/ticket136055
-rw-r--r--changes/ticket208956
-rw-r--r--changes/ticket210317
-rw-r--r--changes/ticket223423
-rw-r--r--changes/ticket228408
-rw-r--r--changes/ticket235777
-rw-r--r--changes/ticket238459
-rw-r--r--changes/ticket239007
-rw-r--r--changes/ticket239103
-rw-r--r--changes/ticket241094
-rw-r--r--configure.ac25
-rw-r--r--contrib/win32build/tor-mingw.nsi.in2
-rw-r--r--doc/HACKING/GettingStartedRust.md19
-rw-r--r--doc/HACKING/ReleasingTor.md3
-rw-r--r--doc/tor.1.txt110
-rwxr-xr-xscripts/codegen/fuzzing_include_am.py2
-rw-r--r--src/common/aes.c2
-rw-r--r--src/common/buffers.c69
-rw-r--r--src/common/buffers.h7
-rw-r--r--src/common/compat.c20
-rw-r--r--src/common/compat.h1
-rw-r--r--src/common/compat_libevent.c2
-rw-r--r--src/common/compat_libevent.h1
-rw-r--r--src/common/compat_rust.c39
-rw-r--r--src/common/compat_rust.h28
-rw-r--r--src/common/compat_time.c4
-rw-r--r--src/common/compat_winthreads.c4
-rw-r--r--src/common/confline.c94
-rw-r--r--src/common/confline.h5
-rw-r--r--src/common/crypto_pwbox.h3
-rw-r--r--src/common/include.am6
-rw-r--r--src/common/sandbox.c3
-rw-r--r--src/common/util.c24
-rw-r--r--src/or/addressmap.c3
-rw-r--r--src/or/circuitbuild.c4
-rw-r--r--src/or/config.c140
-rw-r--r--src/or/connection.c144
-rw-r--r--src/or/connection.h5
-rw-r--r--src/or/connection_edge.c2
-rw-r--r--src/or/connection_or.c2
-rw-r--r--src/or/control.c46
-rw-r--r--src/or/control.h4
-rw-r--r--src/or/directory.c48
-rw-r--r--src/or/directory.h3
-rw-r--r--src/or/dirserv.c16
-rw-r--r--src/or/dns.c4
-rw-r--r--src/or/entrynodes.c6
-rw-r--r--src/or/entrynodes.h4
-rw-r--r--src/or/geoip.c22
-rw-r--r--src/or/git_revision.c17
-rw-r--r--src/or/git_revision.h12
-rw-r--r--src/or/hibernate.c21
-rw-r--r--src/or/hs_circuit.c81
-rw-r--r--src/or/hs_service.c2
-rw-r--r--src/or/include.am12
-rw-r--r--src/or/main.c175
-rw-r--r--src/or/main.h6
-rw-r--r--src/or/networkstatus.c13
-rw-r--r--src/or/nodelist.c32
-rw-r--r--src/or/nodelist.h5
-rw-r--r--src/or/ntmain.c4
-rw-r--r--src/or/or.h20
-rw-r--r--src/or/policies.c39
-rw-r--r--src/or/policies.h3
-rw-r--r--src/or/protover.c45
-rw-r--r--src/or/protover.h13
-rw-r--r--src/or/protover_rust.c19
-rw-r--r--src/or/routerlist.c14
-rw-r--r--src/or/routerparse.c8
-rw-r--r--src/or/scheduler.c2
-rw-r--r--src/or/tor_api.c88
-rw-r--r--src/or/tor_api.h102
-rw-r--r--src/or/tor_api_internal.h20
-rw-r--r--src/or/tor_main.c14
-rw-r--r--src/rust/.cargo/config.in2
-rw-r--r--src/rust/Cargo.lock41
-rw-r--r--src/rust/Cargo.toml2
-rw-r--r--src/rust/external/Cargo.toml13
-rw-r--r--src/rust/external/external.rs33
-rw-r--r--src/rust/external/lib.rs14
-rw-r--r--src/rust/include.am24
-rw-r--r--src/rust/protover/Cargo.toml25
-rw-r--r--src/rust/protover/ffi.rs219
-rw-r--r--src/rust/protover/lib.rs33
-rw-r--r--src/rust/protover/protover.rs906
-rw-r--r--src/rust/protover/tests/protover.rs291
-rw-r--r--src/rust/smartlist/Cargo.toml13
-rw-r--r--src/rust/smartlist/lib.rs8
-rw-r--r--src/rust/smartlist/smartlist.rs115
-rw-r--r--src/rust/tor_allocate/Cargo.toml13
-rw-r--r--src/rust/tor_allocate/lib.rs15
-rw-r--r--src/rust/tor_allocate/tor_allocate.rs97
-rw-r--r--src/rust/tor_rust/Cargo.toml16
-rw-r--r--src/rust/tor_rust/include.am24
-rw-r--r--src/rust/tor_rust/lib.rs5
-rw-r--r--src/rust/tor_util/Cargo.toml5
-rw-r--r--src/rust/tor_util/ffi.rs62
-rw-r--r--src/rust/tor_util/include.am13
-rw-r--r--src/rust/tor_util/lib.rs14
-rw-r--r--src/rust/tor_util/rust_string.rs101
-rw-r--r--src/rust/tor_util/tests/rust_string.rs37
-rw-r--r--src/test/bench.c5
-rw-r--r--src/test/fuzz/fuzzing_common.c3
-rw-r--r--src/test/include.am1
-rw-r--r--src/test/test-memwipe.c3
-rw-r--r--src/test/test.c1
-rw-r--r--src/test/test.h1
-rw-r--r--src/test/test_accounting.c3
-rw-r--r--src/test/test_channelpadding.c3
-rw-r--r--src/test/test_config.c117
-rw-r--r--src/test/test_dns.c3
-rwxr-xr-xsrc/test/test_keygen.sh109
-rw-r--r--src/test/test_protover.c73
-rw-r--r--src/test/test_routerlist.c116
-rw-r--r--src/test/test_routerset.c3
-rw-r--r--src/test/test_rust.c31
-rwxr-xr-xsrc/test/test_rust.sh9
-rw-r--r--src/test/test_shared_random.c3
-rw-r--r--src/test/test_status.c3
-rw-r--r--src/test/testing_common.c6
-rw-r--r--src/tools/include.am5
-rw-r--r--src/tools/tor_runner.c101
-rw-r--r--src/win32/orconfig.h2
170 files changed, 4483 insertions, 923 deletions
diff --git a/.gitignore b/.gitignore
index 671288d418..b8642ee76e 100644
--- a/.gitignore
+++ b/.gitignore
@@ -211,6 +211,7 @@ uptime-*.json
/src/test/fuzz/lf-fuzz-*
# /src/tools/
+/src/tools/libtorrunner.a
/src/tools/tor-checkkey
/src/tools/tor-resolve
/src/tools/tor-cov-resolve
diff --git a/ChangeLog b/ChangeLog
index 6ba0b06dd2..3d6e9f5222 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,442 @@
+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
+ a major reliability issue that has been plaguing fast exit relays in
+ recent months.
+
+ o Major bugfixes (exit relays, DNS):
+ - 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 (scheduler, channel):
+ - Stop processing scheduled channels if they closed while flushing
+ cells. This can happen if the write on the connection fails
+ leading to the channel being closed while in the scheduler loop.
+ Fixes bug 23751; bugfix on 0.3.2.1-alpha.
+
+ o Minor features (logging, scheduler):
+ - Introduce a SCHED_BUG() function to log extra information about
+ the scheduler state if we ever catch a bug in the scheduler.
+ Closes ticket 23753.
+
+ o Minor features (removed deprecations):
+ - The ClientDNSRejectInternalAddresses flag can once again be set in
+ non-testing Tor networks, so long as they do not use the default
+ directory authorities. This change also removes the deprecation of
+ this flag from 0.2.9.2-alpha. Closes ticket 21031.
+
+ o Minor features (testing):
+ - Our fuzzing tests now test the encrypted portions of v3 onion
+ service descriptors. Implements more of 21509.
+
+ o Minor bugfixes (directory client):
+ - On failure to download directory information, delay retry attempts
+ by a random amount based on the "decorrelated jitter" algorithm.
+ Our previous delay algorithm tended to produce extra-long delays
+ too easily. Fixes bug 23816; bugfix on 0.2.9.1-alpha.
+
+ o Minor bugfixes (IPv6, v3 single onion services):
+ - Remove buggy code for IPv6-only v3 single onion services, and
+ reject attempts to configure them. This release supports IPv4,
+ dual-stack, and IPv6-only v3 onion services; and IPv4 and dual-
+ stack v3 single onion services. Fixes bug 23820; bugfix
+ on 0.3.2.1-alpha.
+
+ o Minor bugfixes (logging, relay):
+ - Give only a protocol warning when the ed25519 key is not
+ consistent between the descriptor and microdescriptor of a relay.
+ This can happen, for instance, if the relay has been flagged
+ NoEdConsensus. Fixes bug 24025; bugfix on 0.3.2.1-alpha.
+
+ o Minor bugfixes (manpage, onion service):
+ - Document that the HiddenServiceNumIntroductionPoints option is
+ 0-10 for v2 services and 0-20 for v3 services. Fixes bug 24115;
+ bugfix on 0.3.2.1-alpha.
+
+ o Minor bugfixes (memory leaks):
+ - Fix a minor memory leak at exit in the KIST scheduler. This bug
+ should have no user-visible impact. Fixes bug 23774; bugfix
+ on 0.3.2.1-alpha.
+ - Fix a memory leak when decrypting a badly formatted v3 onion
+ service descriptor. Fixes bug 24150; bugfix on 0.3.2.1-alpha.
+ Found by OSS-Fuzz; this is OSS-Fuzz issue 3994.
+
+ o Minor bugfixes (onion services):
+ - Cache some needed onion service client information instead of
+ constantly computing it over and over again. Fixes bug 23623;
+ bugfix on 0.3.2.1-alpha.
+ - Properly retry HSv3 descriptor fetches when missing required
+ directory information. Fixes bug 23762; bugfix on 0.3.2.1-alpha.
+
+ o Minor bugfixes (path selection):
+ - When selecting relays by bandwidth, avoid a rounding error that
+ could sometimes cause load to be imbalanced incorrectly.
+ Previously, we would always round upwards; now, we round towards
+ the nearest integer. This had the biggest effect when a relay's
+ weight adjustments should have given it weight 0, but it got
+ weight 1 instead. Fixes bug 23318; bugfix on 0.2.4.3-alpha.
+ - When calculating the fraction of nodes that have descriptors, and
+ all nodes in the network have zero bandwidths, count the number of
+ nodes instead. Fixes bug 23318; bugfix on 0.2.4.10-alpha.
+ - Actually log the total bandwidth in compute_weighted_bandwidths().
+ Fixes bug 24170; bugfix on 0.2.4.3-alpha.
+
+ o Minor bugfixes (relay, crash):
+ - 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):
+ - Fix a spurious fuzzing-only use of an uninitialized value. Found
+ by Brian Carpenter. Fixes bug 24082; bugfix on 0.3.0.3-alpha.
+ - Test that IPv6-only clients can use microdescriptors when running
+ "make test-network-all". Requires chutney master 61c28b9 or later.
+ Closes ticket 24109.
+
+
+Changes in version 0.3.2.3-alpha - 2017-10-27
+ Tor 0.3.2.3-alpha is the third release in the 0.3.2 series. It fixes
+ numerous small bugs in earlier versions of 0.3.2.x, and adds a new
+ directory authority, Bastet.
+
+ o Directory authority changes:
+ - Add "Bastet" as a ninth directory authority to the default list.
+ Closes ticket 23910.
+ - The directory authority "Longclaw" has changed its IP address.
+ Closes ticket 23592.
+
+ o Minor features (bridge):
+ - Bridge relays can now set the BridgeDistribution config option to
+ add a "bridge-distribution-request" line to their bridge
+ descriptor, which tells BridgeDB how they'd like their bridge
+ address to be given out. (Note that as of Oct 2017, BridgeDB does
+ not yet implement this feature.) As a side benefit, this feature
+ provides a way to distinguish bridge descriptors from non-bridge
+ descriptors. Implements tickets 18329.
+
+ o Minor features (client, entry guards):
+ - Improve log messages when missing descriptors for primary guards.
+ Resolves ticket 23670.
+
+ o Minor features (geoip):
+ - Update geoip and geoip6 to the October 4 2017 Maxmind GeoLite2
+ Country database.
+
+ o Minor bugfixes (bridge):
+ - Overwrite the bridge address earlier in the process of retrieving
+ its descriptor, to make sure we reach it on the configured
+ address. Fixes bug 20532; bugfix on 0.2.0.10-alpha.
+
+ o Minor bugfixes (documentation):
+ - Document better how to read gcov, and what our gcov postprocessing
+ scripts do. Fixes bug 23739; bugfix on 0.2.9.1-alpha.
+
+ o Minor bugfixes (entry guards):
+ - Tor now updates its guard state when it reads a consensus
+ regardless of whether it's missing descriptors. That makes tor use
+ its primary guards to fetch descriptors in some edge cases where
+ it would previously have used fallback directories. Fixes bug
+ 23862; bugfix on 0.3.0.1-alpha.
+
+ o Minor bugfixes (hidden service client):
+ - When handling multiple SOCKS request for the same .onion address,
+ only fetch the service descriptor once.
+ - When a descriptor fetch fails with a non-recoverable error, close
+ all pending SOCKS requests for that .onion. Fixes bug 23653;
+ bugfix on 0.3.2.1-alpha.
+
+ o Minor bugfixes (hidden service):
+ - Always regenerate missing hidden service public key files. Prior
+ to this, if the public key was deleted from disk, it wouldn't get
+ recreated. Fixes bug 23748; bugfix on 0.3.2.2-alpha. Patch
+ from "cathugger".
+ - Make sure that we have a usable ed25519 key when the intro point
+ relay supports ed25519 link authentication. Fixes bug 24002;
+ bugfix on 0.3.2.1-alpha.
+
+ o Minor bugfixes (hidden service, v2):
+ - When reloading configured hidden services, copy all information
+ from the old service object. Previously, some data was omitted,
+ causing delays in descriptor upload, and other bugs. Fixes bug
+ 23790; bugfix on 0.2.1.9-alpha.
+
+ o Minor bugfixes (memory safety, defensive programming):
+ - Clear the target address when node_get_prim_orport() returns
+ early. Fixes bug 23874; bugfix on 0.2.8.2-alpha.
+
+ o Minor bugfixes (relay):
+ - Avoid a BUG warning when receiving a dubious CREATE cell while an
+ option transition is in progress. Fixes bug 23952; bugfix
+ on 0.3.2.1-alpha.
+
+ o Minor bugfixes (testing):
+ - Adjust the GitLab CI configuration to more closely match that of
+ Travis CI. Fixes bug 23757; bugfix on 0.3.2.2-alpha.
+ - Prevent scripts/test/coverage from attempting to move gcov output
+ to the root directory. Fixes bug 23741; bugfix on 0.2.5.1-alpha.
+ - When running unit tests as root, skip a test that would fail
+ because it expects a permissions error. This affects some
+ continuous integration setups. Fixes bug 23758; bugfix
+ on 0.3.2.2-alpha.
+ - Stop unconditionally mirroring the tor repository in GitLab CI.
+ This prevented developers from enabling GitLab CI on master. Fixes
+ bug 23755; bugfix on 0.3.2.2-alpha.
+ - Fix the hidden service v3 descriptor decoding fuzzing to use the
+ latest decoding API correctly. Fixes bug 21509; bugfix
+ on 0.3.2.1-alpha.
+
+ o Minor bugfixes (warnings):
+ - When we get an HTTP request on a SOCKS port, tell the user about
+ the new HTTPTunnelPort option. Previously, we would give a "Tor is
+ not an HTTP Proxy" message, which stopped being true when
+ HTTPTunnelPort was introduced. Fixes bug 23678; bugfix
+ on 0.3.2.1-alpha.
+
+
+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.
+
+ 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 Directory authority changes:
+ - Add "Bastet" as a ninth directory authority to the default list.
+ Closes ticket 23910.
+ - The directory authority "Longclaw" has changed its IP address.
+ Closes ticket 23592.
+
+ o Major bugfixes (openbsd, denial-of-service, backport from 0.3.1.5-alpha):
+ - Avoid an assertion failure bug affecting our implementation of
+ inet_pton(AF_INET6) on certain OpenBSD systems whose strtol()
+ handling of "0xx" differs from what we had expected. Fixes bug
+ 22789; bugfix on 0.2.3.8-alpha. Also tracked as TROVE-2017-007.
+
+ o Minor features (geoip):
+ - Update geoip and geoip6 to the October 4 2017 Maxmind GeoLite2
+ Country database.
+
+ o Minor bugfixes (defensive programming, undefined behavior, backport from 0.3.1.4-alpha):
+ - Fix a memset() off the end of an array when packing cells. This
+ bug should be harmless in practice, since the corrupted bytes are
+ still in the same structure, and are always padding bytes,
+ ignored, or immediately overwritten, depending on compiler
+ behavior. Nevertheless, because the memset()'s purpose is to make
+ sure that any other cell-handling bugs can't expose bytes to the
+ network, we need to fix it. Fixes bug 22737; bugfix on
+ 0.2.4.11-alpha. Fixes CID 1401591.
+
+ o Build features (backport from 0.3.1.5-alpha):
+ - Tor's repository now includes a Travis Continuous Integration (CI)
+ configuration file (.travis.yml). This is meant to help new
+ developers and contributors who fork Tor to a Github repository be
+ better able to test their changes, and understand what we expect
+ to pass. To use this new build feature, you must fork Tor to your
+ Github account, then go into the "Integrations" menu in the
+ repository settings for your fork and enable Travis, then push
+ your changes. Closes ticket 22636.
+
+
+Changes in version 0.2.8.16 - 2017-10-25
+ Tor 0.2.8.16 backports a collection of bugfixes from later Tor release
+ series, including a bugfix for a crash issue that had affected relays
+ under memory pressure. It also adds a new directory authority, Bastet.
+
+ 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 stick with
+ the 0.2.9 series. Otherwise, please upgrade to 0.3.1 or later.
+
+ o Directory authority changes:
+ - Add "Bastet" as a ninth directory authority to the default list.
+ Closes ticket 23910.
+ - The directory authority "Longclaw" has changed its IP address.
+ Closes ticket 23592.
+
+ o Major bugfixes (relay, crash, assertion failure, backport from 0.3.2.2-alpha):
+ - Fix a timing-based assertion failure that could occur when the
+ circuit out-of-memory handler freed a connection's output buffer.
+ Fixes bug 23690; bugfix on 0.2.6.1-alpha.
+
+ o Minor features (directory authorities, backport from 0.3.2.2-alpha):
+ - Remove longclaw's IPv6 address, as it will soon change. Authority
+ IPv6 addresses were originally added in 0.2.8.1-alpha. This leaves
+ 3/8 directory authorities with IPv6 addresses, but there are also
+ 52 fallback directory mirrors with IPv6 addresses. Resolves 19760.
+
+ o Minor features (geoip):
+ - Update geoip and geoip6 to the October 4 2017 Maxmind GeoLite2
+ Country database.
+
+
+Changes in version 0.2.9.13 - 2017-10-25
+ Tor 0.2.9.13 backports a collection of bugfixes from later Tor release
+ series, including a bugfix for a crash issue that had affected relays
+ under memory pressure. It also adds a new directory authority, Bastet.
+
+ o Directory authority changes:
+ - Add "Bastet" as a ninth directory authority to the default list.
+ Closes ticket 23910.
+ - The directory authority "Longclaw" has changed its IP address.
+ Closes ticket 23592.
+
+ o Major bugfixes (relay, crash, assertion failure, backport from 0.3.2.2-alpha):
+ - Fix a timing-based assertion failure that could occur when the
+ circuit out-of-memory handler freed a connection's output buffer.
+ Fixes bug 23690; bugfix on 0.2.6.1-alpha.
+
+ o Minor features (directory authorities, backport from 0.3.2.2-alpha):
+ - Remove longclaw's IPv6 address, as it will soon change. Authority
+ IPv6 addresses were originally added in 0.2.8.1-alpha. This leaves
+ 3/8 directory authorities with IPv6 addresses, but there are also
+ 52 fallback directory mirrors with IPv6 addresses. Resolves 19760.
+
+ o Minor features (geoip):
+ - Update geoip and geoip6 to the October 4 2017 Maxmind GeoLite2
+ Country database.
+
+ o Minor bugfixes (directory authority, backport from 0.3.1.5-alpha):
+ - When a directory authority rejects a descriptor or extrainfo with
+ a given digest, mark that digest as undownloadable, so that we do
+ not attempt to download it again over and over. We previously
+ tried to avoid downloading such descriptors by other means, but we
+ didn't notice if we accidentally downloaded one anyway. This
+ behavior became problematic in 0.2.7.2-alpha, when authorities
+ began pinning Ed25519 keys. Fixes bug 22349; bugfix
+ on 0.2.1.19-alpha.
+
+ o Minor bugfixes (memory safety, backport from 0.3.2.3-alpha):
+ - Clear the address when node_get_prim_orport() returns early.
+ Fixes bug 23874; bugfix on 0.2.8.2-alpha.
+
+ o Minor bugfixes (Windows service, backport from 0.3.1.6-rc):
+ - When running as a Windows service, set the ID of the main thread
+ correctly. Failure to do so made us fail to send log messages to
+ the controller in 0.2.1.16-rc, slowed down controller event
+ delivery in 0.2.7.3-rc and later, and crash with an assertion
+ failure in 0.3.1.1-alpha. Fixes bug 23081; bugfix on 0.2.1.6-alpha.
+ Patch and diagnosis from "Vort".
+
+
+Changes in version 0.3.0.12 - 2017-10-25
+ Tor 0.3.0.12 backports a collection of bugfixes from later Tor release
+ series, including a bugfix for a crash issue that had affected relays
+ under memory pressure. It also adds a new directory authority, Bastet.
+
+ 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 Directory authority changes:
+ - Add "Bastet" as a ninth directory authority to the default list.
+ Closes ticket 23910.
+ - The directory authority "Longclaw" has changed its IP address.
+ Closes ticket 23592.
+
+ o Major bugfixes (relay, crash, assertion failure, backport from 0.3.2.2-alpha):
+ - Fix a timing-based assertion failure that could occur when the
+ circuit out-of-memory handler freed a connection's output buffer.
+ Fixes bug 23690; bugfix on 0.2.6.1-alpha.
+
+ o Minor features (directory authorities, backport from 0.3.2.2-alpha):
+ - Remove longclaw's IPv6 address, as it will soon change. Authority
+ IPv6 addresses were originally added in 0.2.8.1-alpha. This leaves
+ 3/8 directory authorities with IPv6 addresses, but there are also
+ 52 fallback directory mirrors with IPv6 addresses. Resolves 19760.
+
+ o Minor features (geoip):
+ - Update geoip and geoip6 to the October 4 2017 Maxmind GeoLite2
+ Country database.
+
+ o Minor bugfixes (directory authority, backport from 0.3.1.5-alpha):
+ - When a directory authority rejects a descriptor or extrainfo with
+ a given digest, mark that digest as undownloadable, so that we do
+ not attempt to download it again over and over. We previously
+ tried to avoid downloading such descriptors by other means, but we
+ didn't notice if we accidentally downloaded one anyway. This
+ behavior became problematic in 0.2.7.2-alpha, when authorities
+ began pinning Ed25519 keys. Fixes bug 22349; bugfix
+ on 0.2.1.19-alpha.
+
+ o Minor bugfixes (hidden service, relay, backport from 0.3.2.2-alpha):
+ - Avoid a possible double close of a circuit by the intro point on
+ error of sending the INTRO_ESTABLISHED cell. Fixes bug 23610;
+ bugfix on 0.3.0.1-alpha.
+
+ o Minor bugfixes (memory safety, backport from 0.3.2.3-alpha):
+ - Clear the address when node_get_prim_orport() returns early.
+ Fixes bug 23874; bugfix on 0.2.8.2-alpha.
+
+ o Minor bugfixes (Windows service, backport from 0.3.1.6-rc):
+ - When running as a Windows service, set the ID of the main thread
+ correctly. Failure to do so made us fail to send log messages to
+ the controller in 0.2.1.16-rc, slowed down controller event
+ delivery in 0.2.7.3-rc and later, and crash with an assertion
+ failure in 0.3.1.1-alpha. Fixes bug 23081; bugfix on 0.2.1.6-alpha.
+ Patch and diagnosis from "Vort".
+
+
+Changes in version 0.3.1.8 - 2017-10-25
+ Tor 0.3.1.8 is the second stable release in the 0.3.1 series.
+ It includes several bugfixes, including a bugfix for a crash issue
+ that had affected relays under memory pressure. It also adds
+ a new directory authority, Bastet.
+
+ o Directory authority changes:
+ - Add "Bastet" as a ninth directory authority to the default list.
+ Closes ticket 23910.
+ - The directory authority "Longclaw" has changed its IP address.
+ Closes ticket 23592.
+
+ o Major bugfixes (relay, crash, assertion failure, backport from 0.3.2.2-alpha):
+ - Fix a timing-based assertion failure that could occur when the
+ circuit out-of-memory handler freed a connection's output buffer.
+ Fixes bug 23690; bugfix on 0.2.6.1-alpha.
+
+ o Minor features (directory authorities, backport from 0.3.2.2-alpha):
+ - Remove longclaw's IPv6 address, as it will soon change. Authority
+ IPv6 addresses were originally added in 0.2.8.1-alpha. This leaves
+ 3/8 directory authorities with IPv6 addresses, but there are also
+ 52 fallback directory mirrors with IPv6 addresses. Resolves 19760.
+
+ o Minor features (geoip):
+ - Update geoip and geoip6 to the October 4 2017 Maxmind GeoLite2
+ Country database.
+
+ o Minor bugfixes (compilation, backport from 0.3.2.2-alpha):
+ - Fix a compilation warning when building with zstd support on
+ 32-bit platforms. Fixes bug 23568; bugfix on 0.3.1.1-alpha. Found
+ and fixed by Andreas Stieger.
+
+ o Minor bugfixes (compression, backport from 0.3.2.2-alpha):
+ - Handle a pathological case when decompressing Zstandard data when
+ the output buffer size is zero. Fixes bug 23551; bugfix
+ on 0.3.1.1-alpha.
+
+ o Minor bugfixes (directory authority, backport from 0.3.2.1-alpha):
+ - Remove the length limit on HTTP status lines that authorities can
+ send in their replies. Fixes bug 23499; bugfix on 0.3.1.6-rc.
+
+ o Minor bugfixes (hidden service, relay, backport from 0.3.2.2-alpha):
+ - Avoid a possible double close of a circuit by the intro point on
+ error of sending the INTRO_ESTABLISHED cell. Fixes bug 23610;
+ bugfix on 0.3.0.1-alpha.
+
+ o Minor bugfixes (memory safety, backport from 0.3.2.3-alpha):
+ - Clear the address when node_get_prim_orport() returns early.
+ Fixes bug 23874; bugfix on 0.2.8.2-alpha.
+
+ o Minor bugfixes (unit tests, backport from 0.3.2.2-alpha):
+ - Fix additional channelpadding unit test failures by using mocked
+ time instead of actual time for all tests. Fixes bug 23608; bugfix
+ on 0.3.1.1-alpha.
+
+
Changes in version 0.3.2.2-alpha - 2017-09-29
Tor 0.3.2.2-alpha is the second release in the 0.3.2 series. This
release fixes several minor bugs in the new scheduler and next-
@@ -3220,7 +3659,7 @@ Changes in version 0.3.0.1-alpha - 2016-12-19
initial code by Alec Heifetz.
- Relays now support the HSDir version 3 protocol, so that they can
can store and serve v3 descriptors. This is part of the next-
- generation onion service work detailled in proposal 224. Closes
+ generation onion service work detailed in proposal 224. Closes
ticket 17238.
o Major features (protocol, ed25519 identity keys):
diff --git a/Makefile.am b/Makefile.am
index ad2ceb66a9..3445fc064d 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -26,7 +26,7 @@ TESTING_TOR_BINARY=$(top_builddir)/src/or/tor$(EXEEXT)
endif
if USE_RUST
-rust_ldadd=$(top_builddir)/src/rust/target/release/@TOR_RUST_UTIL_STATIC_NAME@
+rust_ldadd=$(top_builddir)/src/rust/target/release/@TOR_RUST_STATIC_NAME@
else
rust_ldadd=
endif
@@ -246,3 +246,8 @@ mostlyclean-local:
clean-local:
rm -rf $(top_builddir)/src/rust/target
rm -rf $(top_builddir)/src/rust/.cargo/registry
+
+if USE_RUST
+distclean-local: distclean-rust
+endif
+
diff --git a/ReleaseNotes b/ReleaseNotes
index 07a3881acb..1bdf30b814 100644
--- a/ReleaseNotes
+++ b/ReleaseNotes
@@ -2,6 +2,245 @@ 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.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.
+
+ 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 Directory authority changes:
+ - Add "Bastet" as a ninth directory authority to the default list.
+ Closes ticket 23910.
+ - The directory authority "Longclaw" has changed its IP address.
+ Closes ticket 23592.
+
+ o Major bugfixes (openbsd, denial-of-service, backport from 0.3.1.5-alpha):
+ - Avoid an assertion failure bug affecting our implementation of
+ inet_pton(AF_INET6) on certain OpenBSD systems whose strtol()
+ handling of "0xx" differs from what we had expected. Fixes bug
+ 22789; bugfix on 0.2.3.8-alpha. Also tracked as TROVE-2017-007.
+
+ o Minor features (geoip):
+ - Update geoip and geoip6 to the October 4 2017 Maxmind GeoLite2
+ Country database.
+
+ o Minor bugfixes (defensive programming, undefined behavior, backport from 0.3.1.4-alpha):
+ - Fix a memset() off the end of an array when packing cells. This
+ bug should be harmless in practice, since the corrupted bytes are
+ still in the same structure, and are always padding bytes,
+ ignored, or immediately overwritten, depending on compiler
+ behavior. Nevertheless, because the memset()'s purpose is to make
+ sure that any other cell-handling bugs can't expose bytes to the
+ network, we need to fix it. Fixes bug 22737; bugfix on
+ 0.2.4.11-alpha. Fixes CID 1401591.
+
+ o Build features (backport from 0.3.1.5-alpha):
+ - Tor's repository now includes a Travis Continuous Integration (CI)
+ configuration file (.travis.yml). This is meant to help new
+ developers and contributors who fork Tor to a Github repository be
+ better able to test their changes, and understand what we expect
+ to pass. To use this new build feature, you must fork Tor to your
+ Github account, then go into the "Integrations" menu in the
+ repository settings for your fork and enable Travis, then push
+ your changes. Closes ticket 22636.
+
+
+Changes in version 0.2.8.16 - 2017-10-25
+ Tor 0.2.8.16 backports a collection of bugfixes from later Tor release
+ series, including a bugfix for a crash issue that had affected relays
+ under memory pressure. It also adds a new directory authority, Bastet.
+
+ 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 stick with
+ the 0.2.9 series. Otherwise, please upgrade to 0.3.1 or later.
+
+ o Directory authority changes:
+ - Add "Bastet" as a ninth directory authority to the default list.
+ Closes ticket 23910.
+ - The directory authority "Longclaw" has changed its IP address.
+ Closes ticket 23592.
+
+ o Major bugfixes (relay, crash, assertion failure, backport from 0.3.2.2-alpha):
+ - Fix a timing-based assertion failure that could occur when the
+ circuit out-of-memory handler freed a connection's output buffer.
+ Fixes bug 23690; bugfix on 0.2.6.1-alpha.
+
+ o Minor features (directory authorities, backport from 0.3.2.2-alpha):
+ - Remove longclaw's IPv6 address, as it will soon change. Authority
+ IPv6 addresses were originally added in 0.2.8.1-alpha. This leaves
+ 3/8 directory authorities with IPv6 addresses, but there are also
+ 52 fallback directory mirrors with IPv6 addresses. Resolves 19760.
+
+ o Minor features (geoip):
+ - Update geoip and geoip6 to the October 4 2017 Maxmind GeoLite2
+ Country database.
+
+
+Changes in version 0.2.9.13 - 2017-10-25
+ Tor 0.2.9.13 backports a collection of bugfixes from later Tor release
+ series, including a bugfix for a crash issue that had affected relays
+ under memory pressure. It also adds a new directory authority, Bastet.
+
+ o Directory authority changes:
+ - Add "Bastet" as a ninth directory authority to the default list.
+ Closes ticket 23910.
+ - The directory authority "Longclaw" has changed its IP address.
+ Closes ticket 23592.
+
+ o Major bugfixes (relay, crash, assertion failure, backport from 0.3.2.2-alpha):
+ - Fix a timing-based assertion failure that could occur when the
+ circuit out-of-memory handler freed a connection's output buffer.
+ Fixes bug 23690; bugfix on 0.2.6.1-alpha.
+
+ o Minor features (directory authorities, backport from 0.3.2.2-alpha):
+ - Remove longclaw's IPv6 address, as it will soon change. Authority
+ IPv6 addresses were originally added in 0.2.8.1-alpha. This leaves
+ 3/8 directory authorities with IPv6 addresses, but there are also
+ 52 fallback directory mirrors with IPv6 addresses. Resolves 19760.
+
+ o Minor features (geoip):
+ - Update geoip and geoip6 to the October 4 2017 Maxmind GeoLite2
+ Country database.
+
+ o Minor bugfixes (directory authority, backport from 0.3.1.5-alpha):
+ - When a directory authority rejects a descriptor or extrainfo with
+ a given digest, mark that digest as undownloadable, so that we do
+ not attempt to download it again over and over. We previously
+ tried to avoid downloading such descriptors by other means, but we
+ didn't notice if we accidentally downloaded one anyway. This
+ behavior became problematic in 0.2.7.2-alpha, when authorities
+ began pinning Ed25519 keys. Fixes bug 22349; bugfix
+ on 0.2.1.19-alpha.
+
+ o Minor bugfixes (memory safety, backport from 0.3.2.3-alpha):
+ - Clear the address when node_get_prim_orport() returns early.
+ Fixes bug 23874; bugfix on 0.2.8.2-alpha.
+
+ o Minor bugfixes (Windows service, backport from 0.3.1.6-rc):
+ - When running as a Windows service, set the ID of the main thread
+ correctly. Failure to do so made us fail to send log messages to
+ the controller in 0.2.1.16-rc, slowed down controller event
+ delivery in 0.2.7.3-rc and later, and crash with an assertion
+ failure in 0.3.1.1-alpha. Fixes bug 23081; bugfix on 0.2.1.6-alpha.
+ Patch and diagnosis from "Vort".
+
+
+Changes in version 0.3.0.12 - 2017-10-25
+ Tor 0.3.0.12 backports a collection of bugfixes from later Tor release
+ series, including a bugfix for a crash issue that had affected relays
+ under memory pressure. It also adds a new directory authority, Bastet.
+
+ 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 Directory authority changes:
+ - Add "Bastet" as a ninth directory authority to the default list.
+ Closes ticket 23910.
+ - The directory authority "Longclaw" has changed its IP address.
+ Closes ticket 23592.
+
+ o Major bugfixes (relay, crash, assertion failure, backport from 0.3.2.2-alpha):
+ - Fix a timing-based assertion failure that could occur when the
+ circuit out-of-memory handler freed a connection's output buffer.
+ Fixes bug 23690; bugfix on 0.2.6.1-alpha.
+
+ o Minor features (directory authorities, backport from 0.3.2.2-alpha):
+ - Remove longclaw's IPv6 address, as it will soon change. Authority
+ IPv6 addresses were originally added in 0.2.8.1-alpha. This leaves
+ 3/8 directory authorities with IPv6 addresses, but there are also
+ 52 fallback directory mirrors with IPv6 addresses. Resolves 19760.
+
+ o Minor features (geoip):
+ - Update geoip and geoip6 to the October 4 2017 Maxmind GeoLite2
+ Country database.
+
+ o Minor bugfixes (directory authority, backport from 0.3.1.5-alpha):
+ - When a directory authority rejects a descriptor or extrainfo with
+ a given digest, mark that digest as undownloadable, so that we do
+ not attempt to download it again over and over. We previously
+ tried to avoid downloading such descriptors by other means, but we
+ didn't notice if we accidentally downloaded one anyway. This
+ behavior became problematic in 0.2.7.2-alpha, when authorities
+ began pinning Ed25519 keys. Fixes bug 22349; bugfix
+ on 0.2.1.19-alpha.
+
+ o Minor bugfixes (hidden service, relay, backport from 0.3.2.2-alpha):
+ - Avoid a possible double close of a circuit by the intro point on
+ error of sending the INTRO_ESTABLISHED cell. Fixes bug 23610;
+ bugfix on 0.3.0.1-alpha.
+
+ o Minor bugfixes (memory safety, backport from 0.3.2.3-alpha):
+ - Clear the address when node_get_prim_orport() returns early.
+ Fixes bug 23874; bugfix on 0.2.8.2-alpha.
+
+ o Minor bugfixes (Windows service, backport from 0.3.1.6-rc):
+ - When running as a Windows service, set the ID of the main thread
+ correctly. Failure to do so made us fail to send log messages to
+ the controller in 0.2.1.16-rc, slowed down controller event
+ delivery in 0.2.7.3-rc and later, and crash with an assertion
+ failure in 0.3.1.1-alpha. Fixes bug 23081; bugfix on 0.2.1.6-alpha.
+ Patch and diagnosis from "Vort".
+
+
+Changes in version 0.3.1.8 - 2017-10-25
+ Tor 0.3.1.8 is the second stable release in the 0.3.1 series.
+ It includes several bugfixes, including a bugfix for a crash issue
+ that had affected relays under memory pressure. It also adds
+ a new directory authority, Bastet.
+
+ o Directory authority changes:
+ - Add "Bastet" as a ninth directory authority to the default list.
+ Closes ticket 23910.
+ - The directory authority "Longclaw" has changed its IP address.
+ Closes ticket 23592.
+
+ o Major bugfixes (relay, crash, assertion failure, backport from 0.3.2.2-alpha):
+ - Fix a timing-based assertion failure that could occur when the
+ circuit out-of-memory handler freed a connection's output buffer.
+ Fixes bug 23690; bugfix on 0.2.6.1-alpha.
+
+ o Minor features (directory authorities, backport from 0.3.2.2-alpha):
+ - Remove longclaw's IPv6 address, as it will soon change. Authority
+ IPv6 addresses were originally added in 0.2.8.1-alpha. This leaves
+ 3/8 directory authorities with IPv6 addresses, but there are also
+ 52 fallback directory mirrors with IPv6 addresses. Resolves 19760.
+
+ o Minor features (geoip):
+ - Update geoip and geoip6 to the October 4 2017 Maxmind GeoLite2
+ Country database.
+
+ o Minor bugfixes (compilation, backport from 0.3.2.2-alpha):
+ - Fix a compilation warning when building with zstd support on
+ 32-bit platforms. Fixes bug 23568; bugfix on 0.3.1.1-alpha. Found
+ and fixed by Andreas Stieger.
+
+ o Minor bugfixes (compression, backport from 0.3.2.2-alpha):
+ - Handle a pathological case when decompressing Zstandard data when
+ the output buffer size is zero. Fixes bug 23551; bugfix
+ on 0.3.1.1-alpha.
+
+ o Minor bugfixes (directory authority, backport from 0.3.2.1-alpha):
+ - Remove the length limit on HTTP status lines that authorities can
+ send in their replies. Fixes bug 23499; bugfix on 0.3.1.6-rc.
+
+ o Minor bugfixes (hidden service, relay, backport from 0.3.2.2-alpha):
+ - Avoid a possible double close of a circuit by the intro point on
+ error of sending the INTRO_ESTABLISHED cell. Fixes bug 23610;
+ bugfix on 0.3.0.1-alpha.
+
+ o Minor bugfixes (memory safety, backport from 0.3.2.3-alpha):
+ - Clear the address when node_get_prim_orport() returns early.
+ Fixes bug 23874; bugfix on 0.2.8.2-alpha.
+
+ o Minor bugfixes (unit tests, backport from 0.3.2.2-alpha):
+ - Fix additional channelpadding unit test failures by using mocked
+ time instead of actual time for all tests. Fixes bug 23608; bugfix
+ on 0.3.1.1-alpha.
+
+
Changes in version 0.2.8.15 - 2017-09-18
Tor 0.2.8.15 backports a collection of bugfixes from later
Tor series.
@@ -1345,7 +1584,7 @@ Changes in version 0.3.0.6 - 2017-04-26
initial code by Alec Heifetz.
- Relays now support the HSDir version 3 protocol, so that they can
can store and serve v3 descriptors. This is part of the next-
- generation onion service work detailled in proposal 224. Closes
+ generation onion service work detailed in proposal 224. Closes
ticket 17238.
o Major features (protocol, ed25519 identity keys):
diff --git a/changes/bug12062 b/changes/bug12062
new file mode 100644
index 0000000000..8972929d84
--- /dev/null
+++ b/changes/bug12062
@@ -0,0 +1,16 @@
+ o Minor bugfixes (hibernation, bandwidth accounting, shutdown):
+
+ - When hibernating, do not attempt to launch DNS checks. Fixes a
+ case of bug 12062; bugfix on 0.1.2.2-alpha.
+
+ - Resolve several bugs related to descriptor fetching on bridge
+ clients with bandwidth accounting enabled. (This combination is
+ not recommended!) Fixes a case of bug 12062; bugfix on
+ 0.2.0.3-alpha.
+
+ - When hibernating, do not try to upload or download
+ descriptors. Fixes a case of bug 12062; bugfix on 0.0.9pre5.
+
+ - Do not attempt to launch self-reachability tests when entering
+ hibernation. Fixes a base of bug 12062; bugfix on 0.0.9pre5.
+
diff --git a/changes/bug20532 b/changes/bug20532
deleted file mode 100644
index 7c190ea032..0000000000
--- a/changes/bug20532
+++ /dev/null
@@ -1,4 +0,0 @@
- o Minor bugfixes (bridges):
- - Overwrite the bridge address earlier in the process of directly
- retrieving its descriptor, to make sure we reach it on the configured
- address. Fixes bug 20532; bugfix on 0.2.0.10-alpha.
diff --git a/changes/bug21394 b/changes/bug21394
deleted file mode 100644
index e5452e20ba..0000000000
--- a/changes/bug21394
+++ /dev/null
@@ -1,9 +0,0 @@
- o Major bugfixes (Exit nodes):
- - Fix an issue causing high-bandwidth exit nodes to fail a majority
- or all of their DNS requests, making them basically unsuitable for
- regular usage in Tor circuits. The problem is related to
- libevent's DNS handling, but we can work around it in Tor. Fixes
- bugs 21394 and 18580; bugfix on 0.1.2.2-alpha which introduced
- eventdns. Credit goes to Dhalgren for identifying and finding a
- workaround to this bug and to gamambel, arthuredelstein and
- arma in helping to track it down and analyze it.
diff --git a/changes/bug21509 b/changes/bug21509
deleted file mode 100644
index 593a01ef20..0000000000
--- a/changes/bug21509
+++ /dev/null
@@ -1,3 +0,0 @@
- o Minor bugfixes (hidden service v3, fuzzing):
- - Fix the hidden service v3 descriptor decoding fuzzing to use the latest
- decoding API correctly. Fixes bug 21509; bugfix on 0.3.2.1-alpha.
diff --git a/changes/bug22605 b/changes/bug22605
new file mode 100644
index 0000000000..fdfe202021
--- /dev/null
+++ b/changes/bug22605
@@ -0,0 +1,5 @@
+ o Minor bugfixes (linux seccomp2 sandbox):
+ - When running with the sandbox enabled, reload configuration files
+ correctly even when %include was used. Previously we
+ would crash. Fixes bug 22605; bugfix on 0.3.1.
+ Patch from Daniel Pinto.
diff --git a/changes/bug23318 b/changes/bug23318
deleted file mode 100644
index 7fcb8d4487..0000000000
--- a/changes/bug23318
+++ /dev/null
@@ -1,11 +0,0 @@
- o Minor bugfixes (path selection):
- - When selecting relays by bandwidth, avoid a rounding error that
- could sometimes cause load to be imbalanced incorrectly. Previously,
- we would always round upwards; now, we round towards the nearest
- integer. This had the biggest effect when a relay's weight adjustments
- should have given it weight 0, but it got weight 1 instead.
- Fixes bug 23318; bugfix on 0.2.4.3-alpha.
- - When calculating the fraction of nodes that have descriptors, and all
- all nodes in the network have zero bandwidths, count the number of nodes
- instead.
- Fixes bug 23318; bugfix on 0.2.4.10-alpha.
diff --git a/changes/bug23571 b/changes/bug23571
new file mode 100644
index 0000000000..f2efbdfb96
--- /dev/null
+++ b/changes/bug23571
@@ -0,0 +1,3 @@
+ o Minor bugfixes (hibernation):
+ - When hibernating, close connections normally and allow them to flush.
+ Fixes bug 23571; bugfix on 0.2.4.7-alpha. Also fixes bug 7267.
diff --git a/changes/bug23623 b/changes/bug23623
deleted file mode 100644
index 1e2e5c2ac0..0000000000
--- a/changes/bug23623
+++ /dev/null
@@ -1,4 +0,0 @@
- o Minor bugfixes (onion services):
- - Cache some needed onion service client information instead of
- continuously computing it over and over again. Fixes bug 23623; bugfix
- on 0.3.2.1-alpha.
diff --git a/changes/bug23653 b/changes/bug23653
deleted file mode 100644
index 81760cbb82..0000000000
--- a/changes/bug23653
+++ /dev/null
@@ -1,7 +0,0 @@
- o Minor bugfixes (hidden service client):
- - When getting multiple SOCKS request for the same .onion address, don't
- trigger multiple descriptor fetches.
- - When the descriptor fetch fails with an internal error, no more HSDir to
- query or we aren't allowed to fetch (FetchHidServDescriptors 0), close
- all pending SOCKS request for that .onion. Fixes bug 23653; bugfix on
- 0.3.2.1-alpha.
diff --git a/changes/bug23670 b/changes/bug23670
deleted file mode 100644
index 039bc39478..0000000000
--- a/changes/bug23670
+++ /dev/null
@@ -1,3 +0,0 @@
- o Minor features (entry guards):
- - Improve logs issued when we are missing descriptors of primary guards.
- Resolves ticket 23670.
diff --git a/changes/bug23678 b/changes/bug23678
deleted file mode 100644
index 8138ea71ea..0000000000
--- a/changes/bug23678
+++ /dev/null
@@ -1,7 +0,0 @@
- o Minor bugfixes (warnings):
- - When we get an HTTP request on a SOCKS port, tell the user about
- the new HTTPTunnelPort option. Previously, we would give a
- "Tor is not an HTTP Proxy" message, which stopped being true when
- HTTPTunnelPort was introduced. Fixes bug 23678; bugfix on
- 0.3.2.1-alpha.
-
diff --git a/changes/bug23693 b/changes/bug23693
deleted file mode 100644
index 796398be51..0000000000
--- a/changes/bug23693
+++ /dev/null
@@ -1,6 +0,0 @@
- o Minor bugfixes (relay, crash):
- - 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.
-
diff --git a/changes/bug23739 b/changes/bug23739
deleted file mode 100644
index 3207b5eaf3..0000000000
--- a/changes/bug23739
+++ /dev/null
@@ -1,3 +0,0 @@
- o Minor bugfixes (documentation):
- - Document better how to read gcov and what our postprocessing scripts do.
- Fixes bug 23739; bugfix on 0.2.9.1-alpha.
diff --git a/changes/bug23741 b/changes/bug23741
deleted file mode 100644
index 92f06f5270..0000000000
--- a/changes/bug23741
+++ /dev/null
@@ -1,4 +0,0 @@
- o Minor bugfixes (testing):
- - Prevent scripts/test/coverage from attempting to move gcov
- output to the root directory. Fixes bug 23741; bugfix on
- 0.2.5.1-alpha.
diff --git a/changes/bug23748 b/changes/bug23748
deleted file mode 100644
index 0bd3f3f8ff..0000000000
--- a/changes/bug23748
+++ /dev/null
@@ -1,5 +0,0 @@
- o Minor bugfixes (hidden service):
- - Always make sure the hidden service generate the public key file if it
- is missing. Prior to this, if the public key was deleted from disk, it
- wouldn't get recreated. Fixes bug 23748; bugfix on 0.3.2.2-alpha.
- Patch from "cathugger".
diff --git a/changes/bug23751 b/changes/bug23751
deleted file mode 100644
index 2fd7021664..0000000000
--- a/changes/bug23751
+++ /dev/null
@@ -1,6 +0,0 @@
- o Minor bugfixes (scheduler, channel):
- - Ignore channels that have been closed while flushing cells. This can
- happen if the write on the connection fails leading to the channel being
- closed while in the scheduler loop. This is not a complete fix, it is a
- bandaid until we are able to refactor those interactions. Fixes bug
- 23751; bugfix on 0.3.2.1-alpha.
diff --git a/changes/bug23753 b/changes/bug23753
deleted file mode 100644
index 8782a8e2d0..0000000000
--- a/changes/bug23753
+++ /dev/null
@@ -1,4 +0,0 @@
- o Minor features (logging, scheduler):
- - Introduce a SCHED_BUG() function to log extra information about the
- scheduler state if we ever catch a bug in the scheduler. Closes ticket
- 23753.
diff --git a/changes/bug23755 b/changes/bug23755
deleted file mode 100644
index 98f0970344..0000000000
--- a/changes/bug23755
+++ /dev/null
@@ -1,4 +0,0 @@
- o Minor bugfixes (testing):
- - Stop unconditionally mirroring the tor repository in GitLab CI.
- This prevented developers from enabling GitLab CI on master.
- Fixes bug 23755; bugfix on 0.3.2.2-alpha.
diff --git a/changes/bug23757 b/changes/bug23757
deleted file mode 100644
index 02507a0b4d..0000000000
--- a/changes/bug23757
+++ /dev/null
@@ -1,4 +0,0 @@
- o Minor bugfixes (testing):
- - Adjust the GitLab CI configuration to more closely match that of Travis
- CI. Fixes bug 23757; bugfix on 0.3.2.2-alpha.
-
diff --git a/changes/bug23758 b/changes/bug23758
deleted file mode 100644
index 565791e8f4..0000000000
--- a/changes/bug23758
+++ /dev/null
@@ -1,4 +0,0 @@
- o Minor bugfixes (testing):
- - Skip a test that would fail if run as root (because it expects a
- permissions error). This affects some continuous integration setups.
- Fixes bug 23758; bugfix on 0.3.2.2-alpha.
diff --git a/changes/bug23762 b/changes/bug23762
deleted file mode 100644
index 741a88e21f..0000000000
--- a/changes/bug23762
+++ /dev/null
@@ -1,4 +0,0 @@
- o Minor bugfixes (hidden service v3):
- - Properly retry HSv3 descriptor fetches in the case where we were initially
- missing required directory information. Fixes bug 23762; bugfix on
- 0.3.2.1-alpha.
diff --git a/changes/bug23774 b/changes/bug23774
deleted file mode 100644
index 2ea5c0122a..0000000000
--- a/changes/bug23774
+++ /dev/null
@@ -1,4 +0,0 @@
- o Minor bugfixes (memory leak):
- - Fix a minor memory-leak-at-exit in the KIST scheduler. This
- bug should have no user-visible impact. Fixes bug 23774;
- bugfix on 0.3.2.1-alpha.
diff --git a/changes/bug23790 b/changes/bug23790
deleted file mode 100644
index 5ebe77f806..0000000000
--- a/changes/bug23790
+++ /dev/null
@@ -1,6 +0,0 @@
- o Minor bugfixes (hidden service v2):
- - When reloading tor (HUP) configured with hidden service(s), some
- information weren't copy to the new service object. One problem with
- this was that tor would wait at least the RendPostPeriod time before
- uploading the descriptor if the reload happened before the descriptor
- needed to be published. Fixes bug 23790; bugfix on 0.2.1.9-alpha.
diff --git a/changes/bug23816 b/changes/bug23816
deleted file mode 100644
index 6139dec9e8..0000000000
--- a/changes/bug23816
+++ /dev/null
@@ -1,6 +0,0 @@
- o Minor bugfixes (directory client):
- - On failure to download directory information, delay retry attempts
- by a random amount based on the "decorrelated jitter" algorithm.
- Our previous delay algorithm tended to produce extra-long delays too
- easily. Fixes bug 23816; bugfix on 0.2.9.1-alpha.
-
diff --git a/changes/bug23820 b/changes/bug23820
deleted file mode 100644
index 4e920d0498..0000000000
--- a/changes/bug23820
+++ /dev/null
@@ -1,5 +0,0 @@
- o Minor bugfixes (IPv6, v3 single onion services):
- - Remove buggy code for IPv6-only v3 single onion services, and reject
- attempts to configure them. This release supports IPv4, dual-stack, and
- IPv6-only v3 hidden services; and IPv4 and dual-stack v3 single onion
- services. Fixes bug 23820; bugfix on 0.3.2.1-alpha.
diff --git a/changes/bug23848 b/changes/bug23848
new file mode 100644
index 0000000000..e2aec687ca
--- /dev/null
+++ b/changes/bug23848
@@ -0,0 +1,8 @@
+ o Minor features (embedding):
+ - On most errors that would cause Tor to exit, it now tries to return
+ from the tor_main() function, rather than calling the system exit()
+ function. Most users won't notice a difference here, but it should
+ make a significant difference on platforms that try to run Tor inside
+ a separate thread: they should now be able to survive Tor's exit
+ conditions rather than having Tor shut down the entire process.
+ Closes ticket 23848.
diff --git a/changes/bug23862 b/changes/bug23862
deleted file mode 100644
index 301ce73672..0000000000
--- a/changes/bug23862
+++ /dev/null
@@ -1,5 +0,0 @@
- o Minor bugfixes (entry guards):
- - Tor now updates its guard state when it reads a consensus regardless of
- whether it's missing descriptors. That makes tor use its primary guards
- to fetch descriptors in some edge cases where it would have used fallback
- directories in the past. Fixes bug 23862; bugfix on 0.3.0.1-alpha. \ No newline at end of file
diff --git a/changes/bug23874 b/changes/bug23874
deleted file mode 100644
index bf6620553d..0000000000
--- a/changes/bug23874
+++ /dev/null
@@ -1,3 +0,0 @@
- o Minor bugfixes (memory safety):
- - Clear the address when node_get_prim_orport() returns early.
- Fixes bug 23874; bugfix on 0.2.8.2-alpha.
diff --git a/changes/bug23952 b/changes/bug23952
deleted file mode 100644
index ab1462e522..0000000000
--- a/changes/bug23952
+++ /dev/null
@@ -1,4 +0,0 @@
- o Minor bugfixes (relay):
- - Avoid a BUG warning when receiving a dubious CREATE cell while
- an option transition is in progress. Fixes bug 23952; bugfix on
- 0.3.2.1-alpha.
diff --git a/changes/bug23985 b/changes/bug23985
deleted file mode 100644
index 9cb5937962..0000000000
--- a/changes/bug23985
+++ /dev/null
@@ -1,9 +0,0 @@
- o Minor 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.
diff --git a/changes/bug24002 b/changes/bug24002
deleted file mode 100644
index cdb6081110..0000000000
--- a/changes/bug24002
+++ /dev/null
@@ -1,5 +0,0 @@
- o Minor bugfixes (hidden service):
- - Make sure that we have a usable ed25519 key when the intro point relay
- does support ed25519 link authentication. We do check for an empty key
- when the relay does not support it so this makes it nice and symmetric.
- Fixes bug 24002; bugfix on 0.3.2.1-alpha.
diff --git a/changes/bug24025 b/changes/bug24025
deleted file mode 100644
index 1d7841af53..0000000000
--- a/changes/bug24025
+++ /dev/null
@@ -1,5 +0,0 @@
- o Minor bugfixes (logging, relay):
- - Downgrade a warning to a protocol warning in the case the ed25519 key is
- not consistent between the descriptor and micro descriptor of a relay.
- This can happen for instance if the relay has been flagged
- NoEdConsensus. Fixes bug 24025; bugfix on 0.3.2.1-alpha.
diff --git a/changes/bug24082 b/changes/bug24082
deleted file mode 100644
index 1523239351..0000000000
--- a/changes/bug24082
+++ /dev/null
@@ -1,3 +0,0 @@
- o Minor bugfixes (testing):
- - Fix a spurious fuzzing-only use of an uninitialized value.
- Found by Brian Carpenter. Fixes bug 24082; bugfix on 0.3.0.3-alpha.
diff --git a/changes/bug24115 b/changes/bug24115
deleted file mode 100644
index 767f13840b..0000000000
--- a/changes/bug24115
+++ /dev/null
@@ -1,4 +0,0 @@
- o Minor bugfixes (manpage, hidden service):
- - Mention that the HiddenServiceNumIntroductionPoints option is 0-10 for
- v2 service and 0-20 for v3 service. Fixes bug 24115; bugfix on
- 0.3.2.1-alpha.
diff --git a/changes/bug24137 b/changes/bug24137
new file mode 100644
index 0000000000..588e68d199
--- /dev/null
+++ b/changes/bug24137
@@ -0,0 +1,3 @@
+ o Minor bugfixes (Private Networks):
+ - Give out Exit flags in bootstrapping networks. Fixes bug 24137;
+ bugfix on 0.2.3.1-alpha.
diff --git a/changes/bug24150 b/changes/bug24150
deleted file mode 100644
index cfda7c40da..0000000000
--- a/changes/bug24150
+++ /dev/null
@@ -1,4 +0,0 @@
- o Minor bugfixes (v3 onion services):
- - Fix a memory leak when decrypting a badly formatted v3 onion
- service descriptor. Fixes bug 24150; bugfix on 0.3.2.1-alpha.
- Found by OSS-Fuzz; this is OSS-Fuzz issue 3994.
diff --git a/changes/bug24170 b/changes/bug24170
deleted file mode 100644
index d3d7347693..0000000000
--- a/changes/bug24170
+++ /dev/null
@@ -1,3 +0,0 @@
- o Minor bugfixes (path selection):
- - Actually log the total bandwidth in compute_weighted_bandwidths().
- Fixes bug 24170; bugfix on 0.2.4.3-alpha.
diff --git a/changes/bug24247 b/changes/bug24247
deleted file mode 100644
index 1f4ddcdde2..0000000000
--- a/changes/bug24247
+++ /dev/null
@@ -1,6 +0,0 @@
- o Minor bugfixes (fuzzing):
- - 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 wrather in our
- fuzzing code.) Fixes bug 24247; bugfix on 0.3.0.3-alpha.
- Found by OSS-Fuzz as issue 4177.
diff --git a/changes/feature18329 b/changes/feature18329
deleted file mode 100644
index 1dabf50244..0000000000
--- a/changes/feature18329
+++ /dev/null
@@ -1,9 +0,0 @@
- o Minor features (bridge):
- - Bridge relays can now set the BridgeDistribution config option to
- add a "bridge-distribution-request" line to their bridge descriptor,
- which tells BridgeDB how they'd like their bridge address to be
- given out. (Note that as of Oct 2017, BridgeDB does not yet implement
- this feature.) As a side benefit, this feature provides a way
- to distinguish bridge descriptors from non-bridge descriptors.
- Implements tickets 18329.
-
diff --git a/changes/geoip-2017-11-06 b/changes/geoip-2017-11-06
deleted file mode 100644
index f034be9006..0000000000
--- a/changes/geoip-2017-11-06
+++ /dev/null
@@ -1,4 +0,0 @@
- o Minor features (geoip):
- - Update geoip and geoip6 to the November 6 2017 Maxmind GeoLite2
- Country database.
-
diff --git a/changes/geoip-october2017 b/changes/geoip-october2017
deleted file mode 100644
index 11f623e85f..0000000000
--- a/changes/geoip-october2017
+++ /dev/null
@@ -1,4 +0,0 @@
- o Minor features (geoip):
- - Update geoip and geoip6 to the October 4 2017 Maxmind GeoLite2
- Country database.
-
diff --git a/changes/hsdescv3_fuzz_more b/changes/hsdescv3_fuzz_more
deleted file mode 100644
index 25626bb9a4..0000000000
--- a/changes/hsdescv3_fuzz_more
+++ /dev/null
@@ -1,3 +0,0 @@
- o Minor features (testing):
- - Our fuzzing tests now test the encrypted portions of the
- v3 hidden service descriptors. Implements more of 21509.
diff --git a/changes/longclaw_23592 b/changes/longclaw_23592
deleted file mode 100644
index 91e2da8972..0000000000
--- a/changes/longclaw_23592
+++ /dev/null
@@ -1,3 +0,0 @@
- o Directory authority changes:
- - The directory authority "Longclaw" has changed its IP address.
- Closes ticket 23592.
diff --git a/changes/ticket13605 b/changes/ticket13605
new file mode 100644
index 0000000000..0456881ff9
--- /dev/null
+++ b/changes/ticket13605
@@ -0,0 +1,5 @@
+ o Major features (relay):
+ - Implement an option, ReducedExitPolicy, to allow an Tor exit relay
+ operator to use a more reasonable ("reduced") exit policy, rather
+ than the default one. Closes ticket 13605. Patch from Neel Chauhan.
+
diff --git a/changes/ticket20895 b/changes/ticket20895
new file mode 100644
index 0000000000..a1d8204997
--- /dev/null
+++ b/changes/ticket20895
@@ -0,0 +1,6 @@
+ o Minor features (forward-compatibility):
+ - If a relay supports some link authentication protocol that we do not
+ recognize, then include that relay's ed25519 key when telling other
+ relays to extend to it. Previously, we treated future versions as if
+ they were too old to support ed25519 link authentication.
+ Closes ticket 20895.
diff --git a/changes/ticket21031 b/changes/ticket21031
deleted file mode 100644
index b081fb018f..0000000000
--- a/changes/ticket21031
+++ /dev/null
@@ -1,7 +0,0 @@
- o Minor features (removed deprecations):
- - The ClientDNSRejectInternalAddresses flag can once again be set in
- non-testing Tor networks, so long as they do not use the default
- directory authorities.
- This change also removes the deprecation of this
- flag in 0.2.9.2-alpha. Closes ticket 21031.
-
diff --git a/changes/ticket22342 b/changes/ticket22342
new file mode 100644
index 0000000000..53505509d2
--- /dev/null
+++ b/changes/ticket22342
@@ -0,0 +1,3 @@
+ o Code simplification and refactoring:
+ - Small changes to Tor's buf_t API to make it suitable for use as
+ a general-purpose safe string constructor. Closes ticket 22342.
diff --git a/changes/ticket22840 b/changes/ticket22840
new file mode 100644
index 0000000000..6d234fb0d4
--- /dev/null
+++ b/changes/ticket22840
@@ -0,0 +1,8 @@
+ o Major features (Rust experimentation):
+ - Tor now ships with an optional implementation of one of its smaller
+ modules (protover.c) in the Rust programming language. To try it
+ out, install a Rust build environment, and configure Tor with
+ "--enable-rust --enable-cargo-online-mode". This should not
+ cause any user-visible changes, but should help us gain more experience
+ with Rust, and plan future Rust integration work.
+ Implementation by Chelsea Komlo. Closes ticket 22840.
diff --git a/changes/ticket23577 b/changes/ticket23577
new file mode 100644
index 0000000000..7cd80bcb69
--- /dev/null
+++ b/changes/ticket23577
@@ -0,0 +1,7 @@
+ o Major features (v3 onion services):
+ - When v3 onion service clients send introduce cells, include the IPv6
+ address of the rendezvous point, if it has one. v3 onion services running
+ 0.3.2 ignore IPv6 addresses. In future Tor versions, IPv6-only v3 single
+ onion services can use IPv6 addresses to connect directly to the
+ rendezvous point. Closes ticket 23577. Patch by Neel Chauhan.
+
diff --git a/changes/ticket23845 b/changes/ticket23845
new file mode 100644
index 0000000000..93c150bdb0
--- /dev/null
+++ b/changes/ticket23845
@@ -0,0 +1,9 @@
+ o Major features (embedding):
+ - There is now a documented stable API for programs that need to
+ embed Tor. See tor_api.h for full documentation and known bugs.
+ Closes ticket 23684.
+
+ o Code simplification and refactoring:
+ - The tor_git_revision[] constant no longer needs to be redeclared
+ by everything that links against the rest of Tor. Done as part
+ of ticket 23845, to simplify our external API.
diff --git a/changes/ticket23900 b/changes/ticket23900
new file mode 100644
index 0000000000..0f949f4f4e
--- /dev/null
+++ b/changes/ticket23900
@@ -0,0 +1,7 @@
+ o Minor features (API, embedding):
+ - Tor can now start with a preauthenticated control connection
+ created by the process that launched it. This feature is meant
+ for use by programs that want to launch and manage a Tor process
+ without allowing other programs to manage it as well.
+ For more information, see the __OwningControllerFD option
+ documented in control-spec.txt. Closes ticket 23900.
diff --git a/changes/ticket23910 b/changes/ticket23910
deleted file mode 100644
index eb38fcf32f..0000000000
--- a/changes/ticket23910
+++ /dev/null
@@ -1,3 +0,0 @@
- o Directory authority changes:
- - Add bastet as a ninth directory authority to the default list. Closes
- ticket 23910.
diff --git a/changes/ticket24109 b/changes/ticket24109
deleted file mode 100644
index f66271817d..0000000000
--- a/changes/ticket24109
+++ /dev/null
@@ -1,4 +0,0 @@
- o Minor features (integration tests):
- - Test that IPv6-only clients can use microdescriptors when running
- "make test-network-all". Requires chutney master 61c28b9 or later.
- Closes ticket 24109.
diff --git a/configure.ac b/configure.ac
index c92118f732..998bb914b3 100644
--- a/configure.ac
+++ b/configure.ac
@@ -4,7 +4,7 @@ dnl Copyright (c) 2007-2017, The Tor Project, Inc.
dnl See LICENSE for licensing information
AC_PREREQ([2.63])
-AC_INIT([tor],[0.3.2.4-alpha-dev])
+AC_INIT([tor],[0.3.3.0-alpha-dev])
AC_CONFIG_SRCDIR([src/or/main.c])
AC_CONFIG_MACRO_DIR([m4])
@@ -375,6 +375,7 @@ AH_BOTTOM([
AM_CONDITIONAL(BUILD_NT_SERVICES, test "x$bwin32" = "xtrue")
+AM_CONDITIONAL(BUILD_LIBTORRUNNER, test "x$bwin32" != "xtrue")
dnl Enable C99 when compiling with MIPSpro
AC_MSG_CHECKING([for MIPSpro compiler])
@@ -417,34 +418,34 @@ if test "x$enable_rust" = "xyes"; then
dnl When we're not allowed to touch the network, we need crate dependencies
dnl locally available.
AC_MSG_CHECKING([rust crate dependencies])
- AC_ARG_VAR([RUST_DEPENDENCIES], [path to directory with local crate mirror])
- if test "x$RUST_DEPENDENCIES" = "x"; then
- RUST_DEPENDENCIES="$srcdir/src/ext/rust/"
+ AC_ARG_VAR([TOR_RUST_DEPENDENCIES], [path to directory with local crate mirror])
+ if test "x$TOR_RUST_DEPENDENCIES" = "x"; then
+ TOR_RUST_DEPENDENCIES="$srcdir/src/ext/rust/"
NEED_MOD=1
fi
- if test ! -d "$RUST_DEPENDENCIES"; then
- AC_MSG_ERROR([Rust dependency directory $RUST_DEPENDENCIES does not exist. Specify a dependency directory using the RUST_DEPENDENCIES variable or allow cargo to fetch crates using --enable-cargo-online-mode.])
+ if test ! -d "$TOR_RUST_DEPENDENCIES"; then
+ AC_MSG_ERROR([Rust dependency directory $TOR_RUST_DEPENDENCIES does not exist. Specify a dependency directory using the TOR_RUST_DEPENDENCIES variable or allow cargo to fetch crates using --enable-cargo-online-mode.])
fi
for dep in $rust_crates; do
- if test ! -d "$RUST_DEPENDENCIES"/"$dep"; then
- AC_MSG_ERROR([Failure to find rust dependency $RUST_DEPENDENCIES/$dep. Specify a dependency directory using the RUST_DEPENDENCIES variable or allow cargo to fetch crates using --enable-cargo-online-mode.])
+ if test ! -d "$TOR_RUST_DEPENDENCIES"/"$dep"; then
+ AC_MSG_ERROR([Failure to find rust dependency $TOR_RUST_DEPENDENCIES/$dep. Specify a dependency directory using the TOR_RUST_DEPENDENCIES variable or allow cargo to fetch crates using --enable-cargo-online-mode.])
fi
done
if test "x$NEED_MOD" = "x1"; then
dnl When looking for dependencies from cargo, pick right directory
- RUST_DEPENDENCIES="../../src/ext/rust"
+ TOR_RUST_DEPENDENCIES="../../src/ext/rust"
fi
fi
dnl For now both MSVC and MinGW rust libraries will output static libs with
dnl the MSVC naming convention.
if test "$bwin32" = "true"; then
- TOR_RUST_UTIL_STATIC_NAME=tor_util.lib
+ TOR_RUST_STATIC_NAME=tor_rust.lib
else
- TOR_RUST_UTIL_STATIC_NAME=libtor_util.a
+ TOR_RUST_STATIC_NAME=libtor_rust.a
fi
- AC_SUBST(TOR_RUST_UTIL_STATIC_NAME)
+ AC_SUBST(TOR_RUST_STATIC_NAME)
AC_SUBST(CARGO_ONLINE)
AC_SUBST(RUST_DL)
diff --git a/contrib/win32build/tor-mingw.nsi.in b/contrib/win32build/tor-mingw.nsi.in
index c486bd69eb..f3c23ef335 100644
--- a/contrib/win32build/tor-mingw.nsi.in
+++ b/contrib/win32build/tor-mingw.nsi.in
@@ -8,7 +8,7 @@
!include "LogicLib.nsh"
!include "FileFunc.nsh"
!insertmacro GetParameters
-!define VERSION "0.3.2.4-alpha-dev"
+!define VERSION "0.3.3.0-alpha-dev"
!define INSTALLER "tor-${VERSION}-win32.exe"
!define WEBSITE "https://www.torproject.org/"
!define LICENSE "LICENSE"
diff --git a/doc/HACKING/GettingStartedRust.md b/doc/HACKING/GettingStartedRust.md
index a5253b46a6..181535122c 100644
--- a/doc/HACKING/GettingStartedRust.md
+++ b/doc/HACKING/GettingStartedRust.md
@@ -125,6 +125,16 @@ is on our TODO list to try to cultivate good standing with various distro
maintainers of `rustc` and `cargo`, in order to ensure that whatever version we
solidify on is readily available.
+If parts of your Rust code needs to stay in sync with C code (such as handling
+enums across the FFI boundary), annonotate these places in a comment structured
+as follows:
+
+ /// C_RUST_COUPLED: <path_to_file> `<name_of_c_object>`
+
+Where <name_of_c_object> can be an enum, struct, constant, etc. Then, do the
+same in the C code, to note that rust will need to be changed when the C
+does.
+
Adding your Rust module to Tor's build system
-----------------------------------------------
@@ -132,8 +142,13 @@ solidify on is readily available.
in the `.../tor/src/rust/` directory.
1. Add your crate to `.../tor/src/rust/Cargo.toml`, in the
`[workspace.members]` section.
-2. Append your crate's static library to the `rust_ldadd` definition
- (underneath `if USE_RUST`) in `.../tor/Makefile.am`.
+2. Add your crate's files to src/rust/include.am
+
+If your crate should be available to C (rather than just being included as a
+dependency of other Rust modules):
+0. Declare the crate as a dependency of tor_rust in
+ `src/rust/tor_util/Cargo.toml` and include it in
+ `src/rust/tor_rust/lib.rs`
How to test your Rust code
----------------------------
diff --git a/doc/HACKING/ReleasingTor.md b/doc/HACKING/ReleasingTor.md
index 62029b44f0..9cbc8710bb 100644
--- a/doc/HACKING/ReleasingTor.md
+++ b/doc/HACKING/ReleasingTor.md
@@ -171,7 +171,8 @@ new Tor release:
- {mike} at tig dot as
- {tails-rm} at boum dot org
- {simon} at sdeziel.info
- - {yuri} at rawbw.com
+ - {yuri} at freebsd.org
+ - {mh+tor} at scrit.ch
4. Add the version number to Trac. To do this, go to Trac, log in,
select "Admin" near the top of the screen, then select "Versions" from
diff --git a/doc/tor.1.txt b/doc/tor.1.txt
index f052464332..725baaa643 100644
--- a/doc/tor.1.txt
+++ b/doc/tor.1.txt
@@ -1215,8 +1215,8 @@ The following options are useful only for clients (that is, if
nodes via this connection.
**UseIPv4Cache**;;
Tells the client to use any cached IPv4 DNS answers we have when making
- requests via this connection. (NOTE: This option, along UseIPv6Cache
- and UseDNSCache, can harm your anonymity, and probably
+ requests via this connection. (NOTE: This option, or UseIPv6Cache
+ or UseDNSCache, can harm your anonymity, and probably
won't help performance as much as you might expect. Use with care!)
**UseIPv6Cache**;;
Tells the client to use any cached IPv6 DNS answers we have when making
@@ -1763,8 +1763,15 @@ is non-zero):
write your IPv6 rules using accept6/reject6 \*6, and your IPv4 rules using
accept/reject \*4. If you want to \_replace_ the default exit policy, end
your exit policy with either a reject \*:* or an accept \*:*. Otherwise,
- you're \_augmenting_ (prepending to) the default exit policy. The default
- exit policy is: +
+ you're \_augmenting_ (prepending to) the default exit policy. +
+ +
+ If you want to use a reduced exit policy rather than the default exit
+ policy, set "ReducedExitPolicy 1". If you want to _replace_ the default
+ exit policy with your custom exit policy, end your exit policy with either
+ a reject *:* or an accept *:*. Otherwise, you’re _augmenting_ (prepending
+ to) the default or reduced exit policy. +
+ +
+ The default exit policy is:
reject *:25
reject *:119
@@ -1778,7 +1785,7 @@ is non-zero):
reject *:6881-6999
accept *:*
-[[ExitPolicyDefault]]::
+[[ExitPolicyDefault]] **ExitPolicyDefault**::
Since the default exit policy uses accept/reject *, it applies to both
IPv4 and IPv6 addresses.
@@ -1800,6 +1807,99 @@ is non-zero):
to disclose.
(Default: 0)
+[[ReducedExitPolicy]] **ReducedExitPolicy** **0**|**1**::
+ If set, use a reduced exit policy rather than the default one. +
+ +
+ The reduced exit policy is an alternative to the default exit policy. It
+ allows as many Internet services as possible while still blocking the
+ majority of TCP ports. Currently, the policy allows approximately 65 ports.
+ This reduces the odds that your node will be used for peer-to-peer
+ applications. +
+ +
+ The reduced exit policy is:
+
+ accept *:20-21
+ accept *:22
+ accept *:23
+ accept *:43
+ accept *:53
+ accept *:79
+ accept *:80-81
+ accept *:88
+ accept *:110
+ accept *:143
+ accept *:194
+ accept *:220
+ accept *:389
+ accept *:443
+ accept *:464
+ accept *:465
+ accept *:531
+ accept *:543-544
+ accept *:554
+ accept *:563
+ accept *:587
+ accept *:636
+ accept *:706
+ accept *:749
+ accept *:873
+ accept *:902-904
+ accept *:981
+ accept *:989-990
+ accept *:991
+ accept *:992
+ accept *:993
+ accept *:994
+ accept *:995
+ accept *:1194
+ accept *:1220
+ accept *:1293
+ accept *:1500
+ accept *:1533
+ accept *:1677
+ accept *:1723
+ accept *:1755
+ accept *:1863
+ accept *:2082
+ accept *:2083
+ accept *:2086-2087
+ accept *:2095-2096
+ accept *:2102-2104
+ accept *:3128
+ accept *:3389
+ accept *:3690
+ accept *:4321
+ accept *:4643
+ accept *:5050
+ accept *:5190
+ accept *:5222-5223
+ accept *:5228
+ accept *:5900
+ accept *:6660-6669
+ accept *:6679
+ accept *:6697
+ accept *:8000
+ accept *:8008
+ accept *:8074
+ accept *:8080
+ accept *:8082
+ accept *:8087-8088
+ accept *:8232-8233
+ accept *:8332-8333
+ accept *:8443
+ accept *:8888
+ accept *:9418
+ accept *:9999
+ accept *:10000
+ accept *:11371
+ accept *:19294
+ accept *:19638
+ accept *:50002
+ accept *:64738
+ reject *:*
+
+ (Default: 0)
+
[[IPv6Exit]] **IPv6Exit** **0**|**1**::
If set, and we are an exit node, allow clients to use us for IPv6
traffic. (Default: 0)
diff --git a/scripts/codegen/fuzzing_include_am.py b/scripts/codegen/fuzzing_include_am.py
index fee6d4494a..fda57d2ae8 100755
--- a/scripts/codegen/fuzzing_include_am.py
+++ b/scripts/codegen/fuzzing_include_am.py
@@ -9,7 +9,7 @@ FUZZERS = """
hsdescv2
hsdescv3
http
- http-connect
+ http-connect
iptsv2
microdesc
vrs
diff --git a/src/common/aes.c b/src/common/aes.c
index 20b51a6758..df4368fdba 100644
--- a/src/common/aes.c
+++ b/src/common/aes.c
@@ -254,7 +254,7 @@ evaluate_ctr_for_aes(void)
/* LCOV_EXCL_START */
log_err(LD_CRYPTO, "This OpenSSL has a buggy version of counter mode; "
"quitting tor.");
- exit(1);
+ exit(1); // exit ok: openssl is broken.
/* LCOV_EXCL_STOP */
}
return 0;
diff --git a/src/common/buffers.c b/src/common/buffers.c
index c45e13d551..a21cf2ab5b 100644
--- a/src/common/buffers.c
+++ b/src/common/buffers.c
@@ -714,6 +714,53 @@ buf_add(buf_t *buf, const char *string, size_t string_len)
return (int)buf->datalen;
}
+/** Add a nul-terminated <b>string</b> to <b>buf</b>, not including the
+ * terminating NUL. */
+void
+buf_add_string(buf_t *buf, const char *string)
+{
+ buf_add(buf, string, strlen(string));
+}
+
+/** As tor_snprintf, but write the results into a buf_t */
+void
+buf_add_printf(buf_t *buf, const char *format, ...)
+{
+ va_list ap;
+ va_start(ap,format);
+ buf_add_vprintf(buf, format, ap);
+ va_end(ap);
+}
+
+/** As tor_vsnprintf, but write the results into a buf_t. */
+void
+buf_add_vprintf(buf_t *buf, const char *format, va_list args)
+{
+ /* XXXX Faster implementations are easy enough, but let's optimize later */
+ char *tmp;
+ tor_vasprintf(&tmp, format, args);
+ buf_add(buf, tmp, strlen(tmp));
+ tor_free(tmp);
+}
+
+/** Return a heap-allocated string containing the contents of <b>buf</b>, plus
+ * a NUL byte. If <b>sz_out</b> is provided, set *<b>sz_out</b> to the length
+ * of the returned string, not including the terminating NUL. */
+char *
+buf_extract(buf_t *buf, size_t *sz_out)
+{
+ tor_assert(buf);
+
+ size_t sz = buf_datalen(buf);
+ char *result;
+ result = tor_malloc(sz+1);
+ buf_peek(buf, result, sz);
+ result[sz] = 0;
+ if (sz_out)
+ *sz_out = sz;
+ return result;
+}
+
/** Helper: copy the first <b>string_len</b> bytes from <b>buf</b>
* onto <b>string</b>.
*/
@@ -795,6 +842,28 @@ buf_move_to_buf(buf_t *buf_out, buf_t *buf_in, size_t *buf_flushlen)
return (int)cp;
}
+/** Moves all data from <b>buf_in</b> to <b>buf_out</b>, without copying.
+ */
+void
+buf_move_all(buf_t *buf_out, buf_t *buf_in)
+{
+ tor_assert(buf_out);
+ if (!buf_in)
+ return;
+
+ if (buf_out->head == NULL) {
+ buf_out->head = buf_in->head;
+ buf_out->tail = buf_in->tail;
+ } else {
+ buf_out->tail->next = buf_in->head;
+ buf_out->tail = buf_in->tail;
+ }
+
+ buf_out->datalen += buf_in->datalen;
+ buf_in->head = buf_in->tail = NULL;
+ buf_in->datalen = 0;
+}
+
/** Internal structure: represents a position in a buffer. */
typedef struct buf_pos_t {
const chunk_t *chunk; /**< Which chunk are we pointing to? */
diff --git a/src/common/buffers.h b/src/common/buffers.h
index 1eaa5f2d04..dd96ddcb6c 100644
--- a/src/common/buffers.h
+++ b/src/common/buffers.h
@@ -43,9 +43,15 @@ int buf_flush_to_socket(buf_t *buf, tor_socket_t s, size_t sz,
size_t *buf_flushlen);
int buf_add(buf_t *buf, const char *string, size_t string_len);
+void buf_add_string(buf_t *buf, const char *string);
+void buf_add_printf(buf_t *buf, const char *format, ...)
+ CHECK_PRINTF(2, 3);
+void buf_add_vprintf(buf_t *buf, const char *format, va_list args)
+ CHECK_PRINTF(2, 0);
int buf_add_compress(buf_t *buf, struct tor_compress_state_t *state,
const char *data, size_t data_len, int done);
int buf_move_to_buf(buf_t *buf_out, buf_t *buf_in, size_t *buf_flushlen);
+void buf_move_all(buf_t *buf_out, buf_t *buf_in);
void buf_peek(const buf_t *buf, char *string, size_t string_len);
void buf_drain(buf_t *buf, size_t n);
int buf_get_bytes(buf_t *buf, char *string, size_t string_len);
@@ -62,6 +68,7 @@ void buf_assert_ok(buf_t *buf);
int buf_find_string_offset(const buf_t *buf, const char *s, size_t n);
void buf_pullup(buf_t *buf, size_t bytes,
const char **head_out, size_t *len_out);
+char *buf_extract(buf_t *buf, size_t *sz_out);
#ifdef BUFFERS_PRIVATE
#ifdef TOR_UNIT_TESTS
diff --git a/src/common/compat.c b/src/common/compat.c
index 7fe97488e3..38693b21fe 100644
--- a/src/common/compat.c
+++ b/src/common/compat.c
@@ -1186,7 +1186,7 @@ mark_socket_open(tor_socket_t s)
bitarray_set(open_sockets, s);
}
#else /* !(defined(DEBUG_SOCKET_COUNTING)) */
-#define mark_socket_open(s) STMT_NIL
+#define mark_socket_open(s) ((void) (s))
#endif /* defined(DEBUG_SOCKET_COUNTING) */
/** @} */
@@ -1273,11 +1273,22 @@ tor_open_socket_with_extensions(int domain, int type, int protocol,
goto socket_ok; /* So that socket_ok will not be unused. */
socket_ok:
+ tor_take_socket_ownership(s);
+ return s;
+}
+
+/**
+ * For socket accounting: remember that we are the owner of the socket
+ * <b>s</b>. This will prevent us from overallocating sockets, and prevent us
+ * from asserting later when we close the socket <b>s</b>.
+ */
+void
+tor_take_socket_ownership(tor_socket_t s)
+{
socket_accounting_lock();
++n_sockets_open;
mark_socket_open(s);
socket_accounting_unlock();
- return s;
}
/** As accept(), but counts the number of open sockets. */
@@ -1358,10 +1369,7 @@ tor_accept_socket_with_extensions(tor_socket_t sockfd, struct sockaddr *addr,
goto socket_ok; /* So that socket_ok will not be unused. */
socket_ok:
- socket_accounting_lock();
- ++n_sockets_open;
- mark_socket_open(s);
- socket_accounting_unlock();
+ tor_take_socket_ownership(s);
return s;
}
diff --git a/src/common/compat.h b/src/common/compat.h
index fee9e6587d..0aabee68c8 100644
--- a/src/common/compat.h
+++ b/src/common/compat.h
@@ -483,6 +483,7 @@ typedef int socklen_t;
int tor_close_socket_simple(tor_socket_t s);
MOCK_DECL(int, tor_close_socket, (tor_socket_t s));
+void tor_take_socket_ownership(tor_socket_t s);
tor_socket_t tor_open_socket_with_extensions(
int domain, int type, int protocol,
int cloexec, int nonblock);
diff --git a/src/common/compat_libevent.c b/src/common/compat_libevent.c
index 740cc2a11d..1c3a1b9f37 100644
--- a/src/common/compat_libevent.c
+++ b/src/common/compat_libevent.c
@@ -126,7 +126,7 @@ tor_libevent_initialize(tor_libevent_cfg *torcfg)
if (!the_event_base) {
/* LCOV_EXCL_START */
log_err(LD_GENERAL, "Unable to initialize Libevent: cannot continue.");
- exit(1);
+ exit(1); // exit ok: libevent is broken.
/* LCOV_EXCL_STOP */
}
diff --git a/src/common/compat_libevent.h b/src/common/compat_libevent.h
index 834354c405..3d8672fc63 100644
--- a/src/common/compat_libevent.h
+++ b/src/common/compat_libevent.h
@@ -30,6 +30,7 @@ periodic_timer_t *periodic_timer_new(struct event_base *base,
void periodic_timer_free(periodic_timer_t *);
#define tor_event_base_loopexit event_base_loopexit
+#define tor_event_base_loopbreak event_base_loopbreak
/** Defines a configuration for using libevent with Tor: passed as an argument
* to tor_libevent_initialize() to describe how we want to set up. */
diff --git a/src/common/compat_rust.c b/src/common/compat_rust.c
deleted file mode 100644
index 366fd4037b..0000000000
--- a/src/common/compat_rust.c
+++ /dev/null
@@ -1,39 +0,0 @@
-/* Copyright (c) 2017, The Tor Project, Inc. */
-/* See LICENSE for licensing information */
-
-/**
- * \file rust_compat.c
- * \brief Rust FFI compatibility functions and helpers. This file is only built
- * if Rust is not used.
- **/
-
-#include "compat_rust.h"
-#include "util.h"
-
-/**
- * Free storage pointed to by <b>str</b>, and itself.
- */
-void
-rust_str_free(rust_str_t str)
-{
- char *s = (char *)str;
- tor_free(s);
-}
-
-/**
- * Return zero-terminated contained string.
- */
-const char *
-rust_str_get(const rust_str_t str)
-{
- return (const char *)str;
-}
-
-/* If we were using Rust, we'd say so on startup. */
-rust_str_t
-rust_welcome_string(void)
-{
- char *s = tor_malloc_zero(1);
- return (rust_str_t)s;
-}
-
diff --git a/src/common/compat_rust.h b/src/common/compat_rust.h
deleted file mode 100644
index 72fde39296..0000000000
--- a/src/common/compat_rust.h
+++ /dev/null
@@ -1,28 +0,0 @@
-/* Copyright (c) 2017, The Tor Project, Inc. */
-/* See LICENSE for licensing information */
-
-/**
- * \file rust_compat.h
- * \brief Headers for rust_compat.c
- **/
-
-#ifndef TOR_RUST_COMPAT_H
-#define TOR_RUST_COMPAT_H
-
-#include "torint.h"
-
-/**
- * Strings allocated in Rust must be freed from Rust code again. Let's make
- * it less likely to accidentally mess up and call tor_free() on it, because
- * currently it'll just work but might break at any time.
- */
-typedef uintptr_t rust_str_t;
-
-void rust_str_free(rust_str_t);
-
-const char *rust_str_get(const rust_str_t);
-
-rust_str_t rust_welcome_string(void);
-
-#endif /* !defined(TOR_RUST_COMPAT_H) */
-
diff --git a/src/common/compat_time.c b/src/common/compat_time.c
index 1ce6f5ce4e..7fd4281ade 100644
--- a/src/common/compat_time.c
+++ b/src/common/compat_time.c
@@ -90,7 +90,7 @@ tor_gettimeofday(struct timeval *timeval)
if (ft.ft_64 < EPOCH_BIAS) {
/* LCOV_EXCL_START */
log_err(LD_GENERAL,"System time is before 1970; failing.");
- exit(1);
+ exit(1); // exit ok: system clock is broken.
/* LCOV_EXCL_STOP */
}
ft.ft_64 -= EPOCH_BIAS;
@@ -102,7 +102,7 @@ tor_gettimeofday(struct timeval *timeval)
log_err(LD_GENERAL,"gettimeofday failed.");
/* If gettimeofday dies, we have either given a bad timezone (we didn't),
or segfaulted.*/
- exit(1);
+ exit(1); // exit ok: gettimeofday failed.
/* LCOV_EXCL_STOP */
}
#elif defined(HAVE_FTIME)
diff --git a/src/common/compat_winthreads.c b/src/common/compat_winthreads.c
index 50a3c498ca..5f7ec94c23 100644
--- a/src/common/compat_winthreads.c
+++ b/src/common/compat_winthreads.c
@@ -48,10 +48,12 @@ void
spawn_exit(void)
{
_endthread();
+ // LCOV_EXCL_START
//we should never get here. my compiler thinks that _endthread returns, this
//is an attempt to fool it.
tor_assert(0);
- _exit(0);
+ _exit(0); // exit ok: unreachable.
+ // LCOV_EXCL_STOP
}
void
diff --git a/src/common/confline.c b/src/common/confline.c
index 04545bc2c3..781ad2a12b 100644
--- a/src/common/confline.c
+++ b/src/common/confline.c
@@ -12,15 +12,18 @@
static int config_get_lines_aux(const char *string, config_line_t **result,
int extended, int allow_include,
- int *has_include, int recursion_level,
- config_line_t **last);
-static smartlist_t *config_get_file_list(const char *path);
-static int config_get_included_list(const char *path, int recursion_level,
- int extended, config_line_t **list,
- config_line_t **list_last);
+ int *has_include, smartlist_t *opened_lst,
+ int recursion_level, config_line_t **last);
+static smartlist_t *config_get_file_list(const char *path,
+ smartlist_t *opened_files);
+static int config_get_included_config(const char *path, int recursion_level,
+ int extended, config_line_t **config,
+ config_line_t **config_last,
+ smartlist_t *opened_lst);
static int config_process_include(const char *path, int recursion_level,
int extended, config_line_t **list,
- config_line_t **list_last);
+ config_line_t **list_last,
+ smartlist_t *opened_lst);
/** Helper: allocate a new configuration option mapping 'key' to 'val',
* append it to *<b>lst</b>. */
@@ -80,11 +83,13 @@ config_line_find(const config_line_t *lines,
/** Auxiliary function that does all the work of config_get_lines.
* <b>recursion_level</b> is the count of how many nested %includes we have.
+ * <b>opened_lst</b> will have a list of opened files if provided.
* Returns the a pointer to the last element of the <b>result</b> in
* <b>last</b>. */
static int
config_get_lines_aux(const char *string, config_line_t **result, int extended,
- int allow_include, int *has_include, int recursion_level,
+ int allow_include, int *has_include,
+ smartlist_t *opened_lst, int recursion_level,
config_line_t **last)
{
config_line_t *list = NULL, **next, *list_last = NULL;
@@ -134,7 +139,7 @@ config_get_lines_aux(const char *string, config_line_t **result, int extended,
config_line_t *include_list;
if (config_process_include(v, recursion_level, extended, &include_list,
- &list_last) < 0) {
+ &list_last, opened_lst) < 0) {
log_warn(LD_CONFIG, "Error reading included configuration "
"file or directory: \"%s\".", v);
config_free_lines(list);
@@ -176,24 +181,27 @@ config_get_lines_aux(const char *string, config_line_t **result, int extended,
/** Helper: parse the config string and strdup into key/value
* strings. Set *result to the list, or NULL if parsing the string
* failed. Set *has_include to 1 if <b>result</b> has values from
- * %included files. Return 0 on success, -1 on failure. Warn and ignore any
+ * %included files. <b>opened_lst</b> will have a list of opened files if
+ * provided. Return 0 on success, -1 on failure. Warn and ignore any
* misformatted lines.
*
* If <b>extended</b> is set, then treat keys beginning with / and with + as
* indicating "clear" and "append" respectively. */
int
config_get_lines_include(const char *string, config_line_t **result,
- int extended, int *has_include)
+ int extended, int *has_include,
+ smartlist_t *opened_lst)
{
- return config_get_lines_aux(string, result, extended, 1, has_include, 1,
- NULL);
+ return config_get_lines_aux(string, result, extended, 1, has_include,
+ opened_lst, 1, NULL);
}
/** Same as config_get_lines_include but does not allow %include */
int
config_get_lines(const char *string, config_line_t **result, int extended)
{
- return config_get_lines_aux(string, result, extended, 0, NULL, 1, NULL);
+ return config_get_lines_aux(string, result, extended, 0, NULL, NULL, 1,
+ NULL);
}
/** Adds a list of configuration files present on <b>path</b> to
@@ -201,12 +209,18 @@ config_get_lines(const char *string, config_line_t **result, int extended)
* only that file will be added to <b>file_list</b>. If it is a directory,
* all paths for files on that directory root (no recursion) except for files
* whose name starts with a dot will be added to <b>file_list</b>.
- * Return 0 on success, -1 on failure. Ignores empty files.
+ * <b>opened_files</b> will have a list of files opened by this function
+ * if provided. Return 0 on success, -1 on failure. Ignores empty files.
*/
static smartlist_t *
-config_get_file_list(const char *path)
+config_get_file_list(const char *path, smartlist_t *opened_files)
{
smartlist_t *file_list = smartlist_new();
+
+ if (opened_files) {
+ smartlist_add_strdup(opened_files, path);
+ }
+
file_status_t file_type = file_status(path);
if (file_type == FN_FILE) {
smartlist_add_strdup(file_list, path);
@@ -228,6 +242,10 @@ config_get_file_list(const char *path)
tor_asprintf(&fullname, "%s"PATH_SEPARATOR"%s", path, f);
tor_free(f);
+ if (opened_files) {
+ smartlist_add_strdup(opened_files, fullname);
+ }
+
if (file_status(fullname) != FN_FILE) {
tor_free(fullname);
continue;
@@ -245,19 +263,21 @@ config_get_file_list(const char *path)
}
/** Creates a list of config lines present on included <b>path</b>.
- * Set <b>list</b> to the list and <b>list_last</b> to the last element of
- * <b>list</b>. Return 0 on success, -1 on failure. */
+ * Set <b>config</b> to the list and <b>config_last</b> to the last element of
+ * <b>config</b>. <b>opened_lst</b> will have a list of opened files if
+ * provided. Return 0 on success, -1 on failure. */
static int
-config_get_included_list(const char *path, int recursion_level, int extended,
- config_line_t **list, config_line_t **list_last)
+config_get_included_config(const char *path, int recursion_level, int extended,
+ config_line_t **config, config_line_t **config_last,
+ smartlist_t *opened_lst)
{
char *included_conf = read_file_to_str(path, 0, NULL);
if (!included_conf) {
return -1;
}
- if (config_get_lines_aux(included_conf, list, extended, 1, NULL,
- recursion_level+1, list_last) < 0) {
+ if (config_get_lines_aux(included_conf, config, extended, 1, NULL,
+ opened_lst, recursion_level+1, config_last) < 0) {
tor_free(included_conf);
return -1;
}
@@ -268,41 +288,31 @@ config_get_included_list(const char *path, int recursion_level, int extended,
/** Process an %include <b>path</b> in a config file. Set <b>list</b> to the
* list of configuration settings obtained and <b>list_last</b> to the last
- * element of the same list. Return 0 on success, -1 on failure. */
+ * element of the same list. <b>opened_lst</b> will have a list of opened
+ * files if provided. Return 0 on success, -1 on failure. */
static int
config_process_include(const char *path, int recursion_level, int extended,
- config_line_t **list, config_line_t **list_last)
+ config_line_t **list, config_line_t **list_last,
+ smartlist_t *opened_lst)
{
config_line_t *ret_list = NULL;
config_line_t **next = &ret_list;
-#if 0
- // Disabled -- we already unescape_string() on the result. */
- char *unquoted_path = get_unquoted_path(path);
- if (!unquoted_path) {
- return -1;
- }
- smartlist_t *config_files = config_get_file_list(unquoted_path);
- if (!config_files) {
- tor_free(unquoted_path);
- return -1;
- }
- tor_free(unquoted_path);
-#endif /* 0 */
- smartlist_t *config_files = config_get_file_list(path);
+ smartlist_t *config_files = config_get_file_list(path, opened_lst);
if (!config_files) {
return -1;
}
int rv = -1;
SMARTLIST_FOREACH_BEGIN(config_files, const char *, config_file) {
- config_line_t *included_list = NULL;
- if (config_get_included_list(config_file, recursion_level, extended,
- &included_list, list_last) < 0) {
+ config_line_t *included_config = NULL;
+ if (config_get_included_config(config_file, recursion_level, extended,
+ &included_config, list_last,
+ opened_lst) < 0) {
goto done;
}
- *next = included_list;
+ *next = included_config;
if (*list_last)
next = &(*list_last)->next;
diff --git a/src/common/confline.h b/src/common/confline.h
index 8256326f2d..feeb9f249d 100644
--- a/src/common/confline.h
+++ b/src/common/confline.h
@@ -7,6 +7,8 @@
#ifndef TOR_CONFLINE_H
#define TOR_CONFLINE_H
+#include "container.h"
+
/** Ordinary configuration line. */
#define CONFIG_LINE_NORMAL 0
/** Appends to previous configuration for the same option, even if we
@@ -44,7 +46,8 @@ int config_lines_eq(config_line_t *a, config_line_t *b);
int config_count_key(const config_line_t *a, const char *key);
int config_get_lines(const char *string, config_line_t **result, int extended);
int config_get_lines_include(const char *string, config_line_t **result,
- int extended, int *has_include);
+ int extended, int *has_include,
+ smartlist_t *opened_lst);
void config_free_lines(config_line_t *front);
const char *parse_config_line_from_str_verbose(const char *line,
char **key_out, char **value_out,
diff --git a/src/common/crypto_pwbox.h b/src/common/crypto_pwbox.h
index cee8653587..a26b6d2c17 100644
--- a/src/common/crypto_pwbox.h
+++ b/src/common/crypto_pwbox.h
@@ -1,3 +1,6 @@
+/* Copyright (c) 2014-2017, The Tor Project, Inc. */
+/* See LICENSE for licensing information */
+
#ifndef CRYPTO_PWBOX_H_INCLUDED_
#define CRYPTO_PWBOX_H_INCLUDED_
diff --git a/src/common/include.am b/src/common/include.am
index cd5eea3404..2856c40fdc 100644
--- a/src/common/include.am
+++ b/src/common/include.am
@@ -101,11 +101,6 @@ LIBOR_A_SRC = \
$(threads_impl_source) \
$(readpassphrase_source)
-if USE_RUST
-else
-LIBOR_A_SRC += src/common/compat_rust.c
-endif
-
src/common/src_common_libor_testing_a-log.$(OBJEXT) \
src/common/log.$(OBJEXT): micro-revision.i
@@ -156,7 +151,6 @@ COMMONHEADERS = \
src/common/compat.h \
src/common/compat_libevent.h \
src/common/compat_openssl.h \
- src/common/compat_rust.h \
src/common/compat_threads.h \
src/common/compat_time.h \
src/common/compress.h \
diff --git a/src/common/sandbox.c b/src/common/sandbox.c
index 7a4e3ece38..8cb78bd28e 100644
--- a/src/common/sandbox.c
+++ b/src/common/sandbox.c
@@ -151,6 +151,7 @@ static int filter_nopar_gen[] = {
SCMP_SYS(fstat64),
#endif
SCMP_SYS(futex),
+ SCMP_SYS(getdents),
SCMP_SYS(getdents64),
SCMP_SYS(getegid),
#ifdef __NR_getegid32
@@ -1756,7 +1757,7 @@ sigsys_debugging(int nr, siginfo_t *info, void *void_context)
#endif
#if defined(DEBUGGING_CLOSE)
- _exit(1);
+ _exit(1); // exit ok: programming error has led to sandbox failure.
#endif // DEBUGGING_CLOSE
}
diff --git a/src/common/util.c b/src/common/util.c
index 5ff7e104d6..7dc5e8144d 100644
--- a/src/common/util.c
+++ b/src/common/util.c
@@ -156,7 +156,7 @@ tor_malloc_(size_t size DMALLOC_PARAMS)
/* If these functions die within a worker process, they won't call
* spawn_exit, but that's ok, since the parent will run out of memory soon
* anyway. */
- exit(1);
+ exit(1); // exit ok: alloc failed.
/* LCOV_EXCL_STOP */
}
return result;
@@ -244,7 +244,7 @@ tor_realloc_(void *ptr, size_t size DMALLOC_PARAMS)
if (PREDICT_UNLIKELY(result == NULL)) {
/* LCOV_EXCL_START */
log_err(LD_MM,"Out of memory on realloc(). Dying.");
- exit(1);
+ exit(1); // exit ok: alloc failed.
/* LCOV_EXCL_STOP */
}
return result;
@@ -282,7 +282,7 @@ tor_strdup_(const char *s DMALLOC_PARAMS)
if (PREDICT_UNLIKELY(duplicate == NULL)) {
/* LCOV_EXCL_START */
log_err(LD_MM,"Out of memory on strdup(). Dying.");
- exit(1);
+ exit(1); // exit ok: alloc failed.
/* LCOV_EXCL_STOP */
}
return duplicate;
@@ -3590,14 +3590,14 @@ start_daemon(void)
if (pipe(daemon_filedes)) {
/* LCOV_EXCL_START */
log_err(LD_GENERAL,"pipe failed; exiting. Error was %s", strerror(errno));
- exit(1);
+ exit(1); // exit ok: during daemonize, pipe failed.
/* LCOV_EXCL_STOP */
}
pid = fork();
if (pid < 0) {
/* LCOV_EXCL_START */
log_err(LD_GENERAL,"fork failed. Exiting.");
- exit(1);
+ exit(1); // exit ok: during daemonize, fork failed
/* LCOV_EXCL_STOP */
}
if (pid) { /* Parent */
@@ -3612,9 +3612,9 @@ start_daemon(void)
}
fflush(stdout);
if (ok == 1)
- exit(0);
+ exit(0); // exit ok: during daemonize, daemonizing.
else
- exit(1); /* child reported error */
+ exit(1); /* child reported error. exit ok: daemonize failed. */
} else { /* Child */
close(daemon_filedes[0]); /* we only write */
@@ -3626,7 +3626,7 @@ start_daemon(void)
* _Advanced Programming in the Unix Environment_.
*/
if (fork() != 0) {
- exit(0);
+ exit(0); // exit ok: during daemonize, fork failed (2)
}
set_main_thread(); /* We are now the main thread. */
@@ -3655,14 +3655,14 @@ finish_daemon(const char *desired_cwd)
/* Don't hold the wrong FS mounted */
if (chdir(desired_cwd) < 0) {
log_err(LD_GENERAL,"chdir to \"%s\" failed. Exiting.",desired_cwd);
- exit(1);
+ exit(1); // exit ok: during daemonize, chdir failed.
}
nullfd = tor_open_cloexec("/dev/null", O_RDWR, 0);
if (nullfd < 0) {
/* LCOV_EXCL_START */
log_err(LD_GENERAL,"/dev/null can't be opened. Exiting.");
- exit(1);
+ exit(1); // exit ok: during daemonize, couldn't open /dev/null
/* LCOV_EXCL_STOP */
}
/* close fds linking to invoking terminal, but
@@ -3674,7 +3674,7 @@ finish_daemon(const char *desired_cwd)
dup2(nullfd,2) < 0) {
/* LCOV_EXCL_START */
log_err(LD_GENERAL,"dup2 failed. Exiting.");
- exit(1);
+ exit(1); // exit ok: during daemonize, dup2 failed.
/* LCOV_EXCL_STOP */
}
if (nullfd > 2)
@@ -4474,7 +4474,7 @@ tor_spawn_background(const char *const filename, const char **argv,
err += (nbytes < 0);
}
- _exit(err?254:255);
+ _exit(err?254:255); // exit ok: in child.
}
/* Never reached, but avoids compiler warning */
diff --git a/src/or/addressmap.c b/src/or/addressmap.c
index 7e92633601..9a2cc26b3b 100644
--- a/src/or/addressmap.c
+++ b/src/or/addressmap.c
@@ -541,7 +541,7 @@ addressmap_have_mapping(const char *address, int update_expiry)
* (virtual address mapping) from the controller.)
*
* <b>new_address</b> should be a newly dup'ed string, which we'll use or
- * free as appropriate. We will leave address alone.
+ * free as appropriate. We will leave <b>address</b> alone.
*
* If <b>wildcard_addr</b> is true, then the mapping will match any address
* equal to <b>address</b>, or any address ending with a period followed by
@@ -554,7 +554,6 @@ addressmap_have_mapping(const char *address, int update_expiry)
* <b>wildcard_new_addr</b>, remove any mappings that exist from
* <b>address</b>.
*
- *
* It is an error to set <b>wildcard_new_addr</b> if <b>wildcard_addr</b> is
* not set. */
void
diff --git a/src/or/circuitbuild.c b/src/or/circuitbuild.c
index b36fed63b3..7f0bcc4150 100644
--- a/src/or/circuitbuild.c
+++ b/src/or/circuitbuild.c
@@ -1290,7 +1290,7 @@ circuit_extend(cell_t *cell, circuit_t *circ)
const node_t *node = node_get_by_id((const char*)ec.node_id);
const ed25519_public_key_t *node_ed_id = NULL;
if (node &&
- node_supports_ed25519_link_authentication(node) &&
+ node_supports_ed25519_link_authentication(node, 1) &&
(node_ed_id = node_get_ed25519_id(node))) {
ed25519_pubkey_copy(&ec.ed_pubkey, node_ed_id);
}
@@ -2698,7 +2698,7 @@ extend_info_from_node(const node_t *node, int for_direct_connect)
/* Don't send the ed25519 pubkey unless the target node actually supports
* authenticating with it. */
- if (node_supports_ed25519_link_authentication(node)) {
+ if (node_supports_ed25519_link_authentication(node, 0)) {
log_info(LD_CIRC, "Including Ed25519 ID for %s", node_describe(node));
ed_pubkey = node_get_ed25519_id(node);
} else if (node_get_ed25519_id(node)) {
diff --git a/src/or/config.c b/src/or/config.c
index 78db03c68a..b0a140d23b 100644
--- a/src/or/config.c
+++ b/src/or/config.c
@@ -82,6 +82,7 @@
#include "dirvote.h"
#include "dns.h"
#include "entrynodes.h"
+#include "git_revision.h"
#include "geoip.h"
#include "hibernate.h"
#include "main.h"
@@ -483,6 +484,7 @@ static config_var_t option_vars_[] = {
V(RendPostPeriod, INTERVAL, "1 hour"),
V(RephistTrackTime, INTERVAL, "24 hours"),
V(RunAsDaemon, BOOL, "0"),
+ V(ReducedExitPolicy, BOOL, "0"),
OBSOLETE("RunTesting"), // currently unused
V(Sandbox, BOOL, "0"),
V(SafeLogging, STRING, "1"),
@@ -561,6 +563,7 @@ static config_var_t option_vars_[] = {
VAR("__HashedControlSessionPassword", LINELIST, HashedControlSessionPassword,
NULL),
VAR("__OwningControllerProcess",STRING,OwningControllerProcess, NULL),
+ VAR("__OwningControllerFD",INT,OwningControllerFD, "-1"),
V(MinUptimeHidServDirectoryV2, INTERVAL, "96 hours"),
V(TestingServerDownloadSchedule, CSV_INTERVAL, "0, 0, 0, 60, 60, 120, "
"300, 900, 2147483647"),
@@ -833,9 +836,12 @@ set_options(or_options_t *new_val, char **msg)
return -1;
}
if (options_act(old_options) < 0) { /* acting on the options failed. die. */
- log_err(LD_BUG,
- "Acting on config options left us in a broken state. Dying.");
- exit(1);
+ if (! tor_event_loop_shutdown_is_pending()) {
+ log_err(LD_BUG,
+ "Acting on config options left us in a broken state. Dying.");
+ tor_shutdown_event_loop_and_exit(1);
+ }
+ return -1;
}
/* Issues a CONF_CHANGED event to notify controller of the change. If Tor is
* just starting up then the old_options will be undefined. */
@@ -877,8 +883,6 @@ set_options(or_options_t *new_val, char **msg)
return 0;
}
-extern const char tor_git_revision[]; /* from tor_main.c */
-
/** The version of this Tor process, as parsed. */
static char *the_tor_version = NULL;
/** A shorter version of this Tor process's version, for export in our router
@@ -933,6 +937,10 @@ or_options_free(or_options_t *options)
SMARTLIST_FOREACH(options->SchedulerTypes_, int *, i, tor_free(i));
smartlist_free(options->SchedulerTypes_);
}
+ if (options->FilesOpenedByIncludes) {
+ SMARTLIST_FOREACH(options->FilesOpenedByIncludes, char *, f, tor_free(f));
+ smartlist_free(options->FilesOpenedByIncludes);
+ }
tor_free(options->BridgePassword_AuthDigest_);
tor_free(options->command_arg);
tor_free(options->master_key_fname);
@@ -1687,8 +1695,11 @@ options_act(const or_options_t *old_options)
else
protocol_warning_severity_level = LOG_INFO;
- if (consider_adding_dir_servers(options, old_options) < 0)
+ if (consider_adding_dir_servers(options, old_options) < 0) {
+ // XXXX This should get validated earlier, and committed here, to
+ // XXXX lower opportunities for reaching an error case.
return -1;
+ }
if (rend_non_anonymous_mode_enabled(options)) {
log_warn(LD_GENERAL, "This copy of Tor was compiled or configured to run "
@@ -1697,6 +1708,7 @@ options_act(const or_options_t *old_options)
#ifdef ENABLE_TOR2WEB_MODE
/* LCOV_EXCL_START */
+ // XXXX This should move into options_validate()
if (!options->Tor2webMode) {
log_err(LD_CONFIG, "This copy of Tor was compiled to run in "
"'tor2web mode'. It can only be run with the Tor2webMode torrc "
@@ -1705,6 +1717,7 @@ options_act(const or_options_t *old_options)
}
/* LCOV_EXCL_STOP */
#else /* !(defined(ENABLE_TOR2WEB_MODE)) */
+ // XXXX This should move into options_validate()
if (options->Tor2webMode) {
log_err(LD_CONFIG, "This copy of Tor was not compiled to run in "
"'tor2web mode'. It cannot be run with the Tor2webMode torrc "
@@ -1732,9 +1745,11 @@ options_act(const or_options_t *old_options)
for (cl = options->Bridges; cl; cl = cl->next) {
bridge_line_t *bridge_line = parse_bridge_line(cl->value);
if (!bridge_line) {
+ // LCOV_EXCL_START
log_warn(LD_BUG,
"Previously validated Bridge line could not be added!");
return -1;
+ // LCOV_EXCL_STOP
}
bridge_add_from_config(bridge_line);
}
@@ -1742,15 +1757,37 @@ options_act(const or_options_t *old_options)
}
if (running_tor && hs_config_service_all(options, 0)<0) {
+ // LCOV_EXCL_START
log_warn(LD_BUG,
"Previously validated hidden services line could not be added!");
return -1;
+ // LCOV_EXCL_STOP
}
if (running_tor && rend_parse_service_authorization(options, 0) < 0) {
+ // LCOV_EXCL_START
log_warn(LD_BUG, "Previously validated client authorization for "
"hidden services could not be added!");
return -1;
+ // LCOV_EXCL_STOP
+ }
+
+ if (running_tor && !old_options && options->OwningControllerFD != -1) {
+#ifdef _WIN32
+ log_warn(LD_CONFIG, "OwningControllerFD is not supported on Windows. "
+ "If you need it, tell the Tor developers.");
+ return -1;
+#else
+ const unsigned ctrl_flags =
+ CC_LOCAL_FD_IS_OWNER |
+ CC_LOCAL_FD_IS_AUTHENTICATED;
+ tor_socket_t ctrl_sock = (tor_socket_t)options->OwningControllerFD;
+ if (control_connection_add_local_fd(ctrl_sock, ctrl_flags) < 0) {
+ log_warn(LD_CONFIG, "Could not add local controller connection with "
+ "given FD.");
+ return -1;
+ }
+#endif
}
/* Load state */
@@ -1773,10 +1810,12 @@ options_act(const or_options_t *old_options)
if (options->ClientTransportPlugin) {
for (cl = options->ClientTransportPlugin; cl; cl = cl->next) {
if (parse_transport_line(options, cl->value, 0, 0) < 0) {
+ // LCOV_EXCL_START
log_warn(LD_BUG,
"Previously validated ClientTransportPlugin line "
"could not be added!");
return -1;
+ // LCOV_EXCL_STOP
}
}
}
@@ -1784,10 +1823,12 @@ options_act(const or_options_t *old_options)
if (options->ServerTransportPlugin && server_mode(options)) {
for (cl = options->ServerTransportPlugin; cl; cl = cl->next) {
if (parse_transport_line(options, cl->value, 0, 1) < 0) {
+ // LCOV_EXCL_START
log_warn(LD_BUG,
"Previously validated ServerTransportPlugin line "
"could not be added!");
return -1;
+ // LCOV_EXCL_STOP
}
}
}
@@ -1873,8 +1914,10 @@ options_act(const or_options_t *old_options)
/* Set up accounting */
if (accounting_parse_options(options, 0)<0) {
- log_warn(LD_CONFIG,"Error in accounting options");
+ // LCOV_EXCL_START
+ log_warn(LD_BUG,"Error in previously validated accounting options");
return -1;
+ // LCOV_EXCL_STOP
}
if (accounting_is_enabled(options))
configure_accounting(time(NULL));
@@ -1897,6 +1940,7 @@ options_act(const or_options_t *old_options)
char *http_authenticator;
http_authenticator = alloc_http_authenticator(options->BridgePassword);
if (!http_authenticator) {
+ // XXXX This should get validated in options_validate().
log_warn(LD_BUG, "Unable to allocate HTTP authenticator. Not setting "
"BridgePassword.");
return -1;
@@ -1909,9 +1953,12 @@ options_act(const or_options_t *old_options)
}
if (parse_outbound_addresses(options, 0, &msg) < 0) {
- log_warn(LD_BUG, "Failed parsing outbound bind addresses: %s", msg);
+ // LCOV_EXCL_START
+ log_warn(LD_BUG, "Failed parsing previously validated outbound "
+ "bind addresses: %s", msg);
tor_free(msg);
return -1;
+ // LCOV_EXCL_STOP
}
config_maybe_load_geoip_files_(options, old_options);
@@ -4607,6 +4654,12 @@ options_transition_allowed(const or_options_t *old,
return -1;
}
+ if (old->OwningControllerFD != new_val->OwningControllerFD) {
+ *msg = tor_strdup("While Tor is running, changing OwningControllerFD "
+ "is not allowed.");
+ return -1;
+ }
+
if (sandbox_is_active()) {
#define SB_NOCHANGE_STR(opt) \
do { \
@@ -5019,7 +5072,8 @@ load_torrc_from_disk(config_line_t *cmd_arg, int defaults_file)
/** Read a configuration file into <b>options</b>, finding the configuration
* file location based on the command line. After loading the file
* call options_init_from_string() to load the config.
- * Return 0 if success, -1 if failure. */
+ * Return 0 if success, -1 if failure, and 1 if we succeeded but should exit
+ * anyway. */
int
options_init_from_torrc(int argc, char **argv)
{
@@ -5046,22 +5100,22 @@ options_init_from_torrc(int argc, char **argv)
if (config_line_find(cmdline_only_options, "-h") ||
config_line_find(cmdline_only_options, "--help")) {
print_usage();
- exit(0);
+ return 1;
}
if (config_line_find(cmdline_only_options, "--list-torrc-options")) {
/* For validating whether we've documented everything. */
list_torrc_options();
- exit(0);
+ return 1;
}
if (config_line_find(cmdline_only_options, "--list-deprecated-options")) {
/* For validating whether what we have deprecated really exists. */
list_deprecated_options();
- exit(0);
+ return 1;
}
if (config_line_find(cmdline_only_options, "--version")) {
printf("Tor version %s.\n",get_version());
- exit(0);
+ return 1;
}
if (config_line_find(cmdline_only_options, "--library-versions")) {
@@ -5089,7 +5143,7 @@ options_init_from_torrc(int argc, char **argv)
tor_compress_header_version_str(ZSTD_METHOD));
}
//TODO: Hex versions?
- exit(0);
+ return 1;
}
command = CMD_RUN_TOR;
@@ -5150,7 +5204,8 @@ options_init_from_torrc(int argc, char **argv)
get_options_mutable()->keygen_force_passphrase = FORCE_PASSPHRASE_OFF;
} else {
log_err(LD_CONFIG, "--no-passphrase specified without --keygen!");
- exit(1);
+ retval = -1;
+ goto err;
}
}
@@ -5159,7 +5214,8 @@ options_init_from_torrc(int argc, char **argv)
get_options_mutable()->change_key_passphrase = 1;
} else {
log_err(LD_CONFIG, "--newpass specified without --keygen!");
- exit(1);
+ retval = -1;
+ goto err;
}
}
@@ -5169,17 +5225,20 @@ options_init_from_torrc(int argc, char **argv)
if (fd_line) {
if (get_options()->keygen_force_passphrase == FORCE_PASSPHRASE_OFF) {
log_err(LD_CONFIG, "--no-passphrase specified with --passphrase-fd!");
- exit(1);
+ retval = -1;
+ goto err;
} else if (command != CMD_KEYGEN) {
log_err(LD_CONFIG, "--passphrase-fd specified without --keygen!");
- exit(1);
+ retval = -1;
+ goto err;
} else {
const char *v = fd_line->value;
int ok = 1;
long fd = tor_parse_long(v, 10, 0, INT_MAX, &ok, NULL);
if (fd < 0 || ok == 0) {
log_err(LD_CONFIG, "Invalid --passphrase-fd value %s", escaped(v));
- exit(1);
+ retval = -1;
+ goto err;
}
get_options_mutable()->keygen_passphrase_fd = (int)fd;
get_options_mutable()->use_keygen_passphrase_fd = 1;
@@ -5194,7 +5253,8 @@ options_init_from_torrc(int argc, char **argv)
if (key_line) {
if (command != CMD_KEYGEN) {
log_err(LD_CONFIG, "--master-key without --keygen!");
- exit(1);
+ retval = -1;
+ goto err;
} else {
get_options_mutable()->master_key_fname = tor_strdup(key_line->value);
}
@@ -5242,13 +5302,16 @@ options_init_from_string(const char *cf_defaults, const char *cf,
newoptions->command = command;
newoptions->command_arg = command_arg ? tor_strdup(command_arg) : NULL;
+ smartlist_t *opened_files = smartlist_new();
for (int i = 0; i < 2; ++i) {
const char *body = i==0 ? cf_defaults : cf;
if (!body)
continue;
+
/* get config lines, assign them */
retval = config_get_lines_include(body, &cl, 1,
- body == cf ? &cf_has_include : NULL);
+ body == cf ? &cf_has_include : NULL,
+ opened_files);
if (retval < 0) {
err = SETOPT_ERR_PARSE;
goto err;
@@ -5277,6 +5340,7 @@ options_init_from_string(const char *cf_defaults, const char *cf,
}
newoptions->IncludeUsed = cf_has_include;
+ newoptions->FilesOpenedByIncludes = opened_files;
/* If this is a testing network configuration, change defaults
* for a list of dependent config options, re-initialize newoptions
@@ -5316,13 +5380,16 @@ options_init_from_string(const char *cf_defaults, const char *cf,
newoptions->command_arg = command_arg ? tor_strdup(command_arg) : NULL;
/* Assign all options a second time. */
+ opened_files = smartlist_new();
for (int i = 0; i < 2; ++i) {
const char *body = i==0 ? cf_defaults : cf;
if (!body)
continue;
+
/* get config lines, assign them */
retval = config_get_lines_include(body, &cl, 1,
- body == cf ? &cf_has_include : NULL);
+ body == cf ? &cf_has_include : NULL,
+ opened_files);
if (retval < 0) {
err = SETOPT_ERR_PARSE;
goto err;
@@ -5347,6 +5414,7 @@ options_init_from_string(const char *cf_defaults, const char *cf,
newoptions->IncludeUsed = cf_has_include;
in_option_validation = 1;
+ newoptions->FilesOpenedByIncludes = opened_files;
/* Validate newoptions */
if (options_validate(oldoptions, newoptions, newdefaultoptions,
@@ -5373,6 +5441,12 @@ options_init_from_string(const char *cf_defaults, const char *cf,
err:
in_option_validation = 0;
+ if (opened_files) {
+ SMARTLIST_FOREACH(opened_files, char *, f, tor_free(f));
+ smartlist_free(opened_files);
+ }
+ // may have been set to opened_files, avoid double free
+ newoptions->FilesOpenedByIncludes = NULL;
or_options_free(newoptions);
or_options_free(newdefaultoptions);
if (*msg) {
@@ -7889,28 +7963,6 @@ write_to_data_subdir(const char* subdir, const char* fname,
return return_val;
}
-/** Given a file name check to see whether the file exists but has not been
- * modified for a very long time. If so, remove it. */
-void
-remove_file_if_very_old(const char *fname, time_t now)
-{
-#define VERY_OLD_FILE_AGE (28*24*60*60)
- struct stat st;
-
- log_debug(LD_FS, "stat()ing %s", fname);
- if (stat(sandbox_intern_string(fname), &st)==0 &&
- st.st_mtime < now-VERY_OLD_FILE_AGE) {
- char buf[ISO_TIME_LEN+1];
- format_local_iso_time(buf, st.st_mtime);
- log_notice(LD_GENERAL, "Obsolete file %s hasn't been modified since %s. "
- "Removing it.", fname, buf);
- if (unlink(fname) != 0) {
- log_warn(LD_FS, "Failed to unlink %s: %s",
- fname, strerror(errno));
- }
- }
-}
-
/** Return a smartlist of ports that must be forwarded by
* tor-fw-helper. The smartlist contains the ports in a string format
* that is understandable by tor-fw-helper. */
diff --git a/src/or/connection.c b/src/or/connection.c
index 632a833652..24f5a64622 100644
--- a/src/or/connection.c
+++ b/src/or/connection.c
@@ -118,8 +118,6 @@ static connection_t *connection_listener_new(
const port_cfg_t *portcfg);
static void connection_init(time_t now, connection_t *conn, int type,
int socket_family);
-static int connection_init_accepted_conn(connection_t *conn,
- const listener_connection_t *listener);
static int connection_handle_listener_read(connection_t *conn, int new_type);
static int connection_bucket_should_increase(int bucket,
or_connection_t *conn);
@@ -1662,11 +1660,15 @@ connection_handle_listener_read(connection_t *conn, int new_type)
}
/** Initialize states for newly accepted connection <b>conn</b>.
+ *
* If conn is an OR, start the TLS handshake.
+ *
* If conn is a transparent AP, get its original destination
* and place it in circuit_wait.
+ *
+ * The <b>listener</b> parameter is only used for AP connections.
*/
-static int
+int
connection_init_accepted_conn(connection_t *conn,
const listener_connection_t *listener)
{
@@ -1746,7 +1748,11 @@ connection_connect_sockaddr,(connection_t *conn,
if (get_options()->DisableNetwork) {
/* We should never even try to connect anyplace if DisableNetwork is set.
- * Warn if we do, and refuse to make the connection. */
+ * Warn if we do, and refuse to make the connection.
+ *
+ * We only check DisableNetwork here, not we_are_hibernating(), since
+ * we'll still try to fulfill client requests sometimes in the latter case
+ * (if it is soft hibernation) */
static ratelim_t disablenet_violated = RATELIM_INIT(30*60);
*socket_error = SOCK_ERRNO(ENETUNREACH);
log_fn_ratelim(&disablenet_violated, LOG_WARN, LD_BUG,
@@ -4045,6 +4051,68 @@ connection_flush(connection_t *conn)
return connection_handle_write(conn, 1);
}
+/** Helper for connection_write_to_buf_impl and connection_write_buf_to_buf:
+ *
+ * Return true iff it is okay to queue bytes on <b>conn</b>'s outbuf for
+ * writing.
+ */
+static int
+connection_may_write_to_buf(connection_t *conn)
+{
+ /* if it's marked for close, only allow write if we mean to flush it */
+ if (conn->marked_for_close && !conn->hold_open_until_flushed)
+ return 0;
+
+ return 1;
+}
+
+/** Helper for connection_write_to_buf_impl and connection_write_buf_to_buf:
+ *
+ * Called when an attempt to add bytes on <b>conn</b>'s outbuf has failed;
+ * mark the connection and warn as appropriate.
+ */
+static void
+connection_write_to_buf_failed(connection_t *conn)
+{
+ if (CONN_IS_EDGE(conn)) {
+ /* if it failed, it means we have our package/delivery windows set
+ wrong compared to our max outbuf size. close the whole circuit. */
+ log_warn(LD_NET,
+ "write_to_buf failed. Closing circuit (fd %d).", (int)conn->s);
+ circuit_mark_for_close(circuit_get_by_edge_conn(TO_EDGE_CONN(conn)),
+ END_CIRC_REASON_INTERNAL);
+ } else if (conn->type == CONN_TYPE_OR) {
+ or_connection_t *orconn = TO_OR_CONN(conn);
+ log_warn(LD_NET,
+ "write_to_buf failed on an orconn; notifying of error "
+ "(fd %d)", (int)(conn->s));
+ connection_or_close_for_error(orconn, 0);
+ } else {
+ log_warn(LD_NET,
+ "write_to_buf failed. Closing connection (fd %d).",
+ (int)conn->s);
+ connection_mark_for_close(conn);
+ }
+}
+
+/** Helper for connection_write_to_buf_impl and connection_write_buf_to_buf:
+ *
+ * Called when an attempt to add bytes on <b>conn</b>'s outbuf has succeeded:
+ * record the number of bytes added.
+ */
+static void
+connection_write_to_buf_commit(connection_t *conn, size_t len)
+{
+ /* If we receive optimistic data in the EXIT_CONN_STATE_RESOLVING
+ * state, we don't want to try to write it right away, since
+ * conn->write_event won't be set yet. Otherwise, write data from
+ * this conn as the socket is available. */
+ if (conn->write_event) {
+ connection_start_writing(conn);
+ }
+ conn->outbuf_flushlen += len;
+}
+
/** Append <b>len</b> bytes of <b>string</b> onto <b>conn</b>'s
* outbuf, and ask it to start writing.
*
@@ -4059,58 +4127,52 @@ connection_write_to_buf_impl_,(const char *string, size_t len,
{
/* XXXX This function really needs to return -1 on failure. */
int r;
- size_t old_datalen;
if (!len && !(zlib<0))
return;
- /* if it's marked for close, only allow write if we mean to flush it */
- if (conn->marked_for_close && !conn->hold_open_until_flushed)
+
+ if (!connection_may_write_to_buf(conn))
return;
- old_datalen = buf_datalen(conn->outbuf);
+ size_t written;
+
if (zlib) {
+ size_t old_datalen = buf_datalen(conn->outbuf);
dir_connection_t *dir_conn = TO_DIR_CONN(conn);
int done = zlib < 0;
CONN_LOG_PROTECT(conn, r = buf_add_compress(conn->outbuf,
- dir_conn->compress_state,
- string, len, done));
+ dir_conn->compress_state,
+ string, len, done));
+ written = buf_datalen(conn->outbuf) - old_datalen;
} else {
CONN_LOG_PROTECT(conn, r = buf_add(conn->outbuf, string, len));
+ written = len;
}
if (r < 0) {
- if (CONN_IS_EDGE(conn)) {
- /* if it failed, it means we have our package/delivery windows set
- wrong compared to our max outbuf size. close the whole circuit. */
- log_warn(LD_NET,
- "write_to_buf failed. Closing circuit (fd %d).", (int)conn->s);
- circuit_mark_for_close(circuit_get_by_edge_conn(TO_EDGE_CONN(conn)),
- END_CIRC_REASON_INTERNAL);
- } else if (conn->type == CONN_TYPE_OR) {
- or_connection_t *orconn = TO_OR_CONN(conn);
- log_warn(LD_NET,
- "write_to_buf failed on an orconn; notifying of error "
- "(fd %d)", (int)(conn->s));
- connection_or_close_for_error(orconn, 0);
- } else {
- log_warn(LD_NET,
- "write_to_buf failed. Closing connection (fd %d).",
- (int)conn->s);
- connection_mark_for_close(conn);
- }
+ connection_write_to_buf_failed(conn);
return;
}
+ connection_write_to_buf_commit(conn, written);
+}
- /* If we receive optimistic data in the EXIT_CONN_STATE_RESOLVING
- * state, we don't want to try to write it right away, since
- * conn->write_event won't be set yet. Otherwise, write data from
- * this conn as the socket is available. */
- if (conn->write_event) {
- connection_start_writing(conn);
- }
- if (zlib) {
- conn->outbuf_flushlen += buf_datalen(conn->outbuf) - old_datalen;
- } else {
- conn->outbuf_flushlen += len;
- }
+/**
+ * Add all bytes from <b>buf</b> to <b>conn</b>'s outbuf, draining them
+ * from <b>buf</b>. (If the connection is marked and will soon be closed,
+ * nothing is drained.)
+ */
+void
+connection_buf_add_buf(connection_t *conn, buf_t *buf)
+{
+ tor_assert(conn);
+ tor_assert(buf);
+ size_t len = buf_datalen(buf);
+ if (len == 0)
+ return;
+
+ if (!connection_may_write_to_buf(conn))
+ return;
+
+ buf_move_all(conn->outbuf, buf);
+ connection_write_to_buf_commit(conn, len);
}
#define CONN_GET_ALL_TEMPLATE(var, test) \
diff --git a/src/or/connection.h b/src/or/connection.h
index 4a5bd6971b..1d41a3c4f5 100644
--- a/src/or/connection.h
+++ b/src/or/connection.h
@@ -26,7 +26,8 @@ entry_connection_t *entry_connection_new(int type, int socket_family);
control_connection_t *control_connection_new(int socket_family);
listener_connection_t *listener_connection_new(int type, int socket_family);
connection_t *connection_new(int type, int socket_family);
-
+int connection_init_accepted_conn(connection_t *conn,
+ const listener_connection_t *listener);
void connection_link_connections(connection_t *conn_a, connection_t *conn_b);
MOCK_DECL(void,connection_free,(connection_t *conn));
void connection_free_all(void);
@@ -155,6 +156,7 @@ connection_buf_add_compress(const char *string, size_t len,
{
connection_write_to_buf_impl_(string, len, TO_CONN(conn), done ? -1 : 1);
}
+void connection_buf_add_buf(connection_t *conn, buf_t *buf);
/* DOCDOC connection_get_inbuf_len */
static size_t connection_get_inbuf_len(connection_t *conn);
@@ -243,7 +245,6 @@ char *alloc_http_authenticator(const char *authenticator);
void assert_connection_ok(connection_t *conn, time_t now);
int connection_or_nonopen_was_started_here(or_connection_t *conn);
void connection_dump_buffer_mem_stats(int severity);
-void remove_file_if_very_old(const char *fname, time_t now);
void clock_skew_warning(const connection_t *conn, long apparent_skew,
int trusted, log_domain_mask_t domain,
diff --git a/src/or/connection_edge.c b/src/or/connection_edge.c
index f178917f0b..41f0fe6a1d 100644
--- a/src/or/connection_edge.c
+++ b/src/or/connection_edge.c
@@ -999,7 +999,7 @@ connection_ap_mark_as_pending_circuit_(entry_connection_t *entry_conn,
* So the fix is to tell it right now that it ought to finish its loop at
* its next available opportunity.
*/
- tell_event_loop_to_finish();
+ tell_event_loop_to_run_external_code();
}
/** Mark <b>entry_conn</b> as no longer waiting for a circuit. */
diff --git a/src/or/connection_or.c b/src/or/connection_or.c
index 9e34063609..7af1f2b645 100644
--- a/src/or/connection_or.c
+++ b/src/or/connection_or.c
@@ -886,7 +886,7 @@ connection_or_check_canonicity(or_connection_t *conn, int started_here)
const node_t *r = node_get_by_id(id_digest);
if (r &&
- node_supports_ed25519_link_authentication(r) &&
+ node_supports_ed25519_link_authentication(r, 1) &&
! node_ed25519_id_matches(r, ed_id)) {
/* If this node is capable of proving an ed25519 ID,
* we can't call this a canonical connection unless both IDs match. */
diff --git a/src/or/control.c b/src/or/control.c
index 202366aaec..0d462b2d7d 100644
--- a/src/or/control.c
+++ b/src/or/control.c
@@ -549,6 +549,49 @@ decode_escaped_string(const char *start, size_t in_len_max,
return end+1;
}
+/** Create and add a new controller connection on <b>sock</b>. If
+ * <b>CC_LOCAL_FD_IS_OWNER</b> is set in <b>flags</b>, this Tor process should
+ * exit when the connection closes. If <b>CC_LOCAL_FD_IS_AUTHENTICATED</b>
+ * is set, then the connection does not need to authenticate.
+ */
+int
+control_connection_add_local_fd(tor_socket_t sock, unsigned flags)
+{
+ if (BUG(! SOCKET_OK(sock)))
+ return -1;
+ const int is_owner = !!(flags & CC_LOCAL_FD_IS_OWNER);
+ const int is_authenticated = !!(flags & CC_LOCAL_FD_IS_AUTHENTICATED);
+ control_connection_t *control_conn = control_connection_new(AF_UNSPEC);
+ connection_t *conn = TO_CONN(control_conn);
+ conn->s = sock;
+ tor_addr_make_unspec(&conn->addr);
+ conn->port = 1;
+ conn->address = tor_strdup("<local socket>");
+
+ /* We take ownership of this socket so that later, when we close it,
+ * we don't freak out. */
+ tor_take_socket_ownership(sock);
+
+ if (set_socket_nonblocking(sock) < 0 ||
+ connection_add(conn) < 0) {
+ connection_free(conn);
+ return -1;
+ }
+
+ control_conn->is_owning_control_connection = is_owner;
+
+ if (connection_init_accepted_conn(conn, NULL) < 0) {
+ connection_mark_for_close(conn);
+ return -1;
+ }
+
+ if (is_authenticated) {
+ conn->state = CONTROL_CONN_STATE_OPEN;
+ }
+
+ return 0;
+}
+
/** Acts like sprintf, but writes its formatted string to the end of
* <b>conn</b>-\>outbuf. */
static void
@@ -6571,8 +6614,7 @@ monitor_owning_controller_process(const char *process_spec)
"owning controller: %s. Exiting.",
msg);
owning_controller_process_spec = NULL;
- tor_cleanup();
- exit(1);
+ tor_shutdown_event_loop_and_exit(1);
}
}
diff --git a/src/or/control.h b/src/or/control.h
index e957b593a6..7ec182cb78 100644
--- a/src/or/control.h
+++ b/src/or/control.h
@@ -27,6 +27,10 @@ void control_ports_write_to_file(void);
#define LOG_FN_CONN(conn, args) \
CONN_LOG_PROTECT(conn, log_fn args)
+#define CC_LOCAL_FD_IS_OWNER (1u<<0)
+#define CC_LOCAL_FD_IS_AUTHENTICATED (1u<<1)
+int control_connection_add_local_fd(tor_socket_t sock, unsigned flags);
+
int connection_control_finished_flushing(control_connection_t *conn);
int connection_control_reached_eof(control_connection_t *conn);
void connection_control_closed(control_connection_t *conn);
diff --git a/src/or/directory.c b/src/or/directory.c
index 836f862988..6dd40639b6 100644
--- a/src/or/directory.c
+++ b/src/or/directory.c
@@ -2237,8 +2237,6 @@ load_downloaded_routers(const char *body, smartlist_t *which,
return added;
}
-static int handle_response_fetch_consensus(dir_connection_t *,
- const response_handler_args_t *);
static int handle_response_fetch_certificate(dir_connection_t *,
const response_handler_args_t *);
static int handle_response_fetch_status_vote(dir_connection_t *,
@@ -2585,7 +2583,7 @@ connection_dir_client_reached_eof(dir_connection_t *conn)
* consensus document by checking the consensus, storing it, and marking
* router requests as reachable.
**/
-static int
+STATIC int
handle_response_fetch_consensus(dir_connection_t *conn,
const response_handler_args_t *args)
{
@@ -3518,63 +3516,47 @@ write_http_response_header_impl(dir_connection_t *conn, ssize_t length,
long cache_lifetime)
{
char date[RFC1123_TIME_LEN+1];
- char tmp[1024];
- char *cp;
time_t now = time(NULL);
+ buf_t *buf = buf_new_with_capacity(1024);
tor_assert(conn);
format_rfc1123_time(date, now);
- cp = tmp;
- tor_snprintf(cp, sizeof(tmp),
- "HTTP/1.0 200 OK\r\nDate: %s\r\n",
- date);
- cp += strlen(tmp);
+
+ buf_add_printf(buf, "HTTP/1.0 200 OK\r\nDate: %s\r\n", date);
if (type) {
- tor_snprintf(cp, sizeof(tmp)-(cp-tmp), "Content-Type: %s\r\n", type);
- cp += strlen(cp);
+ buf_add_printf(buf, "Content-Type: %s\r\n", type);
}
if (!is_local_addr(&conn->base_.addr)) {
/* Don't report the source address for a nearby/private connection.
* Otherwise we tend to mis-report in cases where incoming ports are
* being forwarded to a Tor server running behind the firewall. */
- tor_snprintf(cp, sizeof(tmp)-(cp-tmp),
- X_ADDRESS_HEADER "%s\r\n", conn->base_.address);
- cp += strlen(cp);
+ buf_add_printf(buf, X_ADDRESS_HEADER "%s\r\n", conn->base_.address);
}
if (encoding) {
- tor_snprintf(cp, sizeof(tmp)-(cp-tmp),
- "Content-Encoding: %s\r\n", encoding);
- cp += strlen(cp);
+ buf_add_printf(buf, "Content-Encoding: %s\r\n", encoding);
}
if (length >= 0) {
- tor_snprintf(cp, sizeof(tmp)-(cp-tmp),
- "Content-Length: %ld\r\n", (long)length);
- cp += strlen(cp);
+ buf_add_printf(buf, "Content-Length: %ld\r\n", (long)length);
}
if (cache_lifetime > 0) {
char expbuf[RFC1123_TIME_LEN+1];
format_rfc1123_time(expbuf, (time_t)(now + cache_lifetime));
/* We could say 'Cache-control: max-age=%d' here if we start doing
* http/1.1 */
- tor_snprintf(cp, sizeof(tmp)-(cp-tmp),
- "Expires: %s\r\n", expbuf);
- cp += strlen(cp);
+ buf_add_printf(buf, "Expires: %s\r\n", expbuf);
} else if (cache_lifetime == 0) {
/* We could say 'Cache-control: no-cache' here if we start doing
* http/1.1 */
- strlcpy(cp, "Pragma: no-cache\r\n", sizeof(tmp)-(cp-tmp));
- cp += strlen(cp);
+ buf_add_string(buf, "Pragma: no-cache\r\n");
}
if (extra_headers) {
- strlcpy(cp, extra_headers, sizeof(tmp)-(cp-tmp));
- cp += strlen(cp);
+ buf_add_string(buf, extra_headers);
}
- if (sizeof(tmp)-(cp-tmp) > 3)
- memcpy(cp, "\r\n", 3);
- else
- tor_assert(0);
- connection_buf_add(tmp, strlen(tmp), TO_CONN(conn));
+ buf_add_string(buf, "\r\n");
+
+ connection_buf_add_buf(TO_CONN(conn), buf);
+ buf_free(buf);
}
/** As write_http_response_header_impl, but sets encoding and content-typed
diff --git a/src/or/directory.h b/src/or/directory.h
index d26d835377..904bdfae46 100644
--- a/src/or/directory.h
+++ b/src/or/directory.h
@@ -194,6 +194,9 @@ 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_consensus(dir_connection_t *conn,
+ const response_handler_args_t *args);
+
#endif /* defined(DIRECTORY_PRIVATE) */
#ifdef TOR_UNIT_TESTS
diff --git a/src/or/dirserv.c b/src/or/dirserv.c
index ddee92da55..432fe6ae2b 100644
--- a/src/or/dirserv.c
+++ b/src/or/dirserv.c
@@ -1519,15 +1519,21 @@ dirserv_compute_performance_thresholds(digestmap_t *omit_as_sybil)
node->ri &&
node->ri->purpose != ROUTER_PURPOSE_BRIDGE)
continue;
+
+ routerinfo_t *ri = node->ri;
+ if (ri) {
+ node->is_exit = (!router_exit_policy_rejects_all(ri) &&
+ exit_policy_is_general_exit(ri->exit_policy));
+ }
+
if (router_counts_toward_thresholds(node, now, omit_as_sybil,
require_mbw)) {
- routerinfo_t *ri = node->ri;
const char *id = node->identity;
uint32_t bw_kb;
+
/* resolve spurious clang shallow analysis null pointer errors */
tor_assert(ri);
- node->is_exit = (!router_exit_policy_rejects_all(ri) &&
- exit_policy_is_general_exit(ri->exit_policy));
+
uptimes[n_active] = (uint32_t)real_uptime(ri, now);
mtbfs[n_active] = rep_hist_get_stability(id, now);
tks [n_active] = rep_hist_get_weighted_time_known(id, now);
@@ -3284,7 +3290,7 @@ dirserv_orconn_tls_done(const tor_addr_t *addr,
ri = node->ri;
if (get_options()->AuthDirTestEd25519LinkKeys &&
- node_supports_ed25519_link_authentication(node) &&
+ node_supports_ed25519_link_authentication(node, 1) &&
ri->cache_info.signing_key_cert) {
/* We allow the node to have an ed25519 key if we haven't been told one in
* the routerinfo, but if we *HAVE* been told one in the routerinfo, it
@@ -3367,7 +3373,7 @@ dirserv_single_reachability_test(time_t now, routerinfo_t *router)
tor_assert(node);
if (options->AuthDirTestEd25519LinkKeys &&
- node_supports_ed25519_link_authentication(node)) {
+ node_supports_ed25519_link_authentication(node, 1)) {
ed_id_key = &router->cache_info.signing_key_cert->signing_key;
} else {
ed_id_key = NULL;
diff --git a/src/or/dns.c b/src/or/dns.c
index 4194a29a6b..c992c8c358 100644
--- a/src/or/dns.c
+++ b/src/or/dns.c
@@ -1665,7 +1665,7 @@ launch_resolve,(cached_resolve_t *resolve))
tor_addr_t a;
int r;
- if (get_options()->DisableNetwork)
+ if (net_is_disabled())
return -1;
/* What? Nameservers not configured? Sounds like a bug. */
@@ -1900,7 +1900,7 @@ launch_test_addresses(evutil_socket_t fd, short event, void *args)
(void)event;
(void)args;
- if (options->DisableNetwork)
+ if (net_is_disabled())
return;
log_info(LD_EXIT, "Launching checks to see whether our nameservers like to "
diff --git a/src/or/entrynodes.c b/src/or/entrynodes.c
index 9fbf426433..76a8f591b9 100644
--- a/src/or/entrynodes.c
+++ b/src/or/entrynodes.c
@@ -2126,9 +2126,9 @@ circuit_guard_state_free(circuit_guard_state_t *state)
/** Allocate and return a new circuit_guard_state_t to track the result
* of using <b>guard</b> for a given operation. */
-static circuit_guard_state_t *
-circuit_guard_state_new(entry_guard_t *guard, unsigned state,
- entry_guard_restriction_t *rst)
+MOCK_IMPL(STATIC circuit_guard_state_t *,
+circuit_guard_state_new,(entry_guard_t *guard, unsigned state,
+ entry_guard_restriction_t *rst))
{
circuit_guard_state_t *result;
diff --git a/src/or/entrynodes.h b/src/or/entrynodes.h
index 9e1e729930..86f0517df2 100644
--- a/src/or/entrynodes.h
+++ b/src/or/entrynodes.h
@@ -488,6 +488,10 @@ STATIC entry_guard_t *get_sampled_guard_with_id(guard_selection_t *gs,
MOCK_DECL(STATIC time_t, randomize_time, (time_t now, time_t max_backdate));
+MOCK_DECL(STATIC circuit_guard_state_t *,
+ circuit_guard_state_new,(entry_guard_t *guard, unsigned state,
+ entry_guard_restriction_t *rst));
+
STATIC entry_guard_t *entry_guard_add_to_sample(guard_selection_t *gs,
const node_t *node);
STATIC entry_guard_t *entry_guards_expand_sample(guard_selection_t *gs);
diff --git a/src/or/geoip.c b/src/or/geoip.c
index 3944b2cf69..c976b8d276 100644
--- a/src/or/geoip.c
+++ b/src/or/geoip.c
@@ -30,6 +30,7 @@
#define GEOIP_PRIVATE
#include "or.h"
#include "ht.h"
+#include "buffers.h"
#include "config.h"
#include "control.h"
#include "dnsserv.h"
@@ -930,9 +931,9 @@ static char *
geoip_get_dirreq_history(dirreq_type_t type)
{
char *result = NULL;
+ buf_t *buf = NULL;
smartlist_t *dirreq_completed = NULL;
uint32_t complete = 0, timeouts = 0, running = 0;
- int bufsize = 1024, written;
dirreq_map_entry_t **ptr, **next;
struct timeval now;
@@ -965,13 +966,9 @@ geoip_get_dirreq_history(dirreq_type_t type)
DIR_REQ_GRANULARITY);
running = round_uint32_to_next_multiple_of(running,
DIR_REQ_GRANULARITY);
- result = tor_malloc_zero(bufsize);
- written = tor_snprintf(result, bufsize, "complete=%u,timeout=%u,"
- "running=%u", complete, timeouts, running);
- if (written < 0) {
- tor_free(result);
- goto done;
- }
+ buf = buf_new_with_capacity(1024);
+ buf_add_printf(buf, "complete=%u,timeout=%u,"
+ "running=%u", complete, timeouts, running);
#define MIN_DIR_REQ_RESPONSES 16
if (complete >= MIN_DIR_REQ_RESPONSES) {
@@ -992,7 +989,7 @@ geoip_get_dirreq_history(dirreq_type_t type)
dltimes[ent_sl_idx] = bytes_per_second;
} SMARTLIST_FOREACH_END(ent);
median_uint32(dltimes, complete); /* sorts as a side effect. */
- written = tor_snprintf(result + written, bufsize - written,
+ buf_add_printf(buf,
",min=%u,d1=%u,d2=%u,q1=%u,d3=%u,d4=%u,md=%u,"
"d6=%u,d7=%u,q3=%u,d8=%u,d9=%u,max=%u",
dltimes[0],
@@ -1008,14 +1005,15 @@ geoip_get_dirreq_history(dirreq_type_t type)
dltimes[8*complete/10-1],
dltimes[9*complete/10-1],
dltimes[complete-1]);
- if (written<0)
- tor_free(result);
tor_free(dltimes);
}
- done:
+
+ result = buf_extract(buf, NULL);
+
SMARTLIST_FOREACH(dirreq_completed, dirreq_map_entry_t *, ent,
tor_free(ent));
smartlist_free(dirreq_completed);
+ buf_free(buf);
return result;
}
diff --git a/src/or/git_revision.c b/src/or/git_revision.c
new file mode 100644
index 0000000000..8f326b8751
--- /dev/null
+++ b/src/or/git_revision.c
@@ -0,0 +1,17 @@
+/* Copyright 2001-2004 Roger Dingledine.
+ * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
+ * Copyright (c) 2007-2017, The Tor Project, Inc. */
+/* See LICENSE for licensing information */
+
+#include "git_revision.h"
+
+/** String describing which Tor Git repository version the source was
+ * built from. This string is generated by a bit of shell kludging in
+ * src/or/include.am, and is usually right.
+ */
+const char tor_git_revision[] =
+#ifndef _MSC_VER
+#include "micro-revision.i"
+#endif
+ "";
+
diff --git a/src/or/git_revision.h b/src/or/git_revision.h
new file mode 100644
index 0000000000..1ceaeedf16
--- /dev/null
+++ b/src/or/git_revision.h
@@ -0,0 +1,12 @@
+/* Copyright 2001-2004 Roger Dingledine.
+ * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
+ * Copyright (c) 2007-2017, The Tor Project, Inc. */
+/* See LICENSE for licensing information */
+
+#ifndef TOR_GIT_REVISION_H
+#define TOR_GIT_REVISION_H
+
+extern const char tor_git_revision[];
+
+#endif
+
diff --git a/src/or/hibernate.c b/src/or/hibernate.c
index 74ab766468..4dc35f68d0 100644
--- a/src/or/hibernate.c
+++ b/src/or/hibernate.c
@@ -34,6 +34,7 @@ hibernating, phase 2:
#include "config.h"
#include "connection.h"
#include "connection_edge.h"
+#include "connection_or.h"
#include "control.h"
#include "hibernate.h"
#include "main.h"
@@ -818,8 +819,8 @@ hibernate_begin(hibernate_state_t new_state, time_t now)
log_notice(LD_GENERAL,"SIGINT received %s; exiting now.",
hibernate_state == HIBERNATE_STATE_EXITING ?
"a second time" : "while hibernating");
- tor_cleanup();
- exit(0);
+ tor_shutdown_event_loop_and_exit(0);
+ return;
}
if (new_state == HIBERNATE_STATE_LOWBANDWIDTH &&
@@ -906,20 +907,23 @@ hibernate_go_dormant(time_t now)
while ((conn = connection_get_by_type(CONN_TYPE_OR)) ||
(conn = connection_get_by_type(CONN_TYPE_AP)) ||
(conn = connection_get_by_type(CONN_TYPE_EXIT))) {
- if (CONN_IS_EDGE(conn))
+ if (CONN_IS_EDGE(conn)) {
connection_edge_end(TO_EDGE_CONN(conn), END_STREAM_REASON_HIBERNATING);
+ }
log_info(LD_NET,"Closing conn type %d", conn->type);
- if (conn->type == CONN_TYPE_AP) /* send socks failure if needed */
+ if (conn->type == CONN_TYPE_AP) {
+ /* send socks failure if needed */
connection_mark_unattached_ap(TO_ENTRY_CONN(conn),
END_STREAM_REASON_HIBERNATING);
- else if (conn->type == CONN_TYPE_OR) {
+ } else if (conn->type == CONN_TYPE_OR) {
if (TO_OR_CONN(conn)->chan) {
- channel_mark_for_close(TLS_CHAN_TO_BASE(TO_OR_CONN(conn)->chan));
+ connection_or_close_normally(TO_OR_CONN(conn), 0);
} else {
connection_mark_for_close(conn);
}
- } else
+ } else {
connection_mark_for_close(conn);
+ }
}
if (now < interval_wakeup_time)
@@ -980,8 +984,7 @@ consider_hibernation(time_t now)
tor_assert(shutdown_time);
if (shutdown_time <= now) {
log_notice(LD_GENERAL, "Clean shutdown finished. Exiting.");
- tor_cleanup();
- exit(0);
+ tor_shutdown_event_loop_and_exit(0);
}
return; /* if exiting soon, don't worry about bandwidth limits */
}
diff --git a/src/or/hs_circuit.c b/src/or/hs_circuit.c
index ee952f4d68..26fe22eb7b 100644
--- a/src/or/hs_circuit.c
+++ b/src/or/hs_circuit.c
@@ -13,6 +13,7 @@
#include "circuitlist.h"
#include "circuituse.h"
#include "config.h"
+#include "nodelist.h"
#include "policies.h"
#include "relay.h"
#include "rendservice.h"
@@ -553,76 +554,98 @@ retry_service_rendezvous_point(const origin_circuit_t *circ)
return;
}
-/* Using an extend info object ei, set all possible link specifiers in lspecs.
- * legacy ID is mandatory thus MUST be present in ei. If IPv4 is not present,
- * logs a BUG() warning, and returns an empty smartlist. Clients never make
- * direct connections to rendezvous points, so they should always have an
- * IPv4 address in ei. */
+/* Add all possible link specifiers in node to lspecs.
+ * legacy ID is mandatory thus MUST be present in node. If the primary address
+ * is not IPv4, log a BUG() warning, and return an empty smartlist.
+ * Includes ed25519 id and IPv6 link specifiers if present in the node. */
static void
-get_lspecs_from_extend_info(const extend_info_t *ei, smartlist_t *lspecs)
+get_lspecs_from_node(const node_t *node, smartlist_t *lspecs)
{
link_specifier_t *ls;
+ tor_addr_port_t ap;
- tor_assert(ei);
+ tor_assert(node);
tor_assert(lspecs);
- /* We require IPv4, we will add IPv6 support in a later tor version */
- if (BUG(!tor_addr_is_v4(&ei->addr))) {
+ /* Get the relay's IPv4 address. */
+ node_get_prim_orport(node, &ap);
+
+ /* We expect the node's primary address to be a valid IPv4 address.
+ * This conforms to the protocol, which requires either an IPv4 or IPv6
+ * address (or both). */
+ if (BUG(!tor_addr_is_v4(&ap.addr)) ||
+ BUG(!tor_addr_port_is_valid_ap(&ap, 0))) {
return;
}
ls = link_specifier_new();
link_specifier_set_ls_type(ls, LS_IPV4);
- link_specifier_set_un_ipv4_addr(ls, tor_addr_to_ipv4h(&ei->addr));
- link_specifier_set_un_ipv4_port(ls, ei->port);
+ link_specifier_set_un_ipv4_addr(ls, tor_addr_to_ipv4h(&ap.addr));
+ link_specifier_set_un_ipv4_port(ls, ap.port);
/* Four bytes IPv4 and two bytes port. */
- link_specifier_set_ls_len(ls, sizeof(ei->addr.addr.in_addr) +
- sizeof(ei->port));
+ link_specifier_set_ls_len(ls, sizeof(ap.addr.addr.in_addr) +
+ sizeof(ap.port));
smartlist_add(lspecs, ls);
- /* Legacy ID is mandatory. */
+ /* Legacy ID is mandatory and will always be present in node. */
ls = link_specifier_new();
link_specifier_set_ls_type(ls, LS_LEGACY_ID);
- memcpy(link_specifier_getarray_un_legacy_id(ls), ei->identity_digest,
+ memcpy(link_specifier_getarray_un_legacy_id(ls), node->identity,
link_specifier_getlen_un_legacy_id(ls));
link_specifier_set_ls_len(ls, link_specifier_getlen_un_legacy_id(ls));
smartlist_add(lspecs, ls);
- /* ed25519 ID is only included if the extend_info has it. */
- if (!ed25519_public_key_is_zero(&ei->ed_identity)) {
+ /* ed25519 ID is only included if the node has it. */
+ if (!ed25519_public_key_is_zero(&node->ed25519_id)) {
ls = link_specifier_new();
link_specifier_set_ls_type(ls, LS_ED25519_ID);
- memcpy(link_specifier_getarray_un_ed25519_id(ls), &ei->ed_identity,
+ memcpy(link_specifier_getarray_un_ed25519_id(ls), &node->ed25519_id,
link_specifier_getlen_un_ed25519_id(ls));
link_specifier_set_ls_len(ls, link_specifier_getlen_un_ed25519_id(ls));
smartlist_add(lspecs, ls);
}
+
+ /* Check for IPv6. If so, include it as well. */
+ if (node_has_ipv6_orport(node)) {
+ ls = link_specifier_new();
+ node_get_pref_ipv6_orport(node, &ap);
+ link_specifier_set_ls_type(ls, LS_IPV6);
+ size_t addr_len = link_specifier_getlen_un_ipv6_addr(ls);
+ const uint8_t *in6_addr = tor_addr_to_in6_addr8(&ap.addr);
+ uint8_t *ipv6_array = link_specifier_getarray_un_ipv6_addr(ls);
+ memcpy(ipv6_array, in6_addr, addr_len);
+ 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));
+ }
}
-/* Using the given descriptor intro point ip, the extend information of the
- * rendezvous point rp_ei and the service's subcredential, populate the
+/* Using the given descriptor intro point ip, the node of the
+ * rendezvous point rp_node and the service's subcredential, populate the
* already allocated intro1_data object with the needed key material and link
* specifiers.
*
- * This can't fail but the ip MUST be a valid object containing the needed
- * keys and authentication method. */
+ * If rp_node has an invalid primary address, intro1_data->link_specifiers
+ * will be an empty list. Otherwise, this function can't fail. The ip
+ * MUST be a valid object containing the needed keys and authentication
+ * method. */
static void
setup_introduce1_data(const hs_desc_intro_point_t *ip,
- const extend_info_t *rp_ei,
+ const node_t *rp_node,
const uint8_t *subcredential,
hs_cell_introduce1_data_t *intro1_data)
{
smartlist_t *rp_lspecs;
tor_assert(ip);
- tor_assert(rp_ei);
+ tor_assert(rp_node);
tor_assert(subcredential);
tor_assert(intro1_data);
/* Build the link specifiers from the extend information of the rendezvous
* circuit that we've picked previously. */
rp_lspecs = smartlist_new();
- get_lspecs_from_extend_info(rp_ei, rp_lspecs);
+ get_lspecs_from_node(rp_node, rp_lspecs);
/* Populate the introduce1 data object. */
memset(intro1_data, 0, sizeof(hs_cell_introduce1_data_t));
@@ -633,7 +656,7 @@ setup_introduce1_data(const hs_desc_intro_point_t *ip,
intro1_data->auth_pk = &ip->auth_key_cert->signed_key;
intro1_data->enc_pk = &ip->enc_key;
intro1_data->subcredential = subcredential;
- intro1_data->onion_pk = &rp_ei->curve25519_onion_key;
+ intro1_data->onion_pk = node_get_curve25519_onion_key(rp_node);
intro1_data->link_specifiers = rp_lspecs;
}
@@ -1079,9 +1102,9 @@ hs_circ_send_introduce1(origin_circuit_t *intro_circ,
/* This takes various objects in order to populate the introduce1 data
* object which is used to build the content of the cell. */
- setup_introduce1_data(ip, rend_circ->build_state->chosen_exit,
- subcredential, &intro1_data);
- /* If we didn't get any link specifiers, it's because our extend info was
+ const node_t *exit_node = build_state_get_exit_node(rend_circ->build_state);
+ setup_introduce1_data(ip, exit_node, subcredential, &intro1_data);
+ /* If we didn't get any link specifiers, it's because our node was
* bad. */
if (BUG(!intro1_data.link_specifiers) ||
!smartlist_len(intro1_data.link_specifiers)) {
diff --git a/src/or/hs_service.c b/src/or/hs_service.c
index a2082b3914..8e2f52dcf0 100644
--- a/src/or/hs_service.c
+++ b/src/or/hs_service.c
@@ -1572,7 +1572,7 @@ pick_intro_point(unsigned int direct_conn, smartlist_t *exclude_nodes)
/* Let's do a basic sanity check here so that we don't end up advertising the
* ed25519 identity key of relays that don't actually support the link
* protocol */
- if (!node_supports_ed25519_link_authentication(node)) {
+ if (!node_supports_ed25519_link_authentication(node, 0)) {
tor_assert_nonfatal(ed25519_public_key_is_zero(&info->ed_identity));
} else {
/* Make sure we *do* have an ed key if we support the link authentication.
diff --git a/src/or/include.am b/src/or/include.am
index 7216aba9af..b783f4855a 100644
--- a/src/or/include.am
+++ b/src/or/include.am
@@ -51,6 +51,7 @@ LIBTOR_A_SOURCES = \
src/or/geoip.c \
src/or/entrynodes.c \
src/or/ext_orport.c \
+ src/or/git_revision.c \
src/or/hibernate.c \
src/or/hs_cache.c \
src/or/hs_cell.c \
@@ -78,6 +79,7 @@ LIBTOR_A_SOURCES = \
src/or/parsecommon.c \
src/or/periodic.c \
src/or/protover.c \
+ src/or/protover_rust.c \
src/or/proto_cell.c \
src/or/proto_control0.c \
src/or/proto_ext_or.c \
@@ -104,6 +106,7 @@ LIBTOR_A_SOURCES = \
src/or/statefile.c \
src/or/status.c \
src/or/torcert.c \
+ src/or/tor_api.c \
src/or/onion_ntor.c \
$(tor_platform_source)
@@ -189,6 +192,7 @@ ORHEADERS = \
src/or/fp_pair.h \
src/or/geoip.h \
src/or/entrynodes.h \
+ src/or/git_revision.h \
src/or/hibernate.h \
src/or/hs_cache.h \
src/or/hs_cell.h \
@@ -243,9 +247,13 @@ ORHEADERS = \
src/or/scheduler.h \
src/or/statefile.h \
src/or/status.h \
- src/or/torcert.h
+ src/or/torcert.h \
+ src/or/tor_api_internal.h
-noinst_HEADERS+= $(ORHEADERS) micro-revision.i
+# This may someday want to be an installed file?
+noinst_HEADERS += src/or/tor_api.h
+
+noinst_HEADERS += $(ORHEADERS) micro-revision.i
micro-revision.i: FORCE
$(AM_V_at)rm -f micro-revision.tmp; \
diff --git a/src/or/main.c b/src/or/main.c
index c340e4128b..e349703918 100644
--- a/src/or/main.c
+++ b/src/or/main.c
@@ -60,7 +60,6 @@
#include "circuitlist.h"
#include "circuituse.h"
#include "command.h"
-#include "compat_rust.h"
#include "compress.h"
#include "config.h"
#include "confparse.h"
@@ -106,6 +105,8 @@
#include "shared_random.h"
#include "statefile.h"
#include "status.h"
+#include "tor_api.h"
+#include "tor_api_internal.h"
#include "util_process.h"
#include "ext_orport.h"
#ifdef USE_DMALLOC
@@ -128,6 +129,12 @@
void evdns_shutdown(int);
+#ifdef HAVE_RUST
+// helper function defined in Rust to output a log message indicating if tor is
+// running with Rust enabled. See src/rust/tor_util
+char *rust_welcome_string(void);
+#endif
+
/********* PROTOTYPES **********/
static void dumpmemusage(int severity);
@@ -140,6 +147,8 @@ static void connection_start_reading_from_linked_conn(connection_t *conn);
static int connection_should_read_from_linked_conn(connection_t *conn);
static int run_main_loop_until_done(void);
static void process_signal(int sig);
+static void shutdown_did_not_work_callback(evutil_socket_t fd, short event,
+ void *arg) ATTR_NORETURN;
/********* START VARIABLES **********/
int global_read_bucket; /**< Max number of bytes I can read this second. */
@@ -192,6 +201,14 @@ static smartlist_t *active_linked_connection_lst = NULL;
* <b>loop_once</b>. If so, there's no need to trigger a loopexit in order
* to handle linked connections. */
static int called_loop_once = 0;
+/** Flag: if true, it's time to shut down, so the main loop should exit as
+ * soon as possible.
+ */
+static int main_loop_should_exit = 0;
+/** The return value that the main loop should yield when it exits, if
+ * main_loop_should_exit is true.
+ */
+static int main_loop_exit_value = 0;
/** We set this to 1 when we've opened a circuit, so we can print a log
* entry to inform the user that Tor is working. We set it to 0 when
@@ -637,9 +654,10 @@ connection_should_read_from_linked_conn(connection_t *conn)
/** If we called event_base_loop() and told it to never stop until it
* runs out of events, now we've changed our mind: tell it we want it to
- * finish. */
+ * exit once the current round of callbacks is done, so that we can
+ * run external code, and then return to the main loop. */
void
-tell_event_loop_to_finish(void)
+tell_event_loop_to_run_external_code(void)
{
if (!called_loop_once) {
struct timeval tv = { 0, 0 };
@@ -648,6 +666,54 @@ tell_event_loop_to_finish(void)
}
}
+/** Failsafe measure that should never actually be necessary: If
+ * tor_shutdown_event_loop_and_exit() somehow doesn't successfully exit the
+ * event loop, then this callback will kill Tor with an assertion failure
+ * seconds later
+ */
+static void
+shutdown_did_not_work_callback(evutil_socket_t fd, short event, void *arg)
+{
+ // LCOV_EXCL_START
+ (void) fd;
+ (void) event;
+ (void) arg;
+ tor_assert_unreached();
+ // LCOV_EXCL_STOP
+}
+
+/**
+ * After finishing the current callback (if any), shut down the main loop,
+ * clean up the process, and exit with <b>exitcode</b>.
+ */
+void
+tor_shutdown_event_loop_and_exit(int exitcode)
+{
+ if (main_loop_should_exit)
+ return; /* Ignore multiple calls to this function. */
+
+ main_loop_should_exit = 1;
+ main_loop_exit_value = exitcode;
+
+ /* Die with an assertion failure in ten seconds, if for some reason we don't
+ * exit normally. */
+ /* XXXX We should consider this code if it's never used. */
+ struct timeval ten_seconds = { 10, 0 };
+ event_base_once(tor_libevent_get_base(), -1, EV_TIMEOUT,
+ shutdown_did_not_work_callback, NULL,
+ &ten_seconds);
+
+ /* Unlike loopexit, loopbreak prevents other callbacks from running. */
+ tor_event_base_loopbreak(tor_libevent_get_base());
+}
+
+/** Return true iff tor_shutdown_event_loop_and_exit() has been called. */
+int
+tor_event_loop_shutdown_is_pending(void)
+{
+ return main_loop_should_exit;
+}
+
/** Helper: Tell the main loop to begin reading bytes into <b>conn</b> from
* its linked connection, if it is not doing so already. Called by
* connection_start_reading and connection_start_writing as appropriate. */
@@ -663,7 +729,7 @@ connection_start_reading_from_linked_conn(connection_t *conn)
/* make sure that the event_base_loop() function exits at
* the end of its run through the current connections, so we can
* activate read events for linked connections. */
- tell_event_loop_to_finish();
+ tell_event_loop_to_run_external_code();
} else {
tor_assert(smartlist_contains(active_linked_connection_lst, conn));
}
@@ -1405,7 +1471,9 @@ run_scheduled_events(time_t now)
/* Maybe enough time elapsed for us to reconsider a circuit. */
circuit_upgrade_circuits_from_guard_wait();
- if (options->UseBridges && !options->DisableNetwork) {
+ if (options->UseBridges && !net_is_disabled()) {
+ /* Note: this check uses net_is_disabled(), not should_delay_dir_fetches()
+ * -- the latter is only for fetching consensus-derived directory info. */
fetch_bridge_descriptors(options, now);
}
@@ -1511,7 +1579,7 @@ rotate_onion_key_callback(time_t now, const or_options_t *options)
if (router_rebuild_descriptor(1)<0) {
log_info(LD_CONFIG, "Couldn't rebuild router descriptor");
}
- if (advertised_server_mode() && !options->DisableNetwork)
+ if (advertised_server_mode() && !net_is_disabled())
router_upload_dir_desc_to_dirservers(0);
return ONION_KEY_CONSENSUS_CHECK_INTERVAL;
}
@@ -1554,8 +1622,7 @@ check_ed_keys_callback(time_t now, const or_options_t *options)
if (new_signing_key < 0 ||
generate_ed_link_cert(options, now, new_signing_key > 0)) {
log_err(LD_OR, "Unable to update Ed25519 keys! Exiting.");
- tor_cleanup();
- exit(1);
+ tor_shutdown_event_loop_and_exit(1);
}
}
return 30;
@@ -1877,9 +1944,11 @@ check_descriptor_callback(time_t now, const or_options_t *options)
* address has changed. */
#define CHECK_DESCRIPTOR_INTERVAL (60)
+ (void)options;
+
/* 2b. Once per minute, regenerate and upload the descriptor if the old
* one is inaccurate. */
- if (!options->DisableNetwork) {
+ if (!net_is_disabled()) {
check_descriptor_bandwidth_changed(now);
check_descriptor_ipaddress_changed(now);
mark_my_descriptor_dirty_if_too_old(now);
@@ -1911,7 +1980,7 @@ check_for_reachability_bw_callback(time_t now, const or_options_t *options)
* 20 minutes of our uptime. */
if (server_mode(options) &&
(have_completed_a_circuit() || !any_predicted_circuits(now)) &&
- !we_are_hibernating()) {
+ !net_is_disabled()) {
if (stats_n_seconds_working < TIMEOUT_UNTIL_UNREACHABILITY_COMPLAINT) {
consider_testing_reachability(1, dirport_reachability_count==0);
if (++dirport_reachability_count > 5)
@@ -2366,10 +2435,18 @@ do_hup(void)
/* first, reload config variables, in case they've changed */
if (options->ReloadTorrcOnSIGHUP) {
/* no need to provide argc/v, they've been cached in init_from_config */
- if (options_init_from_torrc(0, NULL) < 0) {
+ int init_rv = options_init_from_torrc(0, NULL);
+ if (init_rv < 0) {
log_err(LD_CONFIG,"Reading config failed--see warnings above. "
"For usage, try -h.");
return -1;
+ } else if (BUG(init_rv > 0)) {
+ // LCOV_EXCL_START
+ /* This should be impossible: the only "return 1" cases in
+ * options_init_from_torrc are ones caused by command-line arguments;
+ * but they can't change while Tor is running. */
+ return -1;
+ // LCOV_EXCL_STOP
}
options = get_options(); /* they have changed now */
/* Logs are only truncated the first time they are opened, but were
@@ -2405,7 +2482,7 @@ do_hup(void)
/* retry appropriate downloads */
router_reset_status_download_failures();
router_reset_descriptor_download_failures();
- if (!options->DisableNetwork)
+ if (!net_is_disabled())
update_networkstatus_downloads(time(NULL));
/* We'll retry routerstatus downloads in about 10 seconds; no need to
@@ -2595,6 +2672,9 @@ do_main_loop(void)
}
#endif /* defined(HAVE_SYSTEMD) */
+ main_loop_should_exit = 0;
+ main_loop_exit_value = 0;
+
return run_main_loop_until_done();
}
@@ -2610,6 +2690,9 @@ run_main_loop_once(void)
if (nt_service_is_stopping())
return 0;
+ if (main_loop_should_exit)
+ return 0;
+
#ifndef _WIN32
/* Make it easier to tell whether libevent failure is our fault or not. */
errno = 0;
@@ -2656,6 +2739,9 @@ run_main_loop_once(void)
}
}
+ if (main_loop_should_exit)
+ return 0;
+
/* And here is where we put callbacks that happen "every time the event loop
* runs." They must be very fast, or else the whole Tor process will get
* slowed down.
@@ -2684,7 +2770,11 @@ run_main_loop_until_done(void)
do {
loop_result = run_main_loop_once();
} while (loop_result == 1);
- return loop_result;
+
+ if (main_loop_should_exit)
+ return main_loop_exit_value;
+ else
+ return loop_result;
}
/** Libevent callback: invoked when we get a signal.
@@ -2708,14 +2798,13 @@ process_signal(int sig)
{
case SIGTERM:
log_notice(LD_GENERAL,"Catching signal TERM, exiting cleanly.");
- tor_cleanup();
- exit(0);
+ tor_shutdown_event_loop_and_exit(0);
break;
case SIGINT:
if (!server_mode(get_options())) { /* do it now */
log_notice(LD_GENERAL,"Interrupt: exiting cleanly.");
- tor_cleanup();
- exit(0);
+ tor_shutdown_event_loop_and_exit(0);
+ return;
}
#ifdef HAVE_SYSTEMD
sd_notify(0, "STOPPING=1");
@@ -2744,8 +2833,8 @@ process_signal(int sig)
#endif
if (do_hup() < 0) {
log_warn(LD_CONFIG,"Restart failed (config error?). Exiting.");
- tor_cleanup();
- exit(1);
+ tor_shutdown_event_loop_and_exit(1);
+ return;
}
#ifdef HAVE_SYSTEMD
sd_notify(0, "READY=1");
@@ -3019,7 +3108,8 @@ activate_signal(int signal_num)
}
}
-/** Main entry point for the Tor command-line client.
+/** Main entry point for the Tor command-line client. Return 0 on "success",
+ * negative on "failure", and positive on "success and exit".
*/
int
tor_init(int argc, char *argv[])
@@ -3111,14 +3201,13 @@ tor_init(int argc, char *argv[])
"Expect more bugs than usual.");
}
- {
- rust_str_t rust_str = rust_welcome_string();
- const char *s = rust_str_get(rust_str);
- if (strlen(s) > 0) {
- log_notice(LD_GENERAL, "%s", s);
- }
- rust_str_free(rust_str);
+#ifdef HAVE_RUST
+ char *rust_str = rust_welcome_string();
+ if (rust_str != NULL && strlen(rust_str) > 0) {
+ log_notice(LD_GENERAL, "%s", rust_str);
}
+ tor_free(rust_str);
+#endif
if (network_init()<0) {
log_err(LD_BUG,"Error initializing network; exiting.");
@@ -3126,9 +3215,14 @@ tor_init(int argc, char *argv[])
}
atexit(exit_function);
- if (options_init_from_torrc(argc,argv) < 0) {
+ int init_rv = options_init_from_torrc(argc,argv);
+ if (init_rv < 0) {
log_err(LD_CONFIG,"Reading config failed--see warnings above.");
return -1;
+ } else if (init_rv > 0) {
+ // We succeeded, and should exit anyway -- probably the user just said
+ // "--version" or something like that.
+ return 1;
}
/* The options are now initialised */
@@ -3198,7 +3292,7 @@ try_locking(const or_options_t *options, int err_if_locked)
r = try_locking(options, 0);
if (r<0) {
log_err(LD_GENERAL, "No, it's still there. Exiting.");
- exit(1);
+ return -1;
}
return r;
}
@@ -3521,6 +3615,10 @@ sandbox_init_filter(void)
}
}
+ SMARTLIST_FOREACH(options->FilesOpenedByIncludes, char *, f, {
+ OPEN(f);
+ });
+
#define RENAME_SUFFIX(name, suffix) \
sandbox_cfg_allow_rename(&cfg, \
get_datadir_fname(name suffix), \
@@ -3703,14 +3801,16 @@ sandbox_init_filter(void)
return cfg;
}
-/** Main entry point for the Tor process. Called from main(). */
-/* This function is distinct from main() only so we can link main.c into
- * the unittest binary without conflicting with the unittests' main. */
+/* Main entry point for the Tor process. Called from tor_main(), and by
+ * anybody embedding Tor. */
int
-tor_main(int argc, char *argv[])
+tor_run_main(const tor_main_configuration_t *tor_cfg)
{
int result = 0;
+ int argc = tor_cfg->argc;
+ char **argv = tor_cfg->argv;
+
#ifdef _WIN32
#ifndef HeapEnableTerminationOnCorruption
#define HeapEnableTerminationOnCorruption 1
@@ -3754,8 +3854,13 @@ tor_main(int argc, char *argv[])
if (done) return result;
}
#endif /* defined(NT_SERVICE) */
- if (tor_init(argc, argv)<0)
- return -1;
+ {
+ int init_rv = tor_init(argc, argv);
+ if (init_rv < 0)
+ return -1;
+ else if (init_rv > 0)
+ return 0;
+ }
if (get_options()->Sandbox && get_options()->command == CMD_RUN_TOR) {
sandbox_cfg_t* cfg = sandbox_init_filter();
diff --git a/src/or/main.h b/src/or/main.h
index 132ab12bbb..8eb977575e 100644
--- a/src/or/main.h
+++ b/src/or/main.h
@@ -45,7 +45,9 @@ int connection_is_writing(connection_t *conn);
MOCK_DECL(void,connection_stop_writing,(connection_t *conn));
MOCK_DECL(void,connection_start_writing,(connection_t *conn));
-void tell_event_loop_to_finish(void);
+void tell_event_loop_to_run_external_code(void);
+void tor_shutdown_event_loop_and_exit(int exitcode);
+int tor_event_loop_shutdown_is_pending(void);
void connection_stop_reading_from_linked_conn(connection_t *conn);
@@ -74,8 +76,6 @@ void release_lockfile(void);
void tor_cleanup(void);
void tor_free_all(int postfork);
-int tor_main(int argc, char *argv[]);
-
int do_main_loop(void);
int tor_init(int argc, char **argv);
diff --git a/src/or/networkstatus.c b/src/or/networkstatus.c
index 2660e6a329..a7aa01f787 100644
--- a/src/or/networkstatus.c
+++ b/src/or/networkstatus.c
@@ -52,6 +52,7 @@
#include "dirserv.h"
#include "dirvote.h"
#include "entrynodes.h"
+#include "hibernate.h"
#include "main.h"
#include "microdesc.h"
#include "networkstatus.h"
@@ -1208,6 +1209,14 @@ should_delay_dir_fetches(const or_options_t *options, const char **msg_out)
return 1;
}
+ if (we_are_hibernating()) {
+ if (msg_out) {
+ *msg_out = "We are hibernating or shutting down.";
+ }
+ log_info(LD_DIR, "Delaying dir fetches (Hibernating or shutting down)");
+ return 1;
+ }
+
if (options->UseBridges) {
if (!any_bridge_descriptors_known()) {
if (msg_out) {
@@ -1671,7 +1680,7 @@ handle_missing_protocol_warning_impl(const networkstatus_t *c,
}
tor_free(protocol_warning);
if (should_exit)
- exit(1);
+ exit(1); // XXXX bad exit: should return from main.
}
/** Called when we have received a networkstatus <b>c</b>. If there are
@@ -1720,7 +1729,7 @@ networkstatus_set_current_consensus(const char *consensus,
{
networkstatus_t *c=NULL;
int r, result = -1;
- time_t now = time(NULL);
+ time_t now = approx_time();
const or_options_t *options = get_options();
char *unverified_fname = NULL, *consensus_fname = NULL;
int flav = networkstatus_parse_flavor_name(flavor);
diff --git a/src/or/nodelist.c b/src/or/nodelist.c
index f2e979be8b..1ab385cd35 100644
--- a/src/or/nodelist.c
+++ b/src/or/nodelist.c
@@ -951,23 +951,29 @@ node_ed25519_id_matches(const node_t *node, const ed25519_public_key_t *id)
}
/** Return true iff <b>node</b> supports authenticating itself
- * by ed25519 ID during the link handshake in a way that we can understand
- * when we probe it. */
+ * by ed25519 ID during the link handshake. If <b>compatible_with_us</b>,
+ * it needs to be using a link authentication method that we understand.
+ * If not, any plausible link authentication method will do. */
int
-node_supports_ed25519_link_authentication(const node_t *node)
+node_supports_ed25519_link_authentication(const node_t *node,
+ int compatible_with_us)
{
- /* XXXX Oh hm. What if some day in the future there are link handshake
- * versions that aren't 3 but which are ed25519 */
if (! node_get_ed25519_id(node))
return 0;
if (node->ri) {
const char *protos = node->ri->protocol_list;
if (protos == NULL)
return 0;
- return protocol_list_supports_protocol(protos, PRT_LINKAUTH, 3);
+ if (compatible_with_us)
+ return protocol_list_supports_protocol(protos, PRT_LINKAUTH, 3);
+ else
+ return protocol_list_supports_protocol_or_later(protos, PRT_LINKAUTH, 3);
}
if (node->rs) {
- return node->rs->supports_ed25519_link_handshake;
+ if (compatible_with_us)
+ return node->rs->supports_ed25519_link_handshake_compat;
+ else
+ return node->rs->supports_ed25519_link_handshake_any;
}
tor_assert_nonfatal_unreached_once();
return 0;
@@ -1633,6 +1639,18 @@ node_has_curve25519_onion_key(const node_t *node)
return 0;
}
+/** Return the curve25519 key of <b>node</b>, or NULL if none. */
+const curve25519_public_key_t *
+node_get_curve25519_onion_key(const node_t *node)
+{
+ if (node->ri)
+ return node->ri->onion_curve25519_pkey;
+ else if (node->md)
+ return node->md->onion_curve25519_pkey;
+ else
+ return NULL;
+}
+
/** Refresh the country code of <b>ri</b>. This function MUST be called on
* each router when the GeoIP database is reloaded, and on all new routers. */
void
diff --git a/src/or/nodelist.h b/src/or/nodelist.h
index 754990ac8d..e879b4e8ff 100644
--- a/src/or/nodelist.h
+++ b/src/or/nodelist.h
@@ -65,7 +65,8 @@ const smartlist_t *node_get_declared_family(const node_t *node);
const ed25519_public_key_t *node_get_ed25519_id(const node_t *node);
int node_ed25519_id_matches(const node_t *node,
const ed25519_public_key_t *id);
-int node_supports_ed25519_link_authentication(const node_t *node);
+int node_supports_ed25519_link_authentication(const node_t *node,
+ int compatible_with_us);
int node_supports_v3_hsdir(const node_t *node);
int node_supports_ed25519_hs_intro(const node_t *node);
int node_supports_v3_rendezvous_point(const node_t *node);
@@ -85,6 +86,8 @@ int node_get_prim_dirport(const node_t *node, tor_addr_port_t *ap_out);
void node_get_pref_dirport(const node_t *node, tor_addr_port_t *ap_out);
void node_get_pref_ipv6_dirport(const node_t *node, tor_addr_port_t *ap_out);
int node_has_curve25519_onion_key(const node_t *node);
+const curve25519_public_key_t *node_get_curve25519_onion_key(
+ const node_t *node);
MOCK_DECL(smartlist_t *, nodelist_get_list, (void));
diff --git a/src/or/ntmain.c b/src/or/ntmain.c
index 508e5844eb..ebbe0018bd 100644
--- a/src/or/ntmain.c
+++ b/src/or/ntmain.c
@@ -195,7 +195,7 @@ nt_service_loadlibrary(void)
return;
err:
printf("Unable to load library support for NT services: exiting.\n");
- exit(1);
+ exit(1); // exit ok: ntmain can't read libraries
}
/** If we're compiled to run as an NT service, and the service wants to
@@ -318,7 +318,7 @@ nt_service_main(void)
printf("Service error %d : %s\n", (int) result, errmsg);
tor_free(errmsg);
if (result == ERROR_FAILED_SERVICE_CONTROLLER_CONNECT) {
- if (tor_init(backup_argc, backup_argv) < 0)
+ if (tor_init(backup_argc, backup_argv))
return;
switch (get_options()->command) {
case CMD_RUN_TOR:
diff --git a/src/or/or.h b/src/or/or.h
index 809714b5e2..fa5268ac59 100644
--- a/src/or/or.h
+++ b/src/or/or.h
@@ -2234,18 +2234,18 @@ typedef struct {
* uploaded it. */
#define ROUTER_PURPOSE_GENERAL 0
/** Tor should avoid using this router for circuit-building: we got it
- * from a crontroller. If the controller wants to use it, it'll have to
+ * from a controller. If the controller wants to use it, it'll have to
* ask for it by identity. */
#define ROUTER_PURPOSE_CONTROLLER 1
/** Tor should use this router only for bridge positions in circuits: we got
* it via a directory request from the bridge itself, or a bridge
- * authority. x*/
+ * authority. */
#define ROUTER_PURPOSE_BRIDGE 2
/** Tor should not use this router; it was marked in cached-descriptors with
* a purpose we didn't recognize. */
#define ROUTER_PURPOSE_UNKNOWN 255
- /* In what way did we find out about this router? One of ROUTER_PURPOSE_*.
+ /** In what way did we find out about this router? One of ROUTER_PURPOSE_*.
* Routers of different purposes are kept segregated and used for different
* things; see notes on ROUTER_PURPOSE_* macros above.
*/
@@ -2316,8 +2316,12 @@ typedef struct routerstatus_t {
unsigned int supports_extend2_cells:1;
/** True iff this router has a protocol list that allows it to negotiate
- * ed25519 identity keys on a link handshake. */
- unsigned int supports_ed25519_link_handshake:1;
+ * ed25519 identity keys on a link handshake with us. */
+ unsigned int supports_ed25519_link_handshake_compat:1;
+
+ /** True iff this router has a protocol list that allows it to negotiate
+ * ed25519 identity keys on a link handshake, at all. */
+ unsigned int supports_ed25519_link_handshake_any:1;
/** True iff this router has a protocol list that allows it to be an
* introduction point supporting ed25519 authentication key which is part of
@@ -3674,6 +3678,7 @@ typedef struct {
* interface addresses?
* Includes OutboundBindAddresses and
* configured ports. */
+ int ReducedExitPolicy; /**<Should we use the Reduced Exit Policy? */
config_line_t *SocksPolicy; /**< Lists of socks policy components */
config_line_t *DirPolicy; /**< Lists of dir policy components */
/** Local address to bind outbound sockets */
@@ -4070,6 +4075,8 @@ typedef struct {
/** Process specifier for a controller that ‘owns’ this Tor
* instance. Tor will terminate if its owning controller does. */
char *OwningControllerProcess;
+ /** FD specifier for a controller that owns this Tor instance. */
+ int OwningControllerFD;
int ShutdownWaitLength; /**< When we get a SIGINT and we're a server, how
* long do we wait before exiting? */
@@ -4627,6 +4634,9 @@ typedef struct {
smartlist_t *Schedulers;
/* An ordered list of scheduler_types mapped from Schedulers. */
smartlist_t *SchedulerTypes_;
+
+ /** List of files that were opened by %include in torrc and torrc-defaults */
+ smartlist_t *FilesOpenedByIncludes;
} or_options_t;
#define LOG_PROTOCOL_WARN (get_protocol_warning_severity_level())
diff --git a/src/or/policies.c b/src/or/policies.c
index 78451db8fc..1f80130710 100644
--- a/src/or/policies.c
+++ b/src/or/policies.c
@@ -81,7 +81,8 @@ static int policies_parse_exit_policy_internal(
const smartlist_t *configured_addresses,
int reject_interface_addresses,
int reject_configured_port_addresses,
- int add_default_policy);
+ int add_default_policy,
+ int add_reduced_policy);
/** Replace all "private" entries in *<b>policy</b> with their expanded
* equivalents. */
@@ -1144,7 +1145,7 @@ validate_addr_policies(const or_options_t *options, char **msg)
"to 1 to disable this warning, and for forward compatibility.",
options->ExitPolicy == NULL ?
" with the default exit policy" : "");
- if (options->ExitPolicy == NULL) {
+ if (options->ExitPolicy == NULL && options->ReducedExitPolicy == 0) {
log_warn(LD_CONFIG,
"In a future version of Tor, ExitRelay 0 may become the "
"default when no ExitPolicy is given.");
@@ -1877,6 +1878,24 @@ policies_log_first_redundant_entry(const smartlist_t *policy)
"reject *:563,reject *:1214,reject *:4661-4666," \
"reject *:6346-6429,reject *:6699,reject *:6881-6999,accept *:*"
+#define REDUCED_EXIT_POLICY \
+ "accept *:20-23,accept *:43,accept *:53,accept *:79-81,accept *:88," \
+ "accept *:110,accept *:143,accept *:194,accept *:220,accept *:389," \
+ "accept *:443,accept *:464,accept *:465,accept *:531,accept *:543-544," \
+ "accept *:554,accept *:563,accept *:587,accept *:636,accept *:706," \
+ "accept *:749,accept *:873,accept *:902-904,accept *:981,accept *:989-995," \
+ "accept *:1194,accept *:1220,accept *:1293,accept *:1500,accept *:1533," \
+ "accept *:1677,accept *:1723,accept *:1755,accept *:1863," \
+ "accept *:2082-2083,accept *:2086-2087,accept *:2095-2096," \
+ "accept *:2102-2104,accept *:3128,accept *:3389,accept *:3690," \
+ "accept *:4321,accept *:4643,accept *:5050,accept *:5190," \
+ "accept *:5222-5223,accept *:5228,accept *:5900,accept *:6660-6669," \
+ "accept *:6679,accept *:6697,accept *:8000,accept *:8008,accept *:8074," \
+ "accept *:8080,accept *:8082,accept *:8087-8088,accept *:8232-8233," \
+ "accept *:8332-8333,accept *:8443,accept *:8888,accept *:9418," \
+ "accept *:9999,accept *:10000,accept *:11371,accept *:19294," \
+ "accept *:19638,accept *:50002,accept *:64738,reject *:*"
+
/** Parse the exit policy <b>cfg</b> into the linked list *<b>dest</b>.
*
* If <b>ipv6_exit</b> is false, prepend "reject *6:*" to the policy.
@@ -1912,7 +1931,8 @@ policies_parse_exit_policy_internal(config_line_t *cfg,
const smartlist_t *configured_addresses,
int reject_interface_addresses,
int reject_configured_port_addresses,
- int add_default_policy)
+ int add_default_policy,
+ int add_reduced_policy)
{
if (!ipv6_exit) {
append_exit_policy_string(dest, "reject *6:*");
@@ -1938,7 +1958,9 @@ policies_parse_exit_policy_internal(config_line_t *cfg,
* effect, and are most likely an error. */
policies_log_first_redundant_entry(*dest);
- if (add_default_policy) {
+ if (add_reduced_policy) {
+ append_exit_policy_string(dest, REDUCED_EXIT_POLICY);
+ } else if (add_default_policy) {
append_exit_policy_string(dest, DEFAULT_EXIT_POLICY);
} else {
append_exit_policy_string(dest, "reject *4:*");
@@ -1979,13 +2001,15 @@ policies_parse_exit_policy(config_line_t *cfg, smartlist_t **dest,
int add_default = (options & EXIT_POLICY_ADD_DEFAULT) ? 1 : 0;
int reject_local_interfaces = (options &
EXIT_POLICY_REJECT_LOCAL_INTERFACES) ? 1 : 0;
+ int add_reduced = (options & EXIT_POLICY_ADD_REDUCED) ? 1 : 0;
return policies_parse_exit_policy_internal(cfg,dest,ipv6_enabled,
reject_private,
configured_addresses,
reject_local_interfaces,
reject_local_interfaces,
- add_default);
+ add_default,
+ add_reduced);
}
/** Helper function that adds a copy of addr to a smartlist as long as it is
@@ -2095,7 +2119,10 @@ policies_parse_exit_policy_from_options(const or_options_t *or_options,
}
if (!or_options->BridgeRelay) {
- parser_cfg |= EXIT_POLICY_ADD_DEFAULT;
+ if (or_options->ReducedExitPolicy)
+ parser_cfg |= EXIT_POLICY_ADD_REDUCED;
+ else
+ parser_cfg |= EXIT_POLICY_ADD_DEFAULT;
}
if (or_options->ExitPolicyRejectLocalInterfaces) {
diff --git a/src/or/policies.h b/src/or/policies.h
index 52ff4e2f99..cd97ee7f59 100644
--- a/src/or/policies.h
+++ b/src/or/policies.h
@@ -22,7 +22,8 @@
#define EXIT_POLICY_REJECT_PRIVATE (1 << 1)
#define EXIT_POLICY_ADD_DEFAULT (1 << 2)
#define EXIT_POLICY_REJECT_LOCAL_INTERFACES (1 << 3)
-#define EXIT_POLICY_OPTION_MAX EXIT_POLICY_REJECT_LOCAL_INTERFACES
+#define EXIT_POLICY_ADD_REDUCED (1 << 4)
+#define EXIT_POLICY_OPTION_MAX EXIT_POLICY_ADD_REDUCED
/* All options set: used for unit testing */
#define EXIT_POLICY_OPTION_ALL ((EXIT_POLICY_OPTION_MAX << 1) - 1)
diff --git a/src/or/protover.c b/src/or/protover.c
index 1a3e69be10..ae955296e6 100644
--- a/src/or/protover.c
+++ b/src/or/protover.c
@@ -27,11 +27,14 @@
#include "protover.h"
#include "routerparse.h"
+#ifndef HAVE_RUST
+
static const smartlist_t *get_supported_protocol_list(void);
static int protocol_list_contains(const smartlist_t *protos,
protocol_type_t pr, uint32_t ver);
/** Mapping between protocol type string and protocol type. */
+/// C_RUST_COUPLED: src/rust/protover/protover.rs `PROTOCOL_NAMES`
static const struct {
protocol_type_t protover_type;
const char *name;
@@ -280,8 +283,45 @@ protocol_list_supports_protocol(const char *list, protocol_type_t tp,
return contains;
}
+/**
+ * Return true iff "list" encodes a protocol list that includes support for
+ * the indicated protocol and version, or some later version.
+ */
+int
+protocol_list_supports_protocol_or_later(const char *list,
+ protocol_type_t tp,
+ uint32_t version)
+{
+ /* NOTE: This is a pretty inefficient implementation. If it ever shows
+ * up in profiles, we should memoize it.
+ */
+ smartlist_t *protocols = parse_protocol_list(list);
+ if (!protocols) {
+ return 0;
+ }
+ const char *pr_name = protocol_type_to_str(tp);
+
+ int contains = 0;
+ SMARTLIST_FOREACH_BEGIN(protocols, proto_entry_t *, proto) {
+ if (strcasecmp(proto->name, pr_name))
+ continue;
+ SMARTLIST_FOREACH_BEGIN(proto->ranges, const proto_range_t *, range) {
+ if (range->high >= version) {
+ contains = 1;
+ goto found;
+ }
+ } SMARTLIST_FOREACH_END(range);
+ } SMARTLIST_FOREACH_END(proto);
+
+ found:
+ SMARTLIST_FOREACH(protocols, proto_entry_t *, ent, proto_entry_free(ent));
+ smartlist_free(protocols);
+ return contains;
+}
+
/** Return the canonical string containing the list of protocols
* that we support. */
+/// C_RUST_COUPLED: src/rust/protover/protover.rs `SUPPORTED_PROTOCOLS`
const char *
protover_get_supported_protocols(void)
{
@@ -365,6 +405,8 @@ encode_protocol_list(const smartlist_t *sl)
/* We treat any protocol list with more than this many subprotocols in it
* as a DoS attempt. */
+/// C_RUST_COUPLED: src/rust/protover/protover.rs
+/// `MAX_PROTOCOLS_TO_EXPAND`
static const int MAX_PROTOCOLS_TO_EXPAND = (1<<16);
/** Voting helper: Given a list of proto_entry_t, return a newly allocated
@@ -691,6 +733,7 @@ protocol_list_contains(const smartlist_t *protos,
* Note that this is only used to infer protocols for Tor versions that
* can't declare their own.
**/
+/// C_RUST_COUPLED: src/rust/protover/protover.rs `compute_for_old_tor`
const char *
protover_compute_for_old_tor(const char *version)
{
@@ -735,3 +778,5 @@ protover_free_all(void)
}
}
+#endif
+
diff --git a/src/or/protover.h b/src/or/protover.h
index 657977279e..a4dbc8bfc2 100644
--- a/src/or/protover.h
+++ b/src/or/protover.h
@@ -15,6 +15,8 @@
* descriptors. Authorities should use this to decide whether to
* guess proto lines. */
/* This is a guess. */
+/// C_RUST_COUPLED: src/rust/protover/protover.rs
+/// `FIRST_TOR_VERSION_TO_ADVERTISE_PROTOCOLS`
#define FIRST_TOR_VERSION_TO_ADVERTISE_PROTOCOLS "0.2.9.3-alpha"
/** The protover version number that signifies HSDir support for HSv3 */
@@ -25,6 +27,8 @@
#define PROTOVER_HS_RENDEZVOUS_POINT_V3 2
/** List of recognized subprotocols. */
+/// C_RUST_COUPLED: src/rust/protover/ffi.rs `translate_to_rust`
+/// C_RUST_COUPLED: src/rust/protover/protover.rs `Proto`
typedef enum protocol_type_t {
PRT_LINK,
PRT_LINKAUTH,
@@ -47,6 +51,9 @@ char *protover_compute_vote(const smartlist_t *list_of_proto_strings,
const char *protover_compute_for_old_tor(const char *version);
int protocol_list_supports_protocol(const char *list, protocol_type_t tp,
uint32_t version);
+int protocol_list_supports_protocol_or_later(const char *list,
+ protocol_type_t tp,
+ uint32_t version);
void protover_free_all(void);
@@ -70,11 +77,15 @@ typedef struct proto_entry_t {
smartlist_t *ranges;
} proto_entry_t;
+#if !defined(HAVE_RUST) && defined(TOR_UNIT_TESTS)
STATIC smartlist_t *parse_protocol_list(const char *s);
-STATIC void proto_entry_free(proto_entry_t *entry);
STATIC char *encode_protocol_list(const smartlist_t *sl);
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(PROTOVER_PRIVATE) */
#endif /* !defined(TOR_PROTOVER_H) */
diff --git a/src/or/protover_rust.c b/src/or/protover_rust.c
new file mode 100644
index 0000000000..0c409b1681
--- /dev/null
+++ b/src/or/protover_rust.c
@@ -0,0 +1,19 @@
+/* Copyright (c) 2016-2017, The Tor Project, Inc. */
+/* See LICENSE for licensing information */
+
+/*
+ * \file protover_rust.c
+ * \brief Provide a C wrapper for functions exposed in /src/rust/protover,
+ * and safe translation/handling between the Rust/C boundary.
+ */
+
+#include "or.h"
+#include "protover.h"
+
+#ifdef HAVE_RUST
+
+/* Define for compatibility, used in main.c */
+void protover_free_all(void) {}
+
+#endif
+
diff --git a/src/or/routerlist.c b/src/or/routerlist.c
index 355f8e0fa0..fb8225e0d6 100644
--- a/src/or/routerlist.c
+++ b/src/or/routerlist.c
@@ -3096,7 +3096,7 @@ signed_descriptor_get_body_impl(const signed_descriptor_t *desc,
log_err(LD_DIR, "We couldn't read a descriptor that is supposedly "
"mmaped in our cache. Is another process running in our data "
"directory? Exiting.");
- exit(1);
+ exit(1); // XXXX bad exit: should recover.
}
}
if (!r) /* no mmap, or not in cache. */
@@ -3110,7 +3110,7 @@ signed_descriptor_get_body_impl(const signed_descriptor_t *desc,
log_err(LD_DIR, "descriptor at %p begins with unexpected string %s. "
"Is another process running in our data directory? Exiting.",
desc, escaped(cp));
- exit(1);
+ exit(1); // XXXX bad exit: should recover.
}
}
@@ -4545,7 +4545,7 @@ signed_desc_digest_is_recognized(signed_descriptor_t *desc)
void
update_all_descriptor_downloads(time_t now)
{
- if (get_options()->DisableNetwork)
+ if (should_delay_dir_fetches(get_options(), NULL))
return;
update_router_descriptor_downloads(now);
update_microdesc_downloads(now);
@@ -5377,8 +5377,10 @@ update_extrainfo_downloads(time_t now)
smartlist_free(wanted);
}
-/** Reset the descriptor download failure count on all routers, so that we
- * can retry any long-failed routers immediately.
+/** Reset the consensus and extra-info download failure count on all routers.
+ * When we get a new consensus,
+ * routers_update_status_from_consensus_networkstatus() will reset the
+ * download statuses on the descriptors in that consensus.
*/
void
router_reset_descriptor_download_failures(void)
@@ -5390,6 +5392,8 @@ router_reset_descriptor_download_failures(void)
last_descriptor_download_attempted = 0;
if (!routerlist)
return;
+ /* We want to download *all* extra-info descriptors, not just those in
+ * the consensus we currently have (or are about to have) */
SMARTLIST_FOREACH(routerlist->routers, routerinfo_t *, ri,
{
download_status_reset(&ri->cache_info.ei_dl_status);
diff --git a/src/or/routerparse.c b/src/or/routerparse.c
index 15cdb0bbde..f1895ce313 100644
--- a/src/or/routerparse.c
+++ b/src/or/routerparse.c
@@ -2701,8 +2701,10 @@ routerstatus_parse_entry_from_string(memarea_t *area,
rs->protocols_known = 1;
rs->supports_extend2_cells =
protocol_list_supports_protocol(tok->args[0], PRT_RELAY, 2);
- rs->supports_ed25519_link_handshake =
+ rs->supports_ed25519_link_handshake_compat =
protocol_list_supports_protocol(tok->args[0], PRT_LINKAUTH, 3);
+ rs->supports_ed25519_link_handshake_any =
+ protocol_list_supports_protocol_or_later(tok->args[0], PRT_LINKAUTH, 3);
rs->supports_ed25519_hs_intro =
protocol_list_supports_protocol(tok->args[0], PRT_HSINTRO, 4);
rs->supports_v3_hsdir =
@@ -4027,7 +4029,7 @@ networkstatus_parse_vote_from_string(const char *s, const char **eos_out,
/** Return the common_digests_t that holds the digests of the
* <b>flavor_name</b>-flavored networkstatus according to the detached
* signatures document <b>sigs</b>, allocating a new common_digests_t as
- * neeeded. */
+ * needed. */
static common_digests_t *
detached_get_digests(ns_detached_signatures_t *sigs, const char *flavor_name)
{
@@ -4041,7 +4043,7 @@ detached_get_digests(ns_detached_signatures_t *sigs, const char *flavor_name)
/** Return the list of signatures of the <b>flavor_name</b>-flavored
* networkstatus according to the detached signatures document <b>sigs</b>,
- * allocating a new common_digests_t as neeeded. */
+ * allocating a new common_digests_t as needed. */
static smartlist_t *
detached_get_signatures(ns_detached_signatures_t *sigs,
const char *flavor_name)
diff --git a/src/or/scheduler.c b/src/or/scheduler.c
index 1438dc60f6..510c16b217 100644
--- a/src/or/scheduler.c
+++ b/src/or/scheduler.c
@@ -284,7 +284,7 @@ select_scheduler(void)
* wishes of using what it has been configured and don't do a sneaky
* fallback. Because this can be changed at runtime, we have to stop tor
* right now. */
- exit(1);
+ exit(1); // XXXX bad exit
}
/* Set the chosen scheduler. */
diff --git a/src/or/tor_api.c b/src/or/tor_api.c
new file mode 100644
index 0000000000..4260cc88f4
--- /dev/null
+++ b/src/or/tor_api.c
@@ -0,0 +1,88 @@
+/* Copyright (c) 2001 Matej Pfajfar.
+ * Copyright (c) 2001-2004, Roger Dingledine.
+ * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
+ * Copyright (c) 2007-2017, The Tor Project, Inc. */
+/* See LICENSE for licensing information */
+
+/**
+ * \file tor_api.c
+ **/
+
+#include "tor_api.h"
+#include "tor_api_internal.h"
+
+// Include this after the above headers, to insure that they don't
+// depend on anything else.
+#include "orconfig.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+// We don't want to use tor_malloc and tor_free here, since this needs
+// to run before anything is initialized at all, and ought to run when
+// we're not linked to anything at all.
+
+#define raw_malloc malloc
+#define raw_free free
+
+tor_main_configuration_t *
+tor_main_configuration_new(void)
+{
+ static const char *fake_argv[] = { "tor" };
+ tor_main_configuration_t *cfg = raw_malloc(sizeof(*cfg));
+ if (cfg == NULL)
+ return NULL;
+
+ memset(cfg, 0, sizeof(*cfg));
+
+ cfg->argc = 1;
+ cfg->argv = (char **) fake_argv;
+
+ return cfg;
+}
+
+int
+tor_main_configuration_set_command_line(tor_main_configuration_t *cfg,
+ int argc, char *argv[])
+{
+ if (cfg == NULL)
+ return -1;
+ cfg->argc = argc;
+ cfg->argv = argv;
+ return 0;
+}
+
+void
+tor_main_configuration_free(tor_main_configuration_t *cfg)
+{
+ if (cfg == NULL)
+ return;
+ raw_free(cfg);
+}
+
+/* Main entry point for the Tor process. Called from main().
+ *
+ * This function is distinct from main() only so we can link main.c into
+ * the unittest binary without conflicting with the unittests' main.
+ *
+ * Some embedders have historically called this function; but that usage is
+ * deprecated: they should use tor_run_main() instead.
+ */
+int
+tor_main(int argc, char *argv[])
+{
+ tor_main_configuration_t *cfg = tor_main_configuration_new();
+ if (!cfg) {
+ puts("INTERNAL ERROR: Allocation failure. Cannot proceed");
+ return 1;
+ }
+ if (tor_main_configuration_set_command_line(cfg, argc, argv) < 0) {
+ puts("INTERNAL ERROR: Can't set command line. Cannot proceed.");
+ return 1;
+ }
+ int rv = tor_run_main(cfg);
+ tor_main_configuration_free(cfg);
+ return rv;
+}
+
diff --git a/src/or/tor_api.h b/src/or/tor_api.h
new file mode 100644
index 0000000000..b12ed718c1
--- /dev/null
+++ b/src/or/tor_api.h
@@ -0,0 +1,102 @@
+/* Copyright (c) 2001 Matej Pfajfar.
+ * Copyright (c) 2001-2004, Roger Dingledine.
+ * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
+ * Copyright (c) 2007-2017, The Tor Project, Inc. */
+/* See LICENSE for licensing information */
+
+/**
+ * \file tor_api.h
+ * \brief Public C API for the Tor network service.
+ *
+ * This interface is intended for use by programs that need to link Tor as
+ * a library, and launch it in a separate thread. If you have the ability
+ * to run Tor as a separate executable, you should probably do that instead
+ * of embedding it as a library.
+ *
+ * To use this API, first construct a tor_main_configuration_t object using
+ * tor_main_configuration_new(). Then, you use one or more other function
+ * calls (such as tor_main_configuration_set_command_line() to configure how
+ * Tor should be run. Finally, you pass the configuration object to
+ * tor_run_main().
+ *
+ * At this point, tor_run_main() will block its thread to run a Tor daemon;
+ * when the Tor daemon exits, it will return. See notes on bugs and
+ * limitations below.
+ *
+ * There is no other public C API to Tor: calling any C Tor function not
+ * documented in this file is not guaranteed to be stable.
+ **/
+
+#ifndef TOR_API_H
+#define TOR_API_H
+
+typedef struct tor_main_configuration_t tor_main_configuration_t;
+
+/**
+ * Create and return a new tor_main_configuration().
+ */
+tor_main_configuration_t *tor_main_configuration_new(void);
+
+/**
+ * Set the command-line arguments in <b>cfg</b>.
+ *
+ * The <b>argc</b> and <b>argv</b> values here are as for main(). The
+ * contents of the argv pointer must remain unchanged until tor_run_main() has
+ * finished and you call tor_main_configuration_free().
+ *
+ * Return 0 on success, -1 on failure.
+ */
+int tor_main_configuration_set_command_line(tor_main_configuration_t *cfg,
+ int argc, char *argv[]);
+
+/**
+ * Release all storage held in <b>cfg</b>.
+ *
+ * Once you have passed a tor_main_configuration_t to tor_run_main(), you
+ * must not free it until tor_run_main() has finished.
+ */
+void tor_main_configuration_free(tor_main_configuration_t *cfg);
+
+/**
+ * Run the tor process, as if from the command line.
+ *
+ * The command line arguments from tor_main_configuration_set_command_line()
+ * are taken as if they had been passed to main().
+ *
+ * This function will not return until Tor is done running. It returns zero
+ * on success, and nonzero on failure.
+ *
+ * BUG 23848: In many cases, tor_main will call exit() or abort() instead of
+ * returning. This is not the intended long-term behavior; we are trying to
+ * fix it.
+ *
+ * BUG 23847: You can only call tor_main() once in a single process; if it
+ * returns and you call it again, you may crash. This is not intended
+ * long-term behavior; we are trying to fix it.
+ *
+ * LIMITATION: You cannot run more than one instance of Tor in the same
+ * process at the same time. Concurrent calls will cause undefined behavior.
+ * We do not currently have plans to change this.
+ *
+ * LIMITATION: While we will try to fix any problems found here, you
+ * should be aware that Tor was originally written to run as its own
+ * process, and that the functionality of this file was added later. If
+ * you find any bugs or strange behavior, please report them, and we'll
+ * try to straighten them out.
+ */
+int tor_run_main(const tor_main_configuration_t *);
+
+/**
+ * Run the tor process, as if from the command line.
+ *
+ * @deprecated Using this function from outside Tor is deprecated; you should
+ * use tor_run_main() instead.
+ *
+ * BUGS: This function has all the same bugs as tor_run_main().
+ *
+ * LIMITATIONS: This function has all the limitations of tor_run_main().
+ */
+int tor_main(int argc, char **argv);
+
+#endif /* !defined(TOR_API_H) */
+
diff --git a/src/or/tor_api_internal.h b/src/or/tor_api_internal.h
new file mode 100644
index 0000000000..a69ba76420
--- /dev/null
+++ b/src/or/tor_api_internal.h
@@ -0,0 +1,20 @@
+/* Copyright (c) 2001 Matej Pfajfar.
+ * Copyright (c) 2001-2004, Roger Dingledine.
+ * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
+ * Copyright (c) 2007-2017, The Tor Project, Inc. */
+/* See LICENSE for licensing information */
+
+#ifndef TOR_API_INTERNAL_H
+#define TOR_API_INTERNAL_H
+
+/* The contents of this type are private; don't mess with them from outside
+ * Tor. */
+struct tor_main_configuration_t {
+ /** As in main() */
+ int argc;
+ /** As in main(). This pointer is owned by the caller */
+ char **argv;
+};
+
+#endif
+
diff --git a/src/or/tor_main.c b/src/or/tor_main.c
index a3a8838602..c203d8248f 100644
--- a/src/or/tor_main.c
+++ b/src/or/tor_main.c
@@ -3,18 +3,6 @@
* Copyright (c) 2007-2017, The Tor Project, Inc. */
/* See LICENSE for licensing information */
-extern const char tor_git_revision[];
-
-/** String describing which Tor Git repository version the source was
- * built from. This string is generated by a bit of shell kludging in
- * src/or/include.am, and is usually right.
- */
-const char tor_git_revision[] =
-#ifndef _MSC_VER
-#include "micro-revision.i"
-#endif
- "";
-
/**
* \file tor_main.c
* \brief Stub module containing a main() function.
@@ -26,7 +14,7 @@ const char tor_git_revision[] =
int tor_main(int argc, char *argv[]);
/** We keep main() in a separate file so that our unit tests can use
- * functions from main.c)
+ * functions from main.c.
*/
int
main(int argc, char *argv[])
diff --git a/src/rust/.cargo/config.in b/src/rust/.cargo/config.in
index 414b253a57..301e7fdbe7 100644
--- a/src/rust/.cargo/config.in
+++ b/src/rust/.cargo/config.in
@@ -5,4 +5,4 @@
@RUST_DL@ replace-with = 'vendored-sources'
@RUST_DL@ [source.vendored-sources]
-@RUST_DL@ directory = '@RUST_DEPENDENCIES@'
+@RUST_DL@ directory = '@TOR_RUST_DEPENDENCIES@'
diff --git a/src/rust/Cargo.lock b/src/rust/Cargo.lock
index 4ac9606ce8..224d2135bf 100644
--- a/src/rust/Cargo.lock
+++ b/src/rust/Cargo.lock
@@ -3,6 +3,14 @@ name = "tor_util"
version = "0.0.1"
dependencies = [
"libc 0.2.22 (registry+https://github.com/rust-lang/crates.io-index)",
+ "tor_allocate 0.0.1",
+]
+
+[[package]]
+name = "external"
+version = "0.0.1"
+dependencies = [
+ "libc 0.2.22 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
@@ -10,5 +18,38 @@ name = "libc"
version = "0.2.22"
source = "registry+https://github.com/rust-lang/crates.io-index"
+[[package]]
+name = "protover"
+version = "0.0.1"
+dependencies = [
+ "external 0.0.1",
+ "libc 0.2.22 (registry+https://github.com/rust-lang/crates.io-index)",
+ "smartlist 0.0.1",
+ "tor_allocate 0.0.1",
+ "tor_util 0.0.1",
+]
+
+[[package]]
+name = "smartlist"
+version = "0.0.1"
+dependencies = [
+ "libc 0.2.22 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
+[[package]]
+name = "tor_allocate"
+version = "0.0.1"
+dependencies = [
+ "libc 0.2.22 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
+[[package]]
+name = "tor_rust"
+version = "0.1.0"
+dependencies = [
+ "protover 0.0.1",
+ "tor_util 0.0.1",
+]
+
[metadata]
"checksum libc 0.2.22 (registry+https://github.com/rust-lang/crates.io-index)" = "babb8281da88cba992fa1f4ddec7d63ed96280a1a53ec9b919fd37b53d71e502"
diff --git a/src/rust/Cargo.toml b/src/rust/Cargo.toml
index fc4377e8b4..953c9b96b7 100644
--- a/src/rust/Cargo.toml
+++ b/src/rust/Cargo.toml
@@ -1,5 +1,5 @@
[workspace]
-members = ["tor_util"]
+members = ["tor_util", "protover", "smartlist", "external", "tor_allocate", "tor_rust"]
[profile.release]
debug = true
diff --git a/src/rust/external/Cargo.toml b/src/rust/external/Cargo.toml
new file mode 100644
index 0000000000..bccd7033a7
--- /dev/null
+++ b/src/rust/external/Cargo.toml
@@ -0,0 +1,13 @@
+[package]
+authors = ["The Tor Project"]
+version = "0.0.1"
+name = "external"
+
+[dependencies]
+libc = "0.2.22"
+
+[lib]
+name = "external"
+path = "lib.rs"
+crate_type = ["rlib", "staticlib"]
+
diff --git a/src/rust/external/external.rs b/src/rust/external/external.rs
new file mode 100644
index 0000000000..b9e17f021d
--- /dev/null
+++ b/src/rust/external/external.rs
@@ -0,0 +1,33 @@
+// Copyright (c) 2016-2017, The Tor Project, Inc. */
+// See LICENSE for licensing information */
+
+use libc::{c_char, c_int};
+use std::ffi::CString;
+
+extern "C" {
+ fn tor_version_as_new_as(
+ platform: *const c_char,
+ cutoff: *const c_char,
+ ) -> c_int;
+}
+
+/// Wrap calls to tor_version_as_new_as, defined in src/or/routerparse.c
+pub fn c_tor_version_as_new_as(platform: &str, cutoff: &str) -> bool {
+ // CHK: These functions should log a warning if an error occurs. This
+ // can be added when integration with tor's logger is added to rust
+ let c_platform = match CString::new(platform) {
+ Ok(n) => n,
+ Err(_) => return false,
+ };
+
+ let c_cutoff = match CString::new(cutoff) {
+ Ok(n) => n,
+ Err(_) => return false,
+ };
+
+ let result: c_int = unsafe {
+ tor_version_as_new_as(c_platform.as_ptr(), c_cutoff.as_ptr())
+ };
+
+ result == 1
+}
diff --git a/src/rust/external/lib.rs b/src/rust/external/lib.rs
new file mode 100644
index 0000000000..0af0d6452d
--- /dev/null
+++ b/src/rust/external/lib.rs
@@ -0,0 +1,14 @@
+//! Copyright (c) 2016-2017, The Tor Project, Inc. */
+//! See LICENSE for licensing information */
+
+//! Interface for external calls to tor C ABI
+//!
+//! The purpose of this module is to provide a clean interface for when Rust
+//! modules need to interact with functionality in tor C code rather than each
+//! module implementing this functionality repeatedly.
+
+extern crate libc;
+
+mod external;
+
+pub use external::*;
diff --git a/src/rust/include.am b/src/rust/include.am
index 20afc6c4db..9c4337484a 100644
--- a/src/rust/include.am
+++ b/src/rust/include.am
@@ -1,6 +1,26 @@
-include src/rust/tor_util/include.am
+include src/rust/tor_rust/include.am
EXTRA_DIST +=\
src/rust/Cargo.toml \
src/rust/Cargo.lock \
- src/rust/.cargo/config.in
+ src/rust/.cargo/config.in \
+ src/rust/external/Cargo.toml \
+ src/rust/external/external.rs \
+ src/rust/external/lib.rs \
+ src/rust/protover/Cargo.toml \
+ src/rust/protover/ffi.rs \
+ src/rust/protover/lib.rs \
+ src/rust/protover/protover.rs \
+ src/rust/protover/tests/protover.rs \
+ src/rust/smartlist/Cargo.toml \
+ src/rust/smartlist/lib.rs \
+ src/rust/smartlist/smartlist.rs \
+ src/rust/tor_allocate/Cargo.toml \
+ src/rust/tor_allocate/lib.rs \
+ src/rust/tor_allocate/tor_allocate.rs \
+ src/rust/tor_rust/Cargo.toml \
+ src/rust/tor_rust/include.am \
+ src/rust/tor_rust/lib.rs \
+ src/rust/tor_util/Cargo.toml \
+ src/rust/tor_util/ffi.rs \
+ src/rust/tor_util/lib.rs
diff --git a/src/rust/protover/Cargo.toml b/src/rust/protover/Cargo.toml
new file mode 100644
index 0000000000..04d2f2ed7d
--- /dev/null
+++ b/src/rust/protover/Cargo.toml
@@ -0,0 +1,25 @@
+[package]
+authors = ["The Tor Project"]
+version = "0.0.1"
+name = "protover"
+
+[dependencies]
+libc = "0.2.22"
+
+[dependencies.smartlist]
+path = "../smartlist"
+
+[dependencies.external]
+path = "../external"
+
+[dependencies.tor_util]
+path = "../tor_util"
+
+[dependencies.tor_allocate]
+path = "../tor_allocate"
+
+[lib]
+name = "protover"
+path = "lib.rs"
+crate_type = ["rlib", "staticlib"]
+
diff --git a/src/rust/protover/ffi.rs b/src/rust/protover/ffi.rs
new file mode 100644
index 0000000000..3eb22c933e
--- /dev/null
+++ b/src/rust/protover/ffi.rs
@@ -0,0 +1,219 @@
+// Copyright (c) 2016-2017, The Tor Project, Inc. */
+// See LICENSE for licensing information */
+
+//! FFI functions, only to be called from C.
+//!
+//! Equivalent C versions of this api are in `src/or/protover.c`
+
+use libc::{c_char, c_int, uint32_t};
+use std::ffi::CStr;
+use std::ffi::CString;
+
+use protover::*;
+use smartlist::*;
+use tor_allocate::allocate_and_copy_string;
+
+/// Translate C enums to Rust Proto enums, using the integer value of the C
+/// enum to map to its associated Rust enum
+///
+/// C_RUST_COUPLED: src/or/protover.h `protocol_type_t`
+fn translate_to_rust(c_proto: uint32_t) -> Result<Proto, &'static str> {
+ match c_proto {
+ 0 => Ok(Proto::Link),
+ 1 => Ok(Proto::LinkAuth),
+ 2 => Ok(Proto::Relay),
+ 3 => Ok(Proto::DirCache),
+ 4 => Ok(Proto::HSDir),
+ 5 => Ok(Proto::HSIntro),
+ 6 => Ok(Proto::HSRend),
+ 7 => Ok(Proto::Desc),
+ 8 => Ok(Proto::Microdesc),
+ 9 => Ok(Proto::Cons),
+ _ => Err("Invalid protocol type"),
+ }
+}
+
+/// Provide an interface for C to translate arguments and return types for
+/// protover::all_supported
+#[no_mangle]
+pub extern "C" fn protover_all_supported(
+ c_relay_version: *const c_char,
+ missing_out: *mut *mut c_char,
+) -> c_int {
+
+ if c_relay_version.is_null() {
+ return 1;
+ }
+
+ // Require an unsafe block to read the version from a C string. The pointer
+ // is checked above to ensure it is not null.
+ let c_str: &CStr = unsafe { CStr::from_ptr(c_relay_version) };
+
+ let relay_version = match c_str.to_str() {
+ Ok(n) => n,
+ Err(_) => return 1,
+ };
+
+ let (is_supported, unsupported) = all_supported(relay_version);
+
+ if unsupported.len() > 0 {
+ let c_unsupported = match CString::new(unsupported) {
+ Ok(n) => n,
+ Err(_) => return 1,
+ };
+
+ let ptr = c_unsupported.into_raw();
+ unsafe { *missing_out = ptr };
+ }
+
+ return if is_supported { 1 } else { 0 };
+}
+
+/// Provide an interface for C to translate arguments and return types for
+/// protover::list_supports_protocol
+#[no_mangle]
+pub extern "C" fn protocol_list_supports_protocol(
+ c_protocol_list: *const c_char,
+ c_protocol: uint32_t,
+ version: uint32_t,
+) -> c_int {
+ if c_protocol_list.is_null() {
+ return 1;
+ }
+
+ // Require an unsafe block to read the version from a C string. The pointer
+ // is checked above to ensure it is not null.
+ let c_str: &CStr = unsafe { CStr::from_ptr(c_protocol_list) };
+
+ let protocol_list = match c_str.to_str() {
+ Ok(n) => n,
+ Err(_) => return 1,
+ };
+
+ let protocol = match translate_to_rust(c_protocol) {
+ Ok(n) => n,
+ Err(_) => return 0,
+ };
+
+ let is_supported =
+ protover_string_supports_protocol(protocol_list, protocol, version);
+
+ return if is_supported { 1 } else { 0 };
+}
+
+/// Provide an interface for C to translate arguments and return types for
+/// protover::list_supports_protocol_or_later
+#[no_mangle]
+pub extern "C" fn protocol_list_supports_protocol_or_later(
+ c_protocol_list: *const c_char,
+ c_protocol: uint32_t,
+ version: uint32_t,
+) -> c_int {
+ if c_protocol_list.is_null() {
+ return 1;
+ }
+
+ // Require an unsafe block to read the version from a C string. The pointer
+ // is checked above to ensure it is not null.
+ let c_str: &CStr = unsafe { CStr::from_ptr(c_protocol_list) };
+
+ let protocol_list = match c_str.to_str() {
+ Ok(n) => n,
+ Err(_) => return 1,
+ };
+
+ let protocol = match translate_to_rust(c_protocol) {
+ Ok(n) => n,
+ Err(_) => return 0,
+ };
+
+ let is_supported =
+ protover_string_supports_protocol_or_later(
+ protocol_list, protocol, version);
+
+ return if is_supported { 1 } else { 0 };
+}
+
+/// Provide an interface for C to translate arguments and return types for
+/// protover::get_supported_protocols
+#[no_mangle]
+pub extern "C" fn protover_get_supported_protocols() -> *mut c_char {
+ // Not handling errors when unwrapping as the content is controlled
+ // and is an empty string
+ let empty = CString::new("").unwrap();
+
+ let supported = get_supported_protocols();
+ let c_supported = match CString::new(supported) {
+ Ok(n) => n,
+ Err(_) => return empty.into_raw(),
+ };
+
+ c_supported.into_raw()
+}
+
+/// Provide an interface for C to translate arguments and return types for
+/// protover::compute_vote
+#[no_mangle]
+pub extern "C" fn protover_compute_vote(
+ list: *const Stringlist,
+ threshold: c_int,
+) -> *mut c_char {
+
+ if list.is_null() {
+ let empty = String::new();
+ return allocate_and_copy_string(&empty);
+ }
+
+ // Dereference of raw pointer requires an unsafe block. The pointer is
+ // checked above to ensure it is not null.
+ let data: Vec<String> = unsafe { (*list).get_list() };
+
+ let vote = compute_vote(data, threshold);
+
+ allocate_and_copy_string(&vote)
+}
+
+/// Provide an interface for C to translate arguments and return types for
+/// protover::is_supported_here
+#[no_mangle]
+pub extern "C" fn protover_is_supported_here(
+ c_protocol: uint32_t,
+ version: uint32_t,
+) -> c_int {
+ let protocol = match translate_to_rust(c_protocol) {
+ Ok(n) => n,
+ Err(_) => return 0,
+ };
+
+ let is_supported = is_supported_here(protocol, version);
+
+ return if is_supported { 1 } else { 0 };
+}
+
+/// Provide an interface for C to translate arguments and return types for
+/// protover::compute_for_old_tor
+#[no_mangle]
+pub extern "C" fn protover_compute_for_old_tor(
+ version: *const c_char,
+) -> *mut c_char {
+ // Not handling errors when unwrapping as the content is controlled
+ // and is an empty string
+ let empty = String::new();
+
+ if version.is_null() {
+ return allocate_and_copy_string(&empty);
+ }
+
+ // Require an unsafe block to read the version from a C string. The pointer
+ // is checked above to ensure it is not null.
+ let c_str: &CStr = unsafe { CStr::from_ptr(version) };
+
+ let version = match c_str.to_str() {
+ Ok(n) => n,
+ Err(_) => return allocate_and_copy_string(&empty),
+ };
+
+ let supported = compute_for_old_tor(&version);
+
+ allocate_and_copy_string(&supported)
+}
diff --git a/src/rust/protover/lib.rs b/src/rust/protover/lib.rs
new file mode 100644
index 0000000000..5a5dea4408
--- /dev/null
+++ b/src/rust/protover/lib.rs
@@ -0,0 +1,33 @@
+//! Copyright (c) 2016-2017, The Tor Project, Inc. */
+//! See LICENSE for licensing information */
+
+//! Versioning information for different pieces of the Tor protocol.
+//!
+//! The below description is taken from src/rust/protover.c, which is currently
+//! enabled by default. We are in the process of experimenting with Rust in
+//! tor, and this protover module is implemented to help achieve this goal.
+//!
+//! Starting in version 0.2.9.3-alpha, Tor places separate version numbers on
+//! each of the different components of its protocol. Relays use these numbers
+//! to advertise what versions of the protocols they can support, and clients
+//! use them to find what they can ask a given relay to do. Authorities vote
+//! on the supported protocol versions for each relay, and also vote on the
+//! which protocols you should have to support in order to be on the Tor
+//! network. All Tor instances use these required/recommended protocol versions
+//! to tell what level of support for recent protocols each relay has, and
+//! to decide whether they should be running given their current protocols.
+//!
+//! The main advantage of these protocol versions numbers over using Tor
+//! version numbers is that they allow different implementations of the Tor
+//! protocols to develop independently, without having to claim compatibility
+//! with specific versions of Tor.
+
+extern crate libc;
+extern crate smartlist;
+extern crate external;
+extern crate tor_allocate;
+
+mod protover;
+pub mod ffi;
+
+pub use protover::*;
diff --git a/src/rust/protover/protover.rs b/src/rust/protover/protover.rs
new file mode 100644
index 0000000000..7d5947ca2f
--- /dev/null
+++ b/src/rust/protover/protover.rs
@@ -0,0 +1,906 @@
+// Copyright (c) 2016-2017, The Tor Project, Inc. */
+// See LICENSE for licensing information */
+
+use external::c_tor_version_as_new_as;
+
+use std::str::FromStr;
+use std::fmt;
+use std::collections::{HashMap, HashSet};
+use std::string::String;
+
+/// The first version of Tor that included "proto" entries in its descriptors.
+/// Authorities should use this to decide whether to guess proto lines.
+///
+/// C_RUST_COUPLED:
+/// src/or/protover.h `FIRST_TOR_VERSION_TO_ADVERTISE_PROTOCOLS`
+const FIRST_TOR_VERSION_TO_ADVERTISE_PROTOCOLS: &'static str = "0.2.9.3-alpha";
+
+/// The maximum number of subprotocol version numbers we will attempt to expand
+/// before concluding that someone is trying to DoS us
+///
+/// C_RUST_COUPLED: src/or/protover.c `MAX_PROTOCOLS_TO_EXPAND`
+const MAX_PROTOCOLS_TO_EXPAND: u32 = 500;
+
+/// Currently supported protocols and their versions
+///
+/// C_RUST_COUPLED: src/or/protover.c `protover_get_supported_protocols`
+const SUPPORTED_PROTOCOLS: &'static [&'static str] = &[
+ "Cons=1-2",
+ "Desc=1-2",
+ "DirCache=1-2",
+ "HSDir=1-2",
+ "HSIntro=3-4",
+ "HSRend=1-2",
+ "Link=1-4",
+ "LinkAuth=1,3",
+ "Microdesc=1-2",
+ "Relay=1-2",
+];
+
+/// Known subprotocols in Tor. Indicates which subprotocol a relay supports.
+///
+/// C_RUST_COUPLED: src/or/protover.h `protocol_type_t`
+#[derive(Hash, Eq, PartialEq, Debug)]
+pub enum Proto {
+ Cons,
+ Desc,
+ DirCache,
+ HSDir,
+ HSIntro,
+ HSRend,
+ Link,
+ LinkAuth,
+ Microdesc,
+ Relay,
+}
+
+impl fmt::Display for Proto {
+ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+ write!(f, "{:?}", self)
+ }
+}
+
+/// Translates a string representation of a protocol into a Proto type.
+/// Error if the string is an unrecognized protocol name.
+///
+/// C_RUST_COUPLED: src/or/protover.c `PROTOCOL_NAMES`
+impl FromStr for Proto {
+ type Err = &'static str;
+
+ fn from_str(s: &str) -> Result<Self, Self::Err> {
+ match s {
+ "Cons" => Ok(Proto::Cons),
+ "Desc" => Ok(Proto::Desc),
+ "DirCache" => Ok(Proto::DirCache),
+ "HSDir" => Ok(Proto::HSDir),
+ "HSIntro" => Ok(Proto::HSIntro),
+ "HSRend" => Ok(Proto::HSRend),
+ "Link" => Ok(Proto::Link),
+ "LinkAuth" => Ok(Proto::LinkAuth),
+ "Microdesc" => Ok(Proto::Microdesc),
+ "Relay" => Ok(Proto::Relay),
+ _ => Err("Not a valid protocol type"),
+ }
+ }
+}
+
+/// Get the string representation of current supported protocols
+///
+/// # Returns
+///
+/// A `String` whose value is the existing protocols supported by tor.
+/// Returned data is in the format as follows:
+///
+/// "HSDir=1-1 LinkAuth=1"
+///
+pub fn get_supported_protocols() -> String {
+ SUPPORTED_PROTOCOLS.join(" ")
+}
+
+/// Translates a vector representation of a protocol list into a HashMap
+fn parse_protocols(
+ protocols: &[&str],
+) -> Result<HashMap<Proto, HashSet<u32>>, &'static str> {
+ let mut parsed = HashMap::new();
+
+ for subproto in protocols {
+ let (name, version) = get_proto_and_vers(subproto)?;
+ parsed.insert(name, version);
+ }
+ Ok(parsed)
+}
+
+/// Translates a string representation of a protocol list to a HashMap
+fn parse_protocols_from_string<'a>(
+ protocol_string: &'a str,
+) -> Result<HashMap<Proto, HashSet<u32>>, &'static str> {
+ let protocols: &[&'a str] =
+ &protocol_string.split(" ").collect::<Vec<&'a str>>()[..];
+
+ parse_protocols(protocols)
+}
+
+/// Translates supported tor versions from a string into a HashMap, which is
+/// useful when looking up a specific subprotocol.
+///
+/// # Returns
+///
+/// A `Result` whose `Ok` value is a `HashMap<Proto, <u32>>` holding all
+/// subprotocols and versions currently supported by tor.
+///
+/// The returned `Result`'s `Err` value is an `&'static str` with a description
+/// of the error.
+///
+fn tor_supported() -> Result<HashMap<Proto, HashSet<u32>>, &'static str> {
+ parse_protocols(&SUPPORTED_PROTOCOLS)
+}
+
+/// Get the unique version numbers supported by a subprotocol.
+///
+/// # Inputs
+///
+/// * `version_string`, a string comprised of "[0-9,-]"
+///
+/// # Returns
+///
+/// A `Result` whose `Ok` value is a `HashSet<u32>` holding all of the unique
+/// version numbers. If there were ranges in the `version_string`, then these
+/// are expanded, i.e. `"1-3"` would expand to `HashSet<u32>::new([1, 2, 3])`.
+/// The returned HashSet is *unordered*.
+///
+/// The returned `Result`'s `Err` value is an `&'static str` with a description
+/// of the error.
+///
+/// # Errors
+///
+/// This function will error if:
+///
+/// * the `version_string` is empty or contains an equals (`"="`) sign,
+/// * the expansion of a version range produces an error (see
+/// `expand_version_range`),
+/// * any single version number is not parseable as an `u32` in radix 10, or
+/// * there are greater than 2^16 version numbers to expand.
+///
+fn get_versions(version_string: &str) -> Result<HashSet<u32>, &'static str> {
+ if version_string.is_empty() {
+ return Err("version string is empty");
+ }
+
+ let mut versions = HashSet::<u32>::new();
+
+ for piece in version_string.split(",") {
+ if piece.contains("-") {
+ for p in expand_version_range(piece)? {
+ versions.insert(p);
+ }
+ } else {
+ versions.insert(u32::from_str(piece).or(
+ Err("invalid protocol entry"),
+ )?);
+ }
+
+ if versions.len() > MAX_PROTOCOLS_TO_EXPAND as usize {
+ return Err("Too many versions to expand");
+ }
+ }
+ Ok(versions)
+}
+
+
+/// Parse the subprotocol type and its version numbers.
+///
+/// # Inputs
+///
+/// * A `protocol_entry` string, comprised of a keyword, an "=" sign, and one
+/// or more version numbers.
+///
+/// # Returns
+///
+/// A `Result` whose `Ok` value is a tuple of `(Proto, HashSet<u32>)`, where the
+/// first element is the subprotocol type (see `protover::Proto`) and the last
+/// element is a(n unordered) set of unique version numbers which are supported.
+/// Otherwise, the `Err` value of this `Result` is a description of the error
+///
+fn get_proto_and_vers<'a>(
+ protocol_entry: &'a str,
+) -> Result<(Proto, HashSet<u32>), &'static str> {
+ let mut parts = protocol_entry.splitn(2, "=");
+
+ let proto = match parts.next() {
+ Some(n) => n,
+ None => return Err("invalid protover entry"),
+ };
+
+ let vers = match parts.next() {
+ Some(n) => n,
+ None => return Err("invalid protover entry"),
+ };
+
+ let versions = get_versions(vers)?;
+ let proto_name = proto.parse()?;
+
+ Ok((proto_name, versions))
+}
+
+/// Parses a single subprotocol entry string into subprotocol and version
+/// parts, and then checks whether any of those versions are unsupported.
+/// Helper for protover::all_supported
+///
+/// # Inputs
+///
+/// Accepted data is in the string format as follows:
+///
+/// "HSDir=1-1"
+///
+/// # Returns
+///
+/// Returns `true` if the protocol entry is well-formatted and only contains
+/// versions that are also supported in tor. Otherwise, returns false
+///
+fn contains_only_supported_protocols(proto_entry: &str) -> bool {
+ let (name, mut vers) = match get_proto_and_vers(proto_entry) {
+ Ok(n) => n,
+ Err(_) => return false,
+ };
+
+ let currently_supported: HashMap<Proto, HashSet<u32>> =
+ match tor_supported() {
+ Ok(n) => n,
+ Err(_) => return false,
+ };
+
+ let supported_versions = match currently_supported.get(&name) {
+ Some(n) => n,
+ None => return false,
+ };
+
+ vers.retain(|x| !supported_versions.contains(x));
+ vers.is_empty()
+}
+
+/// Determine if we support every protocol a client supports, and if not,
+/// determine which protocols we do not have support for.
+///
+/// # Inputs
+///
+/// Accepted data is in the string format as follows:
+///
+/// "HSDir=1-1 LinkAuth=1-2"
+///
+/// # Returns
+///
+/// Return `true` if every protocol version is one that we support.
+/// Otherwise, return `false`.
+/// Optionally, return parameters which the client supports but which we do not
+///
+/// # Examples
+/// ```
+/// use protover::all_supported;
+///
+/// let (is_supported, unsupported) = all_supported("Link=1");
+/// assert_eq!(true, is_supported);
+///
+/// let (is_supported, unsupported) = all_supported("Link=5-6");
+/// assert_eq!(false, is_supported);
+/// assert_eq!("Link=5-6", unsupported);
+///
+pub fn all_supported(protocols: &str) -> (bool, String) {
+ let unsupported = protocols
+ .split_whitespace()
+ .filter(|v| !contains_only_supported_protocols(v))
+ .collect::<Vec<&str>>();
+
+ (unsupported.is_empty(), unsupported.join(" "))
+}
+
+/// Return true iff the provided protocol list includes support for the
+/// indicated protocol and version.
+/// Otherwise, return false
+///
+/// # Inputs
+///
+/// * `list`, a string representation of a list of protocol entries.
+/// * `proto`, a `Proto` to test support for
+/// * `vers`, a `u32` version which we will go on to determine whether the
+/// specified protocol supports.
+///
+/// # Examples
+/// ```
+/// use protover::*;
+///
+/// let is_supported = protover_string_supports_protocol("Link=3-4 Cons=1",
+/// Proto::Cons,1);
+/// assert_eq!(true, is_supported);
+///
+/// let is_not_supported = protover_string_supports_protocol("Link=3-4 Cons=1",
+/// Proto::Cons,5);
+/// assert_eq!(false, is_not_supported)
+/// ```
+pub fn protover_string_supports_protocol(
+ list: &str,
+ proto: Proto,
+ vers: u32,
+) -> bool {
+ let supported: HashMap<Proto, HashSet<u32>>;
+
+ match parse_protocols_from_string(list) {
+ Ok(result) => supported = result,
+ Err(_) => return false,
+ }
+
+ let supported_versions = match supported.get(&proto) {
+ Some(n) => n,
+ None => return false,
+ };
+
+ supported_versions.contains(&vers)
+}
+
+/// As protover_string_supports_protocol(), but also returns True if
+/// any later version of the protocol is supported.
+///
+/// # Examples
+/// ```
+/// use protover::*;
+///
+/// let is_supported = protover_string_supports_protocol_or_later(
+/// "Link=3-4 Cons=5", Proto::Cons, 5);
+///
+/// assert_eq!(true, is_supported);
+///
+/// let is_supported = protover_string_supports_protocol_or_later(
+/// "Link=3-4 Cons=5", Proto::Cons, 4);
+///
+/// assert_eq!(true, is_supported);
+///
+/// let is_supported = protover_string_supports_protocol_or_later(
+/// "Link=3-4 Cons=5", Proto::Cons, 6);
+///
+/// assert_eq!(false, is_supported);
+/// ```
+pub fn protover_string_supports_protocol_or_later(
+ list: &str,
+ proto: Proto,
+ vers: u32,
+) -> bool {
+ let supported: HashMap<Proto, HashSet<u32>>;
+
+ match parse_protocols_from_string(list) {
+ Ok(result) => supported = result,
+ Err(_) => return false,
+ }
+
+ let supported_versions = match supported.get(&proto) {
+ Some(n) => n,
+ None => return false,
+ };
+
+ supported_versions.iter().any(|v| v >= &vers)
+}
+
+/// Fully expand a version range. For example, 1-3 expands to 1,2,3
+/// Helper for get_versions
+///
+/// # Inputs
+///
+/// `range`, a string comprised of "[0-9,-]"
+///
+/// # Returns
+///
+/// A `Result` whose `Ok` value a vector of unsigned integers representing the
+/// expanded range of supported versions by a single protocol.
+/// Otherwise, the `Err` value of this `Result` is a description of the error
+///
+/// # Errors
+///
+/// This function will error if:
+///
+/// * the specified range is empty
+/// * the version range does not contain both a valid lower and upper bound.
+///
+fn expand_version_range(range: &str) -> Result<Vec<u32>, &'static str> {
+ if range.is_empty() {
+ return Err("version string empty");
+ }
+
+ let mut parts = range.split("-");
+
+ let lower_string = parts.next().ok_or(
+ "cannot parse protocol range lower bound",
+ )?;
+
+ let lower = u32::from_str_radix(lower_string, 10).or(Err(
+ "cannot parse protocol range lower bound",
+ ))?;
+
+ let higher_string = parts.next().ok_or(
+ "cannot parse protocol range upper bound",
+ )?;
+
+ let higher = u32::from_str_radix(higher_string, 10).or(Err(
+ "cannot parse protocol range upper bound",
+ ))?;
+
+ // We can use inclusive range syntax when it becomes stable.
+ Ok((lower..higher + 1).collect())
+}
+
+/// Checks to see if there is a continuous range of integers, starting at the
+/// first in the list. Returns the last integer in the range if a range exists.
+/// Helper for compute_vote
+///
+/// # Inputs
+///
+/// `list`, an ordered vector of `u32` integers of "[0-9,-]" representing the
+/// supported versions for a single protocol.
+///
+/// # Returns
+///
+/// A `bool` indicating whether the list contains a range, starting at the
+/// first in the list, and an `u32` of the last integer in the range.
+///
+/// For example, if given vec![1, 2, 3, 5], find_range will return true,
+/// as there is a continuous range, and 3, which is the last number in the
+/// continuous range.
+///
+fn find_range(list: &Vec<u32>) -> (bool, u32) {
+ if list.len() == 0 {
+ return (false, 0);
+ }
+
+ let mut iterable = list.iter().peekable();
+ let mut range_end = match iterable.next() {
+ Some(n) => *n,
+ None => return (false, 0),
+ };
+
+ let mut has_range = false;
+
+ while iterable.peek().is_some() {
+ let n = *iterable.next().unwrap();
+ if n != range_end + 1 {
+ break;
+ }
+
+ has_range = true;
+ range_end = n;
+ }
+
+ (has_range, range_end)
+}
+
+/// Contracts a HashSet representation of supported versions into a string.
+/// Helper for compute_vote
+///
+/// # Inputs
+///
+/// `supported_set`, a set of integers of "[0-9,-]" representing the
+/// supported versions for a single protocol.
+///
+/// # Returns
+///
+/// A `String` representation of this set in ascending order.
+///
+fn contract_protocol_list<'a>(supported_set: &'a HashSet<u32>) -> String {
+ let mut supported: Vec<u32> = supported_set.iter()
+ .map(|x| *x)
+ .collect();
+ supported.sort();
+
+ let mut final_output: Vec<String> = Vec::new();
+
+ while supported.len() != 0 {
+ let (has_range, end) = find_range(&supported);
+ let current = supported.remove(0);
+
+ if has_range {
+ final_output.push(format!(
+ "{}-{}",
+ current.to_string(),
+ &end.to_string(),
+ ));
+ supported.retain(|&x| x > end);
+ } else {
+ final_output.push(current.to_string());
+ }
+ }
+
+ final_output.join(",")
+}
+
+/// Parses a protocol list without validating the protocol names
+///
+/// # Inputs
+///
+/// * `protocol_string`, a string comprised of keys and values, both which are
+/// strings. The keys are the protocol names while values are a string
+/// representation of the supported versions.
+///
+/// The input is _not_ expected to be a subset of the Proto types
+///
+/// # Returns
+///
+/// A `Result` whose `Ok` value is a `HashSet<u32>` holding all of the unique
+/// version numbers.
+///
+/// The returned `Result`'s `Err` value is an `&'static str` with a description
+/// of the error.
+///
+/// # Errors
+///
+/// This function will error if:
+///
+/// * The protocol string does not follow the "protocol_name=version_list"
+/// expected format
+/// * If the version string is malformed. See `get_versions`.
+///
+fn parse_protocols_from_string_with_no_validation<'a>(
+ protocol_string: &'a str,
+) -> Result<HashMap<String, HashSet<u32>>, &'static str> {
+ let protocols = &protocol_string.split(" ").collect::<Vec<&'a str>>()[..];
+
+ let mut parsed: HashMap<String, HashSet<u32>> = HashMap::new();
+
+ for subproto in protocols {
+ let mut parts = subproto.splitn(2, "=");
+
+ let name = match parts.next() {
+ Some(n) => n,
+ None => return Err("invalid protover entry"),
+ };
+
+ let vers = match parts.next() {
+ Some(n) => n,
+ None => return Err("invalid protover entry"),
+ };
+
+ let versions = get_versions(vers)?;
+
+ parsed.insert(String::from(name), versions);
+ }
+ Ok(parsed)
+}
+
+/// Protocol voting implementation.
+///
+/// Given a list of strings describing protocol versions, return a new
+/// string encoding all of the protocols that are listed by at
+/// least threshold of the inputs.
+///
+/// The string is sorted according to the following conventions:
+/// - Protocols names are alphabetized
+/// - Protocols are in order low to high
+/// - Individual and ranges are listed together. For example,
+/// "3, 5-10,13"
+/// - All entries are unique
+///
+/// # Examples
+/// ```
+/// use protover::compute_vote;
+///
+/// let protos = vec![String::from("Link=3-4"), String::from("Link=3")];
+/// let vote = compute_vote(protos, 2);
+/// assert_eq!("Link=3", vote)
+/// ```
+pub fn compute_vote(
+ list_of_proto_strings: Vec<String>,
+ threshold: i32,
+) -> String {
+ let empty = String::from("");
+
+ if list_of_proto_strings.is_empty() {
+ return empty;
+ }
+
+ // all_count is a structure to represent the count of the number of
+ // supported versions for a specific protocol. For example, in JSON format:
+ // {
+ // "FirstSupportedProtocol": {
+ // "1": "3",
+ // "2": "1"
+ // }
+ // }
+ // means that FirstSupportedProtocol has three votes which support version
+ // 1, and one vote that supports version 2
+ let mut all_count: HashMap<String, HashMap<u32, usize>> = HashMap::new();
+
+ // parse and collect all of the protos and their versions and collect them
+ for vote in list_of_proto_strings {
+ let this_vote: HashMap<String, HashSet<u32>> =
+ match parse_protocols_from_string_with_no_validation(&vote) {
+ Ok(result) => result,
+ Err(_) => continue,
+ };
+
+ for (protocol, versions) in this_vote {
+ let supported_vers: &mut HashMap<u32, usize> =
+ all_count.entry(protocol).or_insert(HashMap::new());
+
+ for version in versions {
+ let counter: &mut usize =
+ supported_vers.entry(version).or_insert(0);
+ *counter += 1;
+ }
+ }
+ }
+
+ let mut final_output: HashMap<String, String> =
+ HashMap::with_capacity(SUPPORTED_PROTOCOLS.len());
+
+ // Go through and remove verstions that are less than the threshold
+ for (protocol, versions) in all_count {
+ let mut meets_threshold = HashSet::new();
+ for (version, count) in versions {
+ if count >= threshold as usize {
+ meets_threshold.insert(version);
+ }
+ }
+
+ // For each protocol, compress its version list into the expected
+ // protocol version string format
+ let contracted = contract_protocol_list(&meets_threshold);
+ if !contracted.is_empty() {
+ final_output.insert(protocol, contracted);
+ }
+ }
+
+ write_vote_to_string(&final_output)
+}
+
+/// Return a String comprised of protocol entries in alphabetical order
+///
+/// # Inputs
+///
+/// * `vote`, a `HashMap` comprised of keys and values, both which are strings.
+/// The keys are the protocol names while values are a string representation of
+/// the supported versions.
+///
+/// # Returns
+///
+/// A `String` whose value is series of pairs, comprising of the protocol name
+/// and versions that it supports. The string takes the following format:
+///
+/// "first_protocol_name=1,2-5, second_protocol_name=4,5"
+///
+/// Sorts the keys in alphabetical order and creates the expected subprotocol
+/// entry format.
+///
+fn write_vote_to_string(vote: &HashMap<String, String>) -> String {
+ let mut keys: Vec<&String> = vote.keys().collect();
+ keys.sort();
+
+ let mut output = Vec::new();
+ for key in keys {
+ // TODO error in indexing here?
+ output.push(format!("{}={}", key, vote[key]));
+ }
+ output.join(" ")
+}
+
+/// Returns a boolean indicating whether the given protocol and version is
+/// supported in any of the existing Tor protocols
+///
+/// # Examples
+/// ```
+/// use protover::*;
+///
+/// let is_supported = is_supported_here(Proto::Link, 5);
+/// assert_eq!(false, is_supported);
+///
+/// let is_supported = is_supported_here(Proto::Link, 1);
+/// assert_eq!(true, is_supported);
+/// ```
+pub fn is_supported_here(proto: Proto, vers: u32) -> bool {
+ let currently_supported: HashMap<Proto, HashSet<u32>>;
+
+ match tor_supported() {
+ Ok(result) => currently_supported = result,
+ Err(_) => return false,
+ }
+
+ let supported_versions = match currently_supported.get(&proto) {
+ Some(n) => n,
+ None => return false,
+ };
+
+ supported_versions.contains(&vers)
+}
+
+/// Older versions of Tor cannot infer their own subprotocols
+/// Used to determine which subprotocols are supported by older Tor versions.
+///
+/// # Inputs
+///
+/// * `version`, a string comprised of "[0-9,-]"
+///
+/// # Returns
+///
+/// A `String` whose value is series of pairs, comprising of the protocol name
+/// and versions that it supports. The string takes the following format:
+///
+/// "HSDir=1-1 LinkAuth=1"
+///
+/// This function returns the protocols that are supported by the version input,
+/// only for tor versions older than FIRST_TOR_VERSION_TO_ADVERTISE_PROTOCOLS.
+///
+/// C_RUST_COUPLED: src/rust/protover.c `compute_for_old_tor`
+pub fn compute_for_old_tor(version: &str) -> String {
+ if c_tor_version_as_new_as(
+ version,
+ FIRST_TOR_VERSION_TO_ADVERTISE_PROTOCOLS,
+ )
+ {
+ return String::new();
+ }
+
+ if c_tor_version_as_new_as(version, "0.2.9.1-alpha") {
+ let ret = "Cons=1-2 Desc=1-2 DirCache=1 HSDir=1 HSIntro=3 HSRend=1-2 \
+ Link=1-4 LinkAuth=1 Microdesc=1-2 Relay=1-2";
+ return String::from(ret);
+ }
+
+ if c_tor_version_as_new_as(version, "0.2.7.5") {
+ let ret = "Cons=1-2 Desc=1-2 DirCache=1 HSDir=1 HSIntro=3 HSRend=1 \
+ Link=1-4 LinkAuth=1 Microdesc=1-2 Relay=1-2";
+ return String::from(ret);
+ }
+
+ if c_tor_version_as_new_as(version, "0.2.4.19") {
+ let ret = "Cons=1 Desc=1 DirCache=1 HSDir=1 HSIntro=3 HSRend=1 \
+ Link=1-4 LinkAuth=1 Microdesc=1 Relay=1-2";
+ return String::from(ret);
+ }
+ String::new()
+}
+
+#[cfg(test)]
+mod test {
+ #[test]
+ fn test_get_versions() {
+ use std::collections::HashSet;
+
+ use super::get_versions;
+
+ assert_eq!(Err("version string is empty"), get_versions(""));
+ assert_eq!(Err("invalid protocol entry"), get_versions("a,b"));
+ assert_eq!(Err("invalid protocol entry"), get_versions("1,!"));
+
+ {
+ let mut versions: HashSet<u32> = HashSet::new();
+ versions.insert(1);
+ assert_eq!(Ok(versions), get_versions("1"));
+ }
+ {
+ let mut versions: HashSet<u32> = HashSet::new();
+ versions.insert(1);
+ versions.insert(2);
+ assert_eq!(Ok(versions), get_versions("1,2"));
+ }
+ {
+ let mut versions: HashSet<u32> = HashSet::new();
+ versions.insert(1);
+ versions.insert(2);
+ versions.insert(3);
+ assert_eq!(Ok(versions), get_versions("1-3"));
+ }
+ {
+ let mut versions: HashSet<u32> = HashSet::new();
+ versions.insert(1);
+ versions.insert(2);
+ versions.insert(5);
+ assert_eq!(Ok(versions), get_versions("1-2,5"));
+ }
+ {
+ let mut versions: HashSet<u32> = HashSet::new();
+ versions.insert(1);
+ versions.insert(3);
+ versions.insert(4);
+ versions.insert(5);
+ assert_eq!(Ok(versions), get_versions("1,3-5"));
+ }
+ }
+
+ #[test]
+ fn test_contains_only_supported_protocols() {
+ use super::contains_only_supported_protocols;
+
+ assert_eq!(false, contains_only_supported_protocols(""));
+ assert_eq!(false, contains_only_supported_protocols("Cons="));
+ assert_eq!(true, contains_only_supported_protocols("Cons=1"));
+ assert_eq!(false, contains_only_supported_protocols("Cons=0"));
+ assert_eq!(false, contains_only_supported_protocols("Cons=0-1"));
+ assert_eq!(false, contains_only_supported_protocols("Cons=5"));
+ assert_eq!(false, contains_only_supported_protocols("Cons=1-5"));
+ assert_eq!(false, contains_only_supported_protocols("Cons=1,5"));
+ assert_eq!(false, contains_only_supported_protocols("Cons=5,6"));
+ assert_eq!(false, contains_only_supported_protocols("Cons=1,5,6"));
+ assert_eq!(true, contains_only_supported_protocols("Cons=1,2"));
+ assert_eq!(true, contains_only_supported_protocols("Cons=1-2"));
+ }
+
+ #[test]
+ fn test_find_range() {
+ use super::find_range;
+
+ assert_eq!((false, 0), find_range(&vec![]));
+ assert_eq!((false, 1), find_range(&vec![1]));
+ assert_eq!((true, 2), find_range(&vec![1, 2]));
+ assert_eq!((true, 3), find_range(&vec![1, 2, 3]));
+ assert_eq!((true, 3), find_range(&vec![1, 2, 3, 5]));
+ }
+
+ #[test]
+ fn test_expand_version_range() {
+ use super::expand_version_range;
+
+ assert_eq!(Err("version string empty"), expand_version_range(""));
+ assert_eq!(Ok(vec![1, 2]), expand_version_range("1-2"));
+ assert_eq!(Ok(vec![1, 2, 3, 4]), expand_version_range("1-4"));
+ assert_eq!(
+ Err("cannot parse protocol range lower bound"),
+ expand_version_range("a")
+ );
+ assert_eq!(
+ Err("cannot parse protocol range upper bound"),
+ expand_version_range("1-a")
+ );
+ }
+
+ #[test]
+ fn test_contract_protocol_list() {
+ use std::collections::HashSet;
+ use super::contract_protocol_list;
+
+ {
+ let mut versions = HashSet::<u32>::new();
+ assert_eq!(String::from(""), contract_protocol_list(&versions));
+
+ versions.insert(1);
+ assert_eq!(String::from("1"), contract_protocol_list(&versions));
+
+ versions.insert(2);
+ assert_eq!(String::from("1-2"), contract_protocol_list(&versions));
+ }
+
+ {
+ let mut versions = HashSet::<u32>::new();
+ versions.insert(1);
+ versions.insert(3);
+ assert_eq!(String::from("1,3"), contract_protocol_list(&versions));
+ }
+
+ {
+ let mut versions = HashSet::<u32>::new();
+ versions.insert(1);
+ versions.insert(2);
+ versions.insert(3);
+ versions.insert(4);
+ assert_eq!(String::from("1-4"), contract_protocol_list(&versions));
+ }
+
+ {
+ let mut versions = HashSet::<u32>::new();
+ versions.insert(1);
+ versions.insert(3);
+ versions.insert(5);
+ versions.insert(6);
+ versions.insert(7);
+ assert_eq!(
+ String::from("1,3,5-7"),
+ contract_protocol_list(&versions)
+ );
+ }
+
+ {
+ let mut versions = HashSet::<u32>::new();
+ versions.insert(1);
+ versions.insert(2);
+ versions.insert(3);
+ versions.insert(500);
+ assert_eq!(
+ String::from("1-3,500"),
+ contract_protocol_list(&versions)
+ );
+ }
+ }
+}
diff --git a/src/rust/protover/tests/protover.rs b/src/rust/protover/tests/protover.rs
new file mode 100644
index 0000000000..f4e394b3e2
--- /dev/null
+++ b/src/rust/protover/tests/protover.rs
@@ -0,0 +1,291 @@
+// Copyright (c) 2016-2017, The Tor Project, Inc. */
+// See LICENSE for licensing information */
+
+extern crate protover;
+
+#[test]
+fn parse_protocol_list_with_single_proto_and_single_version() {
+ let protocol = "Cons=1";
+ let (is_supported, unsupported) = protover::all_supported(protocol);
+ assert_eq!(true, is_supported);
+ assert_eq!("", &unsupported);
+}
+
+#[test]
+fn parse_protocol_list_with_single_protocol_and_multiple_versions() {
+ let protocol = "Cons=1-2";
+ let (is_supported, unsupported) = protover::all_supported(protocol);
+ assert_eq!(true, is_supported);
+ assert_eq!("", &unsupported);
+}
+
+#[test]
+fn parse_protocol_list_with_different_single_protocol_and_single_version() {
+ let protocol = "HSDir=1";
+ let (is_supported, unsupported) = protover::all_supported(protocol);
+ assert_eq!(true, is_supported);
+ assert_eq!("", &unsupported);
+}
+
+#[test]
+fn parse_protocol_list_with_single_protocol_and_supported_version() {
+ let protocol = "Desc=2";
+ let (is_supported, unsupported) = protover::all_supported(protocol);
+ assert_eq!(true, is_supported);
+ assert_eq!("", &unsupported);
+}
+
+#[test]
+fn parse_protocol_list_with_two_protocols_and_single_version() {
+ let protocols = "Cons=1 HSDir=1";
+ let (is_supported, unsupported) = protover::all_supported(protocols);
+ assert_eq!(true, is_supported);
+ assert_eq!("", &unsupported);
+}
+
+
+#[test]
+fn parse_protocol_list_with_single_protocol_and_two_nonsequential_versions() {
+ let protocol = "Desc=1,2";
+ let (is_supported, unsupported) = protover::all_supported(protocol);
+ assert_eq!(true, is_supported);
+ assert_eq!("", &unsupported);
+}
+
+
+#[test]
+fn parse_protocol_list_with_single_protocol_and_two_sequential_versions() {
+ let protocol = "Desc=1-2";
+ let (is_supported, unsupported) = protover::all_supported(protocol);
+ assert_eq!(true, is_supported);
+ assert_eq!("", &unsupported);
+}
+
+#[test]
+fn parse_protocol_list_with_single_protocol_and_protocol_range_returns_set() {
+ let protocol = "Link=1-4";
+ let (is_supported, unsupported) = protover::all_supported(protocol);
+ assert_eq!(true, is_supported);
+ assert_eq!("", &unsupported);
+}
+
+#[test]
+fn parse_protocol_list_with_single_protocol_and_protocol_set() {
+ let protocols = "Link=3-4 Desc=2";
+ let (is_supported, unsupported) = protover::all_supported(protocols);
+ assert_eq!(true, is_supported);
+ assert_eq!("", &unsupported);
+}
+
+#[test]
+fn protover_all_supported_with_two_values() {
+ let protocols = "Microdesc=1-2 Relay=2";
+ let (is_supported, unsupported) = protover::all_supported(protocols);
+ assert_eq!("", &unsupported);
+ assert_eq!(true, is_supported);
+}
+
+#[test]
+fn protover_all_supported_with_one_value() {
+ let protocols = "Microdesc=1-2";
+ let (is_supported, unsupported) = protover::all_supported(protocols);
+ assert_eq!("", &unsupported);
+ assert_eq!(true, is_supported);
+}
+
+#[test]
+fn protover_all_supported_with_empty() {
+ let protocols = "";
+ let (is_supported, unsupported) = protover::all_supported(protocols);
+ assert_eq!(true, is_supported);
+ assert_eq!("", &unsupported);
+}
+
+#[test]
+fn protover_all_supported_with_three_values() {
+ let protocols = "LinkAuth=1 Microdesc=1-2 Relay=2";
+ let (is_supported, unsupported) = protover::all_supported(protocols);
+ assert_eq!("", &unsupported);
+ assert_eq!(true, is_supported);
+}
+
+#[test]
+fn protover_all_supported_with_unsupported_protocol() {
+ let protocols = "Wombat=9";
+ let (is_supported, unsupported) = protover::all_supported(protocols);
+ assert_eq!(false, is_supported);
+ assert_eq!("Wombat=9", &unsupported);
+}
+
+#[test]
+fn protover_all_supported_with_unsupported_versions() {
+ let protocols = "Link=3-999";
+ let (is_supported, unsupported) = protover::all_supported(protocols);
+ assert_eq!(false, is_supported);
+ assert_eq!("Link=3-999", &unsupported);
+}
+
+#[test]
+fn protover_all_supported_with_unsupported_low_version() {
+ let protocols = "Cons=0-1";
+ let (is_supported, unsupported) = protover::all_supported(protocols);
+ assert_eq!(false, is_supported);
+ assert_eq!("Cons=0-1", &unsupported);
+}
+
+#[test]
+fn protover_all_supported_with_unsupported_high_version() {
+ let protocols = "Cons=1-3";
+ let (is_supported, unsupported) = protover::all_supported(protocols);
+ assert_eq!(false, is_supported);
+ assert_eq!("Cons=1-3", &unsupported);
+}
+
+#[test]
+fn protover_all_supported_with_mix_of_supported_and_unsupproted() {
+ let protocols = "Link=3-4 Wombat=9";
+ let (is_supported, unsupported) = protover::all_supported(protocols);
+ assert_eq!(false, is_supported);
+ assert_eq!("Wombat=9", &unsupported);
+}
+
+#[test]
+fn protover_string_supports_protocol_returns_true_for_single_supported() {
+ let protocols = "Link=3-4 Cons=1";
+ let is_supported = protover::protover_string_supports_protocol(
+ protocols,
+ protover::Proto::Cons,
+ 1,
+ );
+ assert_eq!(true, is_supported);
+}
+
+#[test]
+fn protover_string_supports_protocol_returns_false_for_single_unsupported() {
+ let protocols = "Link=3-4 Cons=1";
+ let is_supported = protover::protover_string_supports_protocol(
+ protocols,
+ protover::Proto::Cons,
+ 2,
+ );
+ assert_eq!(false, is_supported);
+}
+
+#[test]
+fn protover_string_supports_protocol_returns_false_for_unsupported() {
+ let protocols = "Link=3-4";
+ let is_supported = protover::protover_string_supports_protocol(
+ protocols,
+ protover::Proto::Cons,
+ 2,
+ );
+ assert_eq!(false, is_supported);
+}
+
+#[test]
+fn protover_all_supported_with_unexpected_characters() {
+ let protocols = "Cons=*-%";
+ let (is_supported, unsupported) = protover::all_supported(protocols);
+ assert_eq!(false, is_supported);
+ assert_eq!("Cons=*-%", &unsupported);
+}
+
+#[test]
+fn protover_compute_vote_returns_empty_for_empty_string() {
+ let protocols = vec![String::from("")];
+ let listed = protover::compute_vote(protocols, 1);
+ assert_eq!("", listed);
+}
+
+#[test]
+fn protover_compute_vote_returns_single_protocol_for_matching() {
+ let protocols = vec![String::from("Cons=1")];
+ let listed = protover::compute_vote(protocols, 1);
+ assert_eq!("Cons=1", listed);
+}
+
+#[test]
+fn protover_compute_vote_returns_two_protocols_for_two_matching() {
+ let protocols = vec![String::from("Link=1 Cons=1")];
+ let listed = protover::compute_vote(protocols, 1);
+ assert_eq!("Cons=1 Link=1", listed);
+}
+
+#[test]
+fn protover_compute_vote_returns_one_protocol_when_one_out_of_two_matches() {
+ let protocols = vec![String::from("Cons=1 Link=2"), String::from("Cons=1")];
+ let listed = protover::compute_vote(protocols, 2);
+ assert_eq!("Cons=1", listed);
+}
+
+#[test]
+fn protover_compute_vote_returns_protocols_that_it_doesnt_currently_support() {
+ let protocols = vec![String::from("Foo=1 Cons=2"), String::from("Bar=1")];
+ let listed = protover::compute_vote(protocols, 1);
+ assert_eq!("Bar=1 Cons=2 Foo=1", listed);
+}
+
+#[test]
+fn protover_compute_vote_returns_matching_for_mix() {
+ let protocols = vec![String::from("Link=1-10,500 Cons=1,3-7,8")];
+ let listed = protover::compute_vote(protocols, 1);
+ assert_eq!("Cons=1,3-8 Link=1-10,500", listed);
+}
+
+#[test]
+fn protover_compute_vote_returns_matching_for_longer_mix() {
+ let protocols = vec![
+ String::from("Desc=1-10,500 Cons=1,3-7,8"),
+ String::from("Link=123-456,78 Cons=2-6,8 Desc=9"),
+ ];
+
+ let listed = protover::compute_vote(protocols, 1);
+ assert_eq!("Cons=1-8 Desc=1-10,500 Link=78,123-456", listed);
+}
+
+#[test]
+fn protover_compute_vote_returns_matching_for_longer_mix_with_threshold_two() {
+ let protocols = vec![
+ String::from("Desc=1-10,500 Cons=1,3-7,8"),
+ String::from("Link=123-456,78 Cons=2-6,8 Desc=9"),
+ ];
+
+ let listed = protover::compute_vote(protocols, 2);
+ assert_eq!("Cons=3-6,8 Desc=9", listed);
+}
+
+#[test]
+fn protover_compute_vote_handles_duplicated_versions() {
+ let protocols = vec![String::from("Cons=1"), String::from("Cons=1")];
+ assert_eq!("Cons=1", protover::compute_vote(protocols, 2));
+
+ let protocols = vec![String::from("Cons=1-2"), String::from("Cons=1-2")];
+ assert_eq!("Cons=1-2", protover::compute_vote(protocols, 2));
+}
+
+#[test]
+fn protover_compute_vote_handles_invalid_proto_entries() {
+ let protocols = vec![
+ String::from("Cons=1"),
+ String::from("Cons=1"),
+ String::from("Link=a"),
+ ];
+ assert_eq!("Cons=1", protover::compute_vote(protocols, 2));
+
+ let protocols = vec![
+ String::from("Cons=1"),
+ String::from("Cons=1"),
+ String::from("Link=1-%"),
+ ];
+ assert_eq!("Cons=1", protover::compute_vote(protocols, 2));
+}
+
+#[test]
+fn protover_is_supported_here_returns_true_for_supported_protocol() {
+ assert_eq!(true, protover::is_supported_here(protover::Proto::Cons, 1));
+}
+
+#[test]
+fn protover_is_supported_here_returns_false_for_unsupported_protocol() {
+ assert_eq!(false, protover::is_supported_here(protover::Proto::Cons, 5));
+}
diff --git a/src/rust/smartlist/Cargo.toml b/src/rust/smartlist/Cargo.toml
new file mode 100644
index 0000000000..51f486c4d7
--- /dev/null
+++ b/src/rust/smartlist/Cargo.toml
@@ -0,0 +1,13 @@
+[package]
+authors = ["The Tor Project"]
+version = "0.0.1"
+name = "smartlist"
+
+[dependencies]
+libc = "0.2.22"
+
+[lib]
+name = "smartlist"
+path = "lib.rs"
+crate_type = ["rlib", "staticlib"]
+
diff --git a/src/rust/smartlist/lib.rs b/src/rust/smartlist/lib.rs
new file mode 100644
index 0000000000..14a8148315
--- /dev/null
+++ b/src/rust/smartlist/lib.rs
@@ -0,0 +1,8 @@
+// Copyright (c) 2016-2017, The Tor Project, Inc. */
+// See LICENSE for licensing information */
+
+extern crate libc;
+
+mod smartlist;
+
+pub use smartlist::*;
diff --git a/src/rust/smartlist/smartlist.rs b/src/rust/smartlist/smartlist.rs
new file mode 100644
index 0000000000..ec5d7a57f5
--- /dev/null
+++ b/src/rust/smartlist/smartlist.rs
@@ -0,0 +1,115 @@
+// Copyright (c) 2016-2017, The Tor Project, Inc. */
+// See LICENSE for licensing information */
+
+use std::slice;
+use libc::{c_char, c_int};
+use std::ffi::CStr;
+
+/// Smartlists are a type used in C code in tor to define a collection of a
+/// generic type, which has a capacity and a number used. Each Smartlist
+/// defines how to extract the list of values from the underlying C structure
+///
+/// Implementations are required to have a C representation, as this module
+/// serves purely to translate smartlists as defined in tor to vectors in Rust.
+pub trait Smartlist<T> {
+ fn get_list(&self) -> Vec<T>;
+}
+
+#[repr(C)]
+pub struct Stringlist {
+ pub list: *const *const c_char,
+ pub num_used: c_int,
+ pub capacity: c_int,
+}
+
+impl Smartlist<String> for Stringlist {
+ fn get_list(&self) -> Vec<String> {
+ let empty: Vec<String> = Vec::new();
+ let mut rust_list: Vec<String> = Vec::new();
+
+ if self.list.is_null() || self.num_used == 0 {
+ return empty;
+ }
+
+ // unsafe, as we need to extract the smartlist list into a vector of
+ // pointers, and then transform each element into a Rust string.
+ let elems: &[*const i8] =
+ unsafe { slice::from_raw_parts(self.list, self.num_used as usize) };
+
+ for elem in elems.iter() {
+ if elem.is_null() {
+ continue;
+ }
+
+ // unsafe, as we need to create a cstring from the referenced
+ // element
+ let c_string = unsafe { CStr::from_ptr(*elem) };
+
+ let r_string = match c_string.to_str() {
+ Ok(n) => n,
+ Err(_) => return empty,
+ };
+
+ rust_list.push(String::from(r_string));
+ }
+
+ rust_list
+ }
+}
+
+// TODO: CHK: this module maybe should be tested from a test in C with a
+// smartlist as defined in tor.
+#[cfg(test)]
+mod test {
+ #[test]
+ fn test_get_list_of_strings() {
+ extern crate libc;
+
+ use std::ffi::CString;
+ use libc::c_char;
+
+ use super::Smartlist;
+ use super::Stringlist;
+
+ {
+ // test to verify that null pointers are gracefully handled
+ use std::ptr;
+
+ let sl = Stringlist {
+ list: ptr::null(),
+ num_used: 0,
+ capacity: 0,
+ };
+
+ let data = sl.get_list();
+ assert_eq!(0, data.len());
+ }
+
+ {
+ let args = vec![String::from("a"), String::from("b")];
+
+ // for each string, transform it into a CString
+ let c_strings: Vec<_> = args.iter()
+ .map(|arg| CString::new(arg.as_str()).unwrap())
+ .collect();
+
+ // then, collect a pointer for each CString
+ let p_args: Vec<_> =
+ c_strings.iter().map(|arg| arg.as_ptr()).collect();
+
+ let p: *const *const c_char = p_args.as_ptr();
+
+ // This is the representation that we expect when receiving a
+ // smartlist at the Rust/C FFI layer.
+ let sl = Stringlist {
+ list: p,
+ num_used: 2,
+ capacity: 2,
+ };
+
+ let data = sl.get_list();
+ assert_eq!("a", &data[0]);
+ assert_eq!("b", &data[1]);
+ }
+ }
+}
diff --git a/src/rust/tor_allocate/Cargo.toml b/src/rust/tor_allocate/Cargo.toml
new file mode 100644
index 0000000000..ceb08b78ab
--- /dev/null
+++ b/src/rust/tor_allocate/Cargo.toml
@@ -0,0 +1,13 @@
+[package]
+authors = ["The Tor Project"]
+version = "0.0.1"
+name = "tor_allocate"
+
+[dependencies]
+libc = "0.2.22"
+
+[lib]
+name = "tor_allocate"
+path = "lib.rs"
+crate_type = ["rlib", "staticlib"]
+
diff --git a/src/rust/tor_allocate/lib.rs b/src/rust/tor_allocate/lib.rs
new file mode 100644
index 0000000000..937a5dcf63
--- /dev/null
+++ b/src/rust/tor_allocate/lib.rs
@@ -0,0 +1,15 @@
+// Copyright (c) 2016-2017, The Tor Project, Inc. */
+// See LICENSE for licensing information */
+
+//! Allocation helper functions that allow data to be allocated in Rust
+//! using tor's specified allocator. In doing so, this can be later freed
+//! from C.
+//!
+//! This is currently a temporary solution, we will later use tor's allocator
+//! by default for any allocation that occurs in Rust. However, as this will
+//! stabalize in 2018, we can use this as a temporary measure.
+
+extern crate libc;
+
+mod tor_allocate;
+pub use tor_allocate::*;
diff --git a/src/rust/tor_allocate/tor_allocate.rs b/src/rust/tor_allocate/tor_allocate.rs
new file mode 100644
index 0000000000..359df1cd7a
--- /dev/null
+++ b/src/rust/tor_allocate/tor_allocate.rs
@@ -0,0 +1,97 @@
+// Copyright (c) 2016-2017, The Tor Project, Inc. */
+// See LICENSE for licensing information */
+
+use libc::{c_char, c_void};
+use std::{ptr, slice, mem};
+
+#[cfg(not(test))]
+extern "C" {
+ fn tor_malloc_(size: usize) -> *mut c_void;
+}
+
+// Defined only for tests, used for testing purposes, so that we don't need
+// to link to tor C files. Uses the system allocator
+#[cfg(test)]
+unsafe extern "C" fn tor_malloc_(size: usize) -> *mut c_void {
+ use libc::malloc;
+ malloc(size)
+}
+
+/// Allocate memory using tor_malloc_ and copy an existing string into the
+/// allocated buffer, returning a pointer that can later be called in C.
+///
+/// # Inputs
+///
+/// * `src`, a reference to a String.
+///
+/// # Returns
+///
+/// A `*mut c_char` that should be freed by tor_free in C
+///
+pub fn allocate_and_copy_string(src: &String) -> *mut c_char {
+ let bytes: &[u8] = src.as_bytes();
+
+ let size = mem::size_of_val::<[u8]>(bytes);
+ let size_one_byte = mem::size_of::<u8>();
+
+ // handle integer overflow when adding one to the calculated length
+ let size_with_null_byte = match size.checked_add(size_one_byte) {
+ Some(n) => n,
+ None => return ptr::null_mut(),
+ };
+
+ let dest = unsafe { tor_malloc_(size_with_null_byte) as *mut u8 };
+
+ if dest.is_null() {
+ return ptr::null_mut();
+ }
+
+ unsafe { ptr::copy_nonoverlapping(bytes.as_ptr(), dest, size) };
+
+ // set the last byte as null, using the ability to index into a slice
+ // rather than doing pointer arithmatic
+ let slice = unsafe { slice::from_raw_parts_mut(dest, size_with_null_byte) };
+ slice[size] = 0; // add a null terminator
+
+ dest as *mut c_char
+}
+
+#[cfg(test)]
+mod test {
+
+ #[test]
+ fn test_allocate_and_copy_string_with_empty() {
+ use std::ffi::CStr;
+ use libc::{free, c_void};
+
+ use tor_allocate::allocate_and_copy_string;
+
+ let empty = String::new();
+ let allocated_empty = allocate_and_copy_string(&empty);
+
+ let allocated_empty_rust =
+ unsafe { CStr::from_ptr(allocated_empty).to_str().unwrap() };
+
+ assert_eq!("", allocated_empty_rust);
+
+ unsafe { free(allocated_empty as *mut c_void) };
+ }
+
+ #[test]
+ fn test_allocate_and_copy_string_with_not_empty_string() {
+ use std::ffi::CStr;
+ use libc::{free, c_void};
+
+ use tor_allocate::allocate_and_copy_string;
+
+ let empty = String::from("foo bar biz");
+ let allocated_empty = allocate_and_copy_string(&empty);
+
+ let allocated_empty_rust =
+ unsafe { CStr::from_ptr(allocated_empty).to_str().unwrap() };
+
+ assert_eq!("foo bar biz", allocated_empty_rust);
+
+ unsafe { free(allocated_empty as *mut c_void) };
+ }
+}
diff --git a/src/rust/tor_rust/Cargo.toml b/src/rust/tor_rust/Cargo.toml
new file mode 100644
index 0000000000..86fad3ee76
--- /dev/null
+++ b/src/rust/tor_rust/Cargo.toml
@@ -0,0 +1,16 @@
+[package]
+authors = ["The Tor Project"]
+name = "tor_rust"
+version = "0.1.0"
+
+[lib]
+name = "tor_rust"
+path = "lib.rs"
+crate_type = ["rlib", "staticlib"]
+
+[dependencies.tor_util]
+path = "../tor_util"
+
+[dependencies.protover]
+path = "../protover"
+
diff --git a/src/rust/tor_rust/include.am b/src/rust/tor_rust/include.am
new file mode 100644
index 0000000000..90f37a9f1b
--- /dev/null
+++ b/src/rust/tor_rust/include.am
@@ -0,0 +1,24 @@
+EXTRA_DIST +=\
+ src/rust/tor_rust/Cargo.toml \
+ src/rust/tor_rust/lib.rs
+
+src/rust/target/release/@TOR_RUST_STATIC_NAME@: FORCE
+ ( cd "$(abs_top_srcdir)/src/rust/tor_rust" ; \
+ CARGO_TARGET_DIR="$(abs_top_builddir)/src/rust/target" \
+ CARGO_HOME="$(abs_top_builddir)/src/rust" \
+ $(CARGO) build --release --quiet $(CARGO_ONLINE) )
+
+distclean-rust:
+ ( cd "$(abs_top_srcdir)/src/rust/tor_rust" ; \
+ CARGO_TARGET_DIR="$(abs_top_builddir)/src/rust/target" \
+ CARGO_HOME="$(abs_top_builddir)/src/rust" \
+ $(CARGO) clean --quiet $(CARGO_ONLINE) )
+ rm -rf "$(abs_top_builddir)/src/rust/registry"
+
+if USE_RUST
+build-rust: src/rust/target/release/@TOR_RUST_STATIC_NAME@
+else
+build-rust:
+endif
+
+FORCE:
diff --git a/src/rust/tor_rust/lib.rs b/src/rust/tor_rust/lib.rs
new file mode 100644
index 0000000000..c1585c0480
--- /dev/null
+++ b/src/rust/tor_rust/lib.rs
@@ -0,0 +1,5 @@
+extern crate tor_util;
+extern crate protover;
+
+pub use tor_util::*;
+pub use protover::*;
diff --git a/src/rust/tor_util/Cargo.toml b/src/rust/tor_util/Cargo.toml
index f175fbdfb0..d7379a5988 100644
--- a/src/rust/tor_util/Cargo.toml
+++ b/src/rust/tor_util/Cargo.toml
@@ -8,6 +8,9 @@ name = "tor_util"
path = "lib.rs"
crate_type = ["rlib", "staticlib"]
+[dependencies.tor_allocate]
+path = "../tor_allocate"
+
[dependencies]
-libc = "*"
+libc = "0.2.22"
diff --git a/src/rust/tor_util/ffi.rs b/src/rust/tor_util/ffi.rs
index af4bfc41af..5c3cdba4be 100644
--- a/src/rust/tor_util/ffi.rs
+++ b/src/rust/tor_util/ffi.rs
@@ -1,56 +1,26 @@
-//! FFI functions, only to be called from C.
-//!
-//! Equivalent C versions of these live in `src/common/compat_rust.c`
-
-use std::mem::forget;
-use std::ffi::CString;
+// Copyright (c) 2016-2017, The Tor Project, Inc. */
+// See LICENSE for licensing information */
-use libc;
-use rust_string::RustString;
-
-/// Free the passed `RustString` (`rust_str_t` in C), to be used in place of
-/// `tor_free`().
-///
-/// # Examples
-/// ```c
-/// rust_str_t r_s = rust_welcome_string();
-/// rust_str_free(r_s);
-/// ```
-#[no_mangle]
-#[cfg_attr(feature = "cargo-clippy", allow(needless_pass_by_value))]
-pub unsafe extern "C" fn rust_str_free(_str: RustString) {
- // Empty body: Just drop _str and we're done (Drop takes care of it).
-}
+//! FFI functions to announce Rust support during tor startup, only to be
+//! called from C.
+//!
-/// Lends an immutable, NUL-terminated C String.
-///
-/// # Examples
-/// ```c
-/// rust_str_t r_s = rust_welcome_string();
-/// const char *s = rust_str_get(r_s);
-/// printf("%s", s);
-/// rust_str_free(r_s);
-/// ```
-#[no_mangle]
-pub unsafe extern "C" fn rust_str_get(str: RustString) -> *const libc::c_char {
- let res = str.as_ptr();
- forget(str);
- res
-}
+use libc::c_char;
+use tor_allocate::allocate_and_copy_string;
/// Returns a short string to announce Rust support during startup.
///
/// # Examples
/// ```c
-/// rust_str_t r_s = rust_welcome_string();
-/// const char *s = rust_str_get(r_s);
-/// printf("%s", s);
-/// rust_str_free(r_s);
+/// char *rust_str = rust_welcome_string();
+/// printf("%s", rust_str);
+/// tor_free(rust_str);
/// ```
#[no_mangle]
-pub extern "C" fn rust_welcome_string() -> RustString {
- let s = CString::new("Tor is running with Rust integration. Please report \
- any bugs you encouter.")
- .unwrap();
- RustString::from(s)
+pub extern "C" fn rust_welcome_string() -> *mut c_char {
+ let rust_welcome = String::from(
+ "Tor is running with Rust integration. Please report \
+ any bugs you encounter.",
+ );
+ allocate_and_copy_string(&rust_welcome)
}
diff --git a/src/rust/tor_util/include.am b/src/rust/tor_util/include.am
deleted file mode 100644
index ec3898577b..0000000000
--- a/src/rust/tor_util/include.am
+++ /dev/null
@@ -1,13 +0,0 @@
-EXTRA_DIST +=\
- src/rust/tor_util/Cargo.toml \
- src/rust/tor_util/lib.rs \
- src/rust/tor_util/ffi.rs \
- src/rust/tor_util/rust_string.rs
-
-src/rust/target/release/@TOR_RUST_UTIL_STATIC_NAME@: FORCE
- ( cd "$(abs_top_srcdir)/src/rust/tor_util" ; \
- CARGO_TARGET_DIR="$(abs_top_builddir)/src/rust/target" \
- CARGO_HOME="$(abs_top_builddir)/src/rust" \
- $(CARGO) build --release --quiet $(CARGO_ONLINE) )
-
-FORCE:
diff --git a/src/rust/tor_util/lib.rs b/src/rust/tor_util/lib.rs
index 79d583d1ae..42fa9d5ad0 100644
--- a/src/rust/tor_util/lib.rs
+++ b/src/rust/tor_util/lib.rs
@@ -1,13 +1,11 @@
-//! C <-> Rust compatibility helpers and types.
+// Copyright (c) 2016-2017, The Tor Project, Inc. */
+// See LICENSE for licensing information */
+
+//! Small module to announce Rust support during startup for demonstration
+//! purposes.
//!
-//! Generically useful, small scale helpers should go here. This goes for both
-//! the C side (in the form of the ffi module) as well as the Rust side
-//! (individual modules per functionality). The corresponding C stuff lives in
-//! `src/common/compat_rust.{c,h}`.
extern crate libc;
+extern crate tor_allocate;
-mod rust_string;
pub mod ffi;
-
-pub use rust_string::*;
diff --git a/src/rust/tor_util/rust_string.rs b/src/rust/tor_util/rust_string.rs
deleted file mode 100644
index 46ec3fd7a8..0000000000
--- a/src/rust/tor_util/rust_string.rs
+++ /dev/null
@@ -1,101 +0,0 @@
-use std::ffi::CString;
-use std::mem::forget;
-use libc;
-
-/// Compatibility wrapper for strings allocated in Rust and passed to C.
-///
-/// Rust doesn't ensure the safety of freeing memory across an FFI boundary, so
-/// we need to take special care to ensure we're not accidentally calling
-/// `tor_free`() on any string allocated in Rust. To more easily differentiate
-/// between strings that possibly (if Rust support is enabled) were allocated
-/// in Rust, C has the `rust_str_t` helper type. The equivalent on the Rust
-/// side is `RustString`.
-///
-/// Note: This type must not be used for strings allocated in C.
-#[repr(C)]
-#[derive(Debug)]
-pub struct RustString(*mut libc::c_char);
-
-impl RustString {
- /// Returns a pointer to the underlying NUL-terminated byte array.
- ///
- /// Note that this function is not typically useful for Rust callers,
- /// except in a direct FFI context.
- ///
- /// # Examples
- /// ```
- /// # use tor_util::RustString;
- /// use std::ffi::CString;
- ///
- /// let r = RustString::from(CString::new("asdf").unwrap());
- /// let c_str = r.as_ptr();
- /// assert_eq!(b'a', unsafe { *c_str as u8});
- /// ```
- pub fn as_ptr(&self) -> *const libc::c_char {
- self.0 as *const libc::c_char
- }
-}
-
-impl From<CString> for RustString {
- /// Constructs a new `RustString`
- ///
- /// # Examples
- /// ```
- /// # use tor_util::RustString;
- /// use std::ffi::CString;
- ///
- /// let r = RustString::from(CString::new("asdf").unwrap());
- /// ```
- fn from(str: CString) -> RustString {
- RustString(str.into_raw())
- }
-}
-
-impl Into<CString> for RustString {
- /// Reconstructs a `CString` from this `RustString`.
- ///
- /// Useful to take ownership back from a `RustString` that was given to C
- /// code.
- ///
- /// # Examples
- /// ```
- /// # use tor_util::RustString;
- /// use std::ffi::CString;
- ///
- /// let cs = CString::new("asdf").unwrap();
- /// let r = RustString::from(cs.clone());
- /// let cs2 = r.into();
- /// assert_eq!(cs, cs2);
- /// ```
- fn into(self) -> CString {
- // Calling from_raw is always OK here: We only construct self using
- // valid CStrings and don't expose anything that could mutate it
- let ret = unsafe { CString::from_raw(self.0) };
- forget(self);
- ret
- }
-}
-
-impl Drop for RustString {
- fn drop(&mut self) {
- // Don't use into() here, because we would need to move out of
- // self. Same safety consideration. Immediately drop the created
- // CString, which takes care of freeing the wrapped string.
- unsafe { CString::from_raw(self.0) };
- }
-}
-
-#[cfg(test)]
-mod test {
- use std::mem;
- use super::*;
-
- use libc;
-
- /// Ensures we're not adding overhead by using RustString.
- #[test]
- fn size_of() {
- assert_eq!(mem::size_of::<*mut libc::c_char>(),
- mem::size_of::<RustString>())
- }
-}
diff --git a/src/rust/tor_util/tests/rust_string.rs b/src/rust/tor_util/tests/rust_string.rs
deleted file mode 100644
index 1ff605a43c..0000000000
--- a/src/rust/tor_util/tests/rust_string.rs
+++ /dev/null
@@ -1,37 +0,0 @@
-extern crate tor_util;
-extern crate libc;
-
-use std::ffi::CString;
-use tor_util::RustString;
-
-#[test]
-fn rust_string_conversions_preserve_c_string() {
- let s = CString::new("asdf foo").unwrap();
- let r = RustString::from(s.clone());
- let r2 = RustString::from(s.clone());
- let c = r2.as_ptr();
- assert_eq!(unsafe { libc::strlen(c) }, 8);
- let c_str = r.into();
- assert_eq!(s, c_str);
-}
-
-#[test]
-fn empty_string() {
- let s = CString::new("").unwrap();
- let r = RustString::from(s.clone());
- let c = r.as_ptr();
- assert_eq!(unsafe { libc::strlen(c) }, 0);
- let c_str = r.into();
- assert_eq!(s, c_str);
-}
-
-#[test]
-fn c_string_with_unicode() {
- // The euro sign is three bytes
- let s = CString::new("asd€asd").unwrap();
- let r = RustString::from(s.clone());
- let c = r.as_ptr();
- assert_eq!(unsafe { libc::strlen(c) }, 9);
- let c_str = r.into();
- assert_eq!(s, c_str);
-}
diff --git a/src/test/bench.c b/src/test/bench.c
index b7b123eee2..f30b609900 100644
--- a/src/test/bench.c
+++ b/src/test/bench.c
@@ -3,11 +3,6 @@
* Copyright (c) 2007-2017, The Tor Project, Inc. */
/* See LICENSE for licensing information */
-extern const char tor_git_revision[];
-/* Ordinarily defined in tor_main.c; this bit is just here to provide one
- * since we're not linking to tor_main.c */
-const char tor_git_revision[] = "";
-
/**
* \file bench.c
* \brief Benchmarks for lower level Tor modules.
diff --git a/src/test/fuzz/fuzzing_common.c b/src/test/fuzz/fuzzing_common.c
index 1e98eb6c85..1d54e41dbd 100644
--- a/src/test/fuzz/fuzzing_common.c
+++ b/src/test/fuzz/fuzzing_common.c
@@ -9,9 +9,6 @@
#include "crypto.h"
#include "crypto_ed25519.h"
-extern const char tor_git_revision[];
-const char tor_git_revision[] = "";
-
static or_options_t *mock_options = NULL;
static const or_options_t *
mock_get_options(void)
diff --git a/src/test/include.am b/src/test/include.am
index 610918e9da..bbf8a370e2 100644
--- a/src/test/include.am
+++ b/src/test/include.am
@@ -152,7 +152,6 @@ src_test_test_SOURCES = \
src/test/test_routerkeys.c \
src/test/test_routerlist.c \
src/test/test_routerset.c \
- src/test/test_rust.c \
src/test/test_scheduler.c \
src/test/test_shared_random.c \
src/test/test_socks.c \
diff --git a/src/test/test-memwipe.c b/src/test/test-memwipe.c
index 484f13dd05..89d946d506 100644
--- a/src/test/test-memwipe.c
+++ b/src/test/test-memwipe.c
@@ -1,3 +1,6 @@
+/* Copyright (c) 2015-2017, The Tor Project, Inc. */
+/* See LICENSE for licensing information */
+
#include "orconfig.h"
#include <string.h>
#include <stdio.h>
diff --git a/src/test/test.c b/src/test/test.c
index da4f7a0553..00857c2386 100644
--- a/src/test/test.c
+++ b/src/test/test.c
@@ -1227,7 +1227,6 @@ struct testgroup_t testgroups[] = {
{ "routerkeys/", routerkeys_tests },
{ "routerlist/", routerlist_tests },
{ "routerset/" , routerset_tests },
- { "rust/", rust_tests },
{ "scheduler/", scheduler_tests },
{ "socks/", socks_tests },
{ "shared-random/", sr_tests },
diff --git a/src/test/test.h b/src/test/test.h
index 634f3e7b02..b1a3366a80 100644
--- a/src/test/test.h
+++ b/src/test/test.h
@@ -239,7 +239,6 @@ extern struct testcase_t router_tests[];
extern struct testcase_t routerkeys_tests[];
extern struct testcase_t routerlist_tests[];
extern struct testcase_t routerset_tests[];
-extern struct testcase_t rust_tests[];
extern struct testcase_t scheduler_tests[];
extern struct testcase_t storagedir_tests[];
extern struct testcase_t socks_tests[];
diff --git a/src/test/test_accounting.c b/src/test/test_accounting.c
index 7edba988a6..b0d37b2989 100644
--- a/src/test/test_accounting.c
+++ b/src/test/test_accounting.c
@@ -1,3 +1,6 @@
+/* Copyright (c) 2014-2017, The Tor Project, Inc. */
+/* See LICENSE for licensing information */
+
#include "or.h"
#include "test.h"
#define HIBERNATE_PRIVATE
diff --git a/src/test/test_channelpadding.c b/src/test/test_channelpadding.c
index d5713688a0..4346ee343f 100644
--- a/src/test/test_channelpadding.c
+++ b/src/test/test_channelpadding.c
@@ -1,3 +1,6 @@
+/* Copyright (c) 2016-2017, The Tor Project, Inc. */
+/* See LICENSE for licensing information */
+
#define TOR_CHANNEL_INTERNAL_
#define MAIN_PRIVATE
#define NETWORKSTATUS_PRIVATE
diff --git a/src/test/test_config.c b/src/test/test_config.c
index 456d8bcc3e..79f72fca1f 100644
--- a/src/test/test_config.c
+++ b/src/test/test_config.c
@@ -4833,7 +4833,7 @@ test_config_include_limit(void *data)
torrc_path);
tt_int_op(write_str_to_file(torrc_path, torrc_contents, 0), OP_EQ, 0);
- tt_int_op(config_get_lines_include(torrc_contents, &result, 0, NULL),
+ tt_int_op(config_get_lines_include(torrc_contents, &result, 0, NULL, NULL),
OP_EQ, -1);
done:
@@ -4863,7 +4863,7 @@ test_config_include_does_not_exist(void *data)
tor_snprintf(torrc_contents, sizeof(torrc_contents), "%%include %s",
missing_path);
- tt_int_op(config_get_lines_include(torrc_contents, &result, 0, NULL),
+ tt_int_op(config_get_lines_include(torrc_contents, &result, 0, NULL, NULL),
OP_EQ, -1);
done:
@@ -4895,7 +4895,7 @@ test_config_include_error_in_included_file(void *data)
tor_snprintf(torrc_contents, sizeof(torrc_contents), "%%include %s",
invalid_path);
- tt_int_op(config_get_lines_include(torrc_contents, &result, 0, NULL),
+ tt_int_op(config_get_lines_include(torrc_contents, &result, 0, NULL, NULL),
OP_EQ, -1);
done:
@@ -4937,8 +4937,8 @@ test_config_include_empty_file_folder(void *data)
folder_path, file_path);
int include_used;
- tt_int_op(config_get_lines_include(torrc_contents, &result, 0,&include_used),
- OP_EQ, 0);
+ tt_int_op(config_get_lines_include(torrc_contents, &result, 0,&include_used,
+ NULL), OP_EQ, 0);
tt_ptr_op(result, OP_EQ, NULL);
tt_int_op(include_used, OP_EQ, 1);
@@ -4975,7 +4975,8 @@ test_config_include_no_permission(void *data)
folder_path);
int include_used;
- tt_int_op(config_get_lines_include(torrc_contents, &result, 0,&include_used),
+ tt_int_op(config_get_lines_include(torrc_contents, &result, 0,
+ &include_used, NULL),
OP_EQ, -1);
tt_ptr_op(result, OP_EQ, NULL);
@@ -5031,8 +5032,8 @@ test_config_include_recursion_before_after(void *data)
}
int include_used;
- tt_int_op(config_get_lines_include(file_contents, &result, 0, &include_used),
- OP_EQ, 0);
+ tt_int_op(config_get_lines_include(file_contents, &result, 0, &include_used,
+ NULL), OP_EQ, 0);
tt_ptr_op(result, OP_NE, NULL);
tt_int_op(include_used, OP_EQ, 1);
@@ -5096,8 +5097,8 @@ test_config_include_recursion_after_only(void *data)
}
int include_used;
- tt_int_op(config_get_lines_include(file_contents, &result, 0, &include_used),
- OP_EQ, 0);
+ tt_int_op(config_get_lines_include(file_contents, &result, 0, &include_used,
+ NULL), OP_EQ, 0);
tt_ptr_op(result, OP_NE, NULL);
tt_int_op(include_used, OP_EQ, 1);
@@ -5185,8 +5186,8 @@ test_config_include_folder_order(void *data)
torrcd);
int include_used;
- tt_int_op(config_get_lines_include(torrc_contents, &result, 0,&include_used),
- OP_EQ, 0);
+ tt_int_op(config_get_lines_include(torrc_contents, &result, 0, &include_used,
+ NULL), OP_EQ, 0);
tt_ptr_op(result, OP_NE, NULL);
tt_int_op(include_used, OP_EQ, 1);
@@ -5239,8 +5240,8 @@ test_config_include_path_syntax(void *data)
esc_dir_with_pathsep);
int include_used;
- tt_int_op(config_get_lines_include(torrc_contents, &result, 0,&include_used),
- OP_EQ, 0);
+ tt_int_op(config_get_lines_include(torrc_contents, &result, 0,&include_used,
+ NULL), OP_EQ, 0);
tt_ptr_op(result, OP_EQ, NULL);
tt_int_op(include_used, OP_EQ, 1);
@@ -5294,14 +5295,14 @@ test_config_include_has_include(void *data)
char torrc_contents[1000] = "Test 1\n";
int include_used;
- tt_int_op(config_get_lines_include(torrc_contents, &result, 0,&include_used),
- OP_EQ, 0);
+ tt_int_op(config_get_lines_include(torrc_contents, &result, 0,&include_used,
+ NULL), OP_EQ, 0);
tt_int_op(include_used, OP_EQ, 0);
config_free_lines(result);
tor_snprintf(torrc_contents, sizeof(torrc_contents), "%%include %s\n", dir);
- tt_int_op(config_get_lines_include(torrc_contents, &result, 0,&include_used),
- OP_EQ, 0);
+ tt_int_op(config_get_lines_include(torrc_contents, &result, 0,&include_used,
+ NULL), OP_EQ, 0);
tt_int_op(include_used, OP_EQ, 1);
done:
@@ -5513,6 +5514,85 @@ test_config_check_bridge_distribution_setting_unrecognised(void *arg)
return;
}
+static void
+test_config_include_opened_file_list(void *data)
+{
+ (void)data;
+
+ config_line_t *result = NULL;
+ smartlist_t *opened_files = smartlist_new();
+ char *dir = tor_strdup(get_fname("test_include_opened_file_list"));
+ tt_ptr_op(dir, OP_NE, NULL);
+
+#ifdef _WIN32
+ tt_int_op(mkdir(dir), OP_EQ, 0);
+#else
+ tt_int_op(mkdir(dir, 0700), OP_EQ, 0);
+#endif
+
+ char torrcd[PATH_MAX+1];
+ tor_snprintf(torrcd, sizeof(torrcd), "%s"PATH_SEPARATOR"%s", dir, "torrc.d");
+
+#ifdef _WIN32
+ tt_int_op(mkdir(torrcd), OP_EQ, 0);
+#else
+ tt_int_op(mkdir(torrcd, 0700), OP_EQ, 0);
+#endif
+
+ char subfolder[PATH_MAX+1];
+ tor_snprintf(subfolder, sizeof(subfolder), "%s"PATH_SEPARATOR"%s", torrcd,
+ "subfolder");
+
+#ifdef _WIN32
+ tt_int_op(mkdir(subfolder), OP_EQ, 0);
+#else
+ tt_int_op(mkdir(subfolder, 0700), OP_EQ, 0);
+#endif
+
+ char path[PATH_MAX+1];
+ tor_snprintf(path, sizeof(path), "%s"PATH_SEPARATOR"%s", subfolder,
+ "01_file_in_subfolder");
+ tt_int_op(write_str_to_file(path, "Test 1\n", 0), OP_EQ, 0);
+
+ char empty[PATH_MAX+1];
+ tor_snprintf(empty, sizeof(empty), "%s"PATH_SEPARATOR"%s", torrcd, "empty");
+ tt_int_op(write_str_to_file(empty, "", 0), OP_EQ, 0);
+
+ char file[PATH_MAX+1];
+ tor_snprintf(file, sizeof(file), "%s"PATH_SEPARATOR"%s", torrcd, "file");
+ tt_int_op(write_str_to_file(file, "Test 2\n", 0), OP_EQ, 0);
+
+ char dot[PATH_MAX+1];
+ tor_snprintf(dot, sizeof(dot), "%s"PATH_SEPARATOR"%s", torrcd, ".dot");
+ tt_int_op(write_str_to_file(dot, "Test 3\n", 0), OP_EQ, 0);
+
+ char torrc_contents[1000];
+ tor_snprintf(torrc_contents, sizeof(torrc_contents),
+ "%%include %s\n",
+ torrcd);
+
+ int include_used;
+ tt_int_op(config_get_lines_include(torrc_contents, &result, 0, &include_used,
+ opened_files), OP_EQ, 0);
+ tt_ptr_op(result, OP_NE, NULL);
+ tt_int_op(include_used, OP_EQ, 1);
+
+ tt_int_op(smartlist_len(opened_files), OP_EQ, 4);
+ tt_int_op(smartlist_contains_string(opened_files, torrcd), OP_EQ, 1);
+ tt_int_op(smartlist_contains_string(opened_files, subfolder), OP_EQ, 1);
+ // files inside subfolders are not opended, only the subfolder is opened
+ tt_int_op(smartlist_contains_string(opened_files, empty), OP_EQ, 1);
+ tt_int_op(smartlist_contains_string(opened_files, file), OP_EQ, 1);
+ // dot files are not opened as we ignore them when we get their name from
+ // their parent folder
+
+ done:
+ SMARTLIST_FOREACH(opened_files, char *, f, tor_free(f));
+ smartlist_free(opened_files);
+ config_free_lines(result);
+ tor_free(dir);
+}
+
#define CONFIG_TEST(name, flags) \
{ #name, test_config_ ## name, flags, NULL, NULL }
@@ -5560,6 +5640,7 @@ struct testcase_t config_tests[] = {
CONFIG_TEST(check_bridge_distribution_setting_valid, 0),
CONFIG_TEST(check_bridge_distribution_setting_invalid, 0),
CONFIG_TEST(check_bridge_distribution_setting_unrecognised, 0),
+ CONFIG_TEST(include_opened_file_list, 0),
END_OF_TESTCASES
};
diff --git a/src/test/test_dns.c b/src/test/test_dns.c
index 19dcb02931..66b231b6da 100644
--- a/src/test/test_dns.c
+++ b/src/test/test_dns.c
@@ -1,3 +1,6 @@
+/* Copyright (c) 2015-2017, The Tor Project, Inc. */
+/* See LICENSE for licensing information */
+
#include "or.h"
#include "test.h"
diff --git a/src/test/test_keygen.sh b/src/test/test_keygen.sh
index 87012cd283..b3d4d8e39a 100755
--- a/src/test/test_keygen.sh
+++ b/src/test/test_keygen.sh
@@ -40,6 +40,12 @@ fi
CASE8=$dflt
CASE9=$dflt
CASE10=$dflt
+ CASE11A=$dflt
+ CASE11B=$dflt
+ CASE11C=$dflt
+ CASE11D=$dflt
+ CASE11E=$dflt
+ CASE11F=$dflt
if [ $# -ge 1 ]; then
eval "CASE${1}"=1
@@ -363,6 +369,109 @@ echo "==== Case 10 ok"
fi
+# Case 11a: -passphrase-fd without --keygen
+
+if [ "$CASE11A" = 1 ]; then
+
+ME="${DATA_DIR}/case11a"
+
+mkdir -p "${ME}/keys"
+
+${TOR} --DataDirectory "${ME}" --passphrase-fd 1 > "${ME}/stdout" && die "Successfully started with passphrase-fd but no keygen?" || true
+
+grep "passphrase-fd specified without --keygen" "${ME}/stdout" >/dev/null || die "Tor didn't declare that there was a problem with the arguments."
+
+echo "==== Case 11A ok"
+
+fi
+
+# Case 11b: --no-passphrase without --keygen
+
+if [ "$CASE11B" = 1 ]; then
+
+ME="${DATA_DIR}/case11b"
+
+mkdir -p "${ME}/keys"
+
+${TOR} --DataDirectory "${ME}" --no-passphrase > "${ME}/stdout" && die "Successfully started with no-passphrase but no keygen?" || true
+
+grep "no-passphrase specified without --keygen" "${ME}/stdout" >/dev/null || die "Tor didn't declare that there was a problem with the arguments."
+
+echo "==== Case 11B ok"
+
+fi
+
+# Case 11c: --newpass without --keygen
+
+if [ "$CASE11C" = 1 ]; then
+
+ME="${DATA_DIR}/case11C"
+
+mkdir -p "${ME}/keys"
+
+${TOR} --DataDirectory "${ME}" --newpass > "${ME}/stdout" && die "Successfully started with newpass but no keygen?" || true
+
+grep "newpass specified without --keygen" "${ME}/stdout" >/dev/null || die "Tor didn't declare that there was a problem with the arguments."
+
+echo "==== Case 11C ok"
+
+fi
+
+######## --master-key does not work yet, but this will test the error case
+######## when it does.
+#
+# Case 11d: --master-key without --keygen
+#
+if [ "$CASE11D" = 1 ]; then
+#
+# ME="${DATA_DIR}/case11d"
+#
+# mkdir -p "${ME}/keys"
+#
+# ${TOR} --DataDirectory "${ME}" --master-key "${ME}/foobar" > "${ME}/stdout" && die "Successfully started with master-key but no keygen?" || true
+#
+# cat "${ME}/stdout"
+#
+# grep "master-key without --keygen" "${ME}/stdout" >/dev/null || die "Tor didn't declare that there was a problem with the arguments."
+
+ echo "==== Case 11D skipped"
+
+fi
+
+
+# Case 11E: Silly passphrase-fd
+
+if [ "$CASE11E" = 1 ]; then
+
+ME="${DATA_DIR}/case11E"
+
+mkdir -p "${ME}/keys"
+
+${TOR} --DataDirectory "${ME}" --keygen --passphrase-fd ewigeblumenkraft > "${ME}/stdout" && die "Successfully started with bogus passphrase-fd?" || true
+
+grep "Invalid --passphrase-fd value" "${ME}/stdout" >/dev/null || die "Tor didn't declare that there was a problem with the arguments."
+
+echo "==== Case 11E ok"
+
+fi
+
+
+# Case 11F: --no-passphrase with --passphrase-fd
+
+if [ "$CASE11F" = 1 ]; then
+
+ME="${DATA_DIR}/case11F"
+
+mkdir -p "${ME}/keys"
+
+${TOR} --DataDirectory "${ME}" --keygen --passphrase-fd 1 --no-passphrase > "${ME}/stdout" && die "Successfully started with bogus passphrase-fd combination?" || true
+
+grep "no-passphrase specified with --passphrase-fd" "${ME}/stdout" >/dev/null || die "Tor didn't declare that there was a problem with the arguments."
+
+echo "==== Case 11F ok"
+
+fi
+
# Check cert-only.
diff --git a/src/test/test_protover.c b/src/test/test_protover.c
index 6ce54890d6..6865362115 100644
--- a/src/test/test_protover.c
+++ b/src/test/test_protover.c
@@ -12,6 +12,13 @@ static void
test_protover_parse(void *arg)
{
(void) arg;
+#ifdef HAVE_RUST
+ /** This test is disabled on rust builds, because it only exists to test
+ * internal C functions. */
+ tt_skip();
+ done:
+ ;
+#else
char *re_encoded = NULL;
const char *orig = "Foo=1,3 Bar=3 Baz= Quux=9-12,14,15-16,900";
@@ -78,12 +85,18 @@ test_protover_parse(void *arg)
SMARTLIST_FOREACH(elts, proto_entry_t *, ent, proto_entry_free(ent));
smartlist_free(elts);
tor_free(re_encoded);
+#endif
}
static void
test_protover_parse_fail(void *arg)
{
(void)arg;
+#ifdef HAVE_RUST
+ /** This test is disabled on rust builds, because it only exists to test
+ * internal C functions. */
+ tt_skip();
+#else
smartlist_t *elts;
/* random junk */
@@ -109,7 +122,7 @@ test_protover_parse_fail(void *arg)
/* Broken range */
elts = parse_protocol_list("Link=1,9-8,3");
tt_ptr_op(elts, OP_EQ, NULL);
-
+#endif
done:
;
}
@@ -182,6 +195,61 @@ test_protover_all_supported(void *arg)
tor_free(msg);
}
+static void
+test_protover_list_supports_protocol_returns_true(void *arg)
+{
+ (void)arg;
+
+ const char *protocols = "Link=1";
+ int is_supported = protocol_list_supports_protocol(protocols, PRT_LINK, 1);
+ tt_int_op(is_supported, OP_EQ, 1);
+
+ done:
+ ;
+}
+
+static void
+test_protover_list_supports_protocol_for_unsupported_returns_false(void *arg)
+{
+ (void)arg;
+
+ const char *protocols = "Link=1";
+ int is_supported = protocol_list_supports_protocol(protocols, PRT_LINK, 10);
+ tt_int_op(is_supported, OP_EQ, 0);
+
+ done:
+ ;
+}
+
+static void
+test_protover_supports_version(void *arg)
+{
+ (void)arg;
+
+ tt_assert(protocol_list_supports_protocol("Link=3-6", PRT_LINK, 3));
+ tt_assert(protocol_list_supports_protocol("Link=3-6", PRT_LINK, 6));
+ tt_assert(!protocol_list_supports_protocol("Link=3-6", PRT_LINK, 7));
+ tt_assert(!protocol_list_supports_protocol("Link=3-6", PRT_LINKAUTH, 3));
+
+ tt_assert(!protocol_list_supports_protocol("Link=4-6 LinkAuth=3",
+ PRT_LINKAUTH, 2));
+ tt_assert(protocol_list_supports_protocol("Link=4-6 LinkAuth=3",
+ PRT_LINKAUTH, 3));
+ tt_assert(!protocol_list_supports_protocol("Link=4-6 LinkAuth=3",
+ PRT_LINKAUTH, 4));
+ tt_assert(!protocol_list_supports_protocol_or_later("Link=4-6 LinkAuth=3",
+ PRT_LINKAUTH, 4));
+ tt_assert(protocol_list_supports_protocol_or_later("Link=4-6 LinkAuth=3",
+ PRT_LINKAUTH, 3));
+ tt_assert(protocol_list_supports_protocol_or_later("Link=4-6 LinkAuth=3",
+ PRT_LINKAUTH, 2));
+
+ tt_assert(!protocol_list_supports_protocol_or_later("Link=4-6 LinkAuth=3",
+ PRT_DESC, 2));
+ done:
+ ;
+}
+
#define PV_TEST(name, flags) \
{ #name, test_protover_ ##name, (flags), NULL, NULL }
@@ -190,6 +258,9 @@ struct testcase_t protover_tests[] = {
PV_TEST(parse_fail, 0),
PV_TEST(vote, 0),
PV_TEST(all_supported, 0),
+ PV_TEST(list_supports_protocol_for_unsupported_returns_false, 0),
+ PV_TEST(list_supports_protocol_returns_true, 0),
+ PV_TEST(supports_version, 0),
END_OF_TESTCASES
};
diff --git a/src/test/test_routerlist.c b/src/test/test_routerlist.c
index 3b0e943ce5..fd29e8f172 100644
--- a/src/test/test_routerlist.c
+++ b/src/test/test_routerlist.c
@@ -5,7 +5,11 @@
#include <math.h>
#include <time.h>
+#define CONNECTION_PRIVATE
+#define DIRECTORY_PRIVATE
#define DIRVOTE_PRIVATE
+#define ENTRYNODES_PRIVATE
+#define HIBERNATE_PRIVATE
#define NETWORKSTATUS_PRIVATE
#define ROUTERLIST_PRIVATE
#define TOR_UNIT_TESTING
@@ -13,19 +17,24 @@
#include "config.h"
#include "connection.h"
#include "container.h"
+#include "control.h"
#include "directory.h"
#include "dirvote.h"
#include "entrynodes.h"
+#include "hibernate.h"
#include "microdesc.h"
#include "networkstatus.h"
#include "nodelist.h"
#include "policies.h"
#include "router.h"
#include "routerlist.h"
+#include "routerset.h"
#include "routerparse.h"
#include "shared_random.h"
+#include "statefile.h"
#include "test.h"
#include "test_dir_common.h"
+#include "log_test_helpers.h"
void construct_consensus(char **consensus_text_md);
@@ -411,6 +420,111 @@ test_router_pick_directory_server_impl(void *arg)
networkstatus_vote_free(con_md);
}
+static or_state_t *dummy_state = NULL;
+static or_state_t *
+get_or_state_replacement(void)
+{
+ return dummy_state;
+}
+
+static void
+mock_directory_initiate_request(directory_request_t *req)
+{
+ (void)req;
+ return;
+}
+
+static circuit_guard_state_t *
+mock_circuit_guard_state_new(entry_guard_t *guard, unsigned state,
+ entry_guard_restriction_t *rst)
+{
+ (void) guard;
+ (void) state;
+ (void) rst;
+ return NULL;
+}
+
+/** Test that we will use our directory guards to fetch mds even if we don't
+ * have any dirinfo (tests bug #23862). */
+static void
+test_directory_guard_fetch_with_no_dirinfo(void *arg)
+{
+ int retval;
+ char *consensus_text_md = NULL;
+ or_options_t *options = get_options_mutable();
+
+ (void) arg;
+
+ hibernate_set_state_for_testing_(HIBERNATE_STATE_LIVE);
+
+ /* Initialize the SRV subsystem */
+ MOCK(get_my_v3_authority_cert, get_my_v3_authority_cert_m);
+ mock_cert = authority_cert_parse_from_string(AUTHORITY_CERT_1, NULL);
+ sr_init(0);
+ UNMOCK(get_my_v3_authority_cert);
+
+ /* Initialize the entry node configuration from the ticket */
+ options->UseEntryGuards = 1;
+ options->StrictNodes = 1;
+ get_options_mutable()->EntryNodes = routerset_new();
+ routerset_parse(get_options_mutable()->EntryNodes,
+ "2121212121212121212121212121212121212121", "foo");
+
+ /* Mock some functions */
+ dummy_state = tor_malloc_zero(sizeof(or_state_t));
+ MOCK(get_or_state, get_or_state_replacement);
+ MOCK(directory_initiate_request, mock_directory_initiate_request);
+ /* we need to mock this one to avoid memleaks */
+ MOCK(circuit_guard_state_new, mock_circuit_guard_state_new);
+
+ /* Call guards_update_all() to simulate loading our state file (see
+ * entry_guards_load_guards_from_state() and ticket #23989). */
+ guards_update_all();
+
+ /* Test logic: Simulate the arrival of a new consensus when we have no
+ * dirinfo at all. Tor will need to fetch the mds from the consensus. Make
+ * sure that Tor will use the specified entry guard instead of relying on the
+ * fallback directories. */
+
+ /* Fixup the dirconn that will deliver the consensus */
+ dir_connection_t *conn = dir_connection_new(AF_INET);
+ tor_addr_from_ipv4h(&conn->base_.addr, 0x7f000001);
+ conn->base_.port = 8800;
+ TO_CONN(conn)->address = tor_strdup("127.0.0.1");
+ conn->base_.purpose = DIR_PURPOSE_FETCH_CONSENSUS;
+ conn->requested_resource = tor_strdup("ns");
+
+ /* Construct a consensus */
+ construct_consensus(&consensus_text_md);
+ tt_assert(consensus_text_md);
+
+ /* Place the consensus in the dirconn */
+ response_handler_args_t args;
+ memset(&args, 0, sizeof(response_handler_args_t));
+ args.status_code = 200;
+ args.body = consensus_text_md;
+ args.body_len = strlen(consensus_text_md);
+
+ /* Update approx time so that the consensus is considered live */
+ update_approx_time(time(NULL)+1010);
+
+ setup_capture_of_logs(LOG_DEBUG);
+
+ /* Now handle the consensus */
+ retval = handle_response_fetch_consensus(conn, &args);
+ tt_int_op(retval, OP_EQ, 0);
+
+ /* Make sure that our primary guard was chosen */
+ expect_log_msg_containing("Selected primary guard router3");
+
+ done:
+ tor_free(consensus_text_md);
+ tor_free(dummy_state);
+ connection_free_(TO_CONN(conn));
+ entry_guards_free_all();
+ teardown_capture_of_logs();
+}
+
static connection_t *mocked_connection = NULL;
/* Mock connection_get_by_type_addr_port_purpose by returning
@@ -494,6 +608,8 @@ struct testcase_t routerlist_tests[] = {
NODE(launch_descriptor_downloads, 0),
NODE(router_is_already_dir_fetching, TT_FORK),
ROUTER(pick_directory_server_impl, TT_FORK),
+ { "directory_guard_fetch_with_no_dirinfo",
+ test_directory_guard_fetch_with_no_dirinfo, TT_FORK, NULL, NULL },
END_OF_TESTCASES
};
diff --git a/src/test/test_routerset.c b/src/test/test_routerset.c
index c9c69911da..6da2275c35 100644
--- a/src/test/test_routerset.c
+++ b/src/test/test_routerset.c
@@ -1,3 +1,6 @@
+/* Copyright (c) 2014-2017, The Tor Project, Inc. */
+/* See LICENSE for licensing information */
+
#define ROUTERSET_PRIVATE
#include "or.h"
diff --git a/src/test/test_rust.c b/src/test/test_rust.c
deleted file mode 100644
index 6ad57d6fcb..0000000000
--- a/src/test/test_rust.c
+++ /dev/null
@@ -1,31 +0,0 @@
-/* Copyright (c) 2017, The Tor Project, Inc. */
-/* See LICENSE for licensing information */
-
-#include "orconfig.h"
-#include "compat_rust.h"
-#include "test.h"
-#include "util.h"
-
-static void
-test_welcome_string(void *arg)
-{
- (void)arg;
- rust_str_t s = rust_welcome_string();
- const char *c_str = rust_str_get(s);
- tt_assert(c_str);
- size_t len = strlen(c_str);
-#ifdef HAVE_RUST
- tt_assert(len > 0);
-#else
- tt_assert(len == 0);
-#endif
-
- done:
- rust_str_free(s);
-}
-
-struct testcase_t rust_tests[] = {
- { "welcome_string", test_welcome_string, 0, NULL, NULL },
- END_OF_TESTCASES
-};
-
diff --git a/src/test/test_rust.sh b/src/test/test_rust.sh
index d559f94ce0..8d7900e1df 100755
--- a/src/test/test_rust.sh
+++ b/src/test/test_rust.sh
@@ -1,13 +1,16 @@
#!/bin/sh
-# Test all the Rust crates we're using
+# Test all Rust crates
-crates=tor_util
+crates="protover tor_util smartlist tor_allocate"
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
+ 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 -
done
exit $exitcode
diff --git a/src/test/test_shared_random.c b/src/test/test_shared_random.c
index cac78baecf..b0278e8a1d 100644
--- a/src/test/test_shared_random.c
+++ b/src/test/test_shared_random.c
@@ -1,3 +1,6 @@
+/* Copyright (c) 2016-2017, The Tor Project, Inc. */
+/* See LICENSE for licensing information */
+
#define SHARED_RANDOM_PRIVATE
#define SHARED_RANDOM_STATE_PRIVATE
#define CONFIG_PRIVATE
diff --git a/src/test/test_status.c b/src/test/test_status.c
index f86f8e3b9e..50ea203e4d 100644
--- a/src/test/test_status.c
+++ b/src/test/test_status.c
@@ -1,3 +1,6 @@
+/* Copyright (c) 2014-2017, The Tor Project, Inc. */
+/* See LICENSE for licensing information */
+
#define STATUS_PRIVATE
#define HIBERNATE_PRIVATE
#define LOG_PRIVATE
diff --git a/src/test/testing_common.c b/src/test/testing_common.c
index 7e9c47b48d..e43fa46c84 100644
--- a/src/test/testing_common.c
+++ b/src/test/testing_common.c
@@ -3,12 +3,6 @@
* Copyright (c) 2007-2017, The Tor Project, Inc. */
/* See LICENSE for licensing information */
-extern const char tor_git_revision[];
-
-/* Ordinarily defined in tor_main.c; this bit is just here to provide one
- * since we're not linking to tor_main.c */
-const char tor_git_revision[] = "";
-
/**
* \file test_common.c
* \brief Common pieces to implement unit tests.
diff --git a/src/tools/include.am b/src/tools/include.am
index 37936c742f..92cc3f10a2 100644
--- a/src/tools/include.am
+++ b/src/tools/include.am
@@ -45,3 +45,8 @@ src_tools_tor_cov_gencert_LDADD = src/common/libor-testing.a \
endif
EXTRA_DIST += src/tools/tor-fw-helper/README
+
+if BUILD_LIBTORRUNNER
+noinst_LIBRARIES += src/tools/libtorrunner.a
+src_tools_libtorrunner_a_SOURCES = src/tools/tor_runner.c src/or/tor_api.c
+endif
diff --git a/src/tools/tor_runner.c b/src/tools/tor_runner.c
new file mode 100644
index 0000000000..9ed2ee5775
--- /dev/null
+++ b/src/tools/tor_runner.c
@@ -0,0 +1,101 @@
+/* Copyright (c) 2001 Matej Pfajfar.
+ * Copyright (c) 2001-2004, Roger Dingledine.
+ * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
+ * Copyright (c) 2007-2017, The Tor Project, Inc. */
+/* See LICENSE for licensing information */
+
+/**
+ * @file tor_runner.c
+ * @brief Experimental module to emulate tor_run_main() API with fork+exec
+ *
+ * The functions here are meant to allow the application developer to
+ * use the tor_run_main() API without having to care whether Tor is
+ * running in-process or out-of-process. For in-process usage, the
+ * developer can link Tor as a library and call tor_run_main(); for
+ * out-of-process usage, the developer can link this library instead.
+ *
+ * This interface is EXPERIMENTAL; please let us know if you would like
+ * to depend on it. We don't know yet whether it will be reliable in
+ * practice.
+ */
+
+/* NOTE: This module is supposed to work without the standard Tor utility
+ * functions. Don't add more dependencies!
+ */
+
+#include "tor_api.h"
+#include "tor_api_internal.h"
+
+#include "orconfig.h"
+#ifdef HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+#ifdef HAVE_SYS_WAIT_H
+#include <sys/wait.h>
+#endif
+#ifdef HAVE_SYS_SOCKET_H
+#include <sys/socket.h>
+#endif
+#include <stdlib.h>
+#include <string.h>
+
+#ifndef __GNUC__
+#define __attribute__(x)
+#endif
+
+static void child(const tor_main_configuration_t *cfg)
+ __attribute__((noreturn));
+
+int
+tor_run_main(const tor_main_configuration_t *cfg)
+{
+ pid_t pid = fork();
+ if (pid == 0) {
+ child(cfg);
+ exit(0); /* Unreachable */
+ }
+
+ pid_t stopped_pid;
+ int status = 0;
+ do {
+ stopped_pid = waitpid(pid, &status, 0);
+ } while (stopped_pid == -1);
+
+ /* Note: these return values are not documented. No return value is
+ * documented! */
+
+ if (stopped_pid != pid) {
+ return -99999;
+ }
+ if (WIFSTOPPED(status)) {
+ return WEXITSTATUS(status);
+ }
+ if (WIFSIGNALED(status)) {
+ return -WTERMSIG(status);
+ }
+
+ return -999988;
+}
+
+/* circumlocution to avoid getting warned about calling calloc instead of
+ * tor_calloc. */
+#define real_calloc calloc
+
+static void
+child(const tor_main_configuration_t *cfg)
+{
+ /* XXXX Close unused file descriptors. */
+
+ char **args = real_calloc(cfg->argc+1, sizeof(char *));
+ memcpy(args, cfg->argv, cfg->argc * sizeof(char *));
+ args[cfg->argc] = NULL;
+
+ int rv = execv(BINDIR "/tor", args);
+
+ if (rv < 0) {
+ exit(254);
+ } else {
+ abort(); /* Unreachable */
+ }
+}
+
diff --git a/src/win32/orconfig.h b/src/win32/orconfig.h
index 4746cc2268..5e3c5d87fe 100644
--- a/src/win32/orconfig.h
+++ b/src/win32/orconfig.h
@@ -218,7 +218,7 @@
#define USING_TWOS_COMPLEMENT
/* Version number of package */
-#define VERSION "0.3.2.4-alpha-dev"
+#define VERSION "0.3.3.0-alpha-dev"