summaryrefslogtreecommitdiffstats
path: root/test/units/TEST-75-RESOLVED.sh
diff options
context:
space:
mode:
Diffstat (limited to '')
-rwxr-xr-xtest/units/TEST-75-RESOLVED.sh (renamed from test/units/testsuite-75.sh)219
1 files changed, 195 insertions, 24 deletions
diff --git a/test/units/testsuite-75.sh b/test/units/TEST-75-RESOLVED.sh
index 86d602d..a4417ce 100755
--- a/test/units/testsuite-75.sh
+++ b/test/units/TEST-75-RESOLVED.sh
@@ -14,6 +14,12 @@ set -o pipefail
# shellcheck source=test/units/util.sh
. "$(dirname "$0")"/util.sh
+# We need at least Knot 3.0 which support (among others) the ds-push directive
+if ! knotc -c /usr/lib/systemd/tests/testdata/knot-data/knot.conf conf-check; then
+ echo "This test requires at least Knot 3.0. skipping..." | tee --append /skipped
+ exit 77
+fi
+
RUN_OUT="$(mktemp)"
run() {
@@ -46,8 +52,7 @@ monitor_check_rr() (
# displayed. We turn off pipefail for this, since we don't care about the
# lhs of this pipe expression, we only care about the rhs' result to be
# clean
- # v255-only: match against a syslog tag as well to work around systemd/systemd#30886
- timeout -v 30s journalctl --since "$since" -f --full _SYSTEMD_UNIT="resolvectl-monitor.service" + SYSLOG_IDENTIFIER="resolvectl-monitor" | grep -m1 "$match"
+ timeout -v 30s journalctl -u resolvectl-monitor.service --since "$since" -f --full | grep -m1 "$match"
)
restart_resolved() {
@@ -103,12 +108,21 @@ assert_in '_localdnsproxy' "$(dig @127.0.0.53 -x 127.0.0.54)"
mkdir -p /run/systemd/resolved.conf.d
{
echo "[Resolve]"
- echo "MulticastDNS=yes"
- echo "LLMNR=yes"
+ echo "MulticastDNS=no"
+ echo "LLMNR=no"
} >/run/systemd/resolved.conf.d/mdns-llmnr.conf
restart_resolved
# make sure networkd is not running.
systemctl stop systemd-networkd.service
+assert_in 'no' "$(resolvectl mdns hoge)"
+assert_in 'no' "$(resolvectl llmnr hoge)"
+# Tests that reloading works
+{
+ echo "[Resolve]"
+ echo "MulticastDNS=yes"
+ echo "LLMNR=yes"
+} >/run/systemd/resolved.conf.d/mdns-llmnr.conf
+systemctl reload systemd-resolved.service
# defaults to yes (both the global and per-link settings are yes)
assert_in 'yes' "$(resolvectl mdns hoge)"
assert_in 'yes' "$(resolvectl llmnr hoge)"
@@ -131,7 +145,7 @@ assert_in 'no' "$(resolvectl llmnr hoge)"
echo "MulticastDNS=resolve"
echo "LLMNR=resolve"
} >/run/systemd/resolved.conf.d/mdns-llmnr.conf
-restart_resolved
+systemctl reload systemd-resolved.service
# set per-link setting
resolvectl mdns hoge yes
resolvectl llmnr hoge yes
@@ -151,7 +165,7 @@ assert_in 'no' "$(resolvectl llmnr hoge)"
echo "MulticastDNS=no"
echo "LLMNR=no"
} >/run/systemd/resolved.conf.d/mdns-llmnr.conf
-restart_resolved
+systemctl reload systemd-resolved.service
# set per-link setting
resolvectl mdns hoge yes
resolvectl llmnr hoge yes
@@ -181,23 +195,44 @@ fd00:dead:beef:cafe::1 ns1.unsigned.test
127.128.0.5 localhost5 localhost5.localdomain localhost5.localdomain4 localhost.localdomain5 localhost5.localdomain5
EOF
-mkdir -p /etc/systemd/network
-cat >/etc/systemd/network/10-dns0.netdev <<EOF
+mkdir -p /run/systemd/network
+cat >/run/systemd/network/10-dns0.netdev <<EOF
[NetDev]
Name=dns0
Kind=dummy
EOF
-cat >/etc/systemd/network/10-dns0.network <<EOF
+cat >/run/systemd/network/10-dns0.network <<EOF
[Match]
Name=dns0
[Network]
+IPv6AcceptRA=no
Address=10.0.0.1/24
Address=fd00:dead:beef:cafe::1/64
DNSSEC=allow-downgrade
DNS=10.0.0.1
DNS=fd00:dead:beef:cafe::1
EOF
+cat >/run/systemd/network/10-dns1.netdev <<EOF
+[NetDev]
+Name=dns1
+Kind=dummy
+EOF
+cat >/run/systemd/network/10-dns1.network <<EOF
+[Match]
+Name=dns1
+
+[Network]
+IPv6AcceptRA=no
+Address=10.99.0.1/24
+DNSSEC=no
+EOF
+systemctl edit --stdin --full --runtime --force "resolved-dummy-server.service" <<EOF
+[Service]
+Type=notify
+Environment=SYSTEMD_LOG_LEVEL=debug
+ExecStart=/usr/lib/systemd/tests/unit-tests/manual/test-resolved-dummy-server 10.99.0.1:53
+EOF
DNS_ADDRESSES=(
"10.0.0.1"
@@ -217,6 +252,14 @@ ln -svf /run/systemd/resolve/stub-resolv.conf /etc/resolv.conf
mkdir -p "/etc/dnssec-trust-anchors.d/"
echo local >/etc/dnssec-trust-anchors.d/local.negative
+# Copy over our knot configuration
+mkdir -p /var/lib/knot/zones/ /etc/knot/
+cp -rfv /usr/lib/systemd/tests/testdata/knot-data/zones/* /var/lib/knot/zones/
+cp -fv /usr/lib/systemd/tests/testdata/knot-data/knot.conf /etc/knot/knot.conf
+chgrp -R knot /etc/knot/ /var/lib/knot/
+chmod -R ug+rwX /var/lib/knot/
+chmod -R g+r /etc/knot/
+
# Sign the root zone
keymgr . generate algorithm=ECDSAP256SHA256 ksk=yes zsk=yes
# Create a trust anchor for resolved with our root zone
@@ -235,8 +278,11 @@ ln -svf /etc/bind.keys /etc/bind/bind.keys
# Start the services
systemctl unmask systemd-networkd
-systemctl start systemd-networkd
-restart_resolved
+systemctl restart systemd-networkd
+/usr/lib/systemd/systemd-networkd-wait-online --interface=dns1:routable --timeout=60
+systemctl reload systemd-resolved
+systemctl start resolved-dummy-server
+
# Create knot's runtime dir, since from certain version it's provided only by
# the package and not created by tmpfiles/systemd
if [[ ! -d /run/knot ]]; then
@@ -247,17 +293,22 @@ systemctl start knot
# Wait a bit for the keys to propagate
sleep 4
+systemctl status resolved-dummy-server
networkctl status
resolvectl status
resolvectl log-level debug
# Start monitoring queries
-systemd-run -u resolvectl-monitor.service -p SyslogIdentifier=resolvectl-monitor -p Type=notify resolvectl monitor
-systemd-run -u resolvectl-monitor-json.service -p SyslogIdentifier=resolvectl-monitor-json -p Type=notify resolvectl monitor --json=short
+systemd-run -u resolvectl-monitor.service -p Type=notify resolvectl monitor
+systemd-run -u resolvectl-monitor-json.service -p Type=notify resolvectl monitor --json=short
-# Check if all the zones are valid (zone-check always returns 0, so let's check
-# if it produces any errors/warnings)
-run knotc zone-check
+# FIXME: knot, unfortunately, incorrectly complains about missing zone files for zones
+# that are forwarded using the `dnsproxy` module. Until the issue is resolved,
+# let's fall back to pre-processing the `zone-check` output a bit before checking it
+#
+# See: https://gitlab.nic.cz/knot/knot-dns/-/issues/913
+run knotc zone-check || :
+sed -i '/forwarded.test./d' "$RUN_OUT"
[[ ! -s "$RUN_OUT" ]]
# We need to manually propagate the DS records of onlinesign.test. to the parent
# zone, since they're generated online
@@ -273,6 +324,7 @@ done < <(keymgr onlinesign.test. ds)
knotc zone-commit test.
knotc reload
+sleep 2
### SETUP END ###
@@ -348,6 +400,12 @@ run dig +noall +authority +comments SRV .
grep -qF "status: NOERROR" "$RUN_OUT"
grep -qE "IN\s+SOA\s+ns1\.unsigned\.test\." "$RUN_OUT"
+run resolvectl query -t SVCB svcb.test
+grep -qF 'alpn="dot"' "$RUN_OUT"
+grep -qF "ipv4hint=10.0.0.1" "$RUN_OUT"
+
+run resolvectl query -t HTTPS https.test
+grep -qF 'alpn="h2,h3"' "$RUN_OUT"
: "--- ZONE: unsigned.test. ---"
run dig @ns1.unsigned.test +short unsigned.test A unsigned.test AAAA
@@ -405,6 +463,27 @@ grep -qF "myservice.signed.test:1234" "$RUN_OUT"
grep -qF "10.0.0.20" "$RUN_OUT"
grep -qF "fd00:dead:beef:cafe::17" "$RUN_OUT"
grep -qF "authenticated: yes" "$RUN_OUT"
+
+# Test service resolve over Varlink
+run varlinkctl call /run/systemd/resolve/io.systemd.Resolve io.systemd.Resolve.ResolveService '{"name":"","type":"_mysvc._tcp","domain":"signed.test"}'
+grep -qF '"services":[{"priority":10,"weight":5,"port":1234,"hostname":"myservice.signed.test","canonicalName":"myservice.signed.test","addresses":[{"ifindex":' "$RUN_OUT"
+grep -qF '"family":10,"address":[253,0,222,173,190,239,202,254,0,0,0,0,0,0,0,23]' "$RUN_OUT"
+grep -qF '"family":2,"address":[10,0,0,20]' "$RUN_OUT"
+grep -qF '}]}],"txt":["This is TXT for myservice"],"canonical":{"name":null,"type":"_mysvc._tcp","domain":"signed.test"},"flags":' "$RUN_OUT"
+
+# without name
+run varlinkctl call /run/systemd/resolve/io.systemd.Resolve io.systemd.Resolve.ResolveService '{"type":"_mysvc._tcp","domain":"signed.test"}'
+# without txt (SD_RESOLVE_NO_TXT)
+run varlinkctl call /run/systemd/resolve/io.systemd.Resolve io.systemd.Resolve.ResolveService '{"type":"_mysvc._tcp","domain":"signed.test","flags":64}'
+(! grep -qF '"txt"' "$RUN_OUT")
+# without address (SD_RESOLVE_NO_ADDRESS)
+run varlinkctl call /run/systemd/resolve/io.systemd.Resolve io.systemd.Resolve.ResolveService '{"type":"_mysvc._tcp","domain":"signed.test","flags":128}'
+(! grep -qF '"addresses"' "$RUN_OUT")
+# without txt and address
+run varlinkctl call /run/systemd/resolve/io.systemd.Resolve io.systemd.Resolve.ResolveService '{"type":"_mysvc._tcp","domain":"signed.test","flags":192}'
+(! grep -qF '"txt"' "$RUN_OUT")
+(! grep -qF '"addresses"' "$RUN_OUT")
+
(! run resolvectl service _invalidsvc._udp signed.test)
grep -qE "invalidservice\.signed\.test' not found" "$RUN_OUT"
run resolvectl service _untrustedsvc._udp signed.test
@@ -418,6 +497,18 @@ grep -qF "; fully validated" "$RUN_OUT"
run resolvectl openpgp mr.smith@signed.test
grep -qF "5a786cdc59c161cdafd818143705026636962198c66ed4c5b3da321e._openpgpkey.signed.test" "$RUN_OUT"
grep -qF "authenticated: yes" "$RUN_OUT"
+# Check zone transfers (AXFR/IXFR)
+# Note: since resolved doesn't support zone transfers, let's just make sure it
+# simply refuses such requests without choking on them
+# See: https://github.com/systemd/systemd/pull/30809#issuecomment-1880102804
+run dig @ns1.unsigned.test AXFR signed.test
+grep -qE "SOA\s+ns1.unsigned.test. root.unsigned.test." "$RUN_OUT"
+run dig AXFR signed.test
+grep -qF "; Transfer failed" "$RUN_OUT"
+run dig @ns1.unsigned.test IXFR=43 signed.test
+grep -qE "SOA\s+ns1.unsigned.test. root.unsigned.test." "$RUN_OUT"
+run dig IXFR=43 signed.test
+grep -qF "; Transfer failed" "$RUN_OUT"
# DNSSEC validation with multiple records of the same type for the same name
# Issue: https://github.com/systemd/systemd/issues/22002
@@ -460,9 +551,9 @@ monitor_check_rr "$TIMESTAMP" "follow13.almost.final.signed.test IN CNAME follow
monitor_check_rr "$TIMESTAMP" "follow14.final.signed.test IN A 10.0.0.14"
# Non-existing RR + CNAME chain
-run dig +dnssec AAAA cname-chain.signed.test
-grep -qF "status: NOERROR" "$RUN_OUT"
-grep -qE "^follow14\.final\.signed\.test\..+IN\s+NSEC\s+" "$RUN_OUT"
+#run dig +dnssec AAAA cname-chain.signed.test
+#grep -qF "status: NOERROR" "$RUN_OUT"
+#grep -qE "^follow14\.final\.signed\.test\..+IN\s+NSEC\s+" "$RUN_OUT"
: "--- ZONE: onlinesign.test (dynamic DNSSEC) ---"
@@ -545,6 +636,61 @@ grep -qF "fd00:dead:beef:cafe::123" "$RUN_OUT"
#run dig +dnssec this.does.not.exist.untrusted.test
#grep -qF "status: NXDOMAIN" "$RUN_OUT"
+: "--- ZONE: forwarded.test (queries forwarded to our dummy test server) ---"
+JOURNAL_CURSOR="$(mktemp)"
+journalctl -n0 -q --cursor-file="$JOURNAL_CURSOR"
+
+# See "test-resolved-dummy-server.c" for the server part
+(! run resolvectl query nope.forwarded.test)
+grep -qF "nope.forwarded.test" "$RUN_OUT"
+grep -qF "not found" "$RUN_OUT"
+
+# SERVFAIL + EDE code 6: DNSSEC Bogus
+(! run resolvectl query edns-bogus-dnssec.forwarded.test)
+grep -qE "^edns-bogus-dnssec.forwarded.test:.+: upstream-failure \(DNSSEC Bogus\)" "$RUN_OUT"
+# Same thing, but over Varlink
+(! run varlinkctl call /run/systemd/resolve/io.systemd.Resolve io.systemd.Resolve.ResolveHostname '{"name" : "edns-bogus-dnssec.forwarded.test"}')
+grep -qF "io.systemd.Resolve.DNSSECValidationFailed" "$RUN_OUT"
+grep -qF '{"result":"upstream-failure","extendedDNSErrorCode":6}' "$RUN_OUT"
+journalctl --sync
+journalctl -u systemd-resolved.service --cursor-file="$JOURNAL_CURSOR" --grep "Server returned error: SERVFAIL \(DNSSEC Bogus\). Lookup failed."
+
+# SERVFAIL + EDE code 16: Censored + extra text
+(! run resolvectl query edns-extra-text.forwarded.test)
+grep -qE "^edns-extra-text.forwarded.test.+: SERVFAIL \(Censored: Nothing to see here!\)" "$RUN_OUT"
+(! run varlinkctl call /run/systemd/resolve/io.systemd.Resolve io.systemd.Resolve.ResolveHostname '{"name" : "edns-extra-text.forwarded.test"}')
+grep -qF "io.systemd.Resolve.DNSError" "$RUN_OUT"
+grep -qF '{"rcode":2,"extendedDNSErrorCode":16,"extendedDNSErrorMessage":"Nothing to see here!"}' "$RUN_OUT"
+journalctl --sync
+journalctl -u systemd-resolved.service --cursor-file="$JOURNAL_CURSOR" --grep "Server returned error: SERVFAIL \(Censored: Nothing to see here!\)"
+
+# SERVFAIL + EDE code 0: Other + extra text
+(! run resolvectl query edns-code-zero.forwarded.test)
+grep -qE "^edns-code-zero.forwarded.test:.+: SERVFAIL \(Other: 🐱\)" "$RUN_OUT"
+(! run varlinkctl call /run/systemd/resolve/io.systemd.Resolve io.systemd.Resolve.ResolveHostname '{"name" : "edns-code-zero.forwarded.test"}')
+grep -qF "io.systemd.Resolve.DNSError" "$RUN_OUT"
+grep -qF '{"rcode":2,"extendedDNSErrorCode":0,"extendedDNSErrorMessage":"🐱"}' "$RUN_OUT"
+journalctl --sync
+journalctl -u systemd-resolved.service --cursor-file="$JOURNAL_CURSOR" --grep "Server returned error: SERVFAIL \(Other: 🐱\)"
+
+# SERVFAIL + invalid EDE code
+(! run resolvectl query edns-invalid-code.forwarded.test)
+grep -qE "^edns-invalid-code.forwarded.test:.+: SERVFAIL \([0-9]+\)" "$RUN_OUT"
+(! run varlinkctl call /run/systemd/resolve/io.systemd.Resolve io.systemd.Resolve.ResolveHostname '{"name" : "edns-invalid-code.forwarded.test"}')
+grep -qF "io.systemd.Resolve.DNSError" "$RUN_OUT"
+grep -qE '{"rcode":2,"extendedDNSErrorCode":[0-9]+}' "$RUN_OUT"
+journalctl --sync
+journalctl -u systemd-resolved.service --cursor-file="$JOURNAL_CURSOR" --grep "Server returned error: SERVFAIL \(\d+\)"
+
+# SERVFAIL + invalid EDE code + extra text
+(! run resolvectl query edns-invalid-code-with-extra-text.forwarded.test)
+grep -qE '^edns-invalid-code-with-extra-text.forwarded.test:.+: SERVFAIL \([0-9]+: Hello \[#\]\$%~ World\)' "$RUN_OUT"
+(! run varlinkctl call /run/systemd/resolve/io.systemd.Resolve io.systemd.Resolve.ResolveHostname '{"name" : "edns-invalid-code-with-extra-text.forwarded.test"}')
+grep -qF "io.systemd.Resolve.DNSError" "$RUN_OUT"
+grep -qE '{"rcode":2,"extendedDNSErrorCode":[0-9]+,"extendedDNSErrorMessage":"Hello \[#\]\$%~ World"}' "$RUN_OUT"
+journalctl --sync
+journalctl -u systemd-resolved.service --cursor-file="$JOURNAL_CURSOR" --grep "Server returned error: SERVFAIL \(\d+: Hello \[\#\]\\$%~ World\)"
+
### Test resolvectl show-cache
run resolvectl show-cache
run resolvectl show-cache --json=short
@@ -559,10 +705,10 @@ systemctl stop resolvectl-monitor-json.service
# Issue: https://github.com/systemd/systemd/issues/29580 (part #2)
#
# Check for any warnings regarding malformed messages
-(! journalctl -p warning --grep malformed _SYSTEMD_UNIT="resolvectl-monitor-json.service" + SYSLOG_IDENTIFIER="resolvectl-monitor-json")
+(! journalctl -u resolvectl-monitor.service -u reseolvectl-monitor-json.service -p warning --grep malformed)
# Verify that all queries recorded by `resolvectl monitor --json` produced a valid JSON
# with expected fields
-journalctl -p info -o cat _SYSTEMD_UNIT="resolvectl-monitor-json.service" + SYSLOG_IDENTIFIER="resolvectl-monitor-json" | while read -r line; do
+journalctl -p info -o cat _SYSTEMD_UNIT="resolvectl-monitor-json.service" | while read -r line; do
# Check that both "question" and "answer" fields are arrays
#
# The expression is slightly more complicated due to the fact that the "answer" field is optional,
@@ -589,7 +735,9 @@ if command -v nft >/dev/null; then
sleep 2
drop_dns_outbound_traffic
set +e
- run dig stale1.unsigned.test -t A
+ # Make sure we give sd-resolved enough time to timeout (5-10s) before giving up
+ # See: https://github.com/systemd/systemd/issues/31639#issuecomment-2009152617
+ run dig +tries=1 +timeout=15 stale1.unsigned.test -t A
set -eux
grep -qE "no servers could be reached" "$RUN_OUT"
nft flush ruleset
@@ -602,13 +750,14 @@ if command -v nft >/dev/null; then
echo "StaleRetentionSec=1d"
} >/run/systemd/resolved.conf.d/test.conf
ln -svf /run/systemd/resolve/stub-resolv.conf /etc/resolv.conf
- restart_resolved
+ systemctl reload systemd-resolved.service
run dig stale1.unsigned.test -t A
grep -qE "NOERROR" "$RUN_OUT"
sleep 2
drop_dns_outbound_traffic
- run dig stale1.unsigned.test -t A
+ # Make sure we give sd-resolved enough time to timeout (5-10s) and serve the stale data (see above)
+ run dig +tries=1 +timeout=15 stale1.unsigned.test -t A
grep -qE "NOERROR" "$RUN_OUT"
grep -qE "10.0.0.112" "$RUN_OUT"
@@ -725,6 +874,28 @@ run resolvectl reset-statistics --json=pretty
run resolvectl reset-statistics --json=short
+test "$(resolvectl --json=short query -t AAAA localhost)" == '{"key":{"class":1,"type":28,"name":"localhost"},"address":[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1]}'
+test "$(resolvectl --json=short query -t A localhost)" == '{"key":{"class":1,"type":1,"name":"localhost"},"address":[127,0,0,1]}'
+
+# Test ResolveRecord RR resolving via Varlink
+test "$(varlinkctl call /run/systemd/resolve/io.systemd.Resolve io.systemd.Resolve.ResolveRecord '{"name":"localhost","type":1}' --json=short | jq -rc 'del(.rrs | .[] | .ifindex)')" == '{"rrs":[{"rr":{"key":{"class":1,"type":1,"name":"localhost"},"address":[127,0,0,1]},"raw":"CWxvY2FsaG9zdAAAAQABAAAAAAAEfwAAAQ=="}],"flags":786945}'
+test "$(varlinkctl call /run/systemd/resolve/io.systemd.Resolve io.systemd.Resolve.ResolveRecord '{"name":"localhost","type":28}' --json=short | jq -rc 'del(.rrs | .[] | .ifindex)')" == '{"rrs":[{"rr":{"key":{"class":1,"type":28,"name":"localhost"},"address":[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1]},"raw":"CWxvY2FsaG9zdAAAHAABAAAAAAAQAAAAAAAAAAAAAAAAAAAAAQ=="}],"flags":786945}'
+
+# Ensure that reloading keeps the manually configured address
+{
+ echo "[Resolve]"
+ echo "DNS=8.8.8.8"
+} >/run/systemd/resolved.conf.d/reload.conf
+resolvectl dns dns0 1.1.1.1
+systemctl reload systemd-resolved.service
+resolvectl status
+resolvectl dns dns0 | grep -qF "1.1.1.1"
+# For some reason piping this last command to grep fails with:
+# 'resolvectl[1378]: Failed to print table: Broken pipe'
+# so use an intermediate file in /tmp/
+resolvectl >/tmp/output
+grep -qF "DNS Servers: 8.8.8.8" /tmp/output
+
# Check if resolved exits cleanly.
restart_resolved