Add --bind-conf flag for BIND domains.conf generation

Generate a BIND-format domains.conf file alongside catalog zones.
New input properties: file= (zone data path) and dnssec (bare flag).
When --bind-conf is set, every zone must have file= or it errors.

Renames ZoneEntry.File to ZonesFile (input path for error messages)
and adds ZoneFile (BIND file path) and DNSSEC (bool) fields.
This commit is contained in:
2026-03-28 11:15:06 -07:00
parent 44d7867a0c
commit 0eddb9fcfe
9 changed files with 451 additions and 51 deletions

64
bindconf.go Normal file
View File

@@ -0,0 +1,64 @@
package main
import (
"fmt"
"os"
"sort"
"strings"
)
// generateBindConf produces a BIND domains.conf from all zone entries.
// Zones are sorted alphabetically. Each zone block uses 8-space indentation.
// DNSSEC zones get dnssec-policy and inline-signing directives on the file line.
func generateBindConf(entries []ZoneEntry) string {
sorted := make([]ZoneEntry, len(entries))
copy(sorted, entries)
sort.Slice(sorted, func(i, j int) bool {
return sorted[i].Zone < sorted[j].Zone
})
var b strings.Builder
b.WriteString("# THIS FILE IS GENERATED BY catalog-zone-gen\n")
b.WriteString("#=============================================\n")
b.WriteString("#\n")
for _, entry := range sorted {
// Strip trailing dot for BIND zone name
zoneName := strings.TrimSuffix(entry.Zone, ".")
fmt.Fprintf(&b, "zone \"%s\" {\n", zoneName)
b.WriteString(" type master;\n")
fileLine := fmt.Sprintf(" file \"%s\";", entry.ZoneFile)
if entry.DNSSEC {
fileLine += " dnssec-policy standard; inline-signing yes;"
}
b.WriteString(fileLine + "\n")
b.WriteString("};\n")
}
return b.String()
}
// validateBindConf checks that every zone entry has a non-empty ZoneFile.
func validateBindConf(entries []ZoneEntry) error {
for _, entry := range entries {
if entry.ZoneFile == "" {
return fmt.Errorf("%s:%d: zone %s missing file= property (required for --bind-conf)",
entry.ZonesFile, entry.Line, entry.Zone)
}
}
return nil
}
// writeBindConf validates entries and writes the BIND config to path.
func writeBindConf(path string, entries []ZoneEntry) error {
if err := validateBindConf(entries); err != nil {
return err
}
content := generateBindConf(entries)
if err := os.WriteFile(path, []byte(content), 0o644); err != nil {
return fmt.Errorf("writing bind config %s: %w", path, err)
}
return nil
}