2019-09-11 14:50:06 -04:00
|
|
|
#!/bin/sh
|
|
|
|
# Copyright 2019, The Tor Project, Inc.
|
|
|
|
# See LICENSE for licensing information
|
|
|
|
|
|
|
|
# Integration test script for verifying that Tor configurations are parsed as
|
|
|
|
# we expect.
|
|
|
|
#
|
|
|
|
# Valid configurations are tested with --dump-config, which parses and
|
|
|
|
# validates the configuration before writing it out. We then make sure that
|
|
|
|
# the result is what we expect, before parsing and dumping it again to make
|
|
|
|
# sure that there is no change.
|
|
|
|
#
|
|
|
|
# Invalid configurations are tested with --verify-config, which parses
|
|
|
|
# and validates the configuration. We capture its output and make sure that
|
|
|
|
# it contains the error message we expect.
|
|
|
|
|
|
|
|
# This script looks for its test cases as individual directories in
|
|
|
|
# src/test/conf_examples/. Each test may have these files:
|
|
|
|
#
|
|
|
|
# torrc -- Usually needed. This file is passed to Tor on the command line
|
|
|
|
# with the "-f" flag. (If you omit it, you'll test Tor's behavior when
|
|
|
|
# it receives a nonexistent configuration file.)
|
|
|
|
#
|
|
|
|
# torrc.defaults -- Optional. If present, it is passed to Tor on the command
|
|
|
|
# line with the --defaults-torrc option. If this file is absent, an empty
|
|
|
|
# file is passed instead to prevent Tor from reading the system defaults.
|
|
|
|
#
|
|
|
|
# cmdline -- Optional. If present, it contains command-line arguments that
|
|
|
|
# will be passed to Tor.
|
|
|
|
#
|
|
|
|
# expected -- If this file is present, then it should be the expected result
|
|
|
|
# of "--dump-config short" for this test case. Exactly one of
|
|
|
|
# "expected" or "error" must be present, or the test will fail.
|
|
|
|
#
|
|
|
|
# error -- If this file is present, then it contains a regex that must be
|
|
|
|
# matched by some line in the output of "--verify-config", which must
|
|
|
|
# fail. Exactly one of "expected" or "error" must be present, or the
|
|
|
|
# test will fail.
|
2019-10-18 15:44:15 +10:00
|
|
|
#
|
2019-11-06 16:52:40 +10:00
|
|
|
# {expected,error}_${TOR_LIBS_ENABLED}* -- If this file is present,
|
|
|
|
# then the outcome is different when some optional libraries are
|
|
|
|
# enabled. If there is no result file matching the exact list of enabled
|
|
|
|
# libraries, the script searches for result files with one or more of
|
|
|
|
# those libraries disabled. The search terminates at the standard result
|
|
|
|
# file.
|
|
|
|
#
|
|
|
|
# For example:
|
|
|
|
# A test that succeeds, regardless of any enabled libraries:
|
|
|
|
# - expected
|
|
|
|
# A test that has a different result if the nss library is enabled
|
|
|
|
# (but the same result if any other library is enabled):
|
|
|
|
# - expected
|
|
|
|
# - expected_nss
|
|
|
|
# A test that fails if the lzma and zstd modules are *not* enabled:
|
|
|
|
# - error
|
|
|
|
# - expected_lzma_zstd
|
|
|
|
#
|
|
|
|
# {expected,error}*_no_${TOR_MODULES_DISABLED} -- If this file is present,
|
2019-10-18 15:44:15 +10:00
|
|
|
# then the outcome is different when some modules are disabled. If there
|
|
|
|
# is no result file matching the exact list of disabled modules, the
|
|
|
|
# standard result file is used.
|
|
|
|
#
|
|
|
|
# For example:
|
|
|
|
# A test that succeeds, regardless of any disabled modules:
|
|
|
|
# - expected
|
|
|
|
# A test that has a different result if the relay module is disabled
|
|
|
|
# (but the same result if just the dirauth module is disabled):
|
|
|
|
# - expected
|
|
|
|
# - expected_no_relay_dirauth
|
|
|
|
# A test that fails if the dirauth module is disabled:
|
|
|
|
# - expected
|
|
|
|
# - error_no_dirauth
|
|
|
|
# - error_no_relay_dirauth
|
|
|
|
# (Disabling the relay module also disables dirauth module. But we don't
|
|
|
|
# want to encode that knowledge in this test script, so we supply a
|
|
|
|
# separate result file for every combination of disabled modules that
|
|
|
|
# has a different result.)
|
2019-09-11 14:50:06 -04:00
|
|
|
|
|
|
|
umask 077
|
|
|
|
set -e
|
|
|
|
|
2019-09-13 16:45:58 -04:00
|
|
|
# emulate realpath(), in case coreutils or equivalent is not installed.
|
|
|
|
abspath() {
|
2019-09-16 09:22:43 -04:00
|
|
|
f="$*"
|
2019-09-13 16:45:58 -04:00
|
|
|
if [ -d "$f" ]; then
|
|
|
|
dir="$f"
|
|
|
|
base=""
|
|
|
|
else
|
|
|
|
dir="$(dirname "$f")"
|
|
|
|
base="/$(basename "$f")"
|
|
|
|
fi
|
|
|
|
dir="$(cd "$dir" && pwd)"
|
|
|
|
echo "$dir$base"
|
|
|
|
}
|
|
|
|
|
2019-09-11 14:50:06 -04:00
|
|
|
# find the tor binary
|
|
|
|
if [ $# -ge 1 ]; then
|
|
|
|
TOR_BINARY="${1}"
|
|
|
|
shift
|
|
|
|
else
|
|
|
|
TOR_BINARY="${TESTING_TOR_BINARY:-./src/app/tor}"
|
|
|
|
fi
|
|
|
|
|
2019-09-13 16:45:58 -04:00
|
|
|
TOR_BINARY="$(abspath "$TOR_BINARY")"
|
|
|
|
|
2019-10-31 00:58:09 +10:00
|
|
|
echo "TOR BINARY IS ${TOR_BINARY}"
|
|
|
|
|
2019-09-11 14:50:06 -04:00
|
|
|
# make a safe space for temporary files
|
|
|
|
DATA_DIR=$(mktemp -d -t tor_parseconf_tests.XXXXXX)
|
|
|
|
trap 'rm -rf "$DATA_DIR"' 0
|
|
|
|
|
|
|
|
# This is where we look for examples
|
|
|
|
EXAMPLEDIR="$(dirname "$0")"/conf_examples
|
|
|
|
|
|
|
|
case "$(uname -s)" in
|
|
|
|
CYGWIN*) WINDOWS=1;;
|
|
|
|
MINGW*) WINDOWS=1;;
|
|
|
|
MSYS*) WINDOWS=1;;
|
|
|
|
*) WINDOWS=0;;
|
|
|
|
esac
|
|
|
|
|
2019-09-16 09:23:09 -04:00
|
|
|
####
|
|
|
|
# BUG WORKAROUND FOR 31757:
|
|
|
|
# On Appveyor, it seems that Tor sometimes randomly fails to produce
|
|
|
|
# output with --dump-config. Whil we are figuring this out, do not treat
|
|
|
|
# windows errors as hard failures.
|
|
|
|
####
|
|
|
|
if test "$WINDOWS" = 1; then
|
|
|
|
EXITCODE=0
|
|
|
|
else
|
|
|
|
EXITCODE=1
|
|
|
|
fi
|
|
|
|
|
2019-11-04 11:18:10 +10:00
|
|
|
FINAL_EXIT=0
|
|
|
|
|
|
|
|
die() { echo "$1" >&2 ; FINAL_EXIT=$EXITCODE; }
|
2019-09-16 09:23:09 -04:00
|
|
|
|
2019-09-11 14:50:06 -04:00
|
|
|
if test "$WINDOWS" = 1; then
|
|
|
|
FILTER="dos2unix"
|
|
|
|
else
|
|
|
|
FILTER="cat"
|
|
|
|
fi
|
|
|
|
|
2019-11-06 16:52:40 +10:00
|
|
|
EMPTY="${DATA_DIR}/EMPTY"
|
|
|
|
|
|
|
|
touch "$EMPTY" || die "Couldn't create empty file."
|
|
|
|
|
|
|
|
STANDARD_LIBS="libevent\\|openssl\\|zlib"
|
|
|
|
# Lib names are restricted to [a-z0-9]* at the moment
|
|
|
|
# We don't actually want to support foreign accents here
|
|
|
|
# shellcheck disable=SC2018,SC2019
|
|
|
|
TOR_LIBS_ENABLED="$("$TOR_BINARY" --verify-config \
|
|
|
|
-f "$EMPTY" --defaults-torrc "$EMPTY" \
|
|
|
|
| sed -n 's/.* Tor .* running on .* with\(.*\)\./\1/p' \
|
|
|
|
| tr 'A-Z' 'a-z' | tr ',' '\n' \
|
|
|
|
| grep -v "$STANDARD_LIBS" | grep -v "n/a" \
|
|
|
|
| sed 's/\( and\)* \(lib\)*\([a-z0-9]*\) .*/\3/' \
|
|
|
|
| sort | tr '\n' '_')"
|
|
|
|
# Remove the last underscore, if there is one
|
|
|
|
TOR_LIBS_ENABLED=${TOR_LIBS_ENABLED%_}
|
|
|
|
|
|
|
|
# If we ever have more than 3 optional libraries, we'll need more code here
|
|
|
|
TOR_LIBS_ENABLED_COUNT="$(echo "$TOR_LIBS_ENABLED_SEARCH" \
|
|
|
|
| tr ' ' '\n' | wc -l)"
|
|
|
|
if [ "$TOR_LIBS_ENABLED_COUNT" -gt 3 ]; then
|
|
|
|
echo "$0 can not handle more than 3 optional libraries"
|
|
|
|
exit 1
|
|
|
|
fi
|
|
|
|
# Brute-force the combinations of libraries
|
|
|
|
TOR_LIBS_ENABLED_SEARCH_3="$(echo "$TOR_LIBS_ENABLED" \
|
|
|
|
| sed -n \
|
|
|
|
's/^\([^_]*\)_\([^_]*\)_\([^_]*\)$/_\1_\2 _\1_\3 _\2_\3 _\1 _\2 _\3/p')"
|
|
|
|
TOR_LIBS_ENABLED_SEARCH_2="$(echo "$TOR_LIBS_ENABLED" \
|
|
|
|
| sed -n 's/^\([^_]*\)_\([^_]*\)$/_\1 _\2/p')"
|
|
|
|
TOR_LIBS_ENABLED_SEARCH="_$TOR_LIBS_ENABLED \
|
|
|
|
$TOR_LIBS_ENABLED_SEARCH_3 \
|
|
|
|
$TOR_LIBS_ENABLED_SEARCH_2"
|
|
|
|
TOR_LIBS_ENABLED_SEARCH="$(echo "$TOR_LIBS_ENABLED_SEARCH" | tr ' ' '\n' \
|
|
|
|
| grep -v '^_*$' | tr '\n' ' ')"
|
|
|
|
|
|
|
|
TOR_MODULES_DISABLED="$("$TOR_BINARY" --list-modules | grep ': no' \
|
|
|
|
| cut -d ':' -f1 | sort | tr '\n' '_')"
|
|
|
|
# Remove the last underscore, if there is one
|
|
|
|
TOR_MODULES_DISABLED=${TOR_MODULES_DISABLED%_}
|
|
|
|
|
|
|
|
echo "Tor is configured with:"
|
|
|
|
echo "Optional Libraries: ${TOR_LIBS_ENABLED:-(None)}"
|
|
|
|
if [ -n "${TOR_LIBS_ENABLED}" ]; then
|
|
|
|
echo "Optional Library Search List: $TOR_LIBS_ENABLED_SEARCH"
|
|
|
|
fi
|
|
|
|
echo "Disabled Modules: ${TOR_MODULES_DISABLED:-(None)}"
|
2019-09-16 09:23:09 -04:00
|
|
|
|
2019-09-11 14:50:06 -04:00
|
|
|
for dir in "${EXAMPLEDIR}"/*; do
|
|
|
|
if ! test -d "${dir}"; then
|
|
|
|
# Only count directories.
|
|
|
|
continue
|
|
|
|
fi
|
|
|
|
|
|
|
|
testname="$(basename "${dir}")"
|
|
|
|
# We use printf since "echo -n" is not standard
|
|
|
|
printf "%s: " "$testname"
|
|
|
|
|
2019-09-13 16:45:58 -04:00
|
|
|
PREV_DIR="$(pwd)"
|
|
|
|
cd "${dir}"
|
|
|
|
|
|
|
|
if test -f "./torrc.defaults"; then
|
|
|
|
DEFAULTS="./torrc.defaults"
|
2019-09-11 14:50:06 -04:00
|
|
|
else
|
|
|
|
DEFAULTS="${DATA_DIR}/EMPTY"
|
|
|
|
fi
|
|
|
|
|
2019-09-13 16:45:58 -04:00
|
|
|
if test -f "./cmdline"; then
|
|
|
|
CMDLINE="$(cat ./cmdline)"
|
2019-09-11 14:50:06 -04:00
|
|
|
else
|
|
|
|
CMDLINE=""
|
|
|
|
fi
|
|
|
|
|
2019-10-31 00:19:11 +10:00
|
|
|
EXPECTED=
|
|
|
|
ERROR=
|
2019-11-06 16:52:40 +10:00
|
|
|
# Search for a custom result file for any combination of enabled optional
|
|
|
|
# libraries
|
|
|
|
# The libs in the list are [A-Za-z0-9_]* and space-separated.
|
|
|
|
# shellcheck disable=SC2086
|
|
|
|
for lib_suffix in $TOR_LIBS_ENABLED_SEARCH ""; do
|
|
|
|
# Search for a custom result file for any disabled modules
|
|
|
|
for mod_suffix in "_no_${TOR_MODULES_DISABLED}" ""; do
|
|
|
|
suffix="${lib_suffix}${mod_suffix}"
|
|
|
|
|
|
|
|
if test -f "./expected${suffix}"; then
|
|
|
|
|
|
|
|
# Check for broken configs
|
|
|
|
if test -f "./error${suffix}"; then
|
|
|
|
echo "FAIL: Found both ${dir}/expected${suffix}" >&2
|
|
|
|
echo "and ${dir}/error${suffix}." >&2
|
|
|
|
echo "(Only one of these files should exist.)" >&2
|
|
|
|
FINAL_EXIT=$EXITCODE
|
|
|
|
fi
|
|
|
|
|
|
|
|
EXPECTED="./expected${suffix}"
|
|
|
|
break
|
|
|
|
|
|
|
|
elif test -f "./error${suffix}"; then
|
|
|
|
ERROR="./error${suffix}"
|
|
|
|
break
|
2019-10-18 15:44:15 +10:00
|
|
|
fi
|
2019-11-06 16:52:40 +10:00
|
|
|
done
|
2019-10-18 15:44:15 +10:00
|
|
|
|
2019-11-06 16:52:40 +10:00
|
|
|
# Exit as soon as the inner loop finds a file
|
|
|
|
if test -f "$EXPECTED" || test -f "$ERROR"; then
|
2019-10-18 15:44:15 +10:00
|
|
|
break
|
2019-09-11 14:50:06 -04:00
|
|
|
fi
|
2019-10-18 15:44:15 +10:00
|
|
|
done
|
|
|
|
|
|
|
|
if test -f "$EXPECTED"; then
|
2019-09-11 14:50:06 -04:00
|
|
|
|
|
|
|
# This case should succeed: run dump-config and see if it does.
|
|
|
|
|
2019-09-13 16:45:58 -04:00
|
|
|
"${TOR_BINARY}" -f "./torrc" \
|
2019-09-11 14:50:06 -04:00
|
|
|
--defaults-torrc "${DEFAULTS}" \
|
|
|
|
--dump-config short \
|
|
|
|
${CMDLINE} \
|
|
|
|
| "${FILTER}" > "${DATA_DIR}/output.${testname}" \
|
2019-11-04 12:28:39 +10:00
|
|
|
|| die "FAIL: $EXPECTED: Tor reported an error."
|
2019-09-11 14:50:06 -04:00
|
|
|
|
2019-10-18 15:44:15 +10:00
|
|
|
if cmp "$EXPECTED" "${DATA_DIR}/output.${testname}">/dev/null ; then
|
2019-09-11 14:50:06 -04:00
|
|
|
# Check round-trip.
|
|
|
|
"${TOR_BINARY}" -f "${DATA_DIR}/output.${testname}" \
|
|
|
|
--defaults-torrc "${DATA_DIR}/empty" \
|
|
|
|
--dump-config short \
|
|
|
|
| "${FILTER}" \
|
|
|
|
> "${DATA_DIR}/output_2.${testname}" \
|
2019-11-04 12:28:39 +10:00
|
|
|
|| die \
|
|
|
|
"FAIL: $EXPECTED: Tor reported an error on round-trip."
|
2019-09-11 14:50:06 -04:00
|
|
|
|
|
|
|
if ! cmp "${DATA_DIR}/output.${testname}" \
|
|
|
|
"${DATA_DIR}/output_2.${testname}"; then
|
2019-11-04 12:28:39 +10:00
|
|
|
echo "FAIL: $EXPECTED did not match on round-trip." >&2
|
2019-11-04 11:18:10 +10:00
|
|
|
FINAL_EXIT=$EXITCODE
|
2019-09-11 14:50:06 -04:00
|
|
|
fi
|
|
|
|
|
|
|
|
echo "OK"
|
|
|
|
else
|
2019-11-04 11:13:00 +10:00
|
|
|
echo "FAIL" >&2
|
2019-09-13 18:31:59 -04:00
|
|
|
if test "$(wc -c < "${DATA_DIR}/output.${testname}")" = 0; then
|
|
|
|
# There was no output -- probably we failed.
|
|
|
|
"${TOR_BINARY}" -f "./torrc" \
|
|
|
|
--defaults-torrc "${DEFAULTS}" \
|
|
|
|
--verify-config \
|
|
|
|
${CMDLINE} || true
|
|
|
|
fi
|
2019-11-04 12:28:39 +10:00
|
|
|
echo "FAIL: $EXPECTED did not match." >&2
|
2019-11-04 11:13:00 +10:00
|
|
|
diff -u "$EXPECTED" "${DATA_DIR}/output.${testname}" >&2 \
|
2019-11-04 11:13:42 +10:00
|
|
|
|| true
|
2019-11-04 11:18:10 +10:00
|
|
|
FINAL_EXIT=$EXITCODE
|
2019-09-11 14:50:06 -04:00
|
|
|
fi
|
|
|
|
|
2019-10-18 15:44:15 +10:00
|
|
|
elif test -f "$ERROR"; then
|
2019-09-11 14:50:06 -04:00
|
|
|
# This case should fail: run verify-config and see if it does.
|
|
|
|
|
2019-11-04 11:13:00 +10:00
|
|
|
if ! test -s "$ERROR"; then
|
|
|
|
echo "FAIL: error file '$ERROR' is empty." >&2
|
|
|
|
echo "Empty error files match any output." >&2
|
2019-11-04 11:18:10 +10:00
|
|
|
FINAL_EXIT=$EXITCODE
|
2019-11-04 11:13:00 +10:00
|
|
|
fi
|
|
|
|
|
2019-09-11 14:50:06 -04:00
|
|
|
"${TOR_BINARY}" --verify-config \
|
2019-09-13 16:45:58 -04:00
|
|
|
-f ./torrc \
|
2019-09-11 14:50:06 -04:00
|
|
|
--defaults-torrc "${DEFAULTS}" \
|
|
|
|
${CMDLINE} \
|
|
|
|
> "${DATA_DIR}/output.${testname}" \
|
2019-11-04 12:28:39 +10:00
|
|
|
&& die "FAIL: $ERROR: Tor did not report an error."
|
2019-09-11 14:50:06 -04:00
|
|
|
|
2019-11-06 16:00:50 +10:00
|
|
|
expect_err="$(cat "$ERROR")"
|
2019-09-11 14:50:06 -04:00
|
|
|
if grep "${expect_err}" "${DATA_DIR}/output.${testname}" >/dev/null; then
|
|
|
|
echo "OK"
|
|
|
|
else
|
2019-11-04 11:13:00 +10:00
|
|
|
echo "FAIL" >&2
|
2019-11-04 12:28:39 +10:00
|
|
|
echo "Expected $ERROR: ${expect_err}" >&2
|
2019-11-04 11:13:00 +10:00
|
|
|
echo "Tor said:" >&2
|
|
|
|
cat "${DATA_DIR}/output.${testname}" >&2
|
2019-11-04 11:18:10 +10:00
|
|
|
FINAL_EXIT=$EXITCODE
|
2019-09-11 14:50:06 -04:00
|
|
|
fi
|
|
|
|
|
|
|
|
else
|
|
|
|
# This case is not actually configured with a success or a failure.
|
|
|
|
# call that an error.
|
|
|
|
|
2019-11-04 11:13:00 +10:00
|
|
|
echo "FAIL: Did not find ${dir}/*expected or ${dir}/*error." >&2
|
2019-11-04 11:18:10 +10:00
|
|
|
FINAL_EXIT=$EXITCODE
|
2019-09-11 14:50:06 -04:00
|
|
|
fi
|
|
|
|
|
2019-09-13 16:45:58 -04:00
|
|
|
cd "${PREV_DIR}"
|
|
|
|
|
2019-09-11 14:50:06 -04:00
|
|
|
done
|
2019-11-04 11:18:10 +10:00
|
|
|
|
|
|
|
exit $FINAL_EXIT
|