Fix: 'host-name'-Option kollidierte mit dem nativen Reservierungs-Hostname

Der Nutzer fragte zu Recht nach, ob eine Reservierung mit gleichzeitig
gesetztem hostname-Feld (aus dem Namen abgeleitet, z.B. 'unraid') UND
einem option-data-Override fuer 'host-name' (Code 12, z.B. 'test') so
beabsichtigt ist. Laut Kea-Dokumentation beantwortet Kea die Host-Name-
Anfrage eines Clients bei einer Reservierung automatisch mit deren
eigenem hostname-Feld -- der zusaetzliche Options-Override fuer dieselbe
Option war eine unbeabsichtigte Dopplung/Quelle fuer Widersprueche, keine
zusaetzliche Funktion.

'host-name' aus den 56 verbleibenden Standard-Optionen entfernt (war eine
von 57), neue Migration v3 loescht eine bereits geseedete/gesetzte
host-name-Zeile samt Wert aus bestehenden Installationen nach. Live auf
der Test-VM verifiziert: Option ist verschwunden, die 'unraid'-Reservierung
enthaelt jetzt nur noch hw-address/ip-address/hostname ohne option-data,
kea-dhcp4 -t weiterhin erfolgreich.
This commit is contained in:
2026-08-11 16:53:33 +02:00
parent 255308f81b
commit d3cf78592f
2 changed files with 52 additions and 26 deletions
+24 -18
View File
@@ -271,27 +271,33 @@ der aktiv weiterentwickelte Nachfolger und bildet „globaler Wert, pro Client
kein "ungültig", da das Fehlen des Netzes hier Absicht ist), statt es kein "ungültig", da das Fehlen des Netzes hier Absicht ist), statt es
jedes Mal neu anlegen zu müssen. jedes Mal neu anlegen zu müssen.
- **DHCP-Options** (`dhcp_option_defs`/`dhcp_option_values`): eine kuratierte - **DHCP-Options** (`dhcp_option_defs`/`dhcp_option_values`): eine kuratierte
Auswahl an **57 Standard-Optionen** (analog den „Vordefinierten Optionen“ Auswahl an **56 Standard-Optionen** (analog den „Vordefinierten Optionen“
eines Windows-DHCP-Servers — u.a. Hostname erzwingen, NTP-/WINS-/TFTP-/ eines Windows-DHCP-Servers — u.a. NTP-/WINS-/TFTP-/SMTP-Server, Boot-Datei,
SMTP-Server, Boot-Datei, Domain-Search, IP-Forwarding) ist automatisch Domain-Search, IP-Forwarding) ist automatisch vorbefüllt und **nicht
vorbefüllt und **nicht löschbar** (Backend lehnt es ab, UI zeigt statt löschbar** (Backend lehnt es ab, UI zeigt statt eines Löschen-Buttons ein
eines Löschen-Buttons ein Schloss-Symbol) — Router/DNS-Server/Domain-Name/ Schloss-Symbol) — Router/DNS-Server/Domain-Name/Lease-Zeiten sind bewusst
Lease-Zeiten sind bewusst ausgenommen, da dafür bereits eigene, dedizierte ausgenommen, da dafür bereits eigene, dedizierte Felder existieren
Felder existieren (Subnetze bzw. globale Einstellungen oben); ebenso (Subnetze bzw. globale Einstellungen oben); ebenso client-/
client-/protokollinterne Optionen (message-type, parameter-request-list, protokollinterne Optionen (message-type, parameter-request-list,
requested-address, ...), die serverseitig nicht sinnvoll setzbar sind. requested-address, ...), die serverseitig nicht sinnvoll setzbar sind.
Alle 57 Namen sind live gegen eine echte Kea-2.4.1-Instanz verifiziert „host-name“ (12) ist ebenfalls bewusst **nicht** enthalten (war es
(`kea-dhcp4 -t`, jede Option einzeln getestet — u.a. „host-name“ mit zwischenzeitlich, wurde aber wieder entfernt): Kea beantwortet die
Bindestrich statt „hostname“ als Kea-Name richtiggestellt). Standard- Host-Name-Anfrage eines Clients bei einer Reservierung bereits automatisch
Optionen bekommen bewusst **kein eigenes `option-def`** in der generierten über deren eigenes `hostname`-Feld (aus dem Namen der Reservierung
Konfiguration — Kea kennt sie bereits nativ, eine Neudefinition würde die abgeleitet) — ein zusätzlicher `option-data`-Override für dieselbe Option
eingebaute duplizieren; nur zusätzlich angelegte, wirklich eigene/ wäre laut Kea-Dokumentation eine Dopplung und Quelle für Widersprüche,
herstellerspezifische Options (z.B. eine Terminal-Boot-URL) bekommen eines live an einer echten Reservierung mit beiden gleichzeitig gesetzten
und bleiben frei löschbar. Werten nachvollzogen. Alle verbleibenden Namen sind live gegen eine echte
Kea-2.4.1-Instanz verifiziert (`kea-dhcp4 -t`, jede Option einzeln
getestet). Standard-Optionen bekommen bewusst **kein eigenes
`option-def`** in der generierten Konfiguration — Kea kennt sie bereits
nativ, eine Neudefinition würde die eingebaute duplizieren; nur
zusätzlich angelegte, wirklich eigene/herstellerspezifische Options (z.B.
eine Terminal-Boot-URL) bekommen eines und bleiben frei löschbar.
In der Tabelle sind grundsätzlich nur **tatsächlich genutzte** Options In der Tabelle sind grundsätzlich nur **tatsächlich genutzte** Options
sichtbar (eigene immer, Standard-Optionen nur mit gesetztem globalen Wert) sichtbar (eigene immer, Standard-Optionen nur mit gesetztem globalen Wert)
— weitere Standard-Optionen kommen über ein Dropdown „+ Standard-Option — weitere Standard-Optionen kommen über ein Dropdown „+ Standard-Option
hinzufügen“ dazu, statt alle 57 dauerhaft als leere Zeilen anzuzeigen. hinzufügen“ dazu, statt alle 56 dauerhaft als leere Zeilen anzuzeigen.
Jede Option hat einen **globalen** Wert sowie optional einen **Wert pro Jede Option hat einen **globalen** Wert sowie optional einen **Wert pro
Client** — ein Client-Override überschreibt den globalen Wert Client** — ein Client-Override überschreibt den globalen Wert
ausschließlich für dieses eine Gerät (technisch: globale Werte landen im ausschließlich für dieses eine Gerät (technisch: globale Werte landen im
@@ -301,7 +307,7 @@ der aktiv weiterentwickelte Nachfolger und bildet „globaler Wert, pro Client
gesetztem Override sind sichtbar, weitere kommen über ein Dropdown dazu. gesetztem Override sind sichtbar, weitere kommen über ein Dropdown dazu.
Das ausgewählte Feld wird dabei direkt unter das Dropdown verschoben und Das ausgewählte Feld wird dabei direkt unter das Dropdown verschoben und
fokussiert, statt an seiner ursprünglichen Stelle irgendwo in der u.U. fokussiert, statt an seiner ursprünglichen Stelle irgendwo in der u.U.
langen Liste (bis zu 57 mögliche Options) zu erscheinen — sonst lag es langen Liste (bis zu 56 mögliche Options) zu erscheinen — sonst lag es
oft außerhalb des sichtbaren Modal-Ausschnitts und wirkte, als wäre nichts oft außerhalb des sichtbaren Modal-Ausschnitts und wirkte, als wäre nichts
passiert (live genau so reproduziert und behoben). passiert (live genau so reproduziert und behoben).
- **Reservierungen aus zwei Quellen**: automatisch für jedes aktive Gerät mit - **Reservierungen aus zwei Quellen**: automatisch für jedes aktive Gerät mit
+28 -8
View File
@@ -516,9 +516,15 @@ def get_db_connection():
# Optionen (message-type, parameter-request-list, requested-address, # Optionen (message-type, parameter-request-list, requested-address,
# client-identifier, server-identifier, ...) ebenfalls bewusst nicht # client-identifier, server-identifier, ...) ebenfalls bewusst nicht
# enthalten — die sind serverseitig nicht sinnvoll setzbar (auch Windows # enthalten — die sind serverseitig nicht sinnvoll setzbar (auch Windows
# Server listet sie nicht unter "Predefined Options"). Alle 57 Namen live # Server listet sie nicht unter "Predefined Options"). "host-name" (12)
# gegen eine echte Kea-2.4.1-Instanz verifiziert (kea-dhcp4 -t je Option # ebenfalls bewusst NICHT enthalten: Kea beantwortet die Host-Name-Anfrage
# einzeln) — u.a. "host-name" (Kea-Name mit Bindestrich, NICHT "hostname"). # eines Clients bei einer Reservierung bereits automatisch mit deren
# eigenem "hostname"-Feld (aus dem Namen der Reservierung abgeleitet, siehe
# _dhcp_safe_hostname) — ein zusätzlicher option-data-Override für dieselbe
# Option in derselben Reservierung wäre eine mit der Kea-Doku belegte
# Dopplung/Quelle für Widersprüche, kein zusätzlicher Nutzen. Alle
# restlichen Namen live gegen eine echte Kea-2.4.1-Instanz verifiziert
# (kea-dhcp4 -t je Option einzeln).
DHCP_STANDARD_OPTIONS = [ DHCP_STANDARD_OPTIONS = [
(4, "time-servers", "ipv4-address", "Zeitserver (RFC 868)"), (4, "time-servers", "ipv4-address", "Zeitserver (RFC 868)"),
(7, "log-servers", "ipv4-address", "Log-Server (MIT-LCS UDP)"), (7, "log-servers", "ipv4-address", "Log-Server (MIT-LCS UDP)"),
@@ -526,7 +532,6 @@ DHCP_STANDARD_OPTIONS = [
(9, "lpr-servers", "ipv4-address", "LPR-Druckserver"), (9, "lpr-servers", "ipv4-address", "LPR-Druckserver"),
(10, "impress-servers", "ipv4-address", "Impress-Server"), (10, "impress-servers", "ipv4-address", "Impress-Server"),
(11, "resource-location-servers", "ipv4-address", "Resource Location Server"), (11, "resource-location-servers", "ipv4-address", "Resource Location Server"),
(12, "host-name", "string", "Hostname (für Reservierung erzwingbar)"),
(13, "boot-size", "uint16", "Boot-Image-Größe (Blöcke)"), (13, "boot-size", "uint16", "Boot-Image-Größe (Blöcke)"),
(14, "merit-dump", "string", "Crash-Dump-Datei"), (14, "merit-dump", "string", "Crash-Dump-Datei"),
(16, "swap-server", "ipv4-address", "Swap-Server"), (16, "swap-server", "ipv4-address", "Swap-Server"),
@@ -718,10 +723,10 @@ def _ensure_schema():
(code, name, opt_type, description), (code, name, opt_type, description),
) )
conn.execute("INSERT OR IGNORE INTO settings (key, value) VALUES (?, '1')", (_migration_key_std_opts,)) conn.execute("INSERT OR IGNORE INTO settings (key, value) VALUES (?, '1')", (_migration_key_std_opts,))
# v2: Liste um weitere verifizierte Standard-Optionen erweitert (u.a. # v2: Liste um weitere verifizierte Standard-Optionen erweitert — eigener
# host-name/12) — eigener Guard, damit bereits auf v1 migrierte # Guard, damit bereits auf v1 migrierte Installationen die neu
# Installationen die neu hinzugekommenen Optionen ebenfalls bekommen, # hinzugekommenen Optionen ebenfalls bekommen, ohne die gesamte
# ohne die gesamte Seed-Logik erneut über alle Zeilen laufen zu lassen. # Seed-Logik erneut über alle Zeilen laufen zu lassen.
_migration_key_std_opts_v2 = "_seeded_dhcp_standard_options_v2" _migration_key_std_opts_v2 = "_seeded_dhcp_standard_options_v2"
if not conn.execute("SELECT 1 FROM settings WHERE key=?", (_migration_key_std_opts_v2,)).fetchone(): if not conn.execute("SELECT 1 FROM settings WHERE key=?", (_migration_key_std_opts_v2,)).fetchone():
for code, name, opt_type, description in DHCP_STANDARD_OPTIONS: for code, name, opt_type, description in DHCP_STANDARD_OPTIONS:
@@ -731,6 +736,21 @@ def _ensure_schema():
(code, name, opt_type, description), (code, name, opt_type, description),
) )
conn.execute("INSERT OR IGNORE INTO settings (key, value) VALUES (?, '1')", (_migration_key_std_opts_v2,)) conn.execute("INSERT OR IGNORE INTO settings (key, value) VALUES (?, '1')", (_migration_key_std_opts_v2,))
# v3: "host-name" (12) als Standard-Option wieder entfernt — Kea
# beantwortet die Host-Name-Anfrage eines Clients bei einer Reservierung
# bereits automatisch über deren eigenes "hostname"-Feld; ein
# zusätzlicher option-data-Override dafür ist laut Kea-Doku eine
# Dopplung/Quelle für Widersprüche (live an einer echten Reservierung
# nachvollzogen, wo beide gleichzeitig gesetzt waren). Löscht auch
# bereits gesetzte Werte für diese Option mit, da sie ohnehin nie
# sinnvoll gewirkt hätten.
_migration_key_std_opts_v3 = "_removed_dhcp_standard_option_hostname_v3"
if not conn.execute("SELECT 1 FROM settings WHERE key=?", (_migration_key_std_opts_v3,)).fetchone():
stale = conn.execute("SELECT id FROM dhcp_option_defs WHERE name='host-name' AND is_standard=1").fetchone()
if stale:
conn.execute("DELETE FROM dhcp_option_values WHERE option_def_id=?", (stale["id"],))
conn.execute("DELETE FROM dhcp_option_defs WHERE id=?", (stale["id"],))
conn.execute("INSERT OR IGNORE INTO settings (key, value) VALUES (?, '1')", (_migration_key_std_opts_v3,))
# DHCP: manuelle Reservierungen — im Unterschied zu den automatisch aus # DHCP: manuelle Reservierungen — im Unterschied zu den automatisch aus
# den Clients (devices-Tabelle) erzeugten Reservierungen für Geräte, die # den Clients (devices-Tabelle) erzeugten Reservierungen für Geräte, die