Files
fips/packaging/freebsd/README.md
T
Johnathan Corgan f0ee81ec7c Prepare the v0.5.1 release content
Move the staged changelog entries under a 0.5.1 heading dated 2026-09-06,
and add an entry for the deb-install hang: the suite started a oneshot unit
that requires the daemon, so a daemon that could not execute left the start
job undispatched and the suite reported nothing at all. That is the whole
class of fault the suite exists to find, and it protects the run that gates
artifact publication, so it is owed an entry.

Add the release notes and mirror them to the root file. The notes lead with
who should upgrade and who is unaffected, because for most users this
release changes nothing and for Debian 12 and Ubuntu 22.04 users the daemon
has never run at all. They state what was measured and what was not, and
give an objdump line that reads the floor of a binary already installed:
2.34 from this release, 2.39 from any earlier one.

The root mirror is not byte-identical to the versioned copy and cannot be.
The two files sit at different depths, so a link that resolves in one breaks
in the other; the mirror is content-identical with the relative link paths
rewritten, and the check is a diff whose every hunk is a link path. Here
that is two hunks, both confirmed to resolve.

The currency audit found five stale version sites and two claims that do
not match the tree, all corrected here. The status badge, the release-notes
link and the status sentence in the README follow the release, as they did
at v0.4.2. The FreeBSD install line gave a filename that does not exist,
since the tree is 0.5.1-dev; it now takes a version placeholder so it stops
going stale at every bump, and the example above it keeps a concrete name.

The design document recorded the first lookup fix and not the second: it
still said a returning copy is dropped as a duplicate, which the next commit
in this release exists to stop doing. It now names the counter that actually
receives the drop.

The README claimed the .deb is exercised per release. The install suite is
real and covers the five distributions it names, but it runs on push and
pull request, not at a tag, and no workflow installs the published artifact.
The sentence now says that, so the released package being checked by hand is
written down rather than assumed.

Getting-started gains the statement this release should have produced:
which distributions are supported and why the binaries run on all of them.
Until now the policy and the floor lived only in the build environment file,
so an operator had nowhere to read either.
2026-09-06 19:10:43 +00:00

4.0 KiB

FIPS FreeBSD packaging

Builds a native FreeBSD .pkg shipping fips, fipsctl, fipstop, rc.d services, and .fips DNS integration. fips-gateway is excluded (its NAT backend is nftables, Linux-only).

Platform notes: the Ethernet and BLE transports are not available on FreeBSD (UDP, TCP, Tor, and Nym are). The UDP datapath deliberately uses the portable single-packet receive loop — FreeBSD's recvmmsg(2) is a libc loop over recvmsg, not a kernel batch, so the Linux/macOS batched arm would gain nothing — and the connected-UDP fast path is not compiled pending FreeBSD-specific SO_REUSEPORT validation.

Build

./packaging/freebsd/build-pkg.sh            # cargo build --release + pkg create
./packaging/freebsd/build-pkg.sh --no-build # package existing release binaries

Output: deploy/fips-<version>-freebsd-<arch>.pkg (e.g. fips-0.5.1.dev-freebsd-amd64.pkg — pkg versions cannot contain -).

Install

pkg add ./deploy/fips-<version>-freebsd-amd64.pkg
# post-install seeds this from the sample if absent, at mode 0600
vi /usr/local/etc/fips/fips.yaml
sysrc fips_enable=YES fips_dns_enable=YES
service fips start
service fips_dns start
fipsctl show status

Config installs sample-style (@sample semantics via manifest scripts), so an edited fips.yaml survives upgrade/removal. fips.yaml is installed 0600 — it may hold the node's private key (nsec:). The daemon runs under daemon(8) with pidfile /var/run/fips/fips.pid and logs to /var/log/fips.log (rc.conf knobs: fips_config, fips_flags, fips_logfile).

The package creates a fips group; members can run fipsctl and fipstop without root (pw groupmod fips -m <user>, then re-login). On pkg upgrade the services are stopped before the binaries are replaced and started again afterwards if enabled; on pkg delete they are stopped and the .fips resolver drop-in is removed.

.fips DNS integration

The daemon answers .fips queries on [::1]:5354. fips_dns points the system resolver's fips. zone there; backends tried in order: base local_unbound (drop-in /var/unbound/conf.d/fips.conf), pkg unbound, pkg dnsmasq. The unbound drop-in must (and does) set:

  • do-not-query-localhost: no — unbound's default silently refuses loopback forwarders, SERVFAILing every .fips query.
  • do-ip6: yes — the daemon binds ::1 only.
  • domain-insecure: "fips." — the zone is unsigned.

One-time host resolver setup (NOT automated)

The package configures the fips. zone only; making the local resolver the system resolver is an operator decision. On a typical box:

sysrc local_unbound_enable=YES
local-unbound-setup 1.1.1.1 9.9.9.9   # explicit upstreams — see below
service local_unbound restart

Field-tested caveats (fips-dns-setup detects and warns about each):

  • /etc/resolv.conf must list a loopback nameserver (ideally only 127.0.0.1), or nothing ever queries unbound and .fips cannot resolve.
  • Do not use a home-router DNS proxy as unbound's upstream. Many CPE forwarders are EDNS-broken; unbound always sends EDNS, so every public query SERVFAILs. Forward to real resolvers (ISP or public).
  • Remove options edns0 from /etc/resolv.conf if present, and set resolv_conf_options="" in /etc/resolvconf.conf so resolvconf(8) does not re-add it — against an EDNS-broken router it breaks libc resolution outright.
  • Never run local-unbound-setup with no arguments while resolv.conf already points at 127.0.0.1 — it snapshots that as upstream and forwards unbound to itself.

Debugging

drill -p 5354 <npub>.fips @::1 AAAA   # daemon directly (bypasses unbound)
drill <npub>.fips AAAA                # full chain; SERVER: must be 127.0.0.1
cat /var/run/fips/dns-backend         # which backend fips_dns configured

The TUN interface gets a kernel-assigned name (tun0, tun1, ...), like utun on macOS, and is destroyed automatically when the daemon exits. ifconfig <name> prints Opened by PID <n> for the process holding a tun device.