mirror of
https://github.com/pi-hole/FTL.git
synced 2026-08-21 22:47:30 +01:00
The API test suite asserts exact DNS query counters. Several of them (`TOTAL`, `DNSKEY`, `DS`, `TOP_DOMAIN`) depend on how many DNSKEY/DS lookups dnsmasq issues while validating DNSSEC. Until now those lookups recursed to the live ICANN root, because FTL configures the real root trust anchors whenever `dns.dnssec` is enabled and the local PowerDNS recursor had no root zone of its own. The number of root DNSKEY queries therefore tracked ICANN's published root key set, so an ongoing key-signing-key rollover silently shifted the counters (9 -> 7 DNSKEY) and broke the suite even on unrelated PRs. We make the whole suite hermetic: 1. Serve a locally-signed root zone from PowerDNS, forward `.` to it and trust its key, so root DNSKEY validation resolves inside the test environment instead of reaching the internet. 2. Mark the locally-served *unsigned* zones (`icloud.com`, `apple-dns.net`, `in-addr.arpa`, `ip6.arpa`) as local domains, so dnsmasq no longer proves them unsigned by walking up to the real root. 3. Give the `bogus` zone a deliberately mismatched local trust anchor so it fails validation locally rather than by failing to find a secure delegation at the root. 4. Drop the root-key pre-warm `dig`, an internet round-trip that no longer serves any purpose. With no query leaving for the real root the counters are stable and independent of ICANN key rollovers, so they are recalibrated accordingly. Marking the extra zones as local emits the same "negative DS reply without NS record" warning already whitelisted for `ftl`, so the `test_final` whitelist is broadened to match it for any zone. Signed-off-by: DL6ER <dl6er@dl6er.de>
199 lines
6.0 KiB
Bash
Executable File
199 lines
6.0 KiB
Bash
Executable File
#!/bin/bash
|
|
|
|
# Skip tests on targets not supporting them
|
|
if [[ ${TEST} == "false" ]]; then
|
|
echo "Skipping tests (CI_ARCH: ${CI_ARCH})!"
|
|
exit 0
|
|
fi
|
|
|
|
# Create pihole user if it does not exist
|
|
if ! id -u pihole &> /dev/null; then
|
|
useradd -m -s /usr/sbin/nologin pihole
|
|
fi
|
|
|
|
# Kill possibly running pihole-FTL process
|
|
while pidof -s pihole-FTL > /dev/null; do
|
|
pid="$(pidof -s pihole-FTL)"
|
|
echo "Terminating running pihole-FTL process with PID ${pid}"
|
|
kill "$pid"
|
|
sleep 1
|
|
done
|
|
|
|
# Clean up possible old files from earlier test runs
|
|
rm -rf /etc/pihole /etc/dnsmasq.d /var/log/pihole /dev/shm/FTL-*
|
|
rm -f /tmp/dnsmasq_warnings /tmp/ftl_test_*.json
|
|
|
|
# Create necessary directories and files
|
|
mkdir -p /home/pihole /etc/pihole /run/pihole /var/log/pihole /etc/pihole/config_backups /var/www/html
|
|
echo "" > /var/log/pihole/FTL.log
|
|
echo "" > /var/log/pihole/pihole.log
|
|
echo "" > /var/log/pihole/webserver.log
|
|
touch /run/pihole-FTL.pid ptr.log
|
|
touch /etc/pihole/dhcp.leases
|
|
chown -R pihole:pihole /etc/pihole /run/pihole /var/log/pihole
|
|
chown pihole:pihole /run/pihole-FTL.pid
|
|
|
|
# Copy binary into a location the new user pihole can access
|
|
cp ./pihole-FTL /home/pihole/pihole-FTL
|
|
chmod +x /home/pihole/pihole-FTL
|
|
# Note: We cannot add CAP_NET_RAW and CAP_NET_ADMIN at this point
|
|
setcap CAP_NET_BIND_SERVICE+eip /home/pihole/pihole-FTL
|
|
|
|
# Prepare gravity database
|
|
./pihole-FTL sqlite3 /etc/pihole/gravity.db < test/gravity.db.sql
|
|
chown pihole:pihole /etc/pihole/gravity.db
|
|
|
|
# Prepare pihole-FTL database
|
|
rm -rf /etc/pihole/pihole-FTL.db
|
|
./pihole-FTL sqlite3 /etc/pihole/pihole-FTL.db < test/pihole-FTL.db.sql
|
|
chown pihole:pihole /etc/pihole/pihole-FTL.db
|
|
|
|
# Prepare TLS key and certificate
|
|
cp test/test.pem /etc/pihole/test.pem
|
|
cp test/test.crt /etc/pihole/test.crt
|
|
|
|
# Prepare pihole.toml
|
|
cp test/pihole.toml /etc/pihole/pihole.toml
|
|
chown pihole:pihole /etc/pihole/pihole.toml
|
|
|
|
# Prepare 01-pihole-tests.conf
|
|
mkdir -p /etc/dnsmasq.d
|
|
cp test/01-pihole-tests.conf /etc/dnsmasq.d/01-pihole-tests.conf
|
|
|
|
# Prepare versions file (read by /api/version)
|
|
cp test/versions /etc/pihole/versions
|
|
|
|
# Prepare Lua test script
|
|
cp test/broken_lua.lp /var/www/html/broken_lua.lp
|
|
cp test/broken_lua_2.lp /var/www/html/broken_lua_2.lp
|
|
|
|
# Prepare local powerDNS resolver
|
|
bash test/pdns/setup.sh
|
|
|
|
# Set restrictive umask
|
|
OLDUMASK=$(umask)
|
|
umask 0022
|
|
|
|
# Set exemplary config value by environment variable
|
|
export FTLCONF_misc_nice="-11"
|
|
export FTLCONF_dns_upstrrr="-11"
|
|
export FTLCONF_debug_api="not_a_bool"
|
|
export FTLCONF_MISC_CHECK_SHMEM=91
|
|
export FTLCONF_files_pcap='*123#./test/pcap'
|
|
|
|
# Start FTL
|
|
if ! su pihole -s /bin/sh -c /home/pihole/pihole-FTL; then
|
|
echo "pihole-FTL failed to start"
|
|
exit 1
|
|
fi
|
|
|
|
# Give FTL some time for startup preparations
|
|
sleep 2
|
|
|
|
# Optionally attach gdb for crash backtraces (opt-in via GDB=1)
|
|
if [[ "${GDB}" == "1" ]]; then
|
|
echo "handle SIGHUP nostop SIGPIPE nostop SIGTERM nostop SIG32 nostop SIG33 nostop SIG34 nostop SIG35 nostop SIG41 nostop" > /root/.gdbinit
|
|
gdb -p $(cat /run/pihole-FTL.pid) --ex continue --ex "bt full" &
|
|
fi
|
|
|
|
# Print versions of pihole-FTL
|
|
echo -n "FTL version (DNS): "
|
|
dig TXT CHAOS version.FTL @127.0.0.1 +short
|
|
echo "FTL verbose version (CLI): "
|
|
/home/pihole/pihole-FTL -vv
|
|
echo -n "Contained dnsmasq version (DNS): "
|
|
dig TXT CHAOS version.bind @127.0.0.1 +short
|
|
|
|
RET=0
|
|
|
|
# Prepare BATS
|
|
if [ -z "$BATS" ]; then
|
|
mkdir -p test/libs
|
|
git clone --depth=1 --quiet https://github.com/bats-core/bats-core test/libs/bats-core > /dev/null
|
|
git clone --depth=1 --quiet https://github.com/bats-core/bats-support test/libs/bats-support > /dev/null
|
|
git clone --depth=1 --quiet https://github.com/bats-core/bats-assert test/libs/bats-assert > /dev/null
|
|
git clone --depth=1 --quiet https://github.com/bats-core/bats-file test/libs/bats-file > /dev/null
|
|
BATS=${PWD}/test/libs/bats-core/bin/bats
|
|
# BATS_LIB_PATH needs to be an absolute path for bats to find the libraries
|
|
BATS_LIB_PATH=${PWD}/test/libs/
|
|
export BATS_LIB_PATH
|
|
fi
|
|
|
|
# Run BATS test suite (includes DNS, regex, CLI, config tests;
|
|
# FTL remains running for the pytest API tests afterwards)
|
|
echo "Running BATS test suite..."
|
|
$BATS -p "test/test_suite.bats"
|
|
RET=$?
|
|
|
|
# Trigger network table update (PARSE_NEIGHBOR_CACHE) so mock-hwaddr
|
|
# devices like ip-127.0.0.1 exist before pytest checks them.
|
|
# RT signal offset 5 maps to PARSE_NEIGHBOR_CACHE in signals.c.
|
|
kill -SIGRTMIN+5 "$(cat /run/pihole-FTL.pid)" 2>/dev/null
|
|
sleep 2
|
|
|
|
# Run pytest API tests (FTL is still running — BATS no longer terminates it)
|
|
# Skip on riscv64 — the emulated runner is too slow for the full API suite
|
|
if [[ "${CI_ARCH}" != "linux/riscv64" ]]; then
|
|
echo "Running pytest API tests..."
|
|
python3 -m pytest test/api/ -v
|
|
PYTEST_RET=$?
|
|
if [[ $PYTEST_RET != 0 ]]; then
|
|
RET=$PYTEST_RET
|
|
fi
|
|
else
|
|
echo "Skipping pytest API tests (too slow on ${CI_ARCH})"
|
|
fi
|
|
|
|
# Run final BATS suite — log validation and FTL termination
|
|
# This runs after both test_suite.bats and pytest to catch any
|
|
# unexpected log messages from the entire run, then terminates FTL.
|
|
echo ""
|
|
echo "Running final log validation..."
|
|
$BATS -p "test/test_final.bats"
|
|
FINAL_RET=$?
|
|
if [[ $FINAL_RET != 0 ]]; then
|
|
RET=$FINAL_RET
|
|
fi
|
|
|
|
curl_to_tricorder() {
|
|
curl --silent --upload-file "${1}" https://tricorder.pi-hole.net
|
|
}
|
|
|
|
if [[ $RET != 0 ]]; then
|
|
echo -n "pihole/pihole.log: "
|
|
curl_to_tricorder /var/log/pihole/pihole.log
|
|
echo ""
|
|
echo -n "pihole/FTL.log: "
|
|
curl_to_tricorder /var/log/pihole/FTL.log
|
|
echo ""
|
|
echo -n "ptr.log: "
|
|
curl_to_tricorder ./ptr.log
|
|
echo ""
|
|
echo -n "webserver.log: "
|
|
curl_to_tricorder /var/log/pihole/webserver.log
|
|
echo ""
|
|
echo -n "pihole.toml: "
|
|
curl_to_tricorder /etc/pihole/pihole.toml
|
|
echo ""
|
|
fi
|
|
|
|
# Restore umask
|
|
umask "$OLDUMASK"
|
|
|
|
# Run performance tests (opt-in via RUN_PERF_TEST=1)
|
|
if [[ "${RUN_PERF_TEST}" == "1" ]]; then
|
|
if ! su pihole -s /bin/sh -c "/home/pihole/pihole-FTL --perf"; then
|
|
echo "pihole-FTL --perf failed to start"
|
|
fi
|
|
fi
|
|
|
|
# Remove copied file
|
|
rm /home/pihole/pihole-FTL
|
|
|
|
# Stop local powerDNS resolver
|
|
killall pdns_server
|
|
killall pdns_recursor
|
|
|
|
# Exit with return code of bats tests
|
|
exit $RET
|