Files
nixos-router/modules/router/dhcp.nix
T
nilsandClaude Sonnet 5.5 6038367252 Add IPv6 prefix delegation and PPPoE uplink
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>
2026-10-27 16:29:52 +01:00

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;
};
};
};
}