rustd-resolved 0.2.1

A compatibility-oriented reimplementation of systemd-resolved
SHELL := /bin/sh
CC ?= cc
undefine FC
FC ?= gfortran
CFLAGS ?= -O2 -g -std=c17 -Wall -Wextra -Werror -fstack-protector-strong -U_FORTIFY_SOURCE -D_FORTIFY_SOURCE=3
FFLAGS ?= -O2 -g -std=f2018 -Wall -Wextra -Werror -fimplicit-none
LDLIBS ?= -lssl -lcrypto
PREFIX ?= /usr
SBINDIR ?= $(PREFIX)/sbin
LIBDIR ?= $(PREFIX)/lib
LIBEXECDIR ?= $(PREFIX)/lib/systemd
RUSTD_LIBEXECDIR ?= $(PREFIX)/lib/rustd
UNITDIR ?= $(PREFIX)/lib/systemd/system
TMPFILESDIR ?= $(PREFIX)/lib/tmpfiles.d
SYSUSERSDIR ?= $(PREFIX)/lib/sysusers.d
DBUSSERVICEDIR ?= $(PREFIX)/share/dbus-1/system-services
DBUSPOLICYDIR ?= $(PREFIX)/share/dbus-1/system.d
POLKITDIR ?= $(PREFIX)/share/polkit-1/actions

.PHONY: all build test check-native check-rust check-formal check-packaging check-live check-nss clean install
.PHONY: supremacy-dirs nss release release-with-nss install-replace uninstall boot-smoke bench

all: build

build:
	cargo build --release --locked

check-native:
	mkdir -p build
	$(FC) $(FFLAGS) -Jbuild -c ffi/routing.f90 -o build/routing.o
	$(CC) $(CFLAGS) -Iffi -c ffi/native.c -o build/native.o
	$(CC) $(CFLAGS) -Iffi -c ffi/interface.c -o build/interface.o
	$(CC) $(CFLAGS) -Iffi -c ffi/tls.c -o build/tls.o
	$(CC) $(CFLAGS) -Iffi -c ffi/dnssec.c -o build/dnssec.o
	$(CC) $(CFLAGS) -Iffi -c ffi/netlink.c -o build/netlink.o
	$(CC) $(CFLAGS) -Iffi -c ffi/networkd.c -o build/networkd.o
	$(CC) $(CFLAGS) -Iffi -c ffi/mdns.c -o build/mdns.o
	$(CC) $(CFLAGS) -Iffi -c ffi/test_native.c -o build/test_native.o
	$(CC) $(CFLAGS) -Iffi -c ffi/test_mdns.c -o build/test_mdns.o
	$(FC) build/test_native.o build/native.o build/interface.o build/tls.o build/dnssec.o build/netlink.o build/networkd.o build/mdns.o build/routing.o $(LDLIBS) -o build/test_native
	./build/test_native
	$(CC) build/test_mdns.o build/mdns.o -o build/test_mdns
	./build/test_mdns

check-rust:
	cargo fmt --all -- --check
	cargo clippy --all-targets --all-features --locked -- -D warnings
	cargo test --all-targets --all-features --locked

check-formal:
	idris2 --build formal/idris/resolved-policy.ipkg
	agda -i formal/agda formal/agda/Resolved/DNS/Name.agda
	agda -i formal/agda formal/agda/Resolved/DNS/Transaction.agda

check-packaging:
	bash -n scripts/install-replace.sh scripts/uninstall-restore.sh scripts/boot-smoke.sh \
		scripts/run-upstream-test-75.sh scripts/certify-replacement-v2.sh \
		scripts/run-boot-replacement-vm.sh scripts/check-rustd-naming.sh \
		scripts/switch-resolved-transactionally-v2.sh scripts/test-package-lifecycle.sh \
		nss/run-tests.sh \
	tests/parity/llmnr_avahi_interop.sh \
		tests/parity/dnssec_ad_bit.sh \
		tests/parity/dbus_manager_methods.sh \
		tests/parity/run_all.sh \
		tests/direct-root-privilege-drop.sh \
		tests/release_feature_boundary.sh \
		tests/ops_runtime_contract.sh \
		scripts/certify-replacement.sh scripts/certify-replacement-v2.sh
	@set -eu; \
	work=$$(mktemp -d); \
	trap 'rm -rf "$$work"' EXIT HUP INT TERM; \
	PYTHONPYCACHEPREFIX="$$work/pycache" python3 -m py_compile \
		tests/live-dns.py tests/deterministic-dns-server.py tests/fake-varlink-resolve.py \
		tests/live-llmnr.py \
		tests/check-varlink-authorization.py \
		tests/check-dnssd-preauthorization.py \
		tests/fake-polkit.py \
		tests/test-readiness-bundle.py \
		tests/test-replacement-proof-validator.py \
		tests/test-upstream-surface-audit.py \
		scripts/audit-upstream-resolver-surfaces.py scripts/check-workflow-fleet.py \
		scripts/download-replacement-proofs.py scripts/import-replacement-proof.py \
		scripts/validate-replacement-proof.py scripts/verify-readiness-bundle.py \
		scripts/probe-stub.py; \
	PYTHONPYCACHEPREFIX="$$work/pycache" python3 tests/test-upstream-surface-audit.py; \
	PYTHONPYCACHEPREFIX="$$work/pycache" python3 tests/test-readiness-bundle.py; \
	PYTHONPYCACHEPREFIX="$$work/pycache" python3 tests/test-replacement-proof-validator.py; \
	python3 scripts/check-workflow-fleet.py; \
	./scripts/check-rustd-naming.sh; \
	./tests/release_feature_boundary.sh; \
	./tests/ops_runtime_contract.sh; \
	./scripts/test-package-lifecycle.sh; \
	varlinkctl validate-idl interfaces/io.systemd.Resolve.varlink >"$$work/resolve.varlink"; \
	varlinkctl validate-idl interfaces/io.systemd.Resolve.Monitor.varlink >"$$work/resolve-monitor.varlink"; \
	: "Validate exact v261 generic IDLs through a comment-free form for older varlinkctl"; \
	for interface in io.systemd io.systemd.service org.varlink.service; do \
		sed '/^[[:space:]]*#/d' "interfaces/$$interface.varlink" >"$$work/$$interface.semantic.varlink"; \
		varlinkctl validate-idl "$$work/$$interface.semantic.varlink" >"$$work/$$interface.varlink"; \
	done; \
	python3 -c 'import pathlib, xml.etree.ElementTree as ET; [ET.parse(path) for path in pathlib.Path("compat").glob("*.xml")]'; \
	cargo metadata --no-deps --format-version 1 >"$$work/cargo-metadata.json"; \
	python3 -c 'import json, sys; data = json.load(open(sys.argv[1], encoding="utf-8")); package = next(package for package in data["packages"] if package["name"] == "rustd-resolved"); bins = sorted(target["name"] for target in package["targets"] if "bin" in target["kind"]); expected = ["resolvectl", "rustd-resolvectl", "rustd-resolved", "systemd-resolved"]; assert bins == expected, f"unexpected Cargo binary targets: {bins}"; default = set(package["features"]["default"]); expected_default = {"fortran-routing", "idna-name"}; assert default == expected_default, f"unexpected production default features: {sorted(default)}"' "$$work/cargo-metadata.json"; \
	test "$$(grep -Fc 'ExecStart=@RUSTD_RESOLVED@' packaging/systemd/systemd-resolved-replacement.service)" -eq 1; \
	mkdir -p "$$work/rustd" "$$work/systemd"; \
	sed 's|ExecStart=/usr/lib/rustd/rustd-resolved|ExecStart=/bin/true|g' \
		packaging/systemd/rustd-resolved.service >"$$work/rustd/rustd-resolved.service"; \
	cp packaging/systemd/rustd-resolved-varlink.socket "$$work/rustd/rustd-resolved-varlink.socket"; \
	cp packaging/systemd/rustd-resolved-monitor.socket "$$work/rustd/rustd-resolved-monitor.socket"; \
	sed 's|@RUSTD_RESOLVED@|/bin/true|g' \
	SYSTEMD_UNIT_PATH="$$work/rustd" systemd-analyze verify \
		"$$work/rustd/rustd-resolved.service" \
		"$$work/rustd/rustd-resolved-monitor.socket" \
		"$$work/rustd/rustd-resolved-varlink.socket"; \
	SYSTEMD_UNIT_PATH="$$work/systemd" systemd-analyze verify \

check-live: build
	python3 tests/live-dns.py target/release/systemd-resolved target/release/resolvectl
	python3 tests/live-dns.py target/release/rustd-resolved target/release/rustd-resolvectl

check-nss:
	$(MAKE) -C nss clean check

test: check-native check-rust check-packaging check-nss

install: build nss
	install -Dm0755 target/release/rustd-resolved $(DESTDIR)$(RUSTD_LIBEXECDIR)/rustd-resolved
	install -Dm0755 target/release/rustd-resolvectl $(DESTDIR)$(PREFIX)/bin/rustd-resolvectl
	install -Dm0755 nss/libnss_rustd.so.2 $(DESTDIR)$(LIBDIR)/libnss_rustd.so.2
	install -d -m0755 $(DESTDIR)$(LIBEXECDIR)
	ln -sfn ../rustd/rustd-resolved $(DESTDIR)$(LIBEXECDIR)/rustd-resolved
	install -Dm0644 packaging/systemd/rustd-resolved.service $(DESTDIR)$(UNITDIR)/rustd-resolved.service
	install -Dm0644 packaging/systemd/rustd-resolved-varlink.socket $(DESTDIR)$(UNITDIR)/rustd-resolved-varlink.socket
	install -Dm0644 packaging/systemd/rustd-resolved-monitor.socket $(DESTDIR)$(UNITDIR)/rustd-resolved-monitor.socket
	install -Dm0644 packaging/tmpfiles/rustd-resolved.conf $(DESTDIR)$(TMPFILESDIR)/rustd-resolved.conf
	install -Dm0644 packaging/sysusers/rustd-resolve.conf $(DESTDIR)$(SYSUSERSDIR)/rustd-resolve.conf
	install -Dm0644 packaging/dbus/org.rustd.resolve1.service $(DESTDIR)$(DBUSSERVICEDIR)/org.rustd.resolve1.service
	install -Dm0644 packaging/dbus/org.rustd.resolve1.conf $(DESTDIR)$(DBUSPOLICYDIR)/org.rustd.resolve1.conf
	install -Dm0644 packaging/polkit/org.rustd.resolve1.policy $(DESTDIR)$(POLKITDIR)/org.rustd.resolve1.policy

clean:
	rm -rf build target
	$(MAKE) -C nss clean

supremacy-dirs:
	mkdir -p src/supremacy src/llmnr src/mdns nss scripts tests/parity tests/supremacy
	mkdir -p packaging/polkit packaging/rpm

nss:
	$(MAKE) -C nss

release: build check-packaging check-nss

release-with-nss: release

install-replace: release
	sudo bash scripts/install-replace.sh

uninstall:
	sudo bash scripts/uninstall-restore.sh

boot-smoke:
	bash scripts/boot-smoke.sh

bench:
	bash tests/supremacy/bench_compare.sh