faildns is a small DNS failure responder for testing DNS fallback flows.
It is intentionally not a general-purpose DNS server. Its main job is to make it easy to generate predictable failure responses and confirm how clients, proxies, or load balancers behave when a DNS backend returns SERVFAIL or REFUSED.
It listens on two ports by default:
SERVFAIL_PORT, default5300, always responds withSERVFAILREFUSED_PORT, default5301, always responds withREFUSED
Both UDP and TCP DNS are enabled. The server listens on 127.0.0.1 by default. Access logs are written to stdout, so under systemd they are available through journald.
The systemd unit enables journald priority parsing, so journalctl shows the message without Python timestamps or level text.
A, AAAA, and ANY queries for a.root-servers.net. through m.root-servers.net. return static IANA root-server addresses with NOERROR. This keeps dnsdist's default health check, A a.root-servers.net., healthy even on the SERVFAIL port. All other queries keep the fixed failure behavior for the port.
whoami.faildns. IN TXT also returns one TXT record each for remote=..., local=..., proto=..., and mode=servfail or mode=refused. This is useful for checking which faildns listener dnsdist reached.
Requirements:
- Debian 12 (bookworm) or newer
- Python 3.11 or newer
- Debian
python3-dnspythonpackage
sudo apt install python3-dnspython
python3 ./faildns.pyGenerate failure responses:
dig @127.0.0.1 -p 5300 example.com A
dig @127.0.0.1 -p 5301 example.com ACheck which faildns listener was reached:
dig @127.0.0.1 -p 5300 whoami.faildns TXTExample log message:
proto=udp local_port=5300 remote=127.0.0.1:53422 id=1234 rcode=SERVFAIL bytes=52 question="example.com. A IN"
python3 ./faildns.py \
--listen-address 127.0.0.1 \
--servfail-port 5300 \
--refused-port 5301Environment variables with the same defaults are also supported:
DNS_LISTEN_ADDRESS, default127.0.0.1SERVFAIL_PORTREFUSED_PORTLOG_LEVEL, defaultINFO
Use --listen-address 0.0.0.0 only when the server should accept remote clients.
Install on Debian 12 (bookworm) or newer:
sudo apt install python3-dnspython
sudo make install
sudo systemctl daemon-reload
sudo systemctl enable --now faildns.serviceView logs:
journalctl -u faildns.service -fmake dev creates .venv with uv-managed dependencies for ad hoc local runs and development tools. uv uses dnspython>=2.3,<3, matching the supported dnspython 2.x series.
make dev
uv run ./faildns.py
make format
make check
make uv-test
make uv-test DNSPYTHON=2.3.0
make uv-test DNSPYTHON=2.7.0
make uv-test DNSPYTHON=2.8.0
make uv-test DNSPYTHON=latest-2.xmake test runs both unit tests and a local loopback integration test that starts faildns.py on random ports. By default, tests use system python3, so install python3-dnspython first. Use make uv-test to run the same tests in the uv-managed environment, optionally selecting DNSPYTHON=2.3.0, DNSPYTHON=2.7.0, DNSPYTHON=2.8.0, or DNSPYTHON=latest-2.x.
MIT.