IPv6: router.wan.ipv6.enable mirrors the existing uplink config (DHCPv6 with
WithoutRA=solicit, delegated prefix). The ISP delegates a single /64, so
exactly one LAN may claim it via router.lans.<name>.ipv6.pd (asserted); other
LANs stay IPv4-only. SLAAC only, no NAT66.
PPPoE: router.wan.ipv4.type = "pppoe" runs pppd on an optional VLAN of the
uplink, with the password read from a file at service start (never the Nix
store). NAT, forwarding and MSS clamping (MTU 1492) use the derived PPP
device; native IPv6 stays on the untagged link.
Tests: basic.nix is parameterised by uplink type; the pppoe variant uses a
fake ISP with pppoe-server (VLAN 7, CHAP). Both variants cover IPv6 PD, SLAAC,
routing without NAT and WAN-deny. Assertion tests gain PD/PPPoE cases and a
full-system evaluation step.
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Add an IPv4 helper lib (parse, netmask, cidr, overlap) and derive
router.lans.<name>.ipv4.subnet from address and prefixLength instead of
requiring it twice. New assertions reject invalid addresses, DHCP pools that
are reversed, outside the subnet or contain the router address, and
overlapping LANs.
Add `lib` unit tests and an `assertions` check that evaluates broken configs
and compares the exact error messages.
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>