On Ubuntu 22 (systemd 249), systemd-resolved applies interface-scoped
routing to per-link DNS servers. Configuring `resolvectl dns fips0
127.0.0.1:5354` caused resolved to attempt reaching 127.0.0.1 through
fips0 (a TUN with only fd00::/8 routes), silently failing. The DNS
responder never received queries. Newer systemd versions (250+) have
explicit handling for loopback servers on non-loopback interfaces.
Changes:
- DNS responder default bind_addr changed from "127.0.0.1" to "::"
so it listens on all interfaces, including fips0. Bind logic in
lifecycle.rs now parses bind_addr as IpAddr and constructs a
SocketAddr, handling IPv6 literal formatting. Factored into
Node::bind_dns_socket with explicit IPV6_V6ONLY=0 via socket2, so
IPv4 clients on 127.0.0.1:5354 still reach the responder
regardless of the kernel's net.ipv6.bindv6only sysctl.
- fips-dns-setup resolvectl backend now waits for fips0 to have a
global IPv6 address, then configures resolved with
[<fips0-addr>]:5354. That address is locally delivered by the
kernel regardless of which interface resolved tries to route
through. The dnsmasq and NetworkManager backends still use
127.0.0.1 (they don't have the interface-scoping issue).
- Dropped hardcoded `bind_addr: "127.0.0.1"` from the packaged
fips.yaml (Debian + OpenWrt). The shipped config was overriding
the new default.
- DNS queries are only accepted from the localhost.
Verified end-to-end in a privileged Ubuntu 22.04 systemd container:
dig @127.0.0.53 AAAA <npub>.fips resolves cleanly through
systemd-resolved.
The dns-delegate backend (systemd 258+) still uses 127.0.0.1; it
has not been verified whether that backend has the same routing
issue.
macOS platform:
- Platform-native TUN interface management with shutdown pipe
- Raw Ethernet transport with macOS socket backend (socket_macos.rs)
- EthernetTransport and TransportHandle::Ethernet ungated from Linux-only
- macOS .pkg packaging (build-pkg.sh, launchd plist, uninstall script)
- CI: macOS build and unit test jobs; x86_64 cross-compiled from
macos-latest via rustup target add x86_64-apple-darwin
Gateway feature flag:
- New opt-in `gateway` Cargo feature activates optional `rustables` dep
- `pub mod gateway` and `Config.gateway` gated behind the feature so
macOS builds never pull in Linux-only nftables bindings
- `fips-gateway` bin has `required-features = ["gateway"]`
- All Linux/OpenWrt/AUR packaging passes `--features gateway`
CI / packaging:
- package-linux, package-macos, package-openwrt now trigger on push to
master/maint/next and on pull requests; release uploads remain tag-gated
- Bloom filter routing fix: fall through to tree routing when no candidate
is strictly closer
- MMP intervals: raise MIN to 1s / MAX to 5s with 5-sample cold-start phase
Add fips-gateway binary to CI artifact and Docker build. Systemd
service unit with After=fips.service dependency and security
hardening. Debian and AUR package entries.
OpenWrt packaging: procd init script managing dnsmasq forwarding,
proxy NDP, RA route advertisements for the virtual IP pool, and a
global IPv6 prefix on br-lan to work around Android suppressing AAAA
queries on ULA-only networks. Sysctl config for IPv6 forwarding.
Gateway enabled by default in OpenWrt config. Ethernet transport
enabled by default.
Default gateway config section (commented out) in common fips.yaml.
BLE transport implementation using L2CAP Connection-Oriented Channels
(SeqPacket mode) via the bluer crate, behind cfg(feature = "ble").
Core transport:
- BleTransport<I> generic over BleIo trait (BluerIo prod, MockBleIo test)
- Connection pool with priority eviction (static > discovered, max 7)
- Connect-on-send via connect_inline() matching TCP behavior
- Per-connection receive loops with pool cleanup on disconnect
Discovery and probing:
- Combined scan_probe_loop using select! over scanner events and a
BinaryHeap delay queue with per-entry random jitter (0-5s) to prevent
herd effects when multiple nodes see the same beacon simultaneously
- Pre-handshake pubkey exchange ([0x00][pubkey:32]) for IK identity
- Cross-probe tie-breaker: smaller NodeAddr's outbound wins (same
convention as FMP/FSP rekey dual-initiation)
- Probed peers reported to DiscoveryBuffer; pool fills through normal
node-layer auto-connect -> send_async -> connect_inline path
Beacon management:
- Periodic advertising: 1s burst every 30s (configurable via
beacon_interval_secs / beacon_duration_secs)
- FIPS service UUID for scan filtering
Configuration (all fields optional with defaults):
- adapter, psm, mtu, max_connections, connect_timeout_ms
- advertise, scan, auto_connect, accept_connections
- beacon_interval_secs (30), beacon_duration_secs (1)
Hardware validated with two BLE nodes:
- 2048-byte MTU, ~60-160ms RTT, zero-config auto-connect
- BLE spike tool at testing/ble/ for standalone adapter validation
42 unit tests + 4 node-level integration tests, all CI-compatible
via MockBleIo (no hardware required). tokio test-util added for
time-dependent scan/probe tests.
Add resolve_socket_addr() with IP fast path and tokio::net::lookup_host()
fallback for DNS hostnames. Peer addresses can now use hostnames like
"peer1.example.com:2121" alongside IP addresses.
UDP transport adds a per-transport DNS cache (60s TTL) to avoid
per-packet resolution. TCP resolves at connect time (one-shot).
Update design docs, config examples, and changelog to reflect hostname
support in transport addressing.
Packaging directory structure:
- packaging/common/ — shared config (fips.yaml) used by all formats
- packaging/systemd/ — systemd-specific installer and service units
Systemd packaging includes:
- build-tarball.sh: builds release binaries and creates a self-contained
install tarball with stripped binaries
- fips.service: systemd unit running the daemon with security hardening
- fips-dns.service: oneshot unit configuring resolvectl to route .fips
domain queries to the FIPS DNS shim on 127.0.0.1:5354
- install.sh: deploys binaries to /usr/local/bin, installs systemd units,
creates fips group for non-root control socket access
- uninstall.sh: removes service and binaries, optional --purge for
config and identity key files
- README.install.md: installation and configuration guide
Default config enables UDP (2121), TCP inbound (8443), TUN, and DNS
resolver. Identity is ephemeral by default for privacy; operators can
uncomment persistent: true to maintain a stable npub for static peer
publishing. Ethernet transport is commented out for per-node setup.