Skip to content
Commits on Source (76)
<!--
* Use this issue template for reporting a new bug.
-->
### Summary
### Steps to reproduce:
1. step 1
2. step 2
3. ...
### What is the current bug behavior?
### What is the expected behavior?
### Environment
<!--
Please fill in the following information in bug reports, removing the comments like this one in brackets.
-->
- Version: e.g. 0.10, output of --version (without backslashes)
- Operating system: Debian GNU/Linux 9.1 (stretch), Windows 7, Ubuntu Xenial, etc
- Install method: distribution package, from source tarball, from git, etc
- etc...
### Relevant logs and/or screenshots:
### Possible fixes:
/label ~bug
<!--
* Use this issue template for suggesting new docs or updates to existing docs.
-->
### Problem to solve
<!-- Include the following detail as necessary:
-->
* What feature(s) affected?
* What docs or doc section affected? Include links or paths.
* Is there a problem with a specific document, or a feature/process that's not addressed sufficiently in docs?
* Any other ideas or requests?
### Further details
<!--
* Include use cases, benefits, and/or goals for this work.
* If adding content: What audience is it intended for? (What roles and scenarios?)
-->
### Proposal
<!-- Further specifics for how can we solve the problem. -->
### Who can address the issue
<!-- What if any special expertise is required to resolve this issue? -->
### Other links/references
<!-- E.g. related Tor issues/MRs -->
/label ~documentation
<!--
* Use this issue template for submitting a feature.
-->
### Summary
### What is the expected behavior?
/label ~Feature
<!-- This template is a great use for issues that are feature::additions or technical tasks for larger issues.-->
### Proposal
<!-- Use this section to explain the proposal and how it will work. It can be helpful to add technical details, design proposals, and links to related epics or issues. -->
......@@ -2,7 +2,7 @@ language: python
# The default python version on Travis is 2.7
# But we add this line to show the python version in the Travis UI
python: "2.7"
python: "3.8"
os:
- linux
......@@ -30,7 +30,7 @@ env:
- TOR="master-nightly" NETWORK_FLAVOUR="basic-min"
matrix:
# include creates Linux, python 2.7, tor master builds by default
# include creates Linux, python 3.8, tor master builds by default
# we use tor master to catch tor issues before stable releases
# the key(s) in each item override these defaults
include:
......@@ -39,9 +39,6 @@ matrix:
##
## We need to use macOS to test IPv6 networks, because Travis Linux doesn't
## support IPv6. But macOS is tricky:
## - We use the default python version on macOS, which is currently 2.7.
## (But we don't show the version, because Travis might change it
## without us noticing.)
## - We use language: c, because language: python fails on Travis macOS.
## - We get the tor version in the homebrew cache on the macOS image.
## The latest tor version in homebrew is on this page:
......@@ -63,19 +60,19 @@ matrix:
##
## IPv6 networks (on macOS)
## "make test-network-all" on all supported tor versions
- env: TOR="stable-release" NETWORK_FLAVOUR="bridges+ipv6-min"
- env: PYTHON="python3" TOR="stable-release" NETWORK_FLAVOUR="bridges+ipv6-min"
os: osx
language: c
python:
## The IPv6 exit test doesn't actually require IPv6, see #30182.
## But we'll keep this test, because it does test IPv6 exit config.
- env: TOR="master-nightly" NETWORK_FLAVOUR="ipv6-exit-min"
- env: TOR="stable-release" NETWORK_FLAVOUR="hs-v23-ipv6-md"
- env: PYTHON="python3" TOR="stable-release" NETWORK_FLAVOUR="hs-v23-ipv6-md"
os: osx
language: c
python:
## v3 onion service IPv6 tests
- env: TOR="stable-release" NETWORK_FLAVOUR="single-onion-v23-ipv6-md"
- env: PYTHON="python3" TOR="stable-release" NETWORK_FLAVOUR="single-onion-v23-ipv6-md"
os: osx
language: c
python:
......@@ -140,10 +137,6 @@ matrix:
## Pre-installed in Travis Bionic:
## https://docs.travis-ci.com/user/reference/bionic/#python-support
## End of Life: 1 January 2020
## https://www.python.org/dev/peps/pep-0373/#update
- python: "2.7"
## End of Life: December 2021
## https://www.python.org/dev/peps/pep-0494/#lifespan
- python: "3.6"
......@@ -174,22 +167,6 @@ matrix:
## Tor master doesn't work on Travis Xenial, because it only has
## OpenSSL 1.1.0
## Pypy 2
## End of Life: "forever"
## http://doc.pypy.org/en/latest/faq.html#how-long-will-pypy-support-python2
## But chutney can decide not to support python 2 after 1 Jan 2020.
- python: "pypy"
dist: xenial
addons:
apt:
sources:
- sourceline: 'deb https://deb.torproject.org/torproject.org tor-nightly-0.4.2.x-xenial main'
key_url: 'https://deb.torproject.org/torproject.org/A3C4F0F979CAA22CDBA8F512EE8CBC9E886DDD89.asc'
packages:
- shellcheck
- tor
env: TOR="0.4.2-nightly" NETWORK_FLAVOUR="basic-min"
## PyPy does not have documented end of life dates
- python: "pypy3"
dist: xenial
......
The Tor Project is committed to fostering a inclusive community
where people feel safe to engage, share their points of view, and
participate. For the latest version of our Code of Conduct, please
see
https://gitweb.torproject.org/community/policies.git/plain/code_of_conduct.txt
This is chutney. It doesn't do much so far. It isn't ready for prime-time.
If it breaks, you get to keep all the pieces.
It is supposed to be a good tool for:
- Configuring a testing tor network
- Launching and monitoring a testing tor network
- Running tests on a testing tor network
Right now it only sorta does these things.
You will need:
- Python 2.7, or a supported Python 3,
- (we support Python versions that are still getting updates), and
- Tor binaries.
Chutney checks for Tor binaries in this order:
- If you run chutney's tools/test-network.sh from a tor build directory,
(or set the environment variable $TOR_DIR to a tor build directory,)
chutney will automatically detect the tor binaries, or
- If you put the location of the 'tor' and 'tor-gencert' binaries in the
environment variables $CHUTNEY_TOR and $CHUTNEY_TOR_GENCERT, respectively,
chutney will use those binaries, or
- You will need tor and tor-gencert installed somewhere in your path.
Stuff to try:
Automated Setup, Verification, and Shutdown:
./tools/test-network.sh --flavor basic-min
./tools/test-network.sh --coverage
./tools/test-network.sh --tor-path <tor-build-directory>
./tools/test-network.sh --tor <name-or-path> --tor-gencert <name-or-path>
(--tor-path and $TOR_DIR override --tor and --tor-gencert.)
(The script tries hard to find tor.)
./tools/test-network.sh --chutney-path <chutney-directory>
(The script is pretty good at finding chutney.)
./tools/test-network.sh --allow-failures <N>
test-network.sh looks for some tor binaries (either in a nearby build
directory or in your $PATH), configures a comprehensive tor test network,
launches it, then verifies data transmission through it, and cleans up after
itself. Relative paths are supported.
You can modify its configuration using command-line arguments, or use the
chutney environmental variables documented below:
Verification Options:
# repeats bootstrap and verify
--allow-failures CHUTNEY_ALLOW_FAILURES=N
# repeats verify
--rounds CHUTNEY_ROUNDS=N
# makes multiple connections within verify
--connections CHUTNEY_CONNECTIONS=N
Timing Options:
--start-time CHUTNEY_START_TIME=N
--min-start-time CHUTNEY_MIN_START_TIME=N
--bootstrap-time CHUTNEY_BOOTSTRAP_TIME=N
--stop-time CHUTNEY_STOP_TIME=N
Traffic Options:
--data CHUTNEY_DATA_BYTES=N
--hs-multi-client CHUTNEY_HS_MULTI_CLIENT=N
Address/DNS Options:
--ipv4 CHUTNEY_LISTEN_ADDRESS=IPV4
--ipv6 CHUTNEY_LISTEN_ADDRESS_V6=IPV6
# Chutney uses /etc/resolv.conf if none of these options are set
--dns-conf CHUTNEY_DNS_CONF=PATH
--offline CHUTNEY_DNS_CONF=/dev/null
# Use tor's compile-time default for ServerDNSResolvConfFile
--dns-conf-default CHUTNEY_DNS_CONF=""
Sandbox Options:
--sandbox CHUTNEY_TOR_SANDBOX=N (0 or 1)
Warning Options:
--all-warnings CHUTNEY_WARNINGS_IGNORE_EXPECTED=false
CHUTNEY_WARNINGS_SUMMARY=false
--no-warnings CHUTNEY_WARNINGS_SKIP=true
--only-warnings CHUTNEY_WARNINGS_ONLY=true
--diagnostics CHUTNEY_DIAGNOSTICS=true
--only-diagnostics CHUTNEY_DIAGNOSTICS_ONLY=true
Expert Options:
--debug CHUTNEY_DEBUG=true
--coverage USE_COVERAGE_BINARY=true
--dry-run NETWORK_DRY_RUN=true
--quiet ECHO=true
--controlling-pid CHUTNEY_CONTROLLING_PID=N
--net-dir CHUTNEY_DATA_DIR=PATH
(These are advanced options: in the past, they have had long-standing bugs.)
Standard Actions:
./chutney configure networks/basic
./chutney start networks/basic
./chutney status networks/basic
./chutney wait_for_bootstrap networks/basic
./chutney verify networks/basic
./chutney hup networks/basic
./chutney stop networks/basic
Bandwidth Tests:
./chutney configure networks/basic-min
./chutney start networks/basic-min
./chutney status networks/basic-min
# Send 100MB of data per client connection
CHUTNEY_DATA_BYTES=104857600 ./chutney verify networks/basic-min
./chutney stop networks/basic-min
If chutney sends at least 5 MB of data, and it takes at least one second,
verify produces performance figures for:
- Single Stream Bandwidth: the speed of the slowest stream, end-to-end
- Overall tor Bandwidth: the sum of the bandwidth across each tor instance
The overall bandwidth approximates the CPU-bound tor performance on the
current machine, assuming tor, chutney, and the OS are multithreaded, and
network performance is infinite.
Connection Tests:
./chutney configure networks/basic-025
./chutney start networks/basic-025
./chutney status networks/basic-025
# Make 5 simultaneous connections from each client through a random exit
CHUTNEY_CONNECTIONS=5 ./chutney verify networks/basic-025
./chutney stop networks/basic-025
# Run 5 sequential verification rounds
CHUTNEY_ROUNDS=5 ./tools/test-network.sh --flavour basic
HS Connection Tests:
./chutney configure networks/hs-025
./chutney start networks/hs-025
./chutney status networks/hs-025
CHUTNEY_HS_MULTI_CLIENT=1 ./chutney verify networks/hs-025
# Make a connection from each client to each hs
# Default behavior is one client connects to each HS
./chutney stop networks/hs-025
Bandwidth File Tests:
./tools/test-network.sh --flavour bwfile
# Warning: Can't open bandwidth file at configured location: /tmp/bwfile
# Create a bwfile with no bandwidths, that is valid for a few days
date +%s > /tmp/bwfile
./tools/test-network.sh --flavour bwfile
Multiple Tests:
Chutney can allow a certain number of failed tests. You can either set
CHUTNEY_ALLOW_FAILURES or use an --allow-failures command-line option to
control this. Chutney will then reattempt the test, from bootstrap
through shutdown, until either it succeeds, or until it has failed
$CHUTNEY_ALLOW_FAILURES+1 times. The default value is zero, so the default
behavior will not change.
You can also use CHUTNEY_ROUNDS=N to run multiple verification rounds, or
CHUTNEY_CONNECTIONS=N to make multiple connections within each verification
round. Any round or connection failure will fail the current test.
Bootstrapping the network:
Chutney expects a tor network to bootstrap in these stages:
1. All directory authorities (DirAuths) bootstrap to 100%.
2. The DirAuths produce the first consensus.
Usually, this consensus only contains authorities.
3. The DirAuths produce a bootstrap consensus.
This consensus has enough relays for:
* clients and relays to bootstrap, and
* relays to perform reachability self-tests.
Usually, this consensus needs at least 3 nodes.
This consensus is usually the first or second consensus.
4. Relays bootstrap to 100%.
5. Relays with "AssumeReachable 1" publish their descriptors to the
DirAuths.
6. Relays perform ORPort reachability self-tests.
If the consensus contains at least 1 exit, relays also perform DirPort
reachability self-tests.
7. Relays publish their descriptors to the DirAuths.
8. The DirAuths produce a complete consensus, microdesc consensus, and
microdescriptors. A complete consensus contains:
* the authorities,
* any bridge authorities, if present, and
* all relays (including exits).
Bridges, clients, and onion services are not included in the consensus.
9. Bridges publish their descriptors to the Bridge Auth.
10. The Bridge Auth produces a bridge networkstatus.
11. Relays and bridges download all consensus flavours, then download
descriptors and microdescriptors.
12. Bridge clients download the descriptors for their bridges.
13. Clients (including bridge clients, and onion services), download the
most recent microdesc consensus, and microdescriptors.
14. Clients bootstrap to 100%.
(Clients can bootstrap as soon as the consensus contains enough nodes,
so this step can depend on step 3, not step 13.)
15. Onion Services publish their descriptors to Onion Service directories
(otherwise known as hidden service directories, or HSDirs).
The tools/test-network.sh script uses the chutney wait_for_bootstrap
command to wait for the network to bootstrap.
wait_for_bootstrap waits up to CHUTNEY_START_TIME seconds (default: 120),
checking whether:
* the logged bootstrapped status for every node is 100% (steps 9 and 14),
and
* directory information has been distributed throughout the network
(steps 7-8, 11-13).
When waiting for dir info distribution, wait_for_bootstrap checks if:
* each relay descriptor has been posted to every authority (step 7),
* each relay is in the consensus, and the microdesc consensus, at every
authority (step 8),
* a complete consensus and microdesc consensus has been distributed to
relays and bridges (step 11),
* all authority and relay descriptors have been distributed to relays
and bridges (step 11),
* all bridge descriptors have been distributed to all bridge clients
(step 12), and
* a complete microdesc consensus has been distributed to clients
(step 13).
wait_for_bootstrap does not currently check the following dir info:
* microdescriptors (steps 8, 11, and 13, chutney ticket #33407),
* bridge descriptors at the bridge authority (steps 9-10,
tor ticket #33582, chutney ticket #33428), and
* onion services have published their descriptors to the HSDirs (step 15,
chutney ticket #33609).
After bootstrapping and dir info distribution, wait_for_bootstrap waits
until the network has been running for at least CHUTNEY_MIN_START_TIME
seconds (default 0 seconds for tor > 0.3.5.*, 65 seconds for tor <= 0.3.5.*),
to compensate for microdesc download issues in older tor versions.
In addition, wait_for_bootstrap also waits an extra:
* 10 seconds for clients to download microdescs, and
* 30 seconds for onion services to upload their descriptors.
We expect that these delays will be removed, once the relevant checks are
implemented in chutney.
If the CHUTNEY_START_TIME has elapsed, and some nodes have not bootstrapped,
or there are some nodes missing from the consensus, wait_for_bootstrap dumps
the bootstrap statuses, and exits with a failure.
Verifying the network:
Commands like "chutney verify" start immediately, and keep trying for
CHUTNEY_BOOTSTRAP_TIME seconds (default: 60). If it hasn't been
successful after that time, it fails. If CHUTNEY_BOOTSTRAP_TIME is negative,
the script leaves the network running, and exits after CHUTNEY_START_TIME
(without verifying).
Shutting down the network:
The tools/test-network.sh script waits CHUTNEY_STOP_TIME seconds
after verifying, then exits (default: immediately). If CHUTNEY_STOP_TIME is
negative, the script leaves the network running, and exits after verifying.
If none of these options are negative, test-network.sh tells the tor
processes to exit after it exits, using CHUTNEY_CONTROLLING_PID. To disable
this functionality, set CHUTNEY_CONTROLLING_PID to 1 or less.
Changing the network address:
Chutney defaults to binding to localhost. To change the IPv4 bind address,
set the CHUTNEY_LISTEN_ADDRESS environment variable. Similarly, change
CHUTNEY_LISTEN_ADDRESS_V6 for IPv6: it defaults to "no IPv6 address".
Setting it to some interface's IP address allows us to make the simulated
Tor network available on the network.
IPv6 support for both Tor and Chutney is a work in progress. Currently,
chutney verifies IPv6 client, bridge client (?), hidden service, and exit
connections. It does not use IPv6 SOCKSPorts or HiddenServicePorts.
Using DNS:
Chutney verify uses IP addresses by default. It does not need to look up
any hostnames. We recommend that chutney users disable DNS using --offline
or CHUTNEY_DNS_CONF=/dev/null , because any DNS failures causes tests to
fail. Chutney's DNS queries also produce external traffic in a predictable
pattern.
If you want to use a hostname with CHUTNEY_LISTEN_ADDRESS[_V6], or you want
to run tests that use DNS, set CHUTNEY_DNS_CONF to the path to a file in
resolv.conf format. Chutney's default of /etc/resolv.conf should be fine for
most UNIX-based operating systems. If your tor is compiled with a different
default, use --dns-resolv-conf-default or CHUTNEY_DNS_CONF="".
When the CHUTNEY_DNS_CONF file does not exist, or is a broken symlink,
chutney uses /dev/null instead. This is a workaround for bugs in tor's
use of eventdns. For example, macOS deletes the resolv.conf file when it
thinks the network is down: this can make tor exits reject all traffic,
even if a working DNS server is running on 127.0.0.1:53.
When tor has no working name servers (including --offline mode), it can
crash on SETCONF. (Chutney does not use SETCONF, but some external tor
controllers do.) To avoid this crash, set CHUTNEY_DNS_CONF to a file
containing a working name server address. For your convenience, chutney
provides a local resolv.conf file containing IPv4, IPv6, and "localhost".
Use --dns-conf resolv.conf (relative paths work).
The tor sandbox:
Chutney can run with the tor seccomp sandbox enabled. But if tor's sandbox
is broken on your local version of glibc, you can set CHUTNEY_TOR_SANDBOX=0
to disable the sandbox. If CHUTNEY_TOR_SANDBOX is unset, Sandbox defaults
to 1 on Linux, and 0 on other platforms.
The configuration files:
networks/basic holds the configuration for the network you're configuring
above. It refers to some torrc template files in torrc_templates/.
Chutney uses a templating system to produce torrc files from the templates.
These torrc files can be modified using various chutney options.
The working files:
chutney sticks its working files, including all generated torrc files,
data directories, log files, etc, in ./net/. Each tor instance gets a
subdirectory of net/nodes.
You can override the directory "./net" with the CHUTNEY_DATA_DIR
environment variable.
Test scripts:
The test scripts are stored in the "scripts/chutney_tests" directory. These
Python files must define a "run_test(network)" function. Files starting with
an underscore ("_") are ignored.
Test scripts can be run using the following syntax:
./chutney <script-name> networks/<network-name>
The chutney verify command is implemented using a test script.
Test scripts in the test directory with the same name as standard commands
are run instead of that standard command. This allows expert users to replace
the standard chutney commands with modified versions.
# Chutney
This is chutney. It doesn't do much so far. It isn't ready for prime-time.
If it breaks, you get to keep all the pieces.
It is supposed to be a good tool for:
- Configuring a testing tor network
- Launching and monitoring a testing tor network
- Running tests on a testing tor network
Right now it only sorta does these things.
## You will need
- A supported version of Python 3
- (we support Python versions that are still getting updates), and
- Tor binaries.
Chutney checks for Tor binaries in this order:
- If you run chutney's `tools/test-network.sh` from a tor build directory,
(or set the environment variable `$TOR_DIR` to a tor build directory,)
chutney will automatically detect the tor binaries, or
- If you put the location of the `tor` and `tor-gencert` binaries in the
environment variables `$CHUTNEY_TOR` and `$CHUTNEY_TOR_GENCERT`, respectively,
chutney will use those binaries, or
- You will need `tor` and `tor-gencert` installed somewhere in your path.
## Stuff to try
Automated Setup, Verification, and Shutdown:
``` shell
./tools/test-network.sh --flavor basic-min
./tools/test-network.sh --coverage
./tools/test-network.sh --tor-path <tor-build-directory>
./tools/test-network.sh --tor <name-or-path> --tor-gencert <name-or-path>
```
(`--tor-path` and `$TOR_DIR` override `--tor` and `--tor-gencert`.)
(The script tries hard to find `tor`.)
``` shell
./tools/test-network.sh --chutney-path <chutney-directory>
```
(The script is pretty good at finding `chutney`.)
``` shell
./tools/test-network.sh --allow-failures <N>
```
`test-network.sh` looks for some tor binaries (either in a nearby build
directory or in your `$PATH`), configures a comprehensive Tor test network,
launches it, then verifies data transmission through it, and cleans up after
itself. Relative paths are supported.
You can modify its configuration using command-line arguments, or use the
chutney environmental variables documented below:
## Verification Options
``` shell
# repeats bootstrap and verify
--allow-failures CHUTNEY_ALLOW_FAILURES=N
# repeats verify
--rounds CHUTNEY_ROUNDS=N
# makes multiple connections within verify
--connections CHUTNEY_CONNECTIONS=N
```
## Timing Options
``` shell
--start-time CHUTNEY_START_TIME=N
--min-start-time CHUTNEY_MIN_START_TIME=N
--bootstrap-time CHUTNEY_BOOTSTRAP_TIME=N
--stop-time CHUTNEY_STOP_TIME=N
```
## Traffic Options
``` shell
--data CHUTNEY_DATA_BYTES=N
--hs-multi-client CHUTNEY_HS_MULTI_CLIENT=N
```
## Address/DNS Options
``` shell
--ipv4 CHUTNEY_LISTEN_ADDRESS=IPV4
--ipv6 CHUTNEY_LISTEN_ADDRESS_V6=IPV6
# Chutney uses /etc/resolv.conf if none of these options are set
--dns-conf CHUTNEY_DNS_CONF=PATH
--offline CHUTNEY_DNS_CONF=/dev/null
# Use tor's compile-time default for ServerDNSResolvConfFile
--dns-conf-default CHUTNEY_DNS_CONF=""
```
## Sandbox Options
``` shell
--sandbox CHUTNEY_TOR_SANDBOX=N (0 or 1)
```
## Warning Options
``` shell
--all-warnings CHUTNEY_WARNINGS_IGNORE_EXPECTED=false
CHUTNEY_WARNINGS_SUMMARY=false
--no-warnings CHUTNEY_WARNINGS_SKIP=true
--only-warnings CHUTNEY_WARNINGS_ONLY=true
--diagnostics CHUTNEY_DIAGNOSTICS=true
--only-diagnostics CHUTNEY_DIAGNOSTICS_ONLY=true
```
## Expert Options
``` shell
--debug CHUTNEY_DEBUG=true
--coverage USE_COVERAGE_BINARY=true
--dry-run NETWORK_DRY_RUN=true
--quiet ECHO=true
--controlling-pid CHUTNEY_CONTROLLING_PID=N
--net-dir CHUTNEY_DATA_DIR=PATH
```
(These are advanced options: in the past, they have had long-standing bugs.)
## Standard Actions
``` shell
./chutney configure networks/basic
./chutney start networks/basic
./chutney status networks/basic
./chutney wait_for_bootstrap networks/basic
./chutney verify networks/basic
./chutney hup networks/basic
./chutney stop networks/basic
```
## Bandwidth Tests
``` shell
./chutney configure networks/basic-min
./chutney start networks/basic-min
./chutney status networks/basic-min
```
Send 100MB of data per client connection:
``` shell
CHUTNEY_DATA_BYTES=104857600 ./chutney verify networks/basic-min
./chutney stop networks/basic-min
```
If chutney sends at least `5 MB` of data, and it takes at least one second,
verify produces performance figures for:
- Single Stream Bandwidth: the speed of the slowest stream, end-to-end
- Overall tor Bandwidth: the sum of the bandwidth across each tor instance
The overall bandwidth approximates the CPU-bound tor performance on the
current machine, assuming tor, chutney, and the OS are multithreaded, and
network performance is infinite.
## Connection Tests
``` shell
./chutney configure networks/basic-025
./chutney start networks/basic-025
./chutney status networks/basic-025
```
Make 5 simultaneous connections from each client through a random exit
``` shell
CHUTNEY_CONNECTIONS=5 ./chutney verify networks/basic-025
./chutney stop networks/basic-025
```
Run 5 sequential verification rounds
``` shell
CHUTNEY_ROUNDS=5 ./tools/test-network.sh --flavour basic
```
## HS Connection Tests
``` shell
./chutney configure networks/hs-025
./chutney start networks/hs-025
./chutney status networks/hs-025
```
Make a connection from each client to each hs Default behavior is one client
connects to each HS:
``` shell
CHUTNEY_HS_MULTI_CLIENT=1 ./chutney verify networks/hs-025
./chutney stop networks/hs-025
```
## Bandwidth File Tests
``` shell
./tools/test-network.sh --flavour bwfile
# Warning: Can't open bandwidth file at configured location: /tmp/bwfile
# Create a bwfile with no bandwidths, that is valid for a few days
date +%s > /tmp/bwfile
./tools/test-network.sh --flavour bwfile
```
## Multiple Tests
Chutney can allow a certain number of failed tests. You can either set
`CHUTNEY_ALLOW_FAILURES` or use an `--allow-failures` command-line option to
control this. Chutney will then reattempt the test, from bootstrap through
shutdown, until either it succeeds, or until it has failed
`$CHUTNEY_ALLOW_FAILURES+1` times. The default value is zero, so the default
behavior will not change.
You can also use `CHUTNEY_ROUNDS=N` to run multiple verification rounds, or
`CHUTNEY_CONNECTIONS=N` to make multiple connections within each verification
round. Any round or connection failure will fail the current test.
## Bootstrapping the network
Chutney expects a tor network to bootstrap in these stages:
1. All directory authorities (`DirAuths`) bootstrap to 100%.
2. The `DirAuths` produce the first consensus.
Usually, this consensus only contains authorities.
3. The `DirAuths` produce a bootstrap consensus.
This consensus has enough relays for:
* clients and relays to bootstrap, and
* relays to perform reachability self-tests.
Usually, this consensus needs at least 3 nodes. This consensus is usually
the first or second consensus.
4. Relays bootstrap to 100%.
5. Relays with `AssumeReachable 1` publish their descriptors to the
`DirAuths`.
6. Relays perform `ORPort` reachability self-tests.
If the consensus contains at least 1 exit, relays also perform `DirPort`
reachability self-tests.
7. Relays publish their descriptors to the `DirAuths`.
8. The `DirAuths` produce a complete consensus, microdesc consensus, and
microdescriptors. A complete consensus contains:
* the authorities,
* any bridge authorities, if present, and
* all relays (including exits).
Bridges, clients, and onion services are not included in the consensus.
9. Bridges publish their descriptors to the Bridge Auth.
10. The Bridge Auth produces a bridge networkstatus.
11. Relays and bridges download all consensus flavours, then download
descriptors and microdescriptors.
12. Bridge clients download the descriptors for their bridges.
13. Clients (including bridge clients, and onion services), download the
most recent microdesc consensus, and microdescriptors.
14. Clients bootstrap to 100%.
(Clients can bootstrap as soon as the consensus contains enough nodes,
so this step can depend on step 3, not step 13.)
15. Onion Services publish their descriptors to Onion Service directories
(otherwise known as hidden service directories, or `HSDirs`).
The `tools/test-network.sh` script uses the chutney `wait_for_bootstrap`
command to wait for the network to bootstrap.
`wait_for_bootstrap` waits up to `CHUTNEY_START_TIME` seconds (default: 120),
checking whether:
* the logged bootstrapped status for every node is 100% (steps 9 and 14),
and
* directory information has been distributed throughout the network
(steps 7-8, 11-13).
When waiting for dir info distribution, `wait_for_bootstrap` checks if:
* each relay descriptor has been posted to every authority (step 7),
* each relay is in the consensus, and the microdesc consensus, at every
authority (step 8),
* a complete consensus and microdesc consensus has been distributed to
relays and bridges (step 11),
* all authority and relay descriptors have been distributed to relays
and bridges (step 11),
* all bridge descriptors have been distributed to all bridge clients
(step 12), and
* a complete microdesc consensus has been distributed to clients
(step 13).
`wait_for_bootstrap` does not currently check the following dir info:
* microdescriptors (steps 8, 11, and 13, chutney ticket #33407),
* bridge descriptors at the bridge authority (steps 9-10,
tor ticket #33582, chutney ticket #33428), and
* onion services have published their descriptors to the HSDirs (step 15,
chutney ticket #33609).
After bootstrapping and dir info distribution, `wait_for_bootstrap` waits
until the network has been running for at least `CHUTNEY_MIN_START_TIME`
seconds (default 0 seconds for `tor` > 0.3.5., 65 seconds for `tor` <= 0.3.5.),
to compensate for microdesc download issues in older tor versions.
In addition, `wait_for_bootstrap` also waits an extra:
- 10 seconds for clients to download microdescs, and
- 30 seconds for onion services to upload their descriptors.
We expect that these delays will be removed, once the relevant checks are
implemented in chutney.
If the `CHUTNEY_START_TIME` has elapsed, and some nodes have not bootstrapped,
or there are some nodes missing from the consensus, `wait_for_bootstrap` dumps
the bootstrap statuses, and exits with a failure.
## Verifying the network
Commands like `chutney verify` start immediately, and keep trying for
`CHUTNEY_BOOTSTRAP_TIME` seconds (default: 60). If it hasn't been
successful after that time, it fails. If `CHUTNEY_BOOTSTRAP_TIME` is negative,
the script leaves the network running, and exits after `CHUTNEY_START_TIME`
(without verifying).
## Shutting down the network
The `tools/test-network.sh` script waits `CHUTNEY_STOP_TIME` seconds
after verifying, then exits (default: immediately). If `CHUTNEY_STOP_TIME` is
negative, the script leaves the network running, and exits after verifying.
If none of these options are negative, `test-network.sh` tells the tor
processes to exit after it exits, using `CHUTNEY_CONTROLLING_PID`. To disable
this functionality, set `CHUTNEY_CONTROLLING_PID` to 1 or less.
## Changing the network address
Chutney defaults to binding to `localhost`. To change the IPv4 bind address,
set the `CHUTNEY_LISTEN_ADDRESS` environment variable. Similarly, change
`CHUTNEY_LISTEN_ADDRESS_V6` for IPv6: it defaults to "no IPv6 address".
Setting it to some interface's IP address allows us to make the simulated
Tor network available on the network.
IPv6 support for both Tor and Chutney is a work in progress. Currently,
chutney verifies IPv6 client, bridge client (?), hidden service, and exit
connections. It does not use IPv6 `SOCKSPorts` or `HiddenServicePorts`.
## Using DNS
Chutney verify uses IP addresses by default. It does not need to look up
any hostnames. We recommend that chutney users disable DNS using `--offline`
or `CHUTNEY_DNS_CONF=/dev/null`, because any DNS failures causes tests to
fail. Chutney's DNS queries also produce external traffic in a predictable
pattern.
If you want to use a hostname with `CHUTNEY_LISTEN_ADDRESS[_V6]`, or you want
to run tests that use DNS, set `CHUTNEY_DNS_CONF` to the path to a file in
`resolv.conf` format. Chutney's default of `/etc/resolv.conf` should be fine for
most UNIX-based operating systems. If your tor is compiled with a different
default, use `--dns-resolv-conf-default` or `CHUTNEY_DNS_CONF=""`.
When the `CHUTNEY_DNS_CONF` file does not exist, or is a broken symlink,
`chutney` uses `/dev/null` instead. This is a workaround for bugs in Tor's
use of `eventdns`. For example, macOS deletes the `resolv.conf` file when it
thinks the network is down: this can make tor exits reject all traffic,
even if a working DNS server is running on 127.0.0.1:53.
When tor has no working name servers (including `--offline` mode), it can
crash on `SETCONF`. (Chutney does not use `SETCONF`, but some external tor
controllers do.) To avoid this crash, set `CHUTNEY_DNS_CONF` to a file
containing a working name server address. For your convenience, chutney
provides a local `resolv.conf` file containing IPv4, IPv6, and `localhost`.
Use `--dns-conf resolv.conf` (relative paths work).
## The Tor sandbox
Chutney can run with the Tor seccomp sandbox enabled. But if Tor's sandbox
is broken on your local version of glibc, you can set `CHUTNEY_TOR_SANDBOX=0`
to disable the sandbox. If `CHUTNEY_TOR_SANDBOX` is unset, Sandbox defaults
to 1 on Linux, and 0 on other platforms.
## The configuration files
`networks/basic` holds the configuration for the network you're configuring
above. It refers to some torrc template files in `torrc_templates/`.
Chutney uses a templating system to produce torrc files from the templates.
These torrc files can be modified using various chutney options.
## The working files
Chutney sticks its working files, including all generated torrc files,
data directories, log files, etc, in `./net/`. Each tor instance gets a
subdirectory of `net/nodes`.
You can override the directory `./net` with the `CHUTNEY_DATA_DIR`
environment variable.
## Test scripts
The test scripts are stored in the `scripts/chutney_tests` directory. These
Python files must define a `run_test(network)` function. Files starting with
an underscore ("_") are ignored.
Test scripts can be run using the following syntax:
``` shell
./chutney <script-name> networks/<network-name>
```
The `chutney verify` command is implemented using a test script.
Test scripts in the test directory with the same name as standard commands
are run instead of that standard command. This allows expert users to replace
the standard chutney commands with modified versions.
......@@ -12,7 +12,15 @@ then
export CHUTNEY_PATH
fi
binaries="python3 python python2"
python_ok ()
{
checkpy="$1"
test -f "${checkpy}" && \
test -x "${checkpy}" && \
"${checkpy}" -c 'import sys;sys.exit(sys.version_info[0]<3)'
}
binaries="python3 python"
if ! test "${PYTHON+y}"
then
......@@ -31,7 +39,7 @@ then
;;
esac
abs_path="${directory}${binary}"
if test -f "${abs_path}" && test -x "${abs_path}"
if python_ok "${abs_path}"
then
PYTHON="${abs_path}"
break
......@@ -44,12 +52,18 @@ then
fi
done
IFS="${saved_IFS}"
else
if ! python_ok "$(command -v "${PYTHON}")"
then
echo "Python in \$PYTHON envvar (\"$PYTHON\") is not present, or is not python 3." >&2
exit 1
fi
fi
if ! test "${PYTHON+y}"
then
printf "No compatible Python version found.\n" >&2
printf "Is Python installed and in your PATH?\n" >&2
printf "Is python 3 installed and in your PATH?\n" >&2
exit 1
fi
......
......@@ -12,14 +12,9 @@ from __future__ import division
from __future__ import print_function
from __future__ import unicode_literals
import cgitb
import os
import sys
# Get verbose tracebacks, so we can diagnose better.
cgitb.enable(format="plain")
# Set debug_flag=True in order to debug this program or to get hints
# about what's going wrong in your system.
debug_flag = os.environ.get("CHUTNEY_DEBUG", "") != ""
......
......@@ -81,6 +81,8 @@ from __future__ import division
from __future__ import print_function
from __future__ import unicode_literals
from pathlib import Path
import string
import os
......@@ -258,18 +260,18 @@ class IncluderDict(_DictWrapper):
if not key.startswith("include:"):
raise KeyError(key)
filename = key[len("include:"):]
if os.path.isabs(filename):
with open(filename, 'r') as f:
filename = Path(key[len("include:"):])
if filename.is_absolute():
with filename.open(mode='r') as f:
stat = os.fstat(f.fileno())
if stat.st_mtime > self._st_mtime:
self._st_mtime = stat.st_mtime
return f.read()
for elt in self._includePath:
fullname = os.path.join(elt, filename)
if os.path.exists(fullname):
with open(fullname, 'r') as f:
fullname = Path(elt, filename)
if fullname.exists():
with fullname.open(mode='r') as f:
stat = os.fstat(f.fileno())
if stat.st_mtime > self._st_mtime:
self._st_mtime = stat.st_mtime
......@@ -298,9 +300,9 @@ class PathDict(_DictWrapper):
key = key[len("path:"):]
for location in self._path:
p = os.path.join(location, key)
p = Path(location, key)
try:
s = os.stat(p)
s = p.stat()
if s and s.st_mode & 0x111:
return p
except OSError:
......
This diff is collapsed.
......@@ -5,10 +5,10 @@ Client = Node(tag="c", client=1, torrc="client.tmpl")
BridgeAuthority = Node(tag="ba", authority=1, bridgeauthority=1,
relay=1, torrc="bridgeauthority.tmpl")
Bridge = Node(tag="br", bridge=1, relay=1, torrc="bridge.tmpl")
BridgeClient = Node(tag="bc", client=1, bridgeclient=1, torrc="bridgeclient.tmpl")
HSv2 = Node(tag="h", hs=1, torrc="hs.tmpl")
HSv3 = Node(tag="h", hs=1, torrc="hs-v3.tmpl")
Bridge = Node(tag="br", bridge=1, relay=1, torrc="bridge.tmpl", launch_phase=2)
HSv2 = Node(tag="h", hs=1, torrc="hs.tmpl", launch_phase=2)
HSv3 = Node(tag="h", hs=1, torrc="hs-v3.tmpl", launch_phase=2)
BridgeClient = Node(tag="bc", client=1, bridgeclient=1, torrc="bridgeclient.tmpl", launch_phase=3)
# We need 5 authorities/relays/exits to ensure we can build HS connections
NODES = Authority.getN(3) + BridgeAuthority.getN(1) + \
......
# By default, Authorities are not configured as exits
Authority = Node(tag="a", authority=1, relay=1, torrc="authority.tmpl")
ExitRelay = Node(tag="r", relay=1, exit=1, torrc="relay.tmpl")
Client = Node(tag="c", client=1, torrc="client.tmpl")
BridgeAuthority = Node(tag="ba", authority=1, bridgeauthority=1,
relay=1, torrc="bridgeauthority.tmpl")
Bridge = Node(tag="br", bridge=1, relay=1, torrc="bridge.tmpl", launch_phase=2)
HSv3 = Node(tag="h", hs=1, torrc="hs-v3.tmpl", launch_phase=2)
BridgeClient = Node(tag="bc", client=1, bridgeclient=1, torrc="bridgeclient.tmpl", launch_phase=3)
# We need 5 authorities/relays/exits to ensure we can build HS connections
NODES = Authority.getN(3) + BridgeAuthority.getN(1) + \
ExitRelay.getN(1) + \
Bridge.getN(1) + \
Client.getN(1) + BridgeClient.getN(1) + \
HSv3.getN(1)
ConfigureNodes(NODES)
Require("IPV6")
# By default, Authorities are not configured as exits
Authority = Node(tag="a", authority=1, relay=1, torrc="authority.tmpl")
ExitRelay = Node(tag="r", relay=1, exit=1, torrc="relay.tmpl")
Authority = Node(tag="a", authority=1, relay=1, ipv6_addr="[::1]",
torrc="authority-orport-v6.tmpl")
ExitRelay = Node(tag="r", relay=1, exit=1, ipv6_addr="[::1]",
torrc="relay-v6.tmpl")
BridgeAuthority = Node(tag="ba", authority=1, bridgeauthority=1,
relay=1, torrc="bridgeauthority.tmpl")
BridgeIPv6 = Node(tag="br", bridge=1, relay=1, ipv6_addr="[::1]",
torrc="bridge-v6.tmpl")
BridgeClient = Node(tag="bc", client=1, bridgeclient=1, torrc="bridgeclient.tmpl")
torrc="bridge-v6.tmpl", launch_phase=2)
BridgeClient = Node(tag="bc", client=1, bridgeclient=1,
torrc="bridgeclient.tmpl",
launch_phase=3)
# Since only 25% of relays get the guard flag,
# TestingDirAuthVoteGuard * may need to be used in small networks
......
......@@ -4,8 +4,13 @@ ExitRelay = Node(tag="r", relay=1, exit=1, torrc="relay.tmpl")
BridgeAuthority = Node(tag="ba", authority=1, bridgeauthority=1,
relay=1, torrc="bridgeauthority.tmpl")
Bridge = Node(tag="br", bridge=1, relay=1, torrc="bridge.tmpl")
BridgeClient = Node(tag="bc", client=1, bridgeclient=1, torrc="bridgeclient.tmpl")
Bridge = Node(tag="br", bridge=1, relay=1, torrc="bridge.tmpl",
launch_phase=2)
BridgeClient = Node(tag="bc", client=1, bridgeclient=1,
torrc="bridgeclient.tmpl",
launch_phase=3)
# Since only 25% of relays get the guard flag,
# TestingDirAuthVoteGuard * may need to be used in small networks
......
# By default, Authorities are not configured as exits
Authority = Node(tag="a", authority=1, relay=1, torrc="authority.tmpl")
# #40013: All the relays get the EXIT flag
# The relay-non-exit.tmpl includes the relay-non-dir.tmpl, which includdes
# `${include:common.i} ExitRelay=0` and common.i generates a torrc file with
# ExitRelay 0
# ExitRelay 0
# ExitPolicy reject *:*
NonExitRelay = Node(tag="m", relay=1, exit=0, torrc="relay-non-exit.tmpl")
ExitRelay = Node(tag="r", relay=1, exit=1, torrc="relay.tmpl")
Client = Node(tag="c", client=1, torrc="client_bwscanner.tmpl")
RelayMAB = Node(tag="relay1mbyteMAB", relay=1, exit=1, torrc="relay-MAB.tmpl")
RelayMBR = Node(tag="relay1mbyteMBR", relay=1, exit=1, torrc="relay-MBR.tmpl")
NODES = Authority.getN(3) + \
NonExitRelay.getN(7) + \
RelayMBR.getN(1) + RelayMAB.getN(1) + \
ExitRelay.getN(3) + Client.getN(1)
ConfigureNodes(NODES)
......@@ -5,8 +5,8 @@
# By default, Authorities are not configured as exits
Authority = Node(tag="a", authority=1, relay=1, torrc="authority.tmpl")
ExitRelay = Node(tag="r", relay=1, exit=1, torrc="relay.tmpl")
Client = Node(tag="c", client=1, torrc="client.tmpl")
HS = Node(tag="h", hs=1, torrc="hs-v3.tmpl")
Client = Node(tag="c", client=1, torrc="client.tmpl", launch_phase=2)
HS = Node(tag="h", hs=1, torrc="hs-v3.tmpl", launch_phase=2)
NODES = Authority.getN(3) + ExitRelay.getN(5) + \
Client.getN(2) + HS.getN(4)
......
......@@ -3,8 +3,8 @@
# By default, Authorities are not configured as exits
Authority = Node(tag="a", authority=1, relay=1, torrc="authority.tmpl")
NonExitRelay = Node(tag="r", relay=1, torrc="relay-non-exit.tmpl")
Client = Node(tag="c", client=1, torrc="client.tmpl")
HS = Node(tag="h", hs=1, torrc="hs.tmpl")
Client = Node(tag="c", client=1, torrc="client.tmpl", launch_phase=2)
HS = Node(tag="h", hs=1, torrc="hs.tmpl", launch_phase=2)
# Since only 25% of relays get the guard flag,
# TestingDirAuthVoteGuard * may need to be used in small networks
......
......@@ -13,11 +13,11 @@ NonExitRelay6 = Node(tag="r", relay=1,
'[::1]'),
torrc="relay-orport-v6-non-exit.tmpl")
Client = Node(tag="c", client=1, torrc="client.tmpl")
Client6 = Node(tag="c", client=1, torrc="client-only-v6-md.tmpl")
Client = Node(tag="c", client=1, torrc="client.tmpl", launch_phase=2)
Client6 = Node(tag="c", client=1, torrc="client-only-v6-md.tmpl", launch_phase=2)
HSv2IPv6 = Node(tag="h", hs=1, torrc="hs-only-v6-md.tmpl")
HSv3IPv6 = Node(tag="h", hs=1, torrc="hs-v3-only-v6-md.tmpl")
HSv2IPv6 = Node(tag="h", hs=1, torrc="hs-only-v6-md.tmpl", launch_phase=2)
HSv3IPv6 = Node(tag="h", hs=1, torrc="hs-v3-only-v6-md.tmpl", launch_phase=2)
# Since only 25% of relays get the guard flag,
# TestingDirAuthVoteGuard * may need to be used in small networks
......