feat(dhcp): DHCPv4-Server via Kea (kea-dhcp4-server) — v1.2.92

Verwalteter DHCPv4-Server analog Unbound/Squid/Chrony.
- Migration 0041: dhcp_settings (singleton, node-lokal), dhcp_subnets, dhcp_reservations.
- internal/kea: Renderer baut Kea-JSON via Go-Struct→Marshal (garantiert valide), managed /etc/edgeguard/kea/kea-dhcp4.conf (Symlink von /etc/kea), Service-Lifecycle an enabled gekoppelt (default AUS, kein rogue DHCP). Interface per NAME (cluster-sicher, kein node-lokaler FK).
- internal/services/dhcp + internal/handlers/dhcp.go: Settings + Subnet/Reservation-CRUD, Validierung (CIDR/IP/MAC/interface exists).
- configgen: Stop/Enable/DisableService. Firewall: AutoFWRule.Iface → udp/67 pro LAN-Interface gescopt (kein WAN). Cluster: subnets/reservations repliziert (hashSpec), dhcp_settings node-lokal (localOnlyTables).
- main.go + render.go + WithAllReloaders Wiring. Packaging: kea-dhcp4-server Dependency, /etc/edgeguard/kea Dir, Symlink, disable-on-install, sudoers (restart/stop/enable/disable).
- UI: DHCP-Seite (Settings + Subnets + Reservierungen pro Subnet), Route/Nav/i18n de/en, HA-Warnung 'nur auf einer Node aktivieren'.
- Tests (guarded EG_FWTEST_DSN): Kea-Renderer gegen DB (valides JSON + Felder), FW-Auto-Rule-Iface inkl. nft -c. Scope v1: DHCPv4.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
Debian
2026-06-05 18:56:30 +02:00
parent 3a707e2e3f
commit bac7c7e349
24 changed files with 1666 additions and 6 deletions

View File

@@ -15,6 +15,7 @@
"wireguard": "WireGuard",
"forwardProxy": "Forward-Proxy",
"dns": "DNS",
"dhcp": "DHCP",
"ntp": "Zeit (NTP)",
"firewall": "Firewall",
"firewallLive": "Firewall-Log",
@@ -1075,6 +1076,52 @@
"failed": "Import fehlgeschlagen"
}
},
"dhcp": {
"title": "DHCP (Kea)",
"intro": "DHCPv4-Server: globale Optionen, pro-Subnet-Pools und statische Reservierungen.",
"csvHint": "Komma-getrennt.",
"saved": "Gespeichert",
"saveFailed": "Speichern fehlgeschlagen",
"deleted": "Gelöscht",
"deleteFailed": "Löschen fehlgeschlagen",
"reservations": "Reservierungen",
"haWarnTitle": "Nur auf EINER Node aktivieren",
"haWarnDesc": "Zwei DHCP-Server im selben LAN führen zu Adresskonflikten. Diese Einstellung ist node-lokal — aktiviere DHCP nur auf einer Cluster-Node.",
"tabs": {
"settings": "Einstellungen",
"subnets": "Subnets"
},
"settings": {
"enabled": "DHCP auf dieser Node aktiv",
"defaultLease": "Standard-Lease-Zeit (Sekunden)",
"maxLease": "Max-Lease-Zeit (Sekunden)",
"domainName": "Domain-Name",
"dnsServers": "DNS-Server (global)"
},
"subnet": {
"name": "Name",
"interface": "Interface",
"cidr": "Subnetz (CIDR)",
"pool": "Pool",
"poolStart": "Pool-Start",
"poolEnd": "Pool-Ende",
"gateway": "Gateway",
"dnsServers": "DNS-Server",
"active": "Aktiv",
"add": "Subnet hinzufügen",
"edit": "Subnet bearbeiten",
"deleteConfirm": "Subnet \"{{name}}\" wirklich löschen?"
},
"reservation": {
"name": "Name",
"mac": "MAC-Adresse",
"ip": "IP-Adresse",
"hostname": "Hostname",
"add": "Reservierung hinzufügen",
"edit": "Reservierung bearbeiten",
"deleteConfirm": "Reservierung wirklich löschen?"
}
},
"ntp": {
"title": "Zeitserver (Chrony)",
"intro": "Chrony als Time-Sync-Daemon (NTP). Quellen oben, Listen-/Serve-Konfig im Settings-Tab. Wenn 'serve_clients' aktiv und LAN-IPs gebound sind, wird die Box selbst zum NTP-Server für das LAN.",

View File

@@ -15,6 +15,7 @@
"wireguard": "WireGuard",
"forwardProxy": "Forward proxy",
"dns": "DNS",
"dhcp": "DHCP",
"ntp": "Time (NTP)",
"firewall": "Firewall",
"firewallLive": "Firewall log",
@@ -1075,6 +1076,52 @@
"failed": "Import failed"
}
},
"dhcp": {
"title": "DHCP (Kea)",
"intro": "DHCPv4 server: global options, per-subnet pools and static reservations.",
"csvHint": "Comma-separated.",
"saved": "Saved",
"saveFailed": "Save failed",
"deleted": "Deleted",
"deleteFailed": "Delete failed",
"reservations": "Reservations",
"haWarnTitle": "Enable on ONE node only",
"haWarnDesc": "Two DHCP servers on the same LAN cause address conflicts. This setting is node-local — enable DHCP on a single cluster node only.",
"tabs": {
"settings": "Settings",
"subnets": "Subnets"
},
"settings": {
"enabled": "DHCP active on this node",
"defaultLease": "Default lease time (seconds)",
"maxLease": "Max lease time (seconds)",
"domainName": "Domain name",
"dnsServers": "DNS servers (global)"
},
"subnet": {
"name": "Name",
"interface": "Interface",
"cidr": "Subnet (CIDR)",
"pool": "Pool",
"poolStart": "Pool start",
"poolEnd": "Pool end",
"gateway": "Gateway",
"dnsServers": "DNS servers",
"active": "Active",
"add": "Add subnet",
"edit": "Edit subnet",
"deleteConfirm": "Really delete subnet \"{{name}}\"?"
},
"reservation": {
"name": "Name",
"mac": "MAC address",
"ip": "IP address",
"hostname": "Hostname",
"add": "Add reservation",
"edit": "Edit reservation",
"deleteConfirm": "Really delete this reservation?"
}
},
"ntp": {
"title": "Time server (Chrony)",
"intro": "Chrony as time-sync daemon (NTP). Sources on top, listen/serve config on the settings tab. With 'serve_clients' on and LAN-IPs bound, the box itself becomes an NTP server for the LAN.",