From 6329ce2427b0fdc1ccbc60042fdb41af5d02529d Mon Sep 17 00:00:00 2001 From: sir_melonchen Date: Sat, 17 Oct 2026 16:20:20 +0200 Subject: [PATCH] fix(bindgen): accept Active Directory names in dynamic zones Netlogon registers A records below _msdcs (gc._msdcs.), which the default check-names of primary zones refuses; dynamic zones now get check-names ignore. Troubleshooting for dcdiag in ACTIVE-DIRECTORY.md, an end-to-end check of such an update. Co-Authored-By: Claude Opus 5.5 --- docs/ACTIVE-DIRECTORY.md | 8 ++++++++ server/internal/configgen/bindgen/namedconf.go | 6 ++++++ .../bindgen/testdata/dynamic-keys/ddi-suite.conf.golden | 2 ++ .../bindgen/testdata/dynamic-update/ddi-suite.conf.golden | 2 ++ .../bindgen/testdata/dynamic/ddi-suite.conf.golden | 1 + test/e2e/run.sh | 3 +++ 6 files changed, 22 insertions(+) diff --git a/docs/ACTIVE-DIRECTORY.md b/docs/ACTIVE-DIRECTORY.md index c46ade2..4109a87 100644 --- a/docs/ACTIVE-DIRECTORY.md +++ b/docs/ACTIVE-DIRECTORY.md @@ -90,3 +90,11 @@ Microsoft-Clients und -DCs beherrschen TSIG nicht; für sie bleibt nur die Freig - Eine Zone von `managed` auf `dynamic` umzustellen ist möglich: Die vorhandene Zonendatei bleibt bestehen und wird ab dann von BIND gepflegt. Der umgekehrte Weg verwirft alle per Update angelegten Records. - Scavenging (Aufräumen veralteter dynamischer Einträge) übernimmt BIND nicht; veraltete Records müssen per `nsupdate` entfernt werden. - MX-Records einer dynamischen Zone, deren Ziel in der Zone liegt, brauchen dort einen A- oder AAAA-Record: Sonst lehnt BIND das Update des Agents ab (Prüfung `check-integrity`), und das Ausrollen der Revision scheitert. + +## Fehlersuche: `dcdiag /test:dns` meldet fehlende Einträge + +- **A-Record des DCs da, SRV-Records fehlen:** Den A-Record trägt der DNS-Client ein (`ipconfig /registerdns`), die SRV-Records, den `._msdcs`-CNAME, `gc._msdcs` und `DomainDnsZones` trägt **Netlogon** ein. Lief `nltest /dsregdns` (oder der Start von Netlogon), bevor die Update-Quellen stimmten, versucht Netlogon es erst Stunden später erneut. Abhilfe auf jedem DC: `nltest /dsregdns` oder `net stop netlogon && net start netlogon`, dann `dcdiag /test:dns` wiederholen. +- **`gc._msdcs` oder andere A-Records unter `_msdcs` fehlen:** BIND prüft in Primary-Zonen Hostnamen (`check-names`) und lehnt Unterstriche ab. Seit v0.9.1 erzeugt DDI für dynamische Zonen `check-names ignore;`; ältere Versionen nach dem Update neu ausrollen. +- **Updates werden abgelehnt:** Windows schickt Updates an den Server aus dem SOA der Zone (Primary). `nslookup -type=SOA ` muss den BIND-Primary nennen, und dessen Name muss auflösen (z. B. als Eintrag in der Adresstabelle). Die Adressen der DCs müssen unter *Update-Quellen* der Zone stehen. Im Log von BIND (`journalctl -u named` bzw. `-u bind9`) steht bei jeder Ablehnung die Quell-IP (`update … denied`). +- **„invalid DNS server“ / keine Internet-Namen:** DDI betreibt BIND standardmäßig rein autoritativ. Zeigen DCs oder Clients ausschließlich auf BIND, unter *DNS/DHCP-Einstellungen* Rekursion einschalten, die eigenen Netze unter „Rekursion erlaubt für“ eintragen und Forwarder angeben (z. B. Router oder Resolver des Providers). +- **Domain Controller mit DHCP-Adresse:** dcdiag warnt zu Recht; DCs sollten ihre IP fest im Betriebssystem eingetragen haben. diff --git a/server/internal/configgen/bindgen/namedconf.go b/server/internal/configgen/bindgen/namedconf.go index 3f8e00e..9e22033 100644 --- a/server/internal/configgen/bindgen/namedconf.go +++ b/server/internal/configgen/bindgen/namedconf.go @@ -143,6 +143,12 @@ func renderConf(m *model) []byte { w.stmt(1, fmt.Sprintf("allow-transfer %s;", braceList([]string{keyElem(z.transferKey)}))) } w.stmt(1, fmt.Sprintf("allow-update %s;", braceList([]string{update}))) + if z.dynamic { + // Active Directory registers A records below _msdcs (e.g. + // gc._msdcs.), which the default host name check of + // primary zones refuses. + w.stmt(1, "check-names ignore;") + } w.stmt(0, "};") } return w.b.Bytes() diff --git a/server/internal/configgen/bindgen/testdata/dynamic-keys/ddi-suite.conf.golden b/server/internal/configgen/bindgen/testdata/dynamic-keys/ddi-suite.conf.golden index 10f27c4..ddf8a7f 100644 --- a/server/internal/configgen/bindgen/testdata/dynamic-keys/ddi-suite.conf.golden +++ b/server/internal/configgen/bindgen/testdata/dynamic-keys/ddi-suite.conf.golden @@ -9,6 +9,7 @@ zone "dyn.test" { file "/etc/bind/ddi-suite/zones/db.dyn.test"; notify no; allow-update { "ddi-update-dyn.test"; }; + check-names ignore; }; zone "keys-only.test" { @@ -16,6 +17,7 @@ zone "keys-only.test" { file "/etc/bind/ddi-suite/zones/db.keys-only.test"; notify no; allow-update { "ddi-update-keys-only.test"; }; + check-names ignore; }; zone "static.test" { diff --git a/server/internal/configgen/bindgen/testdata/dynamic-update/ddi-suite.conf.golden b/server/internal/configgen/bindgen/testdata/dynamic-update/ddi-suite.conf.golden index f92aa74..135299d 100644 --- a/server/internal/configgen/bindgen/testdata/dynamic-update/ddi-suite.conf.golden +++ b/server/internal/configgen/bindgen/testdata/dynamic-update/ddi-suite.conf.golden @@ -9,6 +9,7 @@ zone "2.0.192.in-addr.arpa" { file "/etc/bind/ddi-suite/zones/db.2.0.192.in-addr.arpa"; notify no; allow-update { "ddi-update-2.0.192.in-addr.arpa"; }; + check-names ignore; }; zone "office.test" { @@ -16,6 +17,7 @@ zone "office.test" { file "/etc/bind/ddi-suite/zones/db.office.test"; notify no; allow-update { "ddi-update-office.test"; }; + check-names ignore; }; zone "remote.test" { diff --git a/server/internal/configgen/bindgen/testdata/dynamic/ddi-suite.conf.golden b/server/internal/configgen/bindgen/testdata/dynamic/ddi-suite.conf.golden index 5501ac3..0caf29e 100644 --- a/server/internal/configgen/bindgen/testdata/dynamic/ddi-suite.conf.golden +++ b/server/internal/configgen/bindgen/testdata/dynamic/ddi-suite.conf.golden @@ -8,6 +8,7 @@ zone "dyn.test" { file "/etc/bind/ddi-suite/zones/db.dyn.test"; notify no; allow-update { "ddi-update-dyn.test"; }; + check-names ignore; }; zone "static.test" { diff --git a/test/e2e/run.sh b/test/e2e/run.sh index de41624..e2529b5 100755 --- a/test/e2e/run.sh +++ b/test/e2e/run.sh @@ -245,10 +245,13 @@ server 127.0.0.1 zone ad.e2e.test update add dc1.ad.e2e.test. 300 A 192.0.2.77 update add _ldap._tcp.dc._msdcs.ad.e2e.test. 300 SRV 0 100 389 dc1.ad.e2e.test. +update add gc._msdcs.ad.e2e.test. 300 A 192.0.2.77 send EOF expect "192.0.2.77" dig_short dc1.ad.e2e.test A wait_dig2 "0 100 389 dc1.ad.e2e.test." _ldap._tcp.dc._msdcs.ad.e2e.test SRV +# Active Directory registers A records below _msdcs (check-names ignore). +expect "192.0.2.77" dig_short gc._msdcs.ad.e2e.test A key="$(api tsig-secret e2e-update)" if dc exec -T bind2 nsupdate <