rustd-resolved 0.2.1

A compatibility-oriented reimplementation of systemd-resolved
Security / ops checklist

[x] Binary does not run as root without caps drop (use systemd-resolve user); `tests/direct-root-privilege-drop.sh` asserts UID/GID transition, runtime-directory ownership, and the exact retained/bounding capability set
[ ] `/dev/shm/rustd-resolved-l1` is 0644, content is not secret (public DNS only); the optional research path is asserted by `tests/ops_runtime_contract.sh`, but is not enabled by the production feature set
[ ] Do not put DNSSEC private material in SHM; the optional cache stores only owner/address/rcode/TTL and a secure bit
[x] Open files limit / `LimitNOFILE=524288` (512 KiB) is present in each packaged resolver unit; `tests/ops_runtime_contract.sh` verifies it. This is deployment hardening, not a v261 default.
[ ] journald rate limits — use metrics not debug logs in hot path
[ ] AppArmor/SELinux policy if your distro enforces (Fedora: need .te module)
[ ] Conflict with NetworkManager dns=default vs dns=systemd-resolved; choose one DNS owner per host
[x] document: `nmcli connection modify "$CONNECTION" ipv4.dns-priority -50 ipv6.dns-priority -50` when NetworkManager hands DNS to resolved; the procedure and package ownership assertions are covered by `tests/ops_runtime_contract.sh`, while the active host owner remains deployment-specific
[x] Time sync: DNSSEC needs a sane clock; packaged units order after `time-sync.target`, and `tests/ops_runtime_contract.sh` verifies the ordering. The pinned v261 unit does not include this deployment hardening by default.
[ ] Disable stub on containers if host already binds 127.0.0.53; use `DNSStubListener=no`
[x] Document rollback: [`docs/REPLACEMENT-CERTIFICATION.md`](REPLACEMENT-CERTIFICATION.md) and `scripts/uninstall-restore.sh` restore the captured unit, sockets, binaries, enablement, activity, and `/etc/resolv.conf` state

## SELinux note (Fedora)
```bash
# temporary debug
sudo setenforce 0
# then ausearch -m avc -ts recent | audit2allow
```

## Source-backed deployment procedures

The following settings are deliberately deployment-specific. They are not
claimed as upstream parity, and the host-specific items remain unchecked until
the target deployment supplies evidence. The package units carry the
`LimitNOFILE=524288` and `After=time-sync.target` hardening; a drop-in is still
needed when retaining an unmodified distro unit.

### Optional high-QPS and DNSSEC time ordering

The pinned v261 `systemd-resolved.service` does not set either directive by
default. If a deployment retains that unmodified distro unit and needs a
larger descriptor budget or startup ordering after time synchronization,
install a drop-in and verify it before restart:

```ini
# /etc/systemd/system/systemd-resolved.service.d/10-rustd-ops.conf
[Unit]
After=time-sync.target

[Service]
LimitNOFILE=524288
```

```bash
sudo systemctl daemon-reload
sudo systemd-analyze verify systemd-resolved.service
sudo systemctl show systemd-resolved.service -p LimitNOFILE
```

### NetworkManager ownership and priority

Do not combine NetworkManager's `dns=default` plugin with a resolver-owned
`/etc/resolv.conf`. When NetworkManager should provide per-connection data to
resolved, configure its resolved plugin and use a negative DNS priority (lower
values win):

```ini
# /etc/NetworkManager/NetworkManager.conf
[main]
dns=systemd-resolved
```

```bash
nmcli connection modify "$CONNECTION" \
    ipv4.dns-priority -50 ipv6.dns-priority -50
nmcli connection up "$CONNECTION"
```

### Containers sharing the host network namespace

If the host already owns `127.0.0.53:53`, do not start a second full stub in a
host-network container. Use a container-local configuration with
`DNSStubListener=no` and an explicit upstream or extra listener, then validate
the file without starting the daemon:

```ini
[Resolve]
DNSStubListener=no
```

```bash
systemd-resolved --check-config --config /etc/systemd/resolved.conf
```