1
0
mirror of https://github.com/StackExchange/dnscontrol.git synced 2024-05-11 05:55:12 +00:00

revert to plain providers

This commit is contained in:
Tom Limoncelli
2023-11-18 15:25:02 -05:00
parent e05f0ac38c
commit c5b2ee14f4
38 changed files with 120 additions and 161 deletions

View File

@ -1,5 +1,10 @@
package txtutil package txtutil
// SplitSingleLongTxt does nothing.
// Deprecated: This is a no-op for backwards compatibility.
func SplitSingleLongTxt(records any) {
}
// ToChunks returns the string as chunks of 255-octet strings (the last string being the remainder). // ToChunks returns the string as chunks of 255-octet strings (the last string being the remainder).
func ToChunks(s string) []string { func ToChunks(s string) []string {
return splitChunks(s, 255) return splitChunks(s, 255)

View File

@ -17,6 +17,7 @@ import (
"github.com/StackExchange/dnscontrol/v4/models" "github.com/StackExchange/dnscontrol/v4/models"
"github.com/StackExchange/dnscontrol/v4/pkg/diff" "github.com/StackExchange/dnscontrol/v4/pkg/diff"
"github.com/StackExchange/dnscontrol/v4/pkg/printer" "github.com/StackExchange/dnscontrol/v4/pkg/printer"
"github.com/StackExchange/dnscontrol/v4/pkg/txtutil"
"github.com/StackExchange/dnscontrol/v4/providers" "github.com/StackExchange/dnscontrol/v4/providers"
) )
@ -105,6 +106,7 @@ func (a *edgeDNSProvider) EnsureZoneExists(domain string) error {
// GetZoneRecordsCorrections returns a list of corrections that will turn existing records into dc.Records. // GetZoneRecordsCorrections returns a list of corrections that will turn existing records into dc.Records.
func (a *edgeDNSProvider) GetZoneRecordsCorrections(dc *models.DomainConfig, existingRecords models.Records) ([]*models.Correction, error) { func (a *edgeDNSProvider) GetZoneRecordsCorrections(dc *models.DomainConfig, existingRecords models.Records) ([]*models.Correction, error) {
txtutil.SplitSingleLongTxt(existingRecords)
keysToUpdate, toReport, err := diff.NewCompat(dc).ChangedGroups(existingRecords) keysToUpdate, toReport, err := diff.NewCompat(dc).ChangedGroups(existingRecords)
if err != nil { if err != nil {

View File

@ -11,6 +11,7 @@ import (
"github.com/StackExchange/dnscontrol/v4/models" "github.com/StackExchange/dnscontrol/v4/models"
"github.com/StackExchange/dnscontrol/v4/pkg/diff2" "github.com/StackExchange/dnscontrol/v4/pkg/diff2"
"github.com/StackExchange/dnscontrol/v4/pkg/txtutil"
"github.com/StackExchange/dnscontrol/v4/providers" "github.com/StackExchange/dnscontrol/v4/providers"
) )
@ -67,6 +68,7 @@ func New(settings map[string]string, _ json.RawMessage) (providers.DNSServicePro
// GetZoneRecordsCorrections returns a list of corrections that will turn existing records into dc.Records. // GetZoneRecordsCorrections returns a list of corrections that will turn existing records into dc.Records.
func (api *autoDNSProvider) GetZoneRecordsCorrections(dc *models.DomainConfig, existingRecords models.Records) ([]*models.Correction, error) { func (api *autoDNSProvider) GetZoneRecordsCorrections(dc *models.DomainConfig, existingRecords models.Records) ([]*models.Correction, error) {
domain := dc.Name domain := dc.Name
txtutil.SplitSingleLongTxt(dc.Records) // Autosplit long TXT records
var corrections []*models.Correction var corrections []*models.Correction

View File

@ -25,6 +25,7 @@ import (
"github.com/StackExchange/dnscontrol/v4/models" "github.com/StackExchange/dnscontrol/v4/models"
"github.com/StackExchange/dnscontrol/v4/pkg/diff2" "github.com/StackExchange/dnscontrol/v4/pkg/diff2"
"github.com/StackExchange/dnscontrol/v4/pkg/printer" "github.com/StackExchange/dnscontrol/v4/pkg/printer"
"github.com/StackExchange/dnscontrol/v4/pkg/txtutil"
"github.com/StackExchange/dnscontrol/v4/providers" "github.com/StackExchange/dnscontrol/v4/providers"
"github.com/fatih/color" "github.com/fatih/color"
"github.com/miekg/dns" "github.com/miekg/dns"
@ -409,6 +410,7 @@ func hasNSDeletion(changes diff2.ChangeList) bool {
// GetZoneRecordsCorrections returns a list of corrections that will turn existing records into dc.Records. // GetZoneRecordsCorrections returns a list of corrections that will turn existing records into dc.Records.
func (c *axfrddnsProvider) GetZoneRecordsCorrections(dc *models.DomainConfig, foundRecords models.Records) ([]*models.Correction, error) { func (c *axfrddnsProvider) GetZoneRecordsCorrections(dc *models.DomainConfig, foundRecords models.Records) ([]*models.Correction, error) {
txtutil.SplitSingleLongTxt(foundRecords) // Autosplit long TXT records
// Ignoring the SOA, others providers don't manage it either. // Ignoring the SOA, others providers don't manage it either.
if len(foundRecords) >= 1 && foundRecords[0].Type == "SOA" { if len(foundRecords) >= 1 && foundRecords[0].Type == "SOA" {

View File

@ -13,7 +13,5 @@ func AuditRecords(records []*models.RecordConfig) []error {
a.Add("MX", rejectif.MxNull) // Last verified 2020-12-28 a.Add("MX", rejectif.MxNull) // Last verified 2020-12-28
a.Add("TXT", rejectif.TxtIsEmpty) // Last verified 2023-10-27
return a.Audit(records) return a.Audit(records)
} }

View File

@ -14,6 +14,7 @@ import (
"github.com/StackExchange/dnscontrol/v4/models" "github.com/StackExchange/dnscontrol/v4/models"
"github.com/StackExchange/dnscontrol/v4/pkg/diff2" "github.com/StackExchange/dnscontrol/v4/pkg/diff2"
"github.com/StackExchange/dnscontrol/v4/pkg/printer" "github.com/StackExchange/dnscontrol/v4/pkg/printer"
"github.com/StackExchange/dnscontrol/v4/pkg/txtutil"
"github.com/StackExchange/dnscontrol/v4/providers" "github.com/StackExchange/dnscontrol/v4/providers"
) )
@ -192,6 +193,8 @@ func (a *azurednsProvider) getExistingRecords(domain string) (models.Records, []
// GetZoneRecordsCorrections returns a list of corrections that will turn existing records into dc.Records. // GetZoneRecordsCorrections returns a list of corrections that will turn existing records into dc.Records.
func (a *azurednsProvider) GetZoneRecordsCorrections(dc *models.DomainConfig, existingRecords models.Records) ([]*models.Correction, error) { func (a *azurednsProvider) GetZoneRecordsCorrections(dc *models.DomainConfig, existingRecords models.Records) ([]*models.Correction, error) {
txtutil.SplitSingleLongTxt(existingRecords) // Autosplit long TXT records
var corrections []*models.Correction var corrections []*models.Correction
// Azure is a "ByRecordSet" API. // Azure is a "ByRecordSet" API.
@ -521,7 +524,8 @@ func (a *azurednsProvider) recordToNativeDiff2(recordKey models.RecordKey, recor
if recordSet.Properties.TxtRecords == nil { if recordSet.Properties.TxtRecords == nil {
recordSet.Properties.TxtRecords = []*adns.TxtRecord{} recordSet.Properties.TxtRecords = []*adns.TxtRecord{}
} }
if rec.GetTargetTXTJoined() != "" { // Empty TXT record needs to have no value set in it's properties // Empty TXT record needs to have no value set in it's properties
if !(rec.GetTargetTXTSegmentCount() == 1 && rec.GetTargetTXTSegmented()[0] == "") {
var txts []*string var txts []*string
for _, txt := range rec.GetTargetTXTSegmented() { for _, txt := range rec.GetTargetTXTSegmented() {
txts = append(txts, to.StringPtr(txt)) txts = append(txts, to.StringPtr(txt))

View File

@ -25,6 +25,7 @@ import (
"github.com/StackExchange/dnscontrol/v4/pkg/diff2" "github.com/StackExchange/dnscontrol/v4/pkg/diff2"
"github.com/StackExchange/dnscontrol/v4/pkg/prettyzone" "github.com/StackExchange/dnscontrol/v4/pkg/prettyzone"
"github.com/StackExchange/dnscontrol/v4/pkg/printer" "github.com/StackExchange/dnscontrol/v4/pkg/printer"
"github.com/StackExchange/dnscontrol/v4/pkg/txtutil"
"github.com/StackExchange/dnscontrol/v4/providers" "github.com/StackExchange/dnscontrol/v4/providers"
"github.com/miekg/dns" "github.com/miekg/dns"
) )
@ -194,32 +195,11 @@ func ParseZoneContents(content string, zoneName string, zonefileName string) (mo
foundRecords := models.Records{} foundRecords := models.Records{}
for rr, ok := zp.Next(); ok; rr, ok = zp.Next() { for rr, ok := zp.Next(); ok; rr, ok = zp.Next() {
header := rr.Header() rec, err := models.RRtoRC(rr, zoneName)
rtype := dns.TypeToString[header.Rrtype] if err != nil {
if rtype == "TXT" { return nil, err
v := rr.(*dns.TXT)
t := strings.Join(v.Txt, "")
//fmt.Fprintf(os.Stdout, "DEBUG: ParseZoneContents inbounds=%s\n", t)
td := strings.ReplaceAll(t, `\"`, `"`)
td = strings.ReplaceAll(td, `\\`, `\`)
//fmt.Fprintf(os.Stdout, "DEBUG: ParseZoneContents decodeds=%s\n", td)
rec := models.RecordConfig{Type: "TXT"}
rec.SetLabelFromFQDN(strings.TrimSuffix(header.Name, "."), zoneName)
rec.TTL = header.Ttl
rec.Original = rr
err := rec.SetTargetTXT(td)
if err != nil {
return nil, err
}
foundRecords = append(foundRecords, &rec)
} else {
rec, err := models.RRtoRC(rr, zoneName)
if err != nil {
return nil, err
}
foundRecords = append(foundRecords, &rec)
} }
foundRecords = append(foundRecords, &rec)
} }
if err := zp.Err(); err != nil { if err := zp.Err(); err != nil {
@ -230,6 +210,7 @@ func ParseZoneContents(content string, zoneName string, zonefileName string) (mo
// GetZoneRecordsCorrections returns a list of corrections that will turn existing records into dc.Records. // GetZoneRecordsCorrections returns a list of corrections that will turn existing records into dc.Records.
func (c *bindProvider) GetZoneRecordsCorrections(dc *models.DomainConfig, foundRecords models.Records) ([]*models.Correction, error) { func (c *bindProvider) GetZoneRecordsCorrections(dc *models.DomainConfig, foundRecords models.Records) ([]*models.Correction, error) {
txtutil.SplitSingleLongTxt(dc.Records)
var corrections []*models.Correction var corrections []*models.Correction
changes := false changes := false

View File

@ -11,11 +11,11 @@ import (
func AuditRecords(records []*models.RecordConfig) []error { func AuditRecords(records []*models.RecordConfig) []error {
a := rejectif.Auditor{} a := rejectif.Auditor{}
//a.Add("TXT", rejectif.TxtLongerThan255) // Last verified 2022-06-18 a.Add("TXT", rejectif.TxtHasMultipleSegments) // Last verified 2022-06-18
a.Add("TXT", rejectif.TxtHasTrailingSpace) // Last verified 2023-11-12 a.Add("TXT", rejectif.TxtHasTrailingSpace) // Last verified 2022-06-18
a.Add("TXT", rejectif.TxtIsEmpty) // Last verified 2023-11-12 a.Add("TXT", rejectif.TxtIsEmpty) // Last verified 2022-06-18
return a.Audit(records) return a.Audit(records)
} }

View File

@ -19,7 +19,7 @@ func AuditRecords(records []*models.RecordConfig) []error {
a.Add("TXT", rejectif.TxtHasDoubleQuotes) // Last verified 2021-03-01 a.Add("TXT", rejectif.TxtHasDoubleQuotes) // Last verified 2021-03-01
a.Add("TXT", rejectif.TxtLongerThan255) // Last verified 2021-03-01 a.Add("TXT", rejectif.TxtHasMultipleSegments) // Last verified 2021-03-01
a.Add("SRV", rejectif.SrvHasNullTarget) // Last verified 2023-03-30 a.Add("SRV", rejectif.SrvHasNullTarget) // Last verified 2023-03-30

View File

@ -17,7 +17,7 @@ func AuditRecords(records []*models.RecordConfig) []error {
a.Add("TXT", rejectif.TxtHasDoubleQuotes) // Last verified 2022-08-08 a.Add("TXT", rejectif.TxtHasDoubleQuotes) // Last verified 2022-08-08
a.Add("TXT", rejectif.TxtLongerThan255) // Last verified 2022-06-10 a.Add("TXT", rejectif.TxtHasMultipleSegments) // Last verified 2022-06-10
a.Add("TXT", rejectif.TxtHasTrailingSpace) // Last verified 2022-06-10 a.Add("TXT", rejectif.TxtHasTrailingSpace) // Last verified 2022-06-10

View File

@ -4,10 +4,12 @@ import (
"bytes" "bytes"
"encoding/json" "encoding/json"
"fmt" "fmt"
"sort"
"github.com/StackExchange/dnscontrol/v4/models" "github.com/StackExchange/dnscontrol/v4/models"
"github.com/StackExchange/dnscontrol/v4/pkg/diff" "github.com/StackExchange/dnscontrol/v4/pkg/diff"
"github.com/StackExchange/dnscontrol/v4/pkg/printer" "github.com/StackExchange/dnscontrol/v4/pkg/printer"
"github.com/StackExchange/dnscontrol/v4/pkg/txtutil"
"github.com/StackExchange/dnscontrol/v4/providers" "github.com/StackExchange/dnscontrol/v4/providers"
"github.com/miekg/dns/dnsutil" "github.com/miekg/dns/dnsutil"
) )
@ -149,6 +151,8 @@ func PrepDesiredRecords(dc *models.DomainConfig, minTTL uint32) {
// GetZoneRecordsCorrections returns a list of corrections that will turn existing records into dc.Records. // GetZoneRecordsCorrections returns a list of corrections that will turn existing records into dc.Records.
func (c *desecProvider) GetZoneRecordsCorrections(dc *models.DomainConfig, existing models.Records) ([]*models.Correction, error) { func (c *desecProvider) GetZoneRecordsCorrections(dc *models.DomainConfig, existing models.Records) ([]*models.Correction, error) {
txtutil.SplitSingleLongTxt(dc.Records)
var minTTL uint32 var minTTL uint32
c.mutex.Lock() c.mutex.Lock()
if ttl, ok := c.domainIndex[dc.Name]; !ok { if ttl, ok := c.domainIndex[dc.Name]; !ok {
@ -233,7 +237,7 @@ func (c *desecProvider) GetZoneRecordsCorrections(dc *models.DomainConfig, exist
// However the code doesn't seem to have such situation. All tests // However the code doesn't seem to have such situation. All tests
// pass. That said, if this breaks anything, the easiest fix might // pass. That said, if this breaks anything, the easiest fix might
// be to just remove the sort. // be to just remove the sort.
//sort.Slice(corrections, func(i, j int) bool { return diff.CorrectionLess(corrections, i, j) }) sort.Slice(corrections, func(i, j int) bool { return diff.CorrectionLess(corrections, i, j) })
return corrections, nil return corrections, nil
} }

View File

@ -19,11 +19,9 @@ func AuditRecords(records []*models.RecordConfig) []error {
a.Add("TXT", MaxLengthDO) // Last verified 2021-03-01 a.Add("TXT", MaxLengthDO) // Last verified 2021-03-01
a.Add("TXT", rejectif.TxtHasBackslash) // Last verified 2023-11-12 a.Add("TXT", rejectif.TxtHasDoubleQuotes) // Last verified 2021-03-01
// The web portal rejects blackslashes too // Double-quotes not permitted in TXT strings. I have a hunch that
// this is due to a broken parser on the DO side.
a.Add("TXT", rejectif.TxtHasDoubleQuotes) // Last verified 2023-11-12
// The web portal rejects double quotes
return a.Audit(records) return a.Audit(records)
} }
@ -46,7 +44,7 @@ func MaxLengthDO(rc *models.RecordConfig) error {
// In other words, they're doing the checking on the API protocol // In other words, they're doing the checking on the API protocol
// encoded data instead of on on the resulting TXT record. Sigh. // encoded data instead of on on the resulting TXT record. Sigh.
if len(rc.GetTargetTXTJoined()) > 509 { if len(rc.GetTargetRFC1035Quoted()) > 509 {
return fmt.Errorf("encoded txt too long") return fmt.Errorf("encoded txt too long")
} }

View File

@ -10,7 +10,7 @@ import (
"github.com/StackExchange/dnscontrol/v4/models" "github.com/StackExchange/dnscontrol/v4/models"
"github.com/StackExchange/dnscontrol/v4/pkg/diff" "github.com/StackExchange/dnscontrol/v4/pkg/diff"
"github.com/StackExchange/dnscontrol/v4/pkg/printer" "github.com/StackExchange/dnscontrol/v4/pkg/txtutil"
"github.com/StackExchange/dnscontrol/v4/providers" "github.com/StackExchange/dnscontrol/v4/providers"
"github.com/digitalocean/godo" "github.com/digitalocean/godo"
"github.com/miekg/dns/dnsutil" "github.com/miekg/dns/dnsutil"
@ -168,6 +168,8 @@ func (api *digitaloceanProvider) GetZoneRecords(domain string, meta map[string]s
// GetZoneRecordsCorrections returns a list of corrections that will turn existing records into dc.Records. // GetZoneRecordsCorrections returns a list of corrections that will turn existing records into dc.Records.
func (api *digitaloceanProvider) GetZoneRecordsCorrections(dc *models.DomainConfig, existingRecords models.Records) ([]*models.Correction, error) { func (api *digitaloceanProvider) GetZoneRecordsCorrections(dc *models.DomainConfig, existingRecords models.Records) ([]*models.Correction, error) {
txtutil.SplitSingleLongTxt(dc.Records) // Autosplit long TXT records
ctx := context.Background() ctx := context.Background()
toReport, toCreate, toDelete, toModify, err := diff.NewCompat(dc).IncrementalDiff(existingRecords) toReport, toCreate, toDelete, toModify, err := diff.NewCompat(dc).IncrementalDiff(existingRecords)
@ -298,7 +300,6 @@ func toRc(domain string, r *godo.DomainRecord) *models.RecordConfig {
t.SetLabelFromFQDN(name, domain) t.SetLabelFromFQDN(name, domain)
switch rtype := r.Type; rtype { switch rtype := r.Type; rtype {
case "TXT": case "TXT":
printer.Printf("DEBUG: DIGITAL TXT inbounds=%s q=%q\n", target, target)
t.SetTargetTXT(target) t.SetTargetTXT(target)
default: default:
t.SetTarget(target) t.SetTarget(target)
@ -324,7 +325,6 @@ func toReq(dc *models.DomainConfig, rc *models.RecordConfig) *godo.DomainRecordE
case "TXT": case "TXT":
// TXT records are the one place where DO combines many items into one field. // TXT records are the one place where DO combines many items into one field.
target = rc.GetTargetTXTJoined() target = rc.GetTargetTXTJoined()
printer.Printf("DEBUG: DIGITAL TXT outbounds=%s q=%q\n", target, target)
default: default:
// no action required // no action required
} }

View File

@ -13,7 +13,7 @@ func AuditRecords(records []*models.RecordConfig) []error {
a.Add("MX", rejectif.MxNull) // Last verified 2023-03 a.Add("MX", rejectif.MxNull) // Last verified 2023-03
a.Add("TXT", rejectif.TxtLongerThan255) // Last verified 2023-03 a.Add("TXT", rejectif.TxtHasMultipleSegments) // Last verified 2023-03
a.Add("TXT", rejectif.TxtHasTrailingSpace) // Last verified 2023-03 a.Add("TXT", rejectif.TxtHasTrailingSpace) // Last verified 2023-03

View File

@ -8,6 +8,7 @@ import (
"github.com/StackExchange/dnscontrol/v4/models" "github.com/StackExchange/dnscontrol/v4/models"
"github.com/StackExchange/dnscontrol/v4/pkg/diff" "github.com/StackExchange/dnscontrol/v4/pkg/diff"
"github.com/StackExchange/dnscontrol/v4/pkg/txtutil"
"github.com/StackExchange/dnscontrol/v4/providers" "github.com/StackExchange/dnscontrol/v4/providers"
) )
@ -98,6 +99,8 @@ func New(settings map[string]string, _ json.RawMessage) (providers.DNSServicePro
// } // }
func (api *dnsMadeEasyProvider) GetZoneRecordsCorrections(dc *models.DomainConfig, existingRecords models.Records) ([]*models.Correction, error) { func (api *dnsMadeEasyProvider) GetZoneRecordsCorrections(dc *models.DomainConfig, existingRecords models.Records) ([]*models.Correction, error) {
txtutil.SplitSingleLongTxt(dc.Records) // Autosplit long TXT records
domainName := dc.Name domainName := dc.Name
domain, err := api.findDomain(domainName) domain, err := api.findDomain(domainName)
if err != nil { if err != nil {

View File

@ -7,7 +7,6 @@ import (
"github.com/StackExchange/dnscontrol/v4/models" "github.com/StackExchange/dnscontrol/v4/models"
"github.com/StackExchange/dnscontrol/v4/pkg/printer" "github.com/StackExchange/dnscontrol/v4/pkg/printer"
"github.com/StackExchange/dnscontrol/v4/pkg/txtutil"
"github.com/go-gandi/go-gandi/livedns" "github.com/go-gandi/go-gandi/livedns"
) )
@ -31,18 +30,7 @@ func nativeToRecords(n livedns.DomainRecord, origin string) (rcs []*models.Recor
rc.Type = "ALIAS" rc.Type = "ALIAS"
err = rc.SetTarget(value) err = rc.SetTarget(value)
case "TXT": case "TXT":
t := value err = rc.SetTargetTXTfromRFC1035Quoted(value)
//printer.Printf("DEBUG gandi txt inbounds=%s q=%q\n", t, t)
td, err := txtutil.ParseQuoted(t)
if err != nil {
return nil, err
}
//td := t
//printer.Printf("DEBUG gandi txt decodeds=%s q=%q\n", td, td)
err = rc.SetTargetTXT(td)
if err != nil {
return nil, err
}
default: default:
err = rc.PopulateFromString(rtype, value, origin) err = rc.PopulateFromString(rtype, value, origin)
} }
@ -71,27 +59,17 @@ func recordsToNative(rcs []*models.RecordConfig, origin string) []livedns.Domain
} }
key := r.Key() key := r.Key()
var val string
if r.Type == "TXT" {
t := r.GetTargetTXTJoined()
//printer.Printf("DEBUG: txt outbounds=%s q=%q\n", t, t)
val = txtutil.EncodeQuoted(t)
//printer.Printf("DEBUG: txt encodeds=%s q=%q\n", val, val)
} else {
val = r.GetTargetCombined()
}
if zr, ok := keys[key]; !ok { if zr, ok := keys[key]; !ok {
// Allocate a new ZoneRecord: // Allocate a new ZoneRecord:
zr := livedns.DomainRecord{ zr := livedns.DomainRecord{
RrsetType: r.Type, RrsetType: r.Type,
RrsetTTL: int(r.TTL), RrsetTTL: int(r.TTL),
RrsetName: label, RrsetName: label,
RrsetValues: []string{val}, RrsetValues: []string{r.GetTargetCombined()},
} }
keys[key] = &zr keys[key] = &zr
} else { } else {
zr.RrsetValues = append(zr.RrsetValues, val) zr.RrsetValues = append(zr.RrsetValues, r.GetTargetCombined())
if r.TTL != uint32(zr.RrsetTTL) { if r.TTL != uint32(zr.RrsetTTL) {
printer.Warnf("All TTLs for a rrset (%v) must be the same. Using smaller of %v and %v.\n", key, r.TTL, zr.RrsetTTL) printer.Warnf("All TTLs for a rrset (%v) must be the same. Using smaller of %v and %v.\n", key, r.TTL, zr.RrsetTTL)
@ -99,6 +77,7 @@ func recordsToNative(rcs []*models.RecordConfig, origin string) []livedns.Domain
zr.RrsetTTL = int(r.TTL) zr.RrsetTTL = int(r.TTL)
} }
} }
} }
} }

View File

@ -24,6 +24,7 @@ import (
"github.com/StackExchange/dnscontrol/v4/models" "github.com/StackExchange/dnscontrol/v4/models"
"github.com/StackExchange/dnscontrol/v4/pkg/diff2" "github.com/StackExchange/dnscontrol/v4/pkg/diff2"
"github.com/StackExchange/dnscontrol/v4/pkg/printer" "github.com/StackExchange/dnscontrol/v4/pkg/printer"
"github.com/StackExchange/dnscontrol/v4/pkg/txtutil"
"github.com/StackExchange/dnscontrol/v4/providers" "github.com/StackExchange/dnscontrol/v4/providers"
"github.com/go-gandi/go-gandi" "github.com/go-gandi/go-gandi"
"github.com/go-gandi/go-gandi/config" "github.com/go-gandi/go-gandi/config"
@ -175,6 +176,9 @@ func PrepDesiredRecords(dc *models.DomainConfig) {
printer.Warnf("Gandi does not support ttls > 30 days. Setting %s from %d to 2592000\n", rec.GetLabelFQDN(), rec.TTL) printer.Warnf("Gandi does not support ttls > 30 days. Setting %s from %d to 2592000\n", rec.GetLabelFQDN(), rec.TTL)
rec.TTL = 2592000 rec.TTL = 2592000
} }
if rec.Type == "TXT" {
rec.SetTarget("\"" + rec.GetTargetField() + "\"") // FIXME(tlim): Should do proper quoting.
}
if rec.Type == "NS" && rec.GetLabel() == "@" { if rec.Type == "NS" && rec.GetLabel() == "@" {
if !strings.HasSuffix(rec.GetTargetField(), ".gandi.net.") { if !strings.HasSuffix(rec.GetTargetField(), ".gandi.net.") {
printer.Warnf("Gandi does not support changing apex NS records. Ignoring %s\n", rec.GetTargetField()) printer.Warnf("Gandi does not support changing apex NS records. Ignoring %s\n", rec.GetTargetField())
@ -194,6 +198,7 @@ func (client *gandiv5Provider) GetZoneRecordsCorrections(dc *models.DomainConfig
} }
PrepDesiredRecords(dc) PrepDesiredRecords(dc)
txtutil.SplitSingleLongTxt(dc.Records) // Autosplit long TXT records
g := gandi.NewLiveDNSClient(config.Config{ g := gandi.NewLiveDNSClient(config.Config{
APIKey: client.apikey, APIKey: client.apikey,

View File

@ -259,6 +259,8 @@ type correctionValues struct {
// GetZoneRecordsCorrections returns a list of corrections that will turn existing records into dc.Records. // GetZoneRecordsCorrections returns a list of corrections that will turn existing records into dc.Records.
func (g *gcloudProvider) GetZoneRecordsCorrections(dc *models.DomainConfig, existingRecords models.Records) ([]*models.Correction, error) { func (g *gcloudProvider) GetZoneRecordsCorrections(dc *models.DomainConfig, existingRecords models.Records) ([]*models.Correction, error) {
txtutil.SplitSingleLongTxt(dc.Records) // Autosplit long TXT records
oldRRs, ok := g.oldRRsMap[dc.Name] oldRRs, ok := g.oldRRsMap[dc.Name]
if !ok { if !ok {
return nil, fmt.Errorf("oldRRsMap: no zone named %q", dc.Name) return nil, fmt.Errorf("oldRRsMap: no zone named %q", dc.Name)
@ -304,22 +306,7 @@ func (g *gcloudProvider) GetZoneRecordsCorrections(dc *models.DomainConfig, exis
} }
for _, r := range dc.Records { for _, r := range dc.Records {
if keyForRec(r) == ck { if keyForRec(r) == ck {
if ck.Type == "TXT" { newRRs.Rrdatas = append(newRRs.Rrdatas, r.GetTargetCombined())
// NB(tlim): These next two lines should not be merged. The
// chunks need to be allocated in a way that the memory is
// not re-used in the next iteration.
//chunks := txtutil.ToChunks(r.GetTargetField())
//printer.Printf("DEBUG: gcloud txt chunks=%+v\n", chunks)
//newRRs.Rrdatas = append(newRRs.Rrdatas, chunks[0:]...)
t := r.GetTargetField()
//printer.Printf("DEBUG: gcloud outboundv=%v\n", t)
//tc := txtutil.RFC1035ChunkedAndQuoted(t)
tc := txtutil.EncodeQuoted(t)
//printer.Printf("DEBUG: gcloud encodedv=%v\n", tc)
newRRs.Rrdatas = append(newRRs.Rrdatas, tc)
} else {
newRRs.Rrdatas = append(newRRs.Rrdatas, r.GetTargetCombined())
}
newRRs.Ttl = int64(r.TTL) newRRs.Ttl = int64(r.TTL)
} }
} }
@ -416,7 +403,13 @@ func nativeToRecord(set *gdns.ResourceRecordSet, rec, origin string) (*models.Re
r.SetLabelFromFQDN(set.Name, origin) r.SetLabelFromFQDN(set.Name, origin)
r.TTL = uint32(set.Ttl) r.TTL = uint32(set.Ttl)
rtype := set.Type rtype := set.Type
err := r.PopulateFromString(rtype, rec, origin) var err error
switch rtype {
case "TXT":
err = r.SetTargetTXTs(models.ParseQuotedTxt(rec))
default:
err = r.PopulateFromString(rtype, rec, origin)
}
if err != nil { if err != nil {
return nil, fmt.Errorf("unparsable record %q received from GCLOUD: %w", rtype, err) return nil, fmt.Errorf("unparsable record %q received from GCLOUD: %w", rtype, err)
} }

View File

@ -86,7 +86,7 @@ func recordsToNative(rcs []*models.RecordConfig, expectedKey models.RecordKey) *
} }
case "TXT": // Avoid double quoting for TXT records case "TXT": // Avoid double quoting for TXT records
rr = dnssdk.ResourceRecord{ rr = dnssdk.ResourceRecord{
Content: convertTxtSliceToSdkAnySlice([]string{r.GetTargetCombined()}), Content: convertTxtSliceToSdkAnySlice(r.GetTargetTXTSegmented()),
Meta: nil, Meta: nil,
Enabled: true, Enabled: true,
} }

View File

@ -191,6 +191,9 @@ func (c *hednsProvider) GetZoneRecordsCorrections(dc *models.DomainConfig, recor
} }
} }
// Normalize
txtutil.SplitSingleLongTxt(dc.Records) // Autosplit long TXT records
return c.getDiff2DomainCorrections(dc, zoneID, prunedRecords) return c.getDiff2DomainCorrections(dc, zoneID, prunedRecords)
} }
@ -323,10 +326,7 @@ func (c *hednsProvider) GetZoneRecords(domain string, meta map[string]string) (m
rc.Type = "TXT" rc.Type = "TXT"
fallthrough fallthrough
case "TXT": case "TXT":
//err = rc.SetTargetTXTs(models.ParseQuotedTxt(data)) err = rc.SetTargetTXTs(models.ParseQuotedTxt(data))
var t string
t, err = txtutil.ParseQuoted(data)
err = rc.SetTargetTXT(t)
default: default:
err = rc.PopulateFromString(rc.Type, data, domain) err = rc.PopulateFromString(rc.Type, data, domain)
} }

View File

@ -7,6 +7,7 @@ import (
"github.com/StackExchange/dnscontrol/v4/models" "github.com/StackExchange/dnscontrol/v4/models"
"github.com/StackExchange/dnscontrol/v4/pkg/diff" "github.com/StackExchange/dnscontrol/v4/pkg/diff"
"github.com/StackExchange/dnscontrol/v4/pkg/txtutil"
"github.com/StackExchange/dnscontrol/v4/providers" "github.com/StackExchange/dnscontrol/v4/providers"
) )
@ -71,6 +72,8 @@ func (api *hetznerProvider) EnsureZoneExists(domain string) error {
func (api *hetznerProvider) GetZoneRecordsCorrections(dc *models.DomainConfig, existingRecords models.Records) ([]*models.Correction, error) { func (api *hetznerProvider) GetZoneRecordsCorrections(dc *models.DomainConfig, existingRecords models.Records) ([]*models.Correction, error) {
domain := dc.Name domain := dc.Name
txtutil.SplitSingleLongTxt(dc.Records) // Autosplit long TXT records
toReport, create, del, modify, err := diff.NewCompat(dc).IncrementalDiff(existingRecords) toReport, create, del, modify, err := diff.NewCompat(dc).IncrementalDiff(existingRecords)
if err != nil { if err != nil {
return nil, err return nil, err

View File

@ -13,8 +13,6 @@ func AuditRecords(records []*models.RecordConfig) []error {
a.Add("TXT", rejectif.TxtIsEmpty) // Last verified 2021-10-01 a.Add("TXT", rejectif.TxtIsEmpty) // Last verified 2021-10-01
a.Add("TXT", rejectif.TxtIsEmpty) // Last verified 2023-10-27
a.Add("SRV", rejectif.SrvHasNullTarget) // Last verified 2020-12-28 a.Add("SRV", rejectif.SrvHasNullTarget) // Last verified 2020-12-28
return a.Audit(records) return a.Audit(records)

View File

@ -9,6 +9,7 @@ import (
"github.com/StackExchange/dnscontrol/v4/models" "github.com/StackExchange/dnscontrol/v4/models"
"github.com/StackExchange/dnscontrol/v4/pkg/diff" "github.com/StackExchange/dnscontrol/v4/pkg/diff"
"github.com/StackExchange/dnscontrol/v4/pkg/txtutil"
) )
// HXRecord covers an individual DNS resource record. // HXRecord covers an individual DNS resource record.
@ -57,6 +58,8 @@ func (n *HXClient) GetZoneRecords(domain string, meta map[string]string) (models
// GetZoneRecordsCorrections returns a list of corrections that will turn existing records into dc.Records. // GetZoneRecordsCorrections returns a list of corrections that will turn existing records into dc.Records.
func (n *HXClient) GetZoneRecordsCorrections(dc *models.DomainConfig, actual models.Records) ([]*models.Correction, error) { func (n *HXClient) GetZoneRecordsCorrections(dc *models.DomainConfig, actual models.Records) ([]*models.Correction, error) {
txtutil.SplitSingleLongTxt(dc.Records)
toReport, create, del, mod, err := diff.NewCompat(dc).IncrementalDiff(actual) toReport, create, del, mod, err := diff.NewCompat(dc).IncrementalDiff(actual)
if err != nil { if err != nil {
return nil, err return nil, err
@ -239,7 +242,7 @@ func (n *HXClient) createRecordString(rc *models.RecordConfig, domain string) (s
case "CAA": case "CAA":
record.Answer = fmt.Sprintf(`%v %s "%s"`, rc.CaaFlag, rc.CaaTag, record.Answer) record.Answer = fmt.Sprintf(`%v %s "%s"`, rc.CaaFlag, rc.CaaTag, record.Answer)
case "TXT": case "TXT":
record.Answer = encodeTxt([]string{rc.GetTargetField()}) record.Answer = encodeTxt(rc.GetTargetTXTSegmented())
case "SRV": case "SRV":
if rc.GetTargetField() == "." { if rc.GetTargetField() == "." {
return "", fmt.Errorf("SRV records with empty targets are not supported (as of 2020-02-27, the API returns 'Invalid attribute value syntax')") return "", fmt.Errorf("SRV records with empty targets are not supported (as of 2020-02-27, the API returns 'Invalid attribute value syntax')")

View File

@ -193,9 +193,9 @@ func recordToNative(rc *models.RecordConfig) *record {
case "A", "AAAA", "ALIAS", "CAA", "CNAME", "DNSKEY", "DS", "NS", "NSEC", "NSEC3", "NSEC3PARAM", "PTR", "RRSIG", "SSHFP", "TSLA": case "A", "AAAA", "ALIAS", "CAA", "CNAME", "DNSKEY", "DS", "NS", "NSEC", "NSEC3", "NSEC3PARAM", "PTR", "RRSIG", "SSHFP", "TSLA":
// Nothing special. // Nothing special.
case "TXT": case "TXT":
//txtStrings := make([]string, len(rc.TxtStrings)) // TODO(tlim): Move this to a function with unit tests.
//copy(txtStrings, rc.TxtStrings) txtStrings := make([]string, rc.GetTargetTXTSegmentCount())
txtStrings := []string{rc.GetTargetField()} copy(txtStrings, rc.GetTargetTXTSegmented())
// Escape quotes // Escape quotes
for i := range txtStrings { for i := range txtStrings {

View File

@ -10,6 +10,7 @@ import (
"github.com/StackExchange/dnscontrol/v4/models" "github.com/StackExchange/dnscontrol/v4/models"
"github.com/StackExchange/dnscontrol/v4/pkg/diff" "github.com/StackExchange/dnscontrol/v4/pkg/diff"
"github.com/StackExchange/dnscontrol/v4/pkg/printer" "github.com/StackExchange/dnscontrol/v4/pkg/printer"
"github.com/StackExchange/dnscontrol/v4/pkg/txtutil"
"github.com/StackExchange/dnscontrol/v4/providers" "github.com/StackExchange/dnscontrol/v4/providers"
"github.com/nrdcg/goinwx" "github.com/nrdcg/goinwx"
"github.com/pquerna/otp/totp" "github.com/pquerna/otp/totp"
@ -215,9 +216,10 @@ func checkRecords(records models.Records) error {
// TODO(tlim) Remove this function. auditrecords.go takes care of this now. // TODO(tlim) Remove this function. auditrecords.go takes care of this now.
for _, r := range records { for _, r := range records {
if r.Type == "TXT" { if r.Type == "TXT" {
target := r.GetTargetField() for _, target := range r.GetTargetTXTSegmented() {
if strings.ContainsAny(target, "`") { if strings.ContainsAny(target, "`") {
return fmt.Errorf("INWX TXT records do not support single-quotes in their target") return fmt.Errorf("INWX TXT records do not support single-quotes in their target")
}
} }
} }
} }
@ -226,6 +228,9 @@ func checkRecords(records models.Records) error {
// GetZoneRecordsCorrections returns a list of corrections that will turn existing records into dc.Records. // GetZoneRecordsCorrections returns a list of corrections that will turn existing records into dc.Records.
func (api *inwxAPI) GetZoneRecordsCorrections(dc *models.DomainConfig, foundRecords models.Records) ([]*models.Correction, error) { func (api *inwxAPI) GetZoneRecordsCorrections(dc *models.DomainConfig, foundRecords models.Records) ([]*models.Correction, error) {
txtutil.SplitSingleLongTxt(dc.Records) // Autosplit long TXT records
err := checkRecords(dc.Records) err := checkRecords(dc.Records)
if err != nil { if err != nil {
return nil, err return nil, err

View File

@ -1,6 +1,8 @@
package loopia package loopia
import ( import (
"fmt"
"github.com/StackExchange/dnscontrol/v4/models" "github.com/StackExchange/dnscontrol/v4/models"
"github.com/StackExchange/dnscontrol/v4/pkg/rejectif" "github.com/StackExchange/dnscontrol/v4/pkg/rejectif"
) )
@ -23,6 +25,10 @@ func AuditRecords(records []*models.RecordConfig) []error {
// TxtHasSegmentLen450orLonger audits TXT records for strings that are >450 octets. // TxtHasSegmentLen450orLonger audits TXT records for strings that are >450 octets.
func TxtHasSegmentLen450orLonger(rc *models.RecordConfig) error { func TxtHasSegmentLen450orLonger(rc *models.RecordConfig) error {
// No longer needed. We always generate segments that are 255 octets or fewer. for _, txt := range rc.GetTargetTXTSegmented() {
if len(txt) > 450 {
return fmt.Errorf("%q txtstring length > 450", rc.GetLabel())
}
}
return nil return nil
} }

View File

@ -25,6 +25,7 @@ import (
"github.com/StackExchange/dnscontrol/v4/models" "github.com/StackExchange/dnscontrol/v4/models"
"github.com/StackExchange/dnscontrol/v4/pkg/diff" "github.com/StackExchange/dnscontrol/v4/pkg/diff"
"github.com/StackExchange/dnscontrol/v4/pkg/printer" "github.com/StackExchange/dnscontrol/v4/pkg/printer"
"github.com/StackExchange/dnscontrol/v4/pkg/txtutil"
"github.com/StackExchange/dnscontrol/v4/providers" "github.com/StackExchange/dnscontrol/v4/providers"
"github.com/miekg/dns/dnsutil" "github.com/miekg/dns/dnsutil"
) )
@ -271,6 +272,7 @@ func (c *APIClient) GetZoneRecordsCorrections(dc *models.DomainConfig, existingR
} }
// Normalize // Normalize
txtutil.SplitSingleLongTxt(dc.Records) // Autosplit long TXT records
PrepDesiredRecords(dc) PrepDesiredRecords(dc)
var keysToUpdate map[models.RecordKey][]string var keysToUpdate map[models.RecordKey][]string

View File

@ -19,7 +19,7 @@ func AuditRecords(records []*models.RecordConfig) []error {
a.Add("TXT", rejectif.TxtHasDoubleQuotes) // Last verified 2023-02-02 a.Add("TXT", rejectif.TxtHasDoubleQuotes) // Last verified 2023-02-02
a.Add("TXT", rejectif.TxtLongerThan255) // Last verified 2023-02-02 a.Add("TXT", rejectif.TxtHasMultipleSegments) // Last verified 2023-02-02
a.Add("TXT", rejectif.TxtHasSegmentLen256orLonger) // Last verified 2023-02-02 a.Add("TXT", rejectif.TxtHasSegmentLen256orLonger) // Last verified 2023-02-02
@ -29,5 +29,7 @@ func AuditRecords(records []*models.RecordConfig) []error {
a.Add("TXT", rejectif.TxtIsExactlyLen255) // Last verified 2023-02-02 a.Add("TXT", rejectif.TxtIsExactlyLen255) // Last verified 2023-02-02
a.Add("TXT", rejectif.TxtIsExactlyLen255) // Last verified 2023-02-02
return a.Audit(records) return a.Audit(records)
} }

View File

@ -5,6 +5,7 @@ import (
"github.com/StackExchange/dnscontrol/v4/models" "github.com/StackExchange/dnscontrol/v4/models"
"github.com/StackExchange/dnscontrol/v4/pkg/diff2" "github.com/StackExchange/dnscontrol/v4/pkg/diff2"
"github.com/StackExchange/dnscontrol/v4/pkg/txtutil"
) )
// GetZoneRecordsCorrections returns a list of corrections that will turn existing records into dc.Records. // GetZoneRecordsCorrections returns a list of corrections that will turn existing records into dc.Records.
@ -13,6 +14,7 @@ func (client *msdnsProvider) GetZoneRecordsCorrections(dc *models.DomainConfig,
// Normalize // Normalize
models.PostProcessRecords(foundRecords) models.PostProcessRecords(foundRecords)
txtutil.SplitSingleLongTxt(dc.Records) // Autosplit long TXT records
changes, err := diff2.ByRecord(foundRecords, dc, nil) changes, err := diff2.ByRecord(foundRecords, dc, nil)
if err != nil { if err != nil {

View File

@ -14,15 +14,13 @@ import (
func AuditRecords(records []*models.RecordConfig) []error { func AuditRecords(records []*models.RecordConfig) []error {
a := rejectif.Auditor{} a := rejectif.Auditor{}
a.Add("MX", rejectif.MxNull) // Last verified 2023-10-25 a.Add("MX", rejectif.MxNull) // Last verified 2020-12-28
a.Add("SRV", rejectif.SrvHasNullTarget) // Last verified 2023-10-25 a.Add("SRV", rejectif.SrvHasNullTarget) // Last verified 2020-12-28
a.Add("TXT", MaxLengthNDC) // Last verified 2023-10-25 a.Add("TXT", MaxLengthNDC) // Last verified 2021-03-01
a.Add("TXT", rejectif.TxtIsEmpty) // Last verified 2023-10-25 a.Add("TXT", rejectif.TxtIsEmpty) // Last verified 2021-03-01
a.Add("TXT", rejectif.TxtHasTrailingSpace) // Last verified 2023-10-25
return a.Audit(records) return a.Audit(records)
} }
@ -32,8 +30,7 @@ func AuditRecords(records []*models.RecordConfig) []error {
// length limit is undocumented. This seems to work. // length limit is undocumented. This seems to work.
func MaxLengthNDC(rc *models.RecordConfig) error { func MaxLengthNDC(rc *models.RecordConfig) error {
txtStrings := rc.GetTargetTXTSegmented() txtStrings := rc.GetTargetTXTSegmented()
if len(txtStrings) == 0 {
if rc.GetTargetTXTJoined() == "" {
return nil return nil
} }

View File

@ -11,7 +11,7 @@ import (
func AuditRecords(records []*models.RecordConfig) []error { func AuditRecords(records []*models.RecordConfig) []error {
a := rejectif.Auditor{} a := rejectif.Auditor{}
a.Add("TXT", rejectif.TxtLongerThan255) a.Add("TXT", rejectif.TxtHasMultipleSegments)
return a.Audit(records) return a.Audit(records)
} }

View File

@ -9,7 +9,6 @@ import (
"github.com/StackExchange/dnscontrol/v4/models" "github.com/StackExchange/dnscontrol/v4/models"
"github.com/StackExchange/dnscontrol/v4/pkg/diff2" "github.com/StackExchange/dnscontrol/v4/pkg/diff2"
"github.com/StackExchange/dnscontrol/v4/pkg/txtutil"
"github.com/StackExchange/dnscontrol/v4/providers" "github.com/StackExchange/dnscontrol/v4/providers"
"gopkg.in/ns1/ns1-go.v2/rest" "gopkg.in/ns1/ns1-go.v2/rest"
"gopkg.in/ns1/ns1-go.v2/rest/model/dns" "gopkg.in/ns1/ns1-go.v2/rest/model/dns"
@ -303,7 +302,7 @@ func buildRecord(recs models.Records, domain string, id string) *dns.Record {
if r.Type == "MX" { if r.Type == "MX" {
rec.AddAnswer(&dns.Answer{Rdata: strings.Fields(fmt.Sprintf("%d %v", r.MxPreference, r.GetTargetField()))}) rec.AddAnswer(&dns.Answer{Rdata: strings.Fields(fmt.Sprintf("%d %v", r.MxPreference, r.GetTargetField()))})
} else if r.Type == "TXT" { } else if r.Type == "TXT" {
rec.AddAnswer(&dns.Answer{Rdata: txtutil.ToChunks(r.GetTargetField())}) rec.AddAnswer(&dns.Answer{Rdata: r.GetTargetTXTSegmented()})
} else if r.Type == "CAA" { } else if r.Type == "CAA" {
rec.AddAnswer(&dns.Answer{ rec.AddAnswer(&dns.Answer{
Rdata: []string{ Rdata: []string{

View File

@ -9,6 +9,7 @@ import (
"github.com/StackExchange/dnscontrol/v4/models" "github.com/StackExchange/dnscontrol/v4/models"
"github.com/StackExchange/dnscontrol/v4/pkg/diff" "github.com/StackExchange/dnscontrol/v4/pkg/diff"
"github.com/StackExchange/dnscontrol/v4/pkg/printer" "github.com/StackExchange/dnscontrol/v4/pkg/printer"
"github.com/StackExchange/dnscontrol/v4/pkg/txtutil"
"github.com/StackExchange/dnscontrol/v4/providers" "github.com/StackExchange/dnscontrol/v4/providers"
"github.com/oracle/oci-go-sdk/v32/common" "github.com/oracle/oci-go-sdk/v32/common"
"github.com/oracle/oci-go-sdk/v32/dns" "github.com/oracle/oci-go-sdk/v32/dns"
@ -203,6 +204,7 @@ func (o *oracleProvider) GetZoneRecords(zone string, meta map[string]string) (mo
// GetZoneRecordsCorrections returns a list of corrections that will turn existing records into dc.Records. // GetZoneRecordsCorrections returns a list of corrections that will turn existing records into dc.Records.
func (o *oracleProvider) GetZoneRecordsCorrections(dc *models.DomainConfig, existingRecords models.Records) ([]*models.Correction, error) { func (o *oracleProvider) GetZoneRecordsCorrections(dc *models.DomainConfig, existingRecords models.Records) ([]*models.Correction, error) {
var err error var err error
txtutil.SplitSingleLongTxt(dc.Records) // Autosplit long TXT records
// Ensure we don't emit changes for attempted modification of built-in apex NSs // Ensure we don't emit changes for attempted modification of built-in apex NSs
for _, rec := range dc.Records { for _, rec := range dc.Records {

View File

@ -17,21 +17,19 @@ func TestToRecordConfig(t *testing.T) {
assert.NoError(t, err) assert.NoError(t, err)
assert.Equal(t, "test.example.com", recordConfig.NameFQDN) assert.Equal(t, "test.example.com", recordConfig.NameFQDN)
assert.Equal(t, "simple", recordConfig.GetTargetTXTJoined()) assert.Equal(t, "\"simple\"", recordConfig.String())
assert.Equal(t, uint32(120), recordConfig.TTL) assert.Equal(t, uint32(120), recordConfig.TTL)
assert.Equal(t, "TXT", recordConfig.Type) assert.Equal(t, "TXT", recordConfig.Type)
largeContent := fmt.Sprintf(`"%s" "%s"`, strings.Repeat("A", 300), strings.Repeat("B", 300)) largeContent := fmt.Sprintf("\"%s\" \"%s\"", strings.Repeat("A", 300), strings.Repeat("B", 300))
largeRecord := zones.Record{ largeRecord := zones.Record{
Content: largeContent, Content: largeContent,
} }
recordConfig, err = toRecordConfig("example.com", largeRecord, 5, "large", "TXT") recordConfig, err = toRecordConfig("example.com", largeRecord, 5, "large", "TXT")
//largeJoined := `"` + strings.Repeat("A", 300) + strings.Repeat("B", 300) + `"`
largeJoined := strings.Repeat("A", 300) + strings.Repeat("B", 300)
assert.NoError(t, err) assert.NoError(t, err)
assert.Equal(t, "large.example.com", recordConfig.NameFQDN) assert.Equal(t, "large.example.com", recordConfig.NameFQDN)
assert.Equal(t, largeJoined, recordConfig.GetTargetTXTJoined()) assert.Equal(t, largeContent, recordConfig.String())
assert.Equal(t, uint32(5), recordConfig.TTL) assert.Equal(t, uint32(5), recordConfig.TTL)
assert.Equal(t, "TXT", recordConfig.Type) assert.Equal(t, "TXT", recordConfig.Type)
} }

View File

@ -278,6 +278,8 @@ func (r *route53Provider) getZoneRecords(zone r53Types.HostedZone) (models.Recor
// GetZoneRecordsCorrections returns a list of corrections that will turn existing records into dc.Records. // GetZoneRecordsCorrections returns a list of corrections that will turn existing records into dc.Records.
func (r *route53Provider) GetZoneRecordsCorrections(dc *models.DomainConfig, existingRecords models.Records) ([]*models.Correction, error) { func (r *route53Provider) GetZoneRecordsCorrections(dc *models.DomainConfig, existingRecords models.Records) ([]*models.Correction, error) {
txtutil.SplitSingleLongTxt(dc.Records) // Autosplit long TXT records
zone, err := r.getZone(dc) zone, err := r.getZone(dc)
if err != nil { if err != nil {
return nil, err return nil, err
@ -341,35 +343,10 @@ func (r *route53Provider) GetZoneRecordsCorrections(dc *models.DomainConfig, exi
} }
for _, r := range inst.New { for _, r := range inst.New {
rr := r53Types.ResourceRecord{
var rr r53Types.ResourceRecord Value: aws.String(r.GetTargetCombined()),
if instType == "TXT" {
// //printer.Printf("DEBUG: txt originalv=%v\n", r.GetTargetField())
// //t := txtutil.RFC1035ChunkedAndQuoted(r.GetTargetField())
// //printer.Printf("DEBUG: txt outbound=%q\n", t)
// ts := r.GetTargetTXTChunked255()
// //t = strings.ReplaceAll(t, `\`, `\\`)
// //t = strings.ReplaceAll(t, `"`, `\"`)
// for i := range ts {
// ts[i] = strings.ReplaceAll(ts[i], `\`, `\\`)
// ts[i] = strings.ReplaceAll(ts[i], `"`, `\"`)
// }
// t := `"` + strings.Join(ts, `" "`) + `"`
// printer.Printf("DEBUG: txt outboundv=%v\n", t)
t := txtutil.EncodeQuoted(r.GetTargetField())
//printer.Printf("XXXXXXXXX %v\n", t)
rr = r53Types.ResourceRecord{
Value: aws.String(t),
}
} else {
rr = r53Types.ResourceRecord{
Value: aws.String(r.GetTargetCombined()),
}
} }
rrset.ResourceRecords = append(rrset.ResourceRecords, rr) rrset.ResourceRecords = append(rrset.ResourceRecords, rr)
i := int64(r.TTL) i := int64(r.TTL)
rrset.TTL = &i rrset.TTL = &i
} }
@ -515,20 +492,7 @@ func nativeToRecords(set r53Types.ResourceRecordSet, origin string) ([]*models.R
rc.Original = set rc.Original = set
switch rtypeString { switch rtypeString {
case "TXT": case "TXT":
//printer.Printf("DEBUG: txt inboundv=%v\n", val) err = rc.SetTargetTXTs(models.ParseQuotedTxt(val))
//printer.Printf("DEBUG: txt decoded=%v\n", models.ParseQuotedTxt(val)[0])
//err = rc.SetTargetTXTs(models.ParseQuotedTxt(val))
//dt, _ := models.ParseQuotedFields(val)
//printer.Printf("DEBUG: txt decodedv=%v\n", dt)
//err = rc.SetTargetTXTs(dt)
var t string
t, err = txtutil.ParseQuoted(val)
if err == nil {
err = rc.SetTargetTXT(t)
}
default: default:
err = rc.PopulateFromString(rtypeString, val, origin) err = rc.PopulateFromString(rtypeString, val, origin)
} }

View File

@ -11,7 +11,7 @@ import (
func AuditRecords(records []*models.RecordConfig) []error { func AuditRecords(records []*models.RecordConfig) []error {
a := rejectif.Auditor{} a := rejectif.Auditor{}
a.Add("TXT", rejectif.TxtLongerThan255) a.Add("TXT", rejectif.TxtHasMultipleSegments)
a.Add("TXT", rejectif.TxtHasTrailingSpace) a.Add("TXT", rejectif.TxtHasTrailingSpace)

View File

@ -5,6 +5,7 @@ import (
"github.com/StackExchange/dnscontrol/v4/models" "github.com/StackExchange/dnscontrol/v4/models"
"github.com/StackExchange/dnscontrol/v4/pkg/diff" "github.com/StackExchange/dnscontrol/v4/pkg/diff"
"github.com/StackExchange/dnscontrol/v4/pkg/txtutil"
) )
// RWTHDefaultNs is the default DNS NS for this provider. // RWTHDefaultNs is the default DNS NS for this provider.
@ -30,6 +31,7 @@ func (api *rwthProvider) GetNameservers(domain string) ([]*models.Nameserver, er
// GetZoneRecordsCorrections returns a list of corrections that will turn existing records into dc.Records. // GetZoneRecordsCorrections returns a list of corrections that will turn existing records into dc.Records.
func (api *rwthProvider) GetZoneRecordsCorrections(dc *models.DomainConfig, existingRecords models.Records) ([]*models.Correction, error) { func (api *rwthProvider) GetZoneRecordsCorrections(dc *models.DomainConfig, existingRecords models.Records) ([]*models.Correction, error) {
txtutil.SplitSingleLongTxt(dc.Records) // Autosplit long TXT records
domain := dc.Name domain := dc.Name
toReport, create, del, modify, err := diff.NewCompat(dc).IncrementalDiff(existingRecords) toReport, create, del, modify, err := diff.NewCompat(dc).IncrementalDiff(existingRecords)

View File

@ -17,7 +17,7 @@ func AuditRecords(records []*models.RecordConfig) []error {
// Needs investigation. Could be a dnscontrol issue or // Needs investigation. Could be a dnscontrol issue or
// the provider doesn't support double quotes. // the provider doesn't support double quotes.
a.Add("TXT", rejectif.TxtLongerThan255) a.Add("TXT", rejectif.TxtHasMultipleSegments)
a.Add("CAA", rejectif.CaaTargetContainsWhitespace) // Last verified 2023-01-19 a.Add("CAA", rejectif.CaaTargetContainsWhitespace) // Last verified 2023-01-19