Serve DHCP on LANs plugged in after boot; accept browser logins

Kea skips interfaces without carrier when it opens its sockets and only
looks again on a reload, so a LAN cable plugged in after Kea started got
no DHCP until a restart. networkd-dispatcher now restarts Kea when a DHCP
LAN gets carrier (a restart: a SIGHUP while Kea is starting ends it). The
rule script is the same for every configuration and reads the interfaces
from /etc/router/dhcp-interfaces, so the device never has to rebuild it
(writeShellApplication's shellcheck could not be built offline).

The web UI refused every login from a browser with "forbidden": under
Referrer-Policy no-referrer browsers send "Origin: null" with form posts.
Use http.CrossOriginProtection (Sec-Fetch-Site, then Origin) and a
same-origin referrer policy.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01AeFqV9dZrK6nipHkPfyM4F
This commit is contained in:
2026-10-29 09:19:14 +01:00
co-authored by Claude Opus 5.5
parent 753459f5d7
commit 5ddff44a35
4 changed files with 70 additions and 10 deletions
+11
View File
@@ -512,5 +512,16 @@ pkgs.testers.runNixOSTest {
klog = router.succeed("journalctl -k --no-pager | grep 'router fwd#'")
assert "accepted: " in klog, klog
assert "rate-limited: " in klog, klog
with subtest("a LAN cable plugged in after Kea started still gets DHCP"):
# Like booting with nothing plugged in: Kea starts while the LAN NIC
# (eth2, QEMU netdev vlan2) has no carrier and skips it.
router.send_monitor_command("set_link vlan2 off")
router.wait_until_succeeds("grep -qx 0 /sys/class/net/eth2/carrier")
router.succeed("systemctl restart kea-dhcp4-server.service")
router.wait_until_succeeds("journalctl -u kea-dhcp4-server --since=-1min | grep -q 'eth2 is not running'")
router.send_monitor_command("set_link vlan2 on")
client.succeed("networkctl down eth1 && ip -4 addr flush dev eth1 && networkctl up eth1")
client.wait_until_succeeds("ip -4 addr show dev eth1 | grep -q 192.168.10.", timeout=60)
'';
}