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:
@ -1,5 +1,10 @@
|
||||
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).
|
||||
func ToChunks(s string) []string {
|
||||
return splitChunks(s, 255)
|
||||
|
@ -17,6 +17,7 @@ import (
|
||||
"github.com/StackExchange/dnscontrol/v4/models"
|
||||
"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"
|
||||
)
|
||||
|
||||
@ -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.
|
||||
func (a *edgeDNSProvider) GetZoneRecordsCorrections(dc *models.DomainConfig, existingRecords models.Records) ([]*models.Correction, error) {
|
||||
txtutil.SplitSingleLongTxt(existingRecords)
|
||||
|
||||
keysToUpdate, toReport, err := diff.NewCompat(dc).ChangedGroups(existingRecords)
|
||||
if err != nil {
|
||||
|
@ -11,6 +11,7 @@ import (
|
||||
|
||||
"github.com/StackExchange/dnscontrol/v4/models"
|
||||
"github.com/StackExchange/dnscontrol/v4/pkg/diff2"
|
||||
"github.com/StackExchange/dnscontrol/v4/pkg/txtutil"
|
||||
"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.
|
||||
func (api *autoDNSProvider) GetZoneRecordsCorrections(dc *models.DomainConfig, existingRecords models.Records) ([]*models.Correction, error) {
|
||||
domain := dc.Name
|
||||
txtutil.SplitSingleLongTxt(dc.Records) // Autosplit long TXT records
|
||||
|
||||
var corrections []*models.Correction
|
||||
|
||||
|
@ -25,6 +25,7 @@ import (
|
||||
"github.com/StackExchange/dnscontrol/v4/models"
|
||||
"github.com/StackExchange/dnscontrol/v4/pkg/diff2"
|
||||
"github.com/StackExchange/dnscontrol/v4/pkg/printer"
|
||||
"github.com/StackExchange/dnscontrol/v4/pkg/txtutil"
|
||||
"github.com/StackExchange/dnscontrol/v4/providers"
|
||||
"github.com/fatih/color"
|
||||
"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.
|
||||
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.
|
||||
if len(foundRecords) >= 1 && foundRecords[0].Type == "SOA" {
|
||||
|
@ -13,7 +13,5 @@ func AuditRecords(records []*models.RecordConfig) []error {
|
||||
|
||||
a.Add("MX", rejectif.MxNull) // Last verified 2020-12-28
|
||||
|
||||
a.Add("TXT", rejectif.TxtIsEmpty) // Last verified 2023-10-27
|
||||
|
||||
return a.Audit(records)
|
||||
}
|
||||
|
@ -14,6 +14,7 @@ import (
|
||||
"github.com/StackExchange/dnscontrol/v4/models"
|
||||
"github.com/StackExchange/dnscontrol/v4/pkg/diff2"
|
||||
"github.com/StackExchange/dnscontrol/v4/pkg/printer"
|
||||
"github.com/StackExchange/dnscontrol/v4/pkg/txtutil"
|
||||
"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.
|
||||
func (a *azurednsProvider) GetZoneRecordsCorrections(dc *models.DomainConfig, existingRecords models.Records) ([]*models.Correction, error) {
|
||||
txtutil.SplitSingleLongTxt(existingRecords) // Autosplit long TXT records
|
||||
|
||||
var corrections []*models.Correction
|
||||
|
||||
// Azure is a "ByRecordSet" API.
|
||||
@ -521,7 +524,8 @@ func (a *azurednsProvider) recordToNativeDiff2(recordKey models.RecordKey, recor
|
||||
if recordSet.Properties.TxtRecords == nil {
|
||||
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
|
||||
for _, txt := range rec.GetTargetTXTSegmented() {
|
||||
txts = append(txts, to.StringPtr(txt))
|
||||
|
@ -25,6 +25,7 @@ import (
|
||||
"github.com/StackExchange/dnscontrol/v4/pkg/diff2"
|
||||
"github.com/StackExchange/dnscontrol/v4/pkg/prettyzone"
|
||||
"github.com/StackExchange/dnscontrol/v4/pkg/printer"
|
||||
"github.com/StackExchange/dnscontrol/v4/pkg/txtutil"
|
||||
"github.com/StackExchange/dnscontrol/v4/providers"
|
||||
"github.com/miekg/dns"
|
||||
)
|
||||
@ -194,32 +195,11 @@ func ParseZoneContents(content string, zoneName string, zonefileName string) (mo
|
||||
|
||||
foundRecords := models.Records{}
|
||||
for rr, ok := zp.Next(); ok; rr, ok = zp.Next() {
|
||||
header := rr.Header()
|
||||
rtype := dns.TypeToString[header.Rrtype]
|
||||
if rtype == "TXT" {
|
||||
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)
|
||||
rec, err := models.RRtoRC(rr, zoneName)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
foundRecords = append(foundRecords, &rec)
|
||||
}
|
||||
|
||||
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.
|
||||
func (c *bindProvider) GetZoneRecordsCorrections(dc *models.DomainConfig, foundRecords models.Records) ([]*models.Correction, error) {
|
||||
txtutil.SplitSingleLongTxt(dc.Records)
|
||||
var corrections []*models.Correction
|
||||
|
||||
changes := false
|
||||
|
@ -11,11 +11,11 @@ import (
|
||||
func AuditRecords(records []*models.RecordConfig) []error {
|
||||
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)
|
||||
}
|
||||
|
@ -19,7 +19,7 @@ func AuditRecords(records []*models.RecordConfig) []error {
|
||||
|
||||
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
|
||||
|
||||
|
@ -17,7 +17,7 @@ func AuditRecords(records []*models.RecordConfig) []error {
|
||||
|
||||
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
|
||||
|
||||
|
@ -4,10 +4,12 @@ import (
|
||||
"bytes"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"sort"
|
||||
|
||||
"github.com/StackExchange/dnscontrol/v4/models"
|
||||
"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/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.
|
||||
func (c *desecProvider) GetZoneRecordsCorrections(dc *models.DomainConfig, existing models.Records) ([]*models.Correction, error) {
|
||||
txtutil.SplitSingleLongTxt(dc.Records)
|
||||
|
||||
var minTTL uint32
|
||||
c.mutex.Lock()
|
||||
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
|
||||
// pass. That said, if this breaks anything, the easiest fix might
|
||||
// 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
|
||||
}
|
||||
|
@ -19,11 +19,9 @@ func AuditRecords(records []*models.RecordConfig) []error {
|
||||
|
||||
a.Add("TXT", MaxLengthDO) // Last verified 2021-03-01
|
||||
|
||||
a.Add("TXT", rejectif.TxtHasBackslash) // Last verified 2023-11-12
|
||||
// The web portal rejects blackslashes too
|
||||
|
||||
a.Add("TXT", rejectif.TxtHasDoubleQuotes) // Last verified 2023-11-12
|
||||
// The web portal rejects double quotes
|
||||
a.Add("TXT", rejectif.TxtHasDoubleQuotes) // Last verified 2021-03-01
|
||||
// Double-quotes not permitted in TXT strings. I have a hunch that
|
||||
// this is due to a broken parser on the DO side.
|
||||
|
||||
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
|
||||
// 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")
|
||||
}
|
||||
|
||||
|
@ -10,7 +10,7 @@ import (
|
||||
|
||||
"github.com/StackExchange/dnscontrol/v4/models"
|
||||
"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/digitalocean/godo"
|
||||
"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.
|
||||
func (api *digitaloceanProvider) GetZoneRecordsCorrections(dc *models.DomainConfig, existingRecords models.Records) ([]*models.Correction, error) {
|
||||
txtutil.SplitSingleLongTxt(dc.Records) // Autosplit long TXT records
|
||||
|
||||
ctx := context.Background()
|
||||
|
||||
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)
|
||||
switch rtype := r.Type; rtype {
|
||||
case "TXT":
|
||||
printer.Printf("DEBUG: DIGITAL TXT inbounds=%s q=%q\n", target, target)
|
||||
t.SetTargetTXT(target)
|
||||
default:
|
||||
t.SetTarget(target)
|
||||
@ -324,7 +325,6 @@ func toReq(dc *models.DomainConfig, rc *models.RecordConfig) *godo.DomainRecordE
|
||||
case "TXT":
|
||||
// TXT records are the one place where DO combines many items into one field.
|
||||
target = rc.GetTargetTXTJoined()
|
||||
printer.Printf("DEBUG: DIGITAL TXT outbounds=%s q=%q\n", target, target)
|
||||
default:
|
||||
// no action required
|
||||
}
|
||||
|
@ -13,7 +13,7 @@ func AuditRecords(records []*models.RecordConfig) []error {
|
||||
|
||||
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
|
||||
|
||||
|
@ -8,6 +8,7 @@ import (
|
||||
|
||||
"github.com/StackExchange/dnscontrol/v4/models"
|
||||
"github.com/StackExchange/dnscontrol/v4/pkg/diff"
|
||||
"github.com/StackExchange/dnscontrol/v4/pkg/txtutil"
|
||||
"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) {
|
||||
txtutil.SplitSingleLongTxt(dc.Records) // Autosplit long TXT records
|
||||
|
||||
domainName := dc.Name
|
||||
domain, err := api.findDomain(domainName)
|
||||
if err != nil {
|
||||
|
@ -7,7 +7,6 @@ import (
|
||||
|
||||
"github.com/StackExchange/dnscontrol/v4/models"
|
||||
"github.com/StackExchange/dnscontrol/v4/pkg/printer"
|
||||
"github.com/StackExchange/dnscontrol/v4/pkg/txtutil"
|
||||
"github.com/go-gandi/go-gandi/livedns"
|
||||
)
|
||||
|
||||
@ -31,18 +30,7 @@ func nativeToRecords(n livedns.DomainRecord, origin string) (rcs []*models.Recor
|
||||
rc.Type = "ALIAS"
|
||||
err = rc.SetTarget(value)
|
||||
case "TXT":
|
||||
t := 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
|
||||
}
|
||||
err = rc.SetTargetTXTfromRFC1035Quoted(value)
|
||||
default:
|
||||
err = rc.PopulateFromString(rtype, value, origin)
|
||||
}
|
||||
@ -71,27 +59,17 @@ func recordsToNative(rcs []*models.RecordConfig, origin string) []livedns.Domain
|
||||
}
|
||||
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 {
|
||||
// Allocate a new ZoneRecord:
|
||||
zr := livedns.DomainRecord{
|
||||
RrsetType: r.Type,
|
||||
RrsetTTL: int(r.TTL),
|
||||
RrsetName: label,
|
||||
RrsetValues: []string{val},
|
||||
RrsetValues: []string{r.GetTargetCombined()},
|
||||
}
|
||||
keys[key] = &zr
|
||||
} else {
|
||||
zr.RrsetValues = append(zr.RrsetValues, val)
|
||||
zr.RrsetValues = append(zr.RrsetValues, r.GetTargetCombined())
|
||||
|
||||
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)
|
||||
@ -99,6 +77,7 @@ func recordsToNative(rcs []*models.RecordConfig, origin string) []livedns.Domain
|
||||
zr.RrsetTTL = int(r.TTL)
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -24,6 +24,7 @@ import (
|
||||
"github.com/StackExchange/dnscontrol/v4/models"
|
||||
"github.com/StackExchange/dnscontrol/v4/pkg/diff2"
|
||||
"github.com/StackExchange/dnscontrol/v4/pkg/printer"
|
||||
"github.com/StackExchange/dnscontrol/v4/pkg/txtutil"
|
||||
"github.com/StackExchange/dnscontrol/v4/providers"
|
||||
"github.com/go-gandi/go-gandi"
|
||||
"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)
|
||||
rec.TTL = 2592000
|
||||
}
|
||||
if rec.Type == "TXT" {
|
||||
rec.SetTarget("\"" + rec.GetTargetField() + "\"") // FIXME(tlim): Should do proper quoting.
|
||||
}
|
||||
if rec.Type == "NS" && rec.GetLabel() == "@" {
|
||||
if !strings.HasSuffix(rec.GetTargetField(), ".gandi.net.") {
|
||||
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)
|
||||
txtutil.SplitSingleLongTxt(dc.Records) // Autosplit long TXT records
|
||||
|
||||
g := gandi.NewLiveDNSClient(config.Config{
|
||||
APIKey: client.apikey,
|
||||
|
@ -259,6 +259,8 @@ type correctionValues struct {
|
||||
|
||||
// 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) {
|
||||
txtutil.SplitSingleLongTxt(dc.Records) // Autosplit long TXT records
|
||||
|
||||
oldRRs, ok := g.oldRRsMap[dc.Name]
|
||||
if !ok {
|
||||
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 {
|
||||
if keyForRec(r) == ck {
|
||||
if ck.Type == "TXT" {
|
||||
// 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.Rrdatas = append(newRRs.Rrdatas, r.GetTargetCombined())
|
||||
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.TTL = uint32(set.Ttl)
|
||||
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 {
|
||||
return nil, fmt.Errorf("unparsable record %q received from GCLOUD: %w", rtype, err)
|
||||
}
|
||||
|
@ -86,7 +86,7 @@ func recordsToNative(rcs []*models.RecordConfig, expectedKey models.RecordKey) *
|
||||
}
|
||||
case "TXT": // Avoid double quoting for TXT records
|
||||
rr = dnssdk.ResourceRecord{
|
||||
Content: convertTxtSliceToSdkAnySlice([]string{r.GetTargetCombined()}),
|
||||
Content: convertTxtSliceToSdkAnySlice(r.GetTargetTXTSegmented()),
|
||||
Meta: nil,
|
||||
Enabled: true,
|
||||
}
|
||||
|
@ -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)
|
||||
}
|
||||
|
||||
@ -323,10 +326,7 @@ func (c *hednsProvider) GetZoneRecords(domain string, meta map[string]string) (m
|
||||
rc.Type = "TXT"
|
||||
fallthrough
|
||||
case "TXT":
|
||||
//err = rc.SetTargetTXTs(models.ParseQuotedTxt(data))
|
||||
var t string
|
||||
t, err = txtutil.ParseQuoted(data)
|
||||
err = rc.SetTargetTXT(t)
|
||||
err = rc.SetTargetTXTs(models.ParseQuotedTxt(data))
|
||||
default:
|
||||
err = rc.PopulateFromString(rc.Type, data, domain)
|
||||
}
|
||||
|
@ -7,6 +7,7 @@ import (
|
||||
|
||||
"github.com/StackExchange/dnscontrol/v4/models"
|
||||
"github.com/StackExchange/dnscontrol/v4/pkg/diff"
|
||||
"github.com/StackExchange/dnscontrol/v4/pkg/txtutil"
|
||||
"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) {
|
||||
domain := dc.Name
|
||||
|
||||
txtutil.SplitSingleLongTxt(dc.Records) // Autosplit long TXT records
|
||||
|
||||
toReport, create, del, modify, err := diff.NewCompat(dc).IncrementalDiff(existingRecords)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
|
@ -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 2023-10-27
|
||||
|
||||
a.Add("SRV", rejectif.SrvHasNullTarget) // Last verified 2020-12-28
|
||||
|
||||
return a.Audit(records)
|
||||
|
@ -9,6 +9,7 @@ import (
|
||||
|
||||
"github.com/StackExchange/dnscontrol/v4/models"
|
||||
"github.com/StackExchange/dnscontrol/v4/pkg/diff"
|
||||
"github.com/StackExchange/dnscontrol/v4/pkg/txtutil"
|
||||
)
|
||||
|
||||
// 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.
|
||||
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)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
@ -239,7 +242,7 @@ func (n *HXClient) createRecordString(rc *models.RecordConfig, domain string) (s
|
||||
case "CAA":
|
||||
record.Answer = fmt.Sprintf(`%v %s "%s"`, rc.CaaFlag, rc.CaaTag, record.Answer)
|
||||
case "TXT":
|
||||
record.Answer = encodeTxt([]string{rc.GetTargetField()})
|
||||
record.Answer = encodeTxt(rc.GetTargetTXTSegmented())
|
||||
case "SRV":
|
||||
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')")
|
||||
|
@ -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":
|
||||
// Nothing special.
|
||||
case "TXT":
|
||||
//txtStrings := make([]string, len(rc.TxtStrings))
|
||||
//copy(txtStrings, rc.TxtStrings)
|
||||
txtStrings := []string{rc.GetTargetField()}
|
||||
// TODO(tlim): Move this to a function with unit tests.
|
||||
txtStrings := make([]string, rc.GetTargetTXTSegmentCount())
|
||||
copy(txtStrings, rc.GetTargetTXTSegmented())
|
||||
|
||||
// Escape quotes
|
||||
for i := range txtStrings {
|
||||
|
@ -10,6 +10,7 @@ import (
|
||||
"github.com/StackExchange/dnscontrol/v4/models"
|
||||
"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/nrdcg/goinwx"
|
||||
"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.
|
||||
for _, r := range records {
|
||||
if r.Type == "TXT" {
|
||||
target := r.GetTargetField()
|
||||
if strings.ContainsAny(target, "`") {
|
||||
return fmt.Errorf("INWX TXT records do not support single-quotes in their target")
|
||||
for _, target := range r.GetTargetTXTSegmented() {
|
||||
if strings.ContainsAny(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.
|
||||
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)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
|
@ -1,6 +1,8 @@
|
||||
package loopia
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/StackExchange/dnscontrol/v4/models"
|
||||
"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.
|
||||
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
|
||||
}
|
||||
|
@ -25,6 +25,7 @@ import (
|
||||
"github.com/StackExchange/dnscontrol/v4/models"
|
||||
"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/miekg/dns/dnsutil"
|
||||
)
|
||||
@ -271,6 +272,7 @@ func (c *APIClient) GetZoneRecordsCorrections(dc *models.DomainConfig, existingR
|
||||
}
|
||||
|
||||
// Normalize
|
||||
txtutil.SplitSingleLongTxt(dc.Records) // Autosplit long TXT records
|
||||
PrepDesiredRecords(dc)
|
||||
|
||||
var keysToUpdate map[models.RecordKey][]string
|
||||
|
@ -19,7 +19,7 @@ func AuditRecords(records []*models.RecordConfig) []error {
|
||||
|
||||
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
|
||||
|
||||
@ -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
|
||||
|
||||
return a.Audit(records)
|
||||
}
|
||||
|
@ -5,6 +5,7 @@ import (
|
||||
|
||||
"github.com/StackExchange/dnscontrol/v4/models"
|
||||
"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.
|
||||
@ -13,6 +14,7 @@ func (client *msdnsProvider) GetZoneRecordsCorrections(dc *models.DomainConfig,
|
||||
|
||||
// Normalize
|
||||
models.PostProcessRecords(foundRecords)
|
||||
txtutil.SplitSingleLongTxt(dc.Records) // Autosplit long TXT records
|
||||
|
||||
changes, err := diff2.ByRecord(foundRecords, dc, nil)
|
||||
if err != nil {
|
||||
|
@ -14,15 +14,13 @@ import (
|
||||
func AuditRecords(records []*models.RecordConfig) []error {
|
||||
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.TxtHasTrailingSpace) // Last verified 2023-10-25
|
||||
a.Add("TXT", rejectif.TxtIsEmpty) // Last verified 2021-03-01
|
||||
|
||||
return a.Audit(records)
|
||||
}
|
||||
@ -32,8 +30,7 @@ func AuditRecords(records []*models.RecordConfig) []error {
|
||||
// length limit is undocumented. This seems to work.
|
||||
func MaxLengthNDC(rc *models.RecordConfig) error {
|
||||
txtStrings := rc.GetTargetTXTSegmented()
|
||||
|
||||
if rc.GetTargetTXTJoined() == "" {
|
||||
if len(txtStrings) == 0 {
|
||||
return nil
|
||||
}
|
||||
|
||||
|
@ -11,7 +11,7 @@ import (
|
||||
func AuditRecords(records []*models.RecordConfig) []error {
|
||||
a := rejectif.Auditor{}
|
||||
|
||||
a.Add("TXT", rejectif.TxtLongerThan255)
|
||||
a.Add("TXT", rejectif.TxtHasMultipleSegments)
|
||||
|
||||
return a.Audit(records)
|
||||
}
|
||||
|
@ -9,7 +9,6 @@ import (
|
||||
|
||||
"github.com/StackExchange/dnscontrol/v4/models"
|
||||
"github.com/StackExchange/dnscontrol/v4/pkg/diff2"
|
||||
"github.com/StackExchange/dnscontrol/v4/pkg/txtutil"
|
||||
"github.com/StackExchange/dnscontrol/v4/providers"
|
||||
"gopkg.in/ns1/ns1-go.v2/rest"
|
||||
"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" {
|
||||
rec.AddAnswer(&dns.Answer{Rdata: strings.Fields(fmt.Sprintf("%d %v", r.MxPreference, r.GetTargetField()))})
|
||||
} 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" {
|
||||
rec.AddAnswer(&dns.Answer{
|
||||
Rdata: []string{
|
||||
|
@ -9,6 +9,7 @@ import (
|
||||
"github.com/StackExchange/dnscontrol/v4/models"
|
||||
"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/oracle/oci-go-sdk/v32/common"
|
||||
"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.
|
||||
func (o *oracleProvider) GetZoneRecordsCorrections(dc *models.DomainConfig, existingRecords models.Records) ([]*models.Correction, 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
|
||||
for _, rec := range dc.Records {
|
||||
|
@ -17,21 +17,19 @@ func TestToRecordConfig(t *testing.T) {
|
||||
|
||||
assert.NoError(t, err)
|
||||
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, "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{
|
||||
Content: largeContent,
|
||||
}
|
||||
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.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, "TXT", recordConfig.Type)
|
||||
}
|
||||
|
@ -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.
|
||||
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)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
@ -341,35 +343,10 @@ func (r *route53Provider) GetZoneRecordsCorrections(dc *models.DomainConfig, exi
|
||||
}
|
||||
|
||||
for _, r := range inst.New {
|
||||
|
||||
var rr r53Types.ResourceRecord
|
||||
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()),
|
||||
}
|
||||
rr := r53Types.ResourceRecord{
|
||||
Value: aws.String(r.GetTargetCombined()),
|
||||
}
|
||||
rrset.ResourceRecords = append(rrset.ResourceRecords, rr)
|
||||
|
||||
i := int64(r.TTL)
|
||||
rrset.TTL = &i
|
||||
}
|
||||
@ -515,20 +492,7 @@ func nativeToRecords(set r53Types.ResourceRecordSet, origin string) ([]*models.R
|
||||
rc.Original = set
|
||||
switch rtypeString {
|
||||
case "TXT":
|
||||
//printer.Printf("DEBUG: txt inboundv=%v\n", 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)
|
||||
}
|
||||
|
||||
err = rc.SetTargetTXTs(models.ParseQuotedTxt(val))
|
||||
default:
|
||||
err = rc.PopulateFromString(rtypeString, val, origin)
|
||||
}
|
||||
|
@ -11,7 +11,7 @@ import (
|
||||
func AuditRecords(records []*models.RecordConfig) []error {
|
||||
a := rejectif.Auditor{}
|
||||
|
||||
a.Add("TXT", rejectif.TxtLongerThan255)
|
||||
a.Add("TXT", rejectif.TxtHasMultipleSegments)
|
||||
|
||||
a.Add("TXT", rejectif.TxtHasTrailingSpace)
|
||||
|
||||
|
@ -5,6 +5,7 @@ import (
|
||||
|
||||
"github.com/StackExchange/dnscontrol/v4/models"
|
||||
"github.com/StackExchange/dnscontrol/v4/pkg/diff"
|
||||
"github.com/StackExchange/dnscontrol/v4/pkg/txtutil"
|
||||
)
|
||||
|
||||
// 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.
|
||||
func (api *rwthProvider) GetZoneRecordsCorrections(dc *models.DomainConfig, existingRecords models.Records) ([]*models.Correction, error) {
|
||||
txtutil.SplitSingleLongTxt(dc.Records) // Autosplit long TXT records
|
||||
domain := dc.Name
|
||||
|
||||
toReport, create, del, modify, err := diff.NewCompat(dc).IncrementalDiff(existingRecords)
|
||||
|
@ -17,7 +17,7 @@ func AuditRecords(records []*models.RecordConfig) []error {
|
||||
// Needs investigation. Could be a dnscontrol issue or
|
||||
// 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
|
||||
|
||||
|
Reference in New Issue
Block a user