systemd-resolved-rs 0.1.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 -D_FORTIFY_SOURCE=3
FFLAGS ?= -O2 -g -std=f2018 -Wall -Wextra -Werror -fimplicit-none
LDLIBS ?= -lssl -lcrypto
PREFIX ?= /usr
SBINDIR ?= $(PREFIX)/sbin
LIBEXECDIR ?= $(PREFIX)/lib/systemd
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/switch-resolved-transactionally-v2.sh nss/run-tests.sh \
		tests/direct-root-privilege-drop.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/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; \
	varlinkctl validate-idl interfaces/io.systemd.Resolve.varlink >"$$work/resolve.varlink"; \
	varlinkctl validate-idl interfaces/io.systemd.Resolve.Monitor.varlink >"$$work/resolve-monitor.varlink"; \
	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"] == "systemd-resolved-rs"); bins = sorted(target["name"] for target in package["targets"] if "bin" in target["kind"]); expected = ["resolvectl", "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=@SYSTEMD_RESOLVED_RS@' packaging/systemd/systemd-resolved-replacement.service)" -eq 1; \
	sed 's|@SYSTEMD_RESOLVED_RS@|/bin/true|g' \
		packaging/systemd/systemd-resolved-replacement.service >"$$work/systemd-resolved.service"; \
	cp packaging/systemd/systemd-resolved-varlink.socket "$$work/systemd-resolved-varlink.socket"; \
	cp packaging/systemd/systemd-resolved-monitor.socket "$$work/systemd-resolved-monitor.socket"; \
	SYSTEMD_UNIT_PATH="$$work" systemd-analyze verify \
		"$$work/systemd-resolved.service" \
		"$$work/systemd-resolved-monitor.socket" \
		"$$work/systemd-resolved-varlink.socket"

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

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

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

install: build
	install -Dm0755 target/release/systemd-resolved $(DESTDIR)$(LIBEXECDIR)/systemd-resolved
	install -Dm0755 target/release/resolvectl $(DESTDIR)$(PREFIX)/bin/resolvectl
	ln -sfn resolvectl $(DESTDIR)$(PREFIX)/bin/systemd-resolve
	install -d -m0755 $(DESTDIR)$(SBINDIR)
	ln -sfn ../bin/resolvectl $(DESTDIR)$(SBINDIR)/resolvconf
	install -Dm0644 packaging/systemd/systemd-resolved.service $(DESTDIR)$(UNITDIR)/systemd-resolved.service
	install -Dm0644 packaging/systemd/systemd-resolved-varlink.socket $(DESTDIR)$(UNITDIR)/systemd-resolved-varlink.socket
	install -Dm0644 packaging/systemd/systemd-resolved-monitor.socket $(DESTDIR)$(UNITDIR)/systemd-resolved-monitor.socket
	install -Dm0644 packaging/tmpfiles/systemd-resolved.conf $(DESTDIR)$(TMPFILESDIR)/systemd-resolved.conf
	install -Dm0644 packaging/sysusers/systemd-resolve.conf $(DESTDIR)$(SYSUSERSDIR)/systemd-resolve.conf
	install -Dm0644 packaging/dbus/org.freedesktop.resolve1.service $(DESTDIR)$(DBUSSERVICEDIR)/org.freedesktop.resolve1.service
	install -Dm0644 packaging/dbus/org.freedesktop.resolve1.conf $(DESTDIR)$(DBUSPOLICYDIR)/org.freedesktop.resolve1.conf
	install -Dm0644 packaging/polkit/org.freedesktop.resolve1.policy $(DESTDIR)$(POLKITDIR)/org.freedesktop.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