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>
63 lines
2.5 KiB
SQL
63 lines
2.5 KiB
SQL
-- +goose Up
|
|
-- +goose StatementBegin
|
|
|
|
-- DHCP (Kea) — globale Singleton-Settings (node-lokal, wie dns_settings/
|
|
-- ntp_settings: ob DIESE Node DHCP betreibt). Subnets/Reservierungen sind
|
|
-- geteilte Config und werden repliziert.
|
|
CREATE TABLE IF NOT EXISTS dhcp_settings (
|
|
id INTEGER PRIMARY KEY DEFAULT 1,
|
|
enabled BOOLEAN NOT NULL DEFAULT false,
|
|
default_lease INTEGER NOT NULL DEFAULT 3600,
|
|
max_lease INTEGER NOT NULL DEFAULT 7200,
|
|
domain_name TEXT NOT NULL DEFAULT '',
|
|
dns_servers TEXT NOT NULL DEFAULT '',
|
|
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
|
|
updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
|
|
CONSTRAINT dhcp_settings_singleton CHECK (id = 1)
|
|
);
|
|
INSERT INTO dhcp_settings (id) VALUES (1) ON CONFLICT DO NOTHING;
|
|
|
|
-- Subnets: an ein Interface per NAME gebunden (nicht per node-lokaler FK,
|
|
-- damit die Replikation nicht an divergierenden interface_id bricht).
|
|
CREATE TABLE IF NOT EXISTS dhcp_subnets (
|
|
id BIGSERIAL PRIMARY KEY,
|
|
name TEXT NOT NULL,
|
|
interface_name TEXT NOT NULL,
|
|
subnet_cidr TEXT NOT NULL,
|
|
pool_start TEXT NOT NULL DEFAULT '',
|
|
pool_end TEXT NOT NULL DEFAULT '',
|
|
gateway TEXT NOT NULL DEFAULT '',
|
|
dns_servers TEXT NOT NULL DEFAULT '',
|
|
lease_time INTEGER,
|
|
active BOOLEAN NOT NULL DEFAULT true,
|
|
description TEXT NOT NULL DEFAULT '',
|
|
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
|
|
updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
|
|
CONSTRAINT dhcp_subnets_name_unique UNIQUE (name)
|
|
);
|
|
|
|
CREATE TABLE IF NOT EXISTS dhcp_reservations (
|
|
id BIGSERIAL PRIMARY KEY,
|
|
subnet_id BIGINT NOT NULL REFERENCES dhcp_subnets(id) ON DELETE CASCADE,
|
|
name TEXT NOT NULL DEFAULT '',
|
|
mac_address TEXT NOT NULL,
|
|
ip_address TEXT NOT NULL,
|
|
hostname TEXT NOT NULL DEFAULT '',
|
|
active BOOLEAN NOT NULL DEFAULT true,
|
|
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
|
|
updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
|
|
CONSTRAINT dhcp_reservations_subnet_mac_unique UNIQUE (subnet_id, mac_address)
|
|
);
|
|
CREATE INDEX IF NOT EXISTS idx_dhcp_reservations_subnet ON dhcp_reservations(subnet_id);
|
|
|
|
-- +goose StatementEnd
|
|
|
|
-- +goose Down
|
|
-- +goose StatementBegin
|
|
|
|
DROP TABLE IF EXISTS dhcp_reservations;
|
|
DROP TABLE IF EXISTS dhcp_subnets;
|
|
DROP TABLE IF EXISTS dhcp_settings;
|
|
|
|
-- +goose StatementEnd
|