package dns import ( "bytes" "fmt" "io" "os/exec" "sync" "github.com/stuurmcp/cert-manager-webhook-sthome/pkg/util" "k8s.io/klog/v2" ) const ( nsupdateCmd = "nsupdate" ttl = "7200" ) type output struct { buf *bytes.Buffer lines []string *sync.Mutex } func AddTxtRecord(nameservers []string, domain string, fulldomain string, recordvalue string) error { return processTXT("add", nameservers, domain, fulldomain, recordvalue) } func DeleteTxtRecord(nameservers []string, domain string, fulldomain string, recordvalue string) error { return processTXT("delete", nameservers, domain, fulldomain, recordvalue) } func processTXT(action string, nameservers []string, domain string, fulldomain string, recordvalue string) error { for _, ns := range nameservers { klog.Infof("======= ns: %s =======", ns) zone := extractDomainName(domain) nsucmd := " gsstsig\n server " + ns + "\n zone " + zone + "\n class IN\n update " + action + " " + fulldomain + " " + ttl + " TXT " + recordvalue + "\n send\n" out, err := nsupdate(nsucmd) if err != nil { return err } for _, line := range out.lines { klog.Infof(line) } } return nil } func newOutput() *output { return &output{ buf: &bytes.Buffer{}, lines: []string{}, Mutex: &sync.Mutex{}, } } func (rw *output) Write(p []byte) (int, error) { rw.Lock() defer rw.Unlock() return rw.buf.Write(p) } func nsupdate(nsucmd string) (*output, error) { klog.Infof("nsupdate\n%s", nsucmd) // for debugging cmd := exec.Command(nsupdateCmd) stdout := newOutput() cmd.Stdout = stdout stdinR, stdinW := io.Pipe() stderrR, stderrW := io.Pipe() cmd.Stdin = stdinR cmd.Stderr = stderrW err := cmd.Start() if err != nil { return stdout, fmt.Errorf("could not start %s command: %v", nsupdateCmd, err) } go func() { io.WriteString(stdinW, nsucmd) stdinW.Close() }() errBuf := new(bytes.Buffer) go func() { io.Copy(errBuf, stderrR) stderrR.Close() }() err = cmd.Wait() if err != nil { return stdout, fmt.Errorf("%s did not run successfully: %v stderr: %s", nsupdateCmd, err, errBuf.String()) } return stdout, nil } func extractDomainName(zone string) string { authZone, err := util.FindZoneByFqdn(zone, util.RecursiveNameservers) if err != nil { klog.Errorf("could not get zone by fqdn %v", err) return zone } return util.UnFqdn(authZone) }