dnscontrol/providers/msdns/naptr.go
2023-05-20 13:21:45 -04:00

112 lines
3.5 KiB
Go

package msdns
// NAPTR records are not supported by the PowerShell module.
// Until this bug is fixed we use old-school commands instead.
import (
"bytes"
"encoding/hex"
"fmt"
"log"
"strconv"
"github.com/StackExchange/dnscontrol/v4/models"
"github.com/StackExchange/dnscontrol/v4/pkg/printer"
)
func generatePSCreateNaptr(dnsServerName, domain string, rec *models.RecordConfig) string {
var computername string
if dnsServerName != "" {
computername = escapePS(dnsServerName) + " "
}
var b bytes.Buffer
fmt.Fprintf(&b, `$zoneName = %s ; `, escapePS(domain))
fmt.Fprintf(&b, `$rrName = %s ; `, escapePS(rec.Name))
fmt.Fprintf(&b, `$Order = %d ; `, rec.NaptrOrder)
fmt.Fprintf(&b, `$Preference = %d ; `, rec.NaptrPreference)
fmt.Fprintf(&b, `$Flags = %s ; `, escapePS(rec.NaptrFlags))
fmt.Fprintf(&b, `$Service = %s ; `, escapePS(rec.NaptrService))
fmt.Fprintf(&b, `$Regex = %s ; `, escapePS(rec.NaptrRegexp))
fmt.Fprintf(&b, `$Replacement = %s ; `, escapePS(rec.GetTargetField()))
fmt.Fprintf(&b, `dnscmd %s/recordadd $zoneName $rrName %d naptr $Order $Preference $Flags $Service $Regex $Replacement ; `, computername, rec.TTL)
return b.String()
}
func generatePSDeleteNaptr(dnsServerName, domain string, rec *models.RecordConfig) string {
target := rec.GetTargetField()
if target == "" {
target = "."
}
var computername string
if dnsServerName != "" {
computername = escapePS(dnsServerName) + " "
}
var b bytes.Buffer
fmt.Fprintf(&b, `$zoneName = %s ; `, escapePS(domain))
fmt.Fprintf(&b, `$rrName = %s ; `, escapePS(rec.Name))
fmt.Fprintf(&b, `$Order = %d ; `, rec.NaptrOrder)
fmt.Fprintf(&b, `$Preference = %d ; `, rec.NaptrPreference)
fmt.Fprintf(&b, `$Flags = %s ; `, escapePS(rec.NaptrFlags))
fmt.Fprintf(&b, `$Service = %s ; `, escapePS(rec.NaptrService))
fmt.Fprintf(&b, `$Regex = %s ; `, escapePS(rec.NaptrRegexp))
fmt.Fprintf(&b, `$Replacement = %s ; `, escapePS(target))
fmt.Fprintf(&b, `dnscmd %s/recorddelete $zoneName $rrName naptr $Order $Preference $Flags $Service $Regex $Replacement /f ; `, computername)
return b.String()
}
// decoding
func decodeRecordDataNaptr(s string) models.RecordConfig {
// These strings look like this:
// C8AFB0B30153075349502B4432540474657374165F7369702E5F7463702E6578616D706C652E6F72672E
// The first 2 groups of 16 bits (4 hex digits) are uinet16.
// The rest are 4 length-prefixed strings.
// The string should be entirely consumed.
rc := models.RecordConfig{}
s, rc.NaptrOrder = eatUint16(s)
s, rc.NaptrPreference = eatUint16(s)
s, rc.NaptrFlags = eatString(s)
s, rc.NaptrService = eatString(s)
s, rc.NaptrRegexp = eatString(s)
s, targ := eatString(s)
rc.SetTarget(targ)
// At this point we should have consumed the entire string.
if s != "" {
printer.Printf("WARNING: REMAINDER:=%q\n", s)
}
return rc
}
// eatUint16 consumes the first 16 bits of the string, returns it as a
// uint16, and returns the remaining bytes of the string.
func eatUint16(s string) (string, uint16) {
value, err := strconv.ParseUint(s[2:4]+s[0:2], 16, 16)
if err != nil {
log.Fatal(err)
}
return s[4:], uint16(value)
}
// eatString consumes an encoded string (8-bit length byte, then the string).
func eatString(s string) (string, string) {
sl, err := strconv.ParseUint(s[:2], 16, 64)
if err != nil {
log.Fatal(err)
}
last := 2 + sl*2
hexcoded := s[2:last]
ret, err := hex.DecodeString(hexcoded)
if err != nil {
log.Fatal(err)
}
return s[last:], string(ret)
}