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>
42 lines
1.1 KiB
Nix
42 lines
1.1 KiB
Nix
{ config, lib, ... }:
|
|
let
|
|
cfg = config.router;
|
|
dhcpLans = lib.filter (l: l.dhcp.enable) (lib.attrValues cfg.lans);
|
|
in
|
|
{
|
|
config = lib.mkIf (cfg.enable && dhcpLans != [ ]) {
|
|
services.kea.dhcp4 = {
|
|
enable = true;
|
|
settings = {
|
|
interfaces-config = {
|
|
interfaces = map (l: l.interface) dhcpLans;
|
|
# Interfaces are configured asynchronously by networkd.
|
|
re-detect = true;
|
|
};
|
|
lease-database = {
|
|
type = "memfile";
|
|
persist = true;
|
|
name = "/var/lib/kea/dhcp4.leases";
|
|
};
|
|
valid-lifetime = 3600;
|
|
subnet4 = lib.imap1 (id: l: {
|
|
inherit id;
|
|
inherit (l.ipv4) subnet;
|
|
interface = l.interface;
|
|
pools = [ { pool = "${l.dhcp.pool.start} - ${l.dhcp.pool.end}"; } ];
|
|
option-data = [
|
|
{
|
|
name = "routers";
|
|
data = l.ipv4.address;
|
|
}
|
|
{
|
|
name = "domain-name-servers";
|
|
data = l.ipv4.address;
|
|
}
|
|
];
|
|
}) dhcpLans;
|
|
};
|
|
};
|
|
};
|
|
}
|