From 31723ad146acb1ec46b7791ddf55b9126f401af6 Mon Sep 17 00:00:00 2001 From: Tom Limoncelli Date: Thu, 11 Aug 2022 17:24:47 -0400 Subject: [PATCH] PERFORMANCE: Refactor auditrecords.go to loop only once #1570 (#1658) * stash * Use rejectif idea * rename * wip! * Convert old systems to new * fixup! * fix typo --- integrationTest/integration_test.go | 2 +- pkg/normalize/validate.go | 6 +- pkg/prettyzone/prettyzone.go | 1 + pkg/prettyzone/prettyzone_test.go | 2 +- pkg/recordaudit/txt.go | 159 ------------------ pkg/rejectif/audit.go | 46 +++++ pkg/rejectif/caa.go | 18 ++ pkg/rejectif/txt.go | 104 ++++++++++++ pkg/{recordaudit => rejectif}/ultimate.go | 2 +- providers/akamaiedgedns/auditrecords.go | 6 +- providers/autodns/api.go | 10 +- providers/autodns/auditrecords.go | 7 +- providers/axfrddns/auditrecords.go | 11 +- providers/azuredns/auditrecords.go | 11 +- providers/bind/auditrecords.go | 11 +- providers/cloudflare/auditrecords.go | 24 ++- providers/cloudns/auditrecords.go | 36 ++-- providers/cscglobal/auditrecords.go | 51 +++--- providers/desec/auditrecords.go | 7 +- providers/digitalocean/auditrecords.go | 43 ++--- providers/dnsimple/auditrecords.go | 29 ++-- providers/dnsmadeeasy/auditrecords.go | 18 +- providers/doh/auditrecords.go | 11 +- providers/domainnameshop/auditrecords.go | 10 ++ .../domainnameshop/domainnameshopProvider.go | 7 +- providers/exoscale/auditrecords.go | 11 +- providers/gandiv5/auditrecords.go | 11 +- providers/gcloud/auditrecords.go | 11 +- providers/hedns/auditrecords.go | 11 +- providers/hetzner/auditrecords.go | 11 +- providers/hexonet/auditrecords.go | 17 +- providers/hostingde/auditrecords.go | 11 +- providers/internetbs/auditrecords.go | 11 +- providers/inwx/auditrecords.go | 32 ++-- providers/linode/auditrecords.go | 11 +- providers/msdns/auditrecords.go | 41 ++--- providers/namecheap/auditrecords.go | 11 +- providers/namedotcom/auditrecords.go | 54 +++--- providers/netcup/auditrecords.go | 16 +- providers/ns1/auditrecords.go | 17 +- providers/octodns/auditrecords.go | 11 +- providers/opensrs/auditrecords.go | 11 +- providers/oracle/auditrecords.go | 11 +- providers/ovh/auditrecords.go | 11 +- providers/packetframe/auditrecords.go | 11 +- providers/powerdns/auditrecords.go | 11 +- providers/providers.go | 12 +- providers/route53/auditrecords.go | 11 +- providers/rwth/auditrecords.go | 24 ++- providers/softlayer/auditrecords.go | 11 +- providers/transip/auditrecords.go | 11 +- providers/vultr/auditrecords.go | 23 ++- 52 files changed, 497 insertions(+), 569 deletions(-) delete mode 100644 pkg/recordaudit/txt.go create mode 100644 pkg/rejectif/audit.go create mode 100644 pkg/rejectif/caa.go create mode 100644 pkg/rejectif/txt.go rename pkg/{recordaudit => rejectif}/ultimate.go (96%) create mode 100644 providers/domainnameshop/auditrecords.go diff --git a/integrationTest/integration_test.go b/integrationTest/integration_test.go index 11a2bb840..6b0d60576 100644 --- a/integrationTest/integration_test.go +++ b/integrationTest/integration_test.go @@ -1047,7 +1047,7 @@ func makeTests(t *testing.T) []*TestGroup { tc("CAA change flag", caa("@", "issuewild", 128, "example.com")), ), testgroup("CAA with ;", - requires(providers.CanUseCAA), not("DIGITALOCEAN"), + requires(providers.CanUseCAA), // Test support of ";" as a value tc("CAA many records", caa("@", "issuewild", 0, ";")), ), diff --git a/pkg/normalize/validate.go b/pkg/normalize/validate.go index f3c1f6a5a..0d27e13b3 100644 --- a/pkg/normalize/validate.go +++ b/pkg/normalize/validate.go @@ -485,8 +485,10 @@ func ValidateAndNormalizeConfig(config *models.DNSConfig) (errs []error) { // be performed. continue } - if err := providers.AuditRecords(provider.ProviderBase.ProviderType, domain.Records); err != nil { - errs = append(errs, fmt.Errorf("%s rejects domain %s: %w", provider.ProviderBase.ProviderType, domain.Name, err)) + if es := providers.AuditRecords(provider.ProviderBase.ProviderType, domain.Records); len(es) != 0 { + for _, e := range es { + errs = append(errs, fmt.Errorf("%s rejects domain %s: %w", provider.ProviderBase.ProviderType, domain.Name, e)) + } } } } diff --git a/pkg/prettyzone/prettyzone.go b/pkg/prettyzone/prettyzone.go index 3fcc41399..0f6afb682 100644 --- a/pkg/prettyzone/prettyzone.go +++ b/pkg/prettyzone/prettyzone.go @@ -153,6 +153,7 @@ func (z *ZoneGenData) generateZoneFileHelper(w io.Writer) error { return nil } +// FormatLine formats a zonefile line. func FormatLine(lengths []int, fields []string) string { c := 0 result := "" diff --git a/pkg/prettyzone/prettyzone_test.go b/pkg/prettyzone/prettyzone_test.go index 7f598ce07..e2cc9c1ad 100644 --- a/pkg/prettyzone/prettyzone_test.go +++ b/pkg/prettyzone/prettyzone_test.go @@ -411,7 +411,7 @@ zt.mup IN A 1.2.3.14 zap IN A 1.2.3.15 ` -// func formatLine +// func FormatLine func TestFormatLine(t *testing.T) { tests := []struct { diff --git a/pkg/recordaudit/txt.go b/pkg/recordaudit/txt.go deleted file mode 100644 index d38783d6a..000000000 --- a/pkg/recordaudit/txt.go +++ /dev/null @@ -1,159 +0,0 @@ -package recordaudit - -import ( - "fmt" - "strings" - - "github.com/StackExchange/dnscontrol/v3/models" -) - -// Keep these in alphabetical order. - -// TxtNoBackticks audits TXT records for strings that contain backticks. -func TxtNoBackticks(records []*models.RecordConfig) error { - for _, rc := range records { - - if rc.HasFormatIdenticalToTXT() { - for _, txt := range rc.TxtStrings { - if strings.Contains(txt, "`") { - return fmt.Errorf("txtstring contains backtick") - } - } - } - - } - return nil -} - -// TxtNoSingleQuotes audits TXT records for strings that contain single-quotes. -func TxtNoSingleQuotes(records []*models.RecordConfig) error { - for _, rc := range records { - - if rc.HasFormatIdenticalToTXT() { - for _, txt := range rc.TxtStrings { - if strings.Contains(txt, "'") { - return fmt.Errorf("txtstring contains single-quotes") - } - } - } - - } - return nil -} - -// TxtNoDoubleQuotes audits TXT records for strings that contain doublequotes. -func TxtNoDoubleQuotes(records []*models.RecordConfig) error { - for _, rc := range records { - - if rc.HasFormatIdenticalToTXT() { - for _, txt := range rc.TxtStrings { - if strings.Contains(txt, `"`) { - return fmt.Errorf("txtstring contains doublequotes") - } - } - } - - } - return nil -} - -// TxtNoStringsExactlyLen255 audits TXT records for strings exactly 255 octets long. -// This is rare; you probably want to use TxtNoLongStrings() instead. -func TxtNoStringsExactlyLen255(records []*models.RecordConfig) error { - for _, rc := range records { - - if rc.HasFormatIdenticalToTXT() { // TXT and similar: - for _, txt := range rc.TxtStrings { - if len(txt) == 255 { - return fmt.Errorf("txtstring length is 255") - } - } - } - - } - return nil -} - -// TxtNoStringsLen256orLonger audits TXT records for strings that are >255 octets. -func TxtNoStringsLen256orLonger(records []*models.RecordConfig) error { - for _, rc := range records { - - if rc.HasFormatIdenticalToTXT() { // TXT and similar: - for _, txt := range rc.TxtStrings { - if len(txt) > 255 { - return fmt.Errorf("%q txtstring length > 255", rc.GetLabel()) - } - } - } - - } - - return nil -} - -// TxtNoMultipleStrings audits TXT records for multiple strings -func TxtNoMultipleStrings(records []*models.RecordConfig) error { - for _, rc := range records { - - if rc.HasFormatIdenticalToTXT() { // TXT and similar: - if len(rc.TxtStrings) > 1 { - return fmt.Errorf("multiple strings in one txt") - } - } - - } - return nil -} - -// TxtNoTrailingSpace audits TXT records for strings that end with space. -func TxtNoTrailingSpace(records []*models.RecordConfig) error { - for _, rc := range records { - - if rc.HasFormatIdenticalToTXT() { // TXT and similar: - for _, txt := range rc.TxtStrings { - if txt != "" && txt[ultimate(txt)] == ' ' { - return fmt.Errorf("txtstring ends with space") - } - } - } - - } - return nil -} - -// TxtNotEmpty audits TXT records for empty strings. -func TxtNotEmpty(records []*models.RecordConfig) error { - for _, rc := range records { - - if rc.HasFormatIdenticalToTXT() { // TXT and similar: - // There must be strings. - if len(rc.TxtStrings) == 0 { - return fmt.Errorf("txt with no strings") - } - // Each string must be non-empty. - for _, txt := range rc.TxtStrings { - if len(txt) == 0 { - return fmt.Errorf("txtstring is empty") - } - } - } - - } - return nil -} - -// TxtNoUnpairedDoubleQuotes audits TXT records for strings that contain unpaired doublequotes. -func TxtNoUnpairedDoubleQuotes(records []*models.RecordConfig) error { - for _, rc := range records { - - if rc.HasFormatIdenticalToTXT() { - for _, txt := range rc.TxtStrings { - if strings.Count(txt, `"`)%2 == 1 { - return fmt.Errorf("txtstring contains unpaired doublequotes") - } - } - } - - } - return nil -} diff --git a/pkg/rejectif/audit.go b/pkg/rejectif/audit.go new file mode 100644 index 000000000..7cf494db0 --- /dev/null +++ b/pkg/rejectif/audit.go @@ -0,0 +1,46 @@ +package rejectif + +import ( + "github.com/StackExchange/dnscontrol/v3/models" +) + +// Auditor stores a list of checks to be executed during Audit(). +type Auditor struct { + checksFor map[string][]checker +} + +type checker = func(*models.RecordConfig) error + +// Add registers a function to call on each record of a given type. +func (aud *Auditor) Add(rtype string, fn checker) { + if aud.checksFor == nil { + aud.checksFor = map[string][]checker{} + } + aud.checksFor[rtype] = append(aud.checksFor[rtype], fn) + + // SPF records get any checkers that TXT records do. + if rtype == "TXT" { + aud.Add("SPF", fn) + } +} + +// Audit performs the audit. For each record it calls each function in +// the list of checks. +func (aud *Auditor) Audit(records models.Records) (errs []error) { + // No checks? Exit early. + if aud.checksFor == nil { + return nil + } + + // For each record, call the checks for that type, gather errors. + for _, rc := range records { + for _, f := range aud.checksFor[rc.Type] { + e := f(rc) + if e != nil { + errs = append(errs, e) + } + } + } + + return errs +} diff --git a/pkg/rejectif/caa.go b/pkg/rejectif/caa.go new file mode 100644 index 000000000..0f886997d --- /dev/null +++ b/pkg/rejectif/caa.go @@ -0,0 +1,18 @@ +package rejectif + +import ( + "fmt" + "strings" + + "github.com/StackExchange/dnscontrol/v3/models" +) + +// Keep these in alphabetical order. + +// CaaTargetHasSemicolon audits CAA records for issues that contain semicolons. +func CaaTargetHasSemicolon(rc *models.RecordConfig) error { + if strings.Contains(rc.GetTargetField(), ";") { + return fmt.Errorf("caa target contains semicolon") + } + return nil +} diff --git a/pkg/rejectif/txt.go b/pkg/rejectif/txt.go new file mode 100644 index 000000000..9c1d2dccc --- /dev/null +++ b/pkg/rejectif/txt.go @@ -0,0 +1,104 @@ +package rejectif + +import ( + "fmt" + "strings" + + "github.com/StackExchange/dnscontrol/v3/models" +) + +// Keep these in alphabetical order. + +// TxtHasBackticks audits TXT records for strings that contain backticks. +func TxtHasBackticks(rc *models.RecordConfig) error { + for _, txt := range rc.TxtStrings { + if strings.Contains(txt, "`") { + return fmt.Errorf("txtstring contains backtick") + } + } + return nil +} + +// TxtHasSingleQuotes audits TXT records for strings that contain single-quotes. +func TxtHasSingleQuotes(rc *models.RecordConfig) error { + for _, txt := range rc.TxtStrings { + if strings.Contains(txt, "'") { + return fmt.Errorf("txtstring contains single-quotes") + } + } + return nil +} + +// TxtHasDoubleQuotes audits TXT records for strings that contain doublequotes. +func TxtHasDoubleQuotes(rc *models.RecordConfig) error { + for _, txt := range rc.TxtStrings { + if strings.Contains(txt, `"`) { + return fmt.Errorf("txtstring contains doublequotes") + } + } + return nil +} + +// TxtIsExactlyLen255 audits TXT records for strings exactly 255 octets long. +// This is rare; you probably want to use TxtNoStringsLen256orLonger() instead. +func TxtIsExactlyLen255(rc *models.RecordConfig) error { + for _, txt := range rc.TxtStrings { + if len(txt) == 255 { + return fmt.Errorf("txtstring length is 255") + } + } + return nil +} + +// TxtHasSegmentLen256orLonger audits TXT records for strings that are >255 octets. +func TxtHasSegmentLen256orLonger(rc *models.RecordConfig) error { + for _, txt := range rc.TxtStrings { + if len(txt) > 255 { + return fmt.Errorf("%q txtstring length > 255", rc.GetLabel()) + } + } + return nil +} + +// TxtHasMultipleSegments audits TXT records for multiple strings +func TxtHasMultipleSegments(rc *models.RecordConfig) error { + if len(rc.TxtStrings) > 1 { + return fmt.Errorf("multiple strings in one txt") + } + return nil +} + +// TxtHasTrailingSpace audits TXT records for strings that end with space. +func TxtHasTrailingSpace(rc *models.RecordConfig) error { + for _, txt := range rc.TxtStrings { + if txt != "" && txt[ultimate(txt)] == ' ' { + return fmt.Errorf("txtstring ends with space") + } + } + return nil +} + +// TxtIsEmpty audits TXT records for empty strings. +func TxtIsEmpty(rc *models.RecordConfig) error { + // There must be strings. + if len(rc.TxtStrings) == 0 { + return fmt.Errorf("txt with no strings") + } + // Each string must be non-empty. + for _, txt := range rc.TxtStrings { + if len(txt) == 0 { + return fmt.Errorf("txtstring is empty") + } + } + return nil +} + +// TxtHasUnpairedDoubleQuotes audits TXT records for strings that contain unpaired doublequotes. +func TxtHasUnpairedDoubleQuotes(rc *models.RecordConfig) error { + for _, txt := range rc.TxtStrings { + if strings.Count(txt, `"`)%2 == 1 { + return fmt.Errorf("txtstring contains unpaired doublequotes") + } + } + return nil +} diff --git a/pkg/recordaudit/ultimate.go b/pkg/rejectif/ultimate.go similarity index 96% rename from pkg/recordaudit/ultimate.go rename to pkg/rejectif/ultimate.go index 54fcdcde6..791afa470 100644 --- a/pkg/recordaudit/ultimate.go +++ b/pkg/rejectif/ultimate.go @@ -1,4 +1,4 @@ -package recordaudit +package rejectif /* I proposed that Go add something like "len()" that returns the highest diff --git a/providers/akamaiedgedns/auditrecords.go b/providers/akamaiedgedns/auditrecords.go index 4729c6d8f..5db57330d 100644 --- a/providers/akamaiedgedns/auditrecords.go +++ b/providers/akamaiedgedns/auditrecords.go @@ -2,7 +2,9 @@ package akamaiedgedns import "github.com/StackExchange/dnscontrol/v3/models" -// AuditRecords returns an error if any records are not supportable by this provider. -func AuditRecords(records []*models.RecordConfig) error { +// AuditRecords returns a list of errors corresponding to the records +// that aren't supported by this provider. If all records are +// supported, an empty list is returned. +func AuditRecords(records []*models.RecordConfig) []error { return nil } diff --git a/providers/autodns/api.go b/providers/autodns/api.go index c6315ecf0..2b97c494c 100644 --- a/providers/autodns/api.go +++ b/providers/autodns/api.go @@ -12,6 +12,7 @@ import ( "github.com/StackExchange/dnscontrol/v3/models" ) +// ZoneListFilter describes a JSON list filter. type ZoneListFilter struct { Key string `json:"key"` Value string `json:"value"` @@ -20,6 +21,7 @@ type ZoneListFilter struct { Filter []*ZoneListFilter `json:"filters,omitempty"` } +// ZoneListRequest describes a JSON zone list request. type ZoneListRequest struct { Filter []*ZoneListFilter `json:"filters"` } @@ -27,11 +29,11 @@ type ZoneListRequest struct { func (api *autoDnsProvider) request(method string, requestPath string, data interface{}) ([]byte, error) { client := &http.Client{} - requestUrl := api.baseURL - requestUrl.Path = api.baseURL.Path + requestPath + requestURL := api.baseURL + requestURL.Path = api.baseURL.Path + requestPath request := &http.Request{ - URL: &requestUrl, + URL: &requestURL, Header: api.defaultHeaders, Method: method, } @@ -50,7 +52,7 @@ func (api *autoDnsProvider) request(method string, requestPath string, data inte responseText, _ := ioutil.ReadAll(response.Body) if response.StatusCode != 200 { - return nil, errors.New("Request to " + requestUrl.Path + " failed: " + string(responseText)) + return nil, errors.New("Request to " + requestURL.Path + " failed: " + string(responseText)) } return responseText, nil diff --git a/providers/autodns/auditrecords.go b/providers/autodns/auditrecords.go index 320cb526e..e114d1305 100644 --- a/providers/autodns/auditrecords.go +++ b/providers/autodns/auditrecords.go @@ -2,8 +2,9 @@ package autodns import "github.com/StackExchange/dnscontrol/v3/models" -// AuditRecords returns an error if any records are not -// supportable by this provider. -func AuditRecords(records []*models.RecordConfig) error { +// AuditRecords returns a list of errors corresponding to the records +// that aren't supported by this provider. If all records are +// supported, an empty list is returned. +func AuditRecords(records []*models.RecordConfig) []error { return nil } diff --git a/providers/axfrddns/auditrecords.go b/providers/axfrddns/auditrecords.go index 8232f277b..8b8b23a66 100644 --- a/providers/axfrddns/auditrecords.go +++ b/providers/axfrddns/auditrecords.go @@ -1,11 +1,10 @@ package axfrddns -import ( - "github.com/StackExchange/dnscontrol/v3/models" -) +import "github.com/StackExchange/dnscontrol/v3/models" -// AuditRecords returns an error if any records are not -// supportable by this provider. -func AuditRecords(records []*models.RecordConfig) error { +// AuditRecords returns a list of errors corresponding to the records +// that aren't supported by this provider. If all records are +// supported, an empty list is returned. +func AuditRecords(records []*models.RecordConfig) []error { return nil } diff --git a/providers/azuredns/auditrecords.go b/providers/azuredns/auditrecords.go index 46f946f2d..25a912470 100644 --- a/providers/azuredns/auditrecords.go +++ b/providers/azuredns/auditrecords.go @@ -1,11 +1,10 @@ package azuredns -import ( - "github.com/StackExchange/dnscontrol/v3/models" -) +import "github.com/StackExchange/dnscontrol/v3/models" -// AuditRecords returns an error if any records are not -// supportable by this provider. -func AuditRecords(records []*models.RecordConfig) error { +// AuditRecords returns a list of errors corresponding to the records +// that aren't supported by this provider. If all records are +// supported, an empty list is returned. +func AuditRecords(records []*models.RecordConfig) []error { return nil } diff --git a/providers/bind/auditrecords.go b/providers/bind/auditrecords.go index 3834ecfe6..1bbf39301 100644 --- a/providers/bind/auditrecords.go +++ b/providers/bind/auditrecords.go @@ -1,11 +1,10 @@ package bind -import ( - "github.com/StackExchange/dnscontrol/v3/models" -) +import "github.com/StackExchange/dnscontrol/v3/models" -// AuditRecords returns an error if any records are not -// supportable by this provider. -func AuditRecords(records []*models.RecordConfig) error { +// AuditRecords returns a list of errors corresponding to the records +// that aren't supported by this provider. If all records are +// supported, an empty list is returned. +func AuditRecords(records []*models.RecordConfig) []error { return nil } diff --git a/providers/cloudflare/auditrecords.go b/providers/cloudflare/auditrecords.go index 805e818fb..8feae2308 100644 --- a/providers/cloudflare/auditrecords.go +++ b/providers/cloudflare/auditrecords.go @@ -2,24 +2,20 @@ package cloudflare import ( "github.com/StackExchange/dnscontrol/v3/models" - "github.com/StackExchange/dnscontrol/v3/pkg/recordaudit" + "github.com/StackExchange/dnscontrol/v3/pkg/rejectif" ) -// AuditRecords returns an error if any records are not -// supportable by this provider. -func AuditRecords(records []*models.RecordConfig) error { +// AuditRecords returns a list of errors corresponding to the records +// that aren't supported by this provider. If all records are +// supported, an empty list is returned. +func AuditRecords(records []*models.RecordConfig) []error { + a := rejectif.Auditor{} - if err := recordaudit.TxtNoMultipleStrings(records); err != nil { - return err - } // Still needed as of 2022-06-18 + a.Add("TXT", rejectif.TxtHasMultipleSegments) // Last verified 2022-06-18 - if err := recordaudit.TxtNoTrailingSpace(records); err != nil { - return err - } // Still needed as of 2022-06-18 + a.Add("TXT", rejectif.TxtHasTrailingSpace) // Last verified 2022-06-18 - if err := recordaudit.TxtNotEmpty(records); err != nil { - return err - } // Still needed as of 2022-06-18 + a.Add("TXT", rejectif.TxtIsEmpty) // Last verified 2022-06-18 - return nil + return a.Audit(records) } diff --git a/providers/cloudns/auditrecords.go b/providers/cloudns/auditrecords.go index dd801e958..8c4b7c708 100644 --- a/providers/cloudns/auditrecords.go +++ b/providers/cloudns/auditrecords.go @@ -2,36 +2,24 @@ package cloudns import ( "github.com/StackExchange/dnscontrol/v3/models" - "github.com/StackExchange/dnscontrol/v3/pkg/recordaudit" + "github.com/StackExchange/dnscontrol/v3/pkg/rejectif" ) -// AuditRecords returns an error if any records are not -// supportable by this provider. -func AuditRecords(records []*models.RecordConfig) error { +// AuditRecords returns a list of errors corresponding to the records +// that aren't supported by this provider. If all records are +// supported, an empty list is returned. +func AuditRecords(records []*models.RecordConfig) []error { + a := rejectif.Auditor{} - if err := recordaudit.TxtNoBackticks(records); err != nil { - return err - } - // Still needed as of 2021-03-01 + a.Add("TXT", rejectif.TxtHasBackticks) // Last verified 2021-03-01 - if err := recordaudit.TxtNotEmpty(records); err != nil { - return err - } - // Still needed as of 2021-03-01 + a.Add("TXT", rejectif.TxtIsEmpty) // Last verified 2021-03-01 - if err := recordaudit.TxtNoTrailingSpace(records); err != nil { - return err - } - // Still needed as of 2021-03-01 + a.Add("TXT", rejectif.TxtHasTrailingSpace) // Last verified 2021-03-01 - if err := recordaudit.TxtNoDoubleQuotes(records); err != nil { - return err - } - // Still needed as of 2021-03-11 + a.Add("TXT", rejectif.TxtHasDoubleQuotes) // Last verified 2021-03-01 - if err := recordaudit.TxtNoMultipleStrings(records); err != nil { - return err - } + a.Add("TXT", rejectif.TxtHasMultipleSegments) // Last verified 2021-03-01 - return nil + return a.Audit(records) } diff --git a/providers/cscglobal/auditrecords.go b/providers/cscglobal/auditrecords.go index 1cafa59df..c8a8d3b61 100644 --- a/providers/cscglobal/auditrecords.go +++ b/providers/cscglobal/auditrecords.go @@ -2,39 +2,34 @@ package cscglobal import ( "github.com/StackExchange/dnscontrol/v3/models" - "github.com/StackExchange/dnscontrol/v3/pkg/recordaudit" + "github.com/StackExchange/dnscontrol/v3/pkg/rejectif" ) -// AuditRecords returns an error if any records are not -// supportable by this provider. -func AuditRecords(records []*models.RecordConfig) error { +// AuditRecords returns a list of errors corresponding to the records +// that aren't supported by this provider. If all records are +// supported, an empty list is returned. +func AuditRecords(records []*models.RecordConfig) []error { + a := rejectif.Auditor{} - // Each test should be encapsulated in a function that can be tested - // individually. If the test is of general use, add it to the - // recordaudit module. + a.Add("TXT", rejectif.TxtHasMultipleSegments) // Last verified 2022-06-10 - // Each test should document the last time we verified the test was - // still needed. Sometimes companies change their API. + a.Add("TXT", rejectif.TxtHasTrailingSpace) // Last verified 2022-06-10 - if err := recordaudit.TxtNoDoubleQuotes(records); err != nil { - return err - } // Needed as of 2022-08-08 + a.Add("TXT", rejectif.TxtIsEmpty) // Last verified 2022-06-10 - // if err := recordaudit.TxtNoStringsLen256orLonger(records); err != nil { - // return err - // } // Needed as of 2022-06-10 + a.Add("TXT", rejectif.TxtHasDoubleQuotes) // Last verified 2022-08-08 - if err := recordaudit.TxtNoMultipleStrings(records); err != nil { - return err - } // Needed as of 2022-06-10 - - if err := recordaudit.TxtNoTrailingSpace(records); err != nil { - return err - } // Needed as of 2022-06-10 - - if err := recordaudit.TxtNotEmpty(records); err != nil { - return err - } // Needed as of 2022-06-10 - - return nil + return a.Audit(records) } + +/* How To Write Providers: + +Each test should be encapsulated in a function that can be tested +individually. If the test is of general use, add it to the +rejectif module. + +The "Last verified" comment logs the last time we verified this +test was needed. Sometimes companies change their API. Once a year, +try removing tests one at a time to verify they are still needed. + +*/ diff --git a/providers/desec/auditrecords.go b/providers/desec/auditrecords.go index 91b77c59c..5ff25d863 100644 --- a/providers/desec/auditrecords.go +++ b/providers/desec/auditrecords.go @@ -4,8 +4,9 @@ import ( "github.com/StackExchange/dnscontrol/v3/models" ) -// AuditRecords returns an error if any records are not -// supportable by this provider. -func AuditRecords(records []*models.RecordConfig) error { +// AuditRecords returns a list of errors corresponding to the records +// that aren't supported by this provider. If all records are +// supported, an empty list is returned. +func AuditRecords(records []*models.RecordConfig) []error { return nil } diff --git a/providers/digitalocean/auditrecords.go b/providers/digitalocean/auditrecords.go index b1d093024..9e700ae20 100644 --- a/providers/digitalocean/auditrecords.go +++ b/providers/digitalocean/auditrecords.go @@ -2,37 +2,32 @@ package digitalocean import ( "fmt" + "github.com/StackExchange/dnscontrol/v3/models" - "github.com/StackExchange/dnscontrol/v3/pkg/recordaudit" + "github.com/StackExchange/dnscontrol/v3/pkg/rejectif" ) -// AuditRecords returns an error if any records are not -// supportable by this provider. -func AuditRecords(records []*models.RecordConfig) error { +// AuditRecords returns a list of errors corresponding to the records +// that aren't supported by this provider. If all records are +// supported, an empty list is returned. +func AuditRecords(records []*models.RecordConfig) []error { + a := rejectif.Auditor{} - // TODO(tlim): Audit CAA records. - // "Semicolons not supported in issue/issuewild fields.", "https://www.digitalocean.com/docs/networking/dns/how-to/create-caa-records"), - // Users are warned about these limits in docs/_providers/digitalocean.md + a.Add("TXT", MaxLengthDO) // Last verified 2021-03-01 - if err := MaxLengthDO(records); err != nil { - return err - } - // Still needed as of 2021-03-01 + a.Add("CAA", rejectif.CaaTargetHasSemicolon) // Last verified 2021-03-01 + 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. - if err := recordaudit.TxtNoDoubleQuotes(records); err != nil { - return err - } - // Still needed as of 2021-03-01 - return nil + return a.Audit(records) } -// MaxLengthDO returns and error if the strings are longer than +// MaxLengthDO returns and error if the string is longer than // permitted by DigitalOcean. Sadly their length limit is // undocumented. This is a guess. -func MaxLengthDO(records []*models.RecordConfig) error { +func MaxLengthDO(rc *models.RecordConfig) error { // The total length of all strings can't be longer than 512; and in // reality must be shorter due to sloppy validation checks. // https://github.com/StackExchange/dnscontrol/issues/370 @@ -47,14 +42,10 @@ func MaxLengthDO(records []*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. - for _, rc := range records { - - if rc.HasFormatIdenticalToTXT() { // TXT and similar: - if len(rc.GetTargetField()) > 509 { - return fmt.Errorf("encoded txt too long") - } - } - + if len(rc.GetTargetField()) > 509 { + return fmt.Errorf("encoded txt too long") } + // FIXME(tlim): Try replacing GetTargetField() with (2 + (3*len(rc.TxtStrings) - 1)) + return nil } diff --git a/providers/dnsimple/auditrecords.go b/providers/dnsimple/auditrecords.go index c10fa308b..029524b23 100644 --- a/providers/dnsimple/auditrecords.go +++ b/providers/dnsimple/auditrecords.go @@ -2,28 +2,23 @@ package dnsimple import ( "github.com/StackExchange/dnscontrol/v3/models" - "github.com/StackExchange/dnscontrol/v3/pkg/recordaudit" + "github.com/StackExchange/dnscontrol/v3/pkg/rejectif" ) -// AuditRecords returns an error if any records are not -// supportable by this provider. -func AuditRecords(records []*models.RecordConfig) error { +// AuditRecords returns a list of errors corresponding to the records +// that aren't supported by this provider. If all records are +// supported, an empty list is returned. +func AuditRecords(records []*models.RecordConfig) []error { + a := rejectif.Auditor{} + + a.Add("TXT", rejectif.TxtHasMultipleSegments) // Last verified 2022-07 //TODO(onlyhavecans) I think we can support multiple strings. - if err := recordaudit.TxtNoMultipleStrings(records); err != nil { - return err - } - if err := recordaudit.TxtNoTrailingSpace(records); err != nil { - return err - } // as of 2022-07 + a.Add("TXT", rejectif.TxtHasTrailingSpace) // Last verified 2022-07 - if err := recordaudit.TxtNotEmpty(records); err != nil { - return err - } // as of 2022-07 + a.Add("TXT", rejectif.TxtIsEmpty) // Last verified 2022-07 - if err := recordaudit.TxtNoUnpairedDoubleQuotes(records); err != nil { - return err - } // as of 2022-07 + a.Add("TXT", rejectif.TxtHasUnpairedDoubleQuotes) // Last verified 2022-07 - return nil + return a.Audit(records) } diff --git a/providers/dnsmadeeasy/auditrecords.go b/providers/dnsmadeeasy/auditrecords.go index 272e602ad..dafd1ad6c 100644 --- a/providers/dnsmadeeasy/auditrecords.go +++ b/providers/dnsmadeeasy/auditrecords.go @@ -2,16 +2,16 @@ package dnsmadeeasy import ( "github.com/StackExchange/dnscontrol/v3/models" - "github.com/StackExchange/dnscontrol/v3/pkg/recordaudit" + "github.com/StackExchange/dnscontrol/v3/pkg/rejectif" ) -// AuditRecords returns an error if any records are not -// supportable by this provider. -func AuditRecords(records []*models.RecordConfig) error { - if err := recordaudit.TxtNoDoubleQuotes(records); err != nil { - return err - } - // Still needed as of 2021-03-11 +// AuditRecords returns a list of errors corresponding to the records +// that aren't supported by this provider. If all records are +// supported, an empty list is returned. +func AuditRecords(records []*models.RecordConfig) []error { + a := rejectif.Auditor{} - return nil + a.Add("TXT", rejectif.TxtHasDoubleQuotes) // Last verified 2021-03-11 + + return a.Audit(records) } diff --git a/providers/doh/auditrecords.go b/providers/doh/auditrecords.go index 030da7bc5..12503c850 100644 --- a/providers/doh/auditrecords.go +++ b/providers/doh/auditrecords.go @@ -1,11 +1,10 @@ package doh -import ( - "github.com/StackExchange/dnscontrol/v3/models" -) +import "github.com/StackExchange/dnscontrol/v3/models" -// AuditRecords returns an error if any records are not -// supportable by this provider. -func AuditRecords(records []*models.RecordConfig) error { +// AuditRecords returns a list of errors corresponding to the records +// that aren't supported by this provider. If all records are +// supported, an empty list is returned. +func AuditRecords(records []*models.RecordConfig) []error { return nil } diff --git a/providers/domainnameshop/auditrecords.go b/providers/domainnameshop/auditrecords.go new file mode 100644 index 000000000..e3a9400ed --- /dev/null +++ b/providers/domainnameshop/auditrecords.go @@ -0,0 +1,10 @@ +package domainnameshop + +import "github.com/StackExchange/dnscontrol/v3/models" + +// AuditRecords returns a list of errors corresponding to the records +// that aren't supported by this provider. If all records are +// supported, an empty list is returned. +func AuditRecords(records []*models.RecordConfig) []error { + return nil +} diff --git a/providers/domainnameshop/domainnameshopProvider.go b/providers/domainnameshop/domainnameshopProvider.go index 47e09bb99..1dc97d5d1 100644 --- a/providers/domainnameshop/domainnameshopProvider.go +++ b/providers/domainnameshop/domainnameshopProvider.go @@ -4,7 +4,6 @@ import ( "encoding/json" "fmt" - "github.com/StackExchange/dnscontrol/v3/models" "github.com/StackExchange/dnscontrol/v3/providers" ) @@ -46,7 +45,7 @@ var features = providers.DocumentationNotes{ func init() { fns := providers.DspFuncs{ Initializer: newDomainNameShopProvider, - RecordAuditor: auditRecords, + RecordAuditor: AuditRecords, } providers.RegisterDomainServiceProviderType("DOMAINNAMESHOP", fns, features) @@ -69,10 +68,6 @@ func newDomainNameShopProvider(conf map[string]string, metadata json.RawMessage) return api, nil } -func auditRecords(records []*models.RecordConfig) error { - return nil -} - type domainResponse struct { ID int `json:"id"` Domain string `json:"domain"` diff --git a/providers/exoscale/auditrecords.go b/providers/exoscale/auditrecords.go index c112e493d..a72cfa68a 100644 --- a/providers/exoscale/auditrecords.go +++ b/providers/exoscale/auditrecords.go @@ -1,11 +1,10 @@ package exoscale -import ( - "github.com/StackExchange/dnscontrol/v3/models" -) +import "github.com/StackExchange/dnscontrol/v3/models" -// AuditRecords returns an error if any records are not -// supportable by this provider. -func AuditRecords(records []*models.RecordConfig) error { +// AuditRecords returns a list of errors corresponding to the records +// that aren't supported by this provider. If all records are +// supported, an empty list is returned. +func AuditRecords(records []*models.RecordConfig) []error { return nil } diff --git a/providers/gandiv5/auditrecords.go b/providers/gandiv5/auditrecords.go index 90b195624..aea3da3fb 100644 --- a/providers/gandiv5/auditrecords.go +++ b/providers/gandiv5/auditrecords.go @@ -1,11 +1,10 @@ package gandiv5 -import ( - "github.com/StackExchange/dnscontrol/v3/models" -) +import "github.com/StackExchange/dnscontrol/v3/models" -// AuditRecords returns an error if any records are not -// supportable by this provider. -func AuditRecords(records []*models.RecordConfig) error { +// AuditRecords returns a list of errors corresponding to the records +// that aren't supported by this provider. If all records are +// supported, an empty list is returned. +func AuditRecords(records []*models.RecordConfig) []error { return nil } diff --git a/providers/gcloud/auditrecords.go b/providers/gcloud/auditrecords.go index 891b914fc..36beace3a 100644 --- a/providers/gcloud/auditrecords.go +++ b/providers/gcloud/auditrecords.go @@ -1,11 +1,10 @@ package gcloud -import ( - "github.com/StackExchange/dnscontrol/v3/models" -) +import "github.com/StackExchange/dnscontrol/v3/models" -// AuditRecords returns an error if any records are not -// supportable by this provider. -func AuditRecords(records []*models.RecordConfig) error { +// AuditRecords returns a list of errors corresponding to the records +// that aren't supported by this provider. If all records are +// supported, an empty list is returned. +func AuditRecords(records []*models.RecordConfig) []error { return nil } diff --git a/providers/hedns/auditrecords.go b/providers/hedns/auditrecords.go index 800dff618..c567c8161 100644 --- a/providers/hedns/auditrecords.go +++ b/providers/hedns/auditrecords.go @@ -1,11 +1,10 @@ package hedns -import ( - "github.com/StackExchange/dnscontrol/v3/models" -) +import "github.com/StackExchange/dnscontrol/v3/models" -// AuditRecords returns an error if any records are not -// supportable by this provider. -func AuditRecords(records []*models.RecordConfig) error { +// AuditRecords returns a list of errors corresponding to the records +// that aren't supported by this provider. If all records are +// supported, an empty list is returned. +func AuditRecords(records []*models.RecordConfig) []error { return nil } diff --git a/providers/hetzner/auditrecords.go b/providers/hetzner/auditrecords.go index c7ace1249..c690cbd53 100644 --- a/providers/hetzner/auditrecords.go +++ b/providers/hetzner/auditrecords.go @@ -1,11 +1,10 @@ package hetzner -import ( - "github.com/StackExchange/dnscontrol/v3/models" -) +import "github.com/StackExchange/dnscontrol/v3/models" -// AuditRecords returns an error if any records are not -// supportable by this provider. -func AuditRecords(records []*models.RecordConfig) error { +// AuditRecords returns a list of errors corresponding to the records +// that aren't supported by this provider. If all records are +// supported, an empty list is returned. +func AuditRecords(records []*models.RecordConfig) []error { return nil } diff --git a/providers/hexonet/auditrecords.go b/providers/hexonet/auditrecords.go index 4d2a3eddd..0b79d1e27 100644 --- a/providers/hexonet/auditrecords.go +++ b/providers/hexonet/auditrecords.go @@ -2,17 +2,16 @@ package hexonet import ( "github.com/StackExchange/dnscontrol/v3/models" - "github.com/StackExchange/dnscontrol/v3/pkg/recordaudit" + "github.com/StackExchange/dnscontrol/v3/pkg/rejectif" ) -// AuditRecords returns an error if any records are not -// supportable by this provider. -func AuditRecords(records []*models.RecordConfig) error { +// AuditRecords returns a list of errors corresponding to the records +// that aren't supported by this provider. If all records are +// supported, an empty list is returned. +func AuditRecords(records []*models.RecordConfig) []error { + a := rejectif.Auditor{} - if err := recordaudit.TxtNotEmpty(records); err != nil { - return err - } - // Still needed as of 2021-10-01 + a.Add("TXT", rejectif.TxtIsEmpty) // Last verified 2021-10-01 - return nil + return a.Audit(records) } diff --git a/providers/hostingde/auditrecords.go b/providers/hostingde/auditrecords.go index 91ef6c807..ca0adb5a1 100644 --- a/providers/hostingde/auditrecords.go +++ b/providers/hostingde/auditrecords.go @@ -1,11 +1,10 @@ package hostingde -import ( - "github.com/StackExchange/dnscontrol/v3/models" -) +import "github.com/StackExchange/dnscontrol/v3/models" -// AuditRecords returns an error if any records are not -// supportable by this provider. -func AuditRecords(records []*models.RecordConfig) error { +// AuditRecords returns a list of errors corresponding to the records +// that aren't supported by this provider. If all records are +// supported, an empty list is returned. +func AuditRecords(records []*models.RecordConfig) []error { return nil } diff --git a/providers/internetbs/auditrecords.go b/providers/internetbs/auditrecords.go index b48d32e7c..ab205a4ba 100644 --- a/providers/internetbs/auditrecords.go +++ b/providers/internetbs/auditrecords.go @@ -1,11 +1,10 @@ package internetbs -import ( - "github.com/StackExchange/dnscontrol/v3/models" -) +import "github.com/StackExchange/dnscontrol/v3/models" -// AuditRecords returns an error if any records are not -// supportable by this provider. -func AuditRecords(records []*models.RecordConfig) error { +// AuditRecords returns a list of errors corresponding to the records +// that aren't supported by this provider. If all records are +// supported, an empty list is returned. +func AuditRecords(records []*models.RecordConfig) []error { return nil } diff --git a/providers/inwx/auditrecords.go b/providers/inwx/auditrecords.go index 5ff053eb0..8b293385d 100644 --- a/providers/inwx/auditrecords.go +++ b/providers/inwx/auditrecords.go @@ -2,32 +2,22 @@ package inwx import ( "github.com/StackExchange/dnscontrol/v3/models" - "github.com/StackExchange/dnscontrol/v3/pkg/recordaudit" + "github.com/StackExchange/dnscontrol/v3/pkg/rejectif" ) -// AuditRecords returns an error if any records are not -// supportable by this provider. -func AuditRecords(records []*models.RecordConfig) error { +// AuditRecords returns a list of errors corresponding to the records +// that aren't supported by this provider. If all records are +// supported, an empty list is returned. +func AuditRecords(records []*models.RecordConfig) []error { + a := rejectif.Auditor{} - if err := recordaudit.TxtNoBackticks(records); err != nil { - return err - } - // Still needed as of 2021-03-01 + a.Add("TXT", rejectif.TxtHasBackticks) // Last verified 2021-03-01 - if err := recordaudit.TxtNoStringsExactlyLen255(records); err != nil { - return err - } - // Still needed as of 2021-03-01 + a.Add("TXT", rejectif.TxtIsExactlyLen255) // Last verified 2021-03-01 - if err := recordaudit.TxtNoTrailingSpace(records); err != nil { - return err - } - // Still needed as of 2021-03-01 + a.Add("TXT", rejectif.TxtHasTrailingSpace) // Last verified 2021-03-01 - if err := recordaudit.TxtNotEmpty(records); err != nil { - return err - } - // Still needed as of 2021-03-01 + a.Add("TXT", rejectif.TxtIsEmpty) // Last verified 2021-03-01 - return nil + return a.Audit(records) } diff --git a/providers/linode/auditrecords.go b/providers/linode/auditrecords.go index b132e215f..0f386d2b1 100644 --- a/providers/linode/auditrecords.go +++ b/providers/linode/auditrecords.go @@ -1,11 +1,10 @@ package linode -import ( - "github.com/StackExchange/dnscontrol/v3/models" -) +import "github.com/StackExchange/dnscontrol/v3/models" -// AuditRecords returns an error if any records are not -// supportable by this provider. -func AuditRecords(records []*models.RecordConfig) error { +// AuditRecords returns a list of errors corresponding to the records +// that aren't supported by this provider. If all records are +// supported, an empty list is returned. +func AuditRecords(records []*models.RecordConfig) []error { return nil } diff --git a/providers/msdns/auditrecords.go b/providers/msdns/auditrecords.go index 2599597ec..fbe27a60f 100644 --- a/providers/msdns/auditrecords.go +++ b/providers/msdns/auditrecords.go @@ -2,41 +2,26 @@ package msdns import ( "github.com/StackExchange/dnscontrol/v3/models" - "github.com/StackExchange/dnscontrol/v3/pkg/recordaudit" + "github.com/StackExchange/dnscontrol/v3/pkg/rejectif" ) -// AuditRecords returns an error if any records are not -// supportable by this provider. -func AuditRecords(records []*models.RecordConfig) error { +// AuditRecords returns a list of errors corresponding to the records +// that aren't supported by this provider. If all records are +// supported, an empty list is returned. +func AuditRecords(records []*models.RecordConfig) []error { + a := rejectif.Auditor{} - if err := recordaudit.TxtNoMultipleStrings(records); err != nil { - return err - } - // Still needed as of 2021-03-01 + a.Add("TXT", rejectif.TxtHasBackticks) // Last verified 2021-03-01 - if err := recordaudit.TxtNoStringsLen256orLonger(records); err != nil { - return err - } + a.Add("TXT", rejectif.TxtHasDoubleQuotes) // Last verified 2021-03-01 - if err := recordaudit.TxtNotEmpty(records); err != nil { - return err - } - // Still needed as of 2021-03-01 + a.Add("TXT", rejectif.TxtHasMultipleSegments) // Last verified 2021-03-01 - if err := recordaudit.TxtNoBackticks(records); err != nil { - return err - } - // Still needed as of 2021-03-01 + a.Add("TXT", rejectif.TxtHasSingleQuotes) // Last verified 2021-03-01 - if err := recordaudit.TxtNoDoubleQuotes(records); err != nil { - return err - } - // Still needed as of 2021-03-01 + a.Add("TXT", rejectif.TxtHasSegmentLen256orLonger) - if err := recordaudit.TxtNoSingleQuotes(records); err != nil { - return err - } - // Still needed as of 2021-03-01 + a.Add("TXT", rejectif.TxtIsEmpty) // Last verified 2021-03-01 - return nil + return a.Audit(records) } diff --git a/providers/namecheap/auditrecords.go b/providers/namecheap/auditrecords.go index 1b9ffb9a0..940305865 100644 --- a/providers/namecheap/auditrecords.go +++ b/providers/namecheap/auditrecords.go @@ -1,11 +1,10 @@ package namecheap -import ( - "github.com/StackExchange/dnscontrol/v3/models" -) +import "github.com/StackExchange/dnscontrol/v3/models" -// AuditRecords returns an error if any records are not -// supportable by this provider. -func AuditRecords(records []*models.RecordConfig) error { +// AuditRecords returns a list of errors corresponding to the records +// that aren't supported by this provider. If all records are +// supported, an empty list is returned. +func AuditRecords(records []*models.RecordConfig) []error { return nil } diff --git a/providers/namedotcom/auditrecords.go b/providers/namedotcom/auditrecords.go index 3fcbe6667..dd20eebcd 100644 --- a/providers/namedotcom/auditrecords.go +++ b/providers/namedotcom/auditrecords.go @@ -5,49 +5,41 @@ import ( "strings" "github.com/StackExchange/dnscontrol/v3/models" - "github.com/StackExchange/dnscontrol/v3/pkg/recordaudit" + "github.com/StackExchange/dnscontrol/v3/pkg/rejectif" ) -// AuditRecords returns an error if any records are not -// supportable by this provider. -func AuditRecords(records []*models.RecordConfig) error { +// AuditRecords returns a list of errors corresponding to the records +// that aren't supported by this provider. If all records are +// supported, an empty list is returned. +func AuditRecords(records []*models.RecordConfig) []error { + a := rejectif.Auditor{} - if err := MaxLengthNDC(records); err != nil { - return err - } - // Still needed as of 2021-03-01 + a.Add("TXT", MaxLengthNDC) // Last verified 2021-03-01 - if err := recordaudit.TxtNotEmpty(records); err != nil { - return err - } - // Still needed as of 2021-03-01 + a.Add("TXT", rejectif.TxtIsEmpty) // Last verified 2021-03-01 - return nil + return a.Audit(records) } // MaxLengthNDC returns and error if the sum of the strings // are longer than permitted by NDC. Sadly their // length limit is undocumented. This seems to work. -func MaxLengthNDC(records []*models.RecordConfig) error { - for _, rc := range records { +func MaxLengthNDC(rc *models.RecordConfig) error { + if len(rc.TxtStrings) == 0 { + return nil + } - if rc.HasFormatIdenticalToTXT() { // TXT and similar: - // Sum the length of the segments: - sum := 0 - for _, segment := range rc.TxtStrings { - sum += len(segment) // The length of each segment - sum += strings.Count(segment, `"`) // Add 1 for any char to be escaped - } - // Add the overhead of quoting them: - n := len(rc.TxtStrings) - if n > 0 { - sum += 2 + 3*(n-1) // Start and end double-quotes, plus `" "` between each segment. - } - if sum > 512 { - return fmt.Errorf("encoded txt too long") - } - } + sum := 2 // Count the start and end quote. + // Add the length of each segment. + for _, segment := range rc.TxtStrings { + sum += len(segment) // The length of each segment + sum += strings.Count(segment, `"`) // Add 1 for any char to be escaped + } + // Add 3 (quote space quote) for each interior join. + sum += 3 * (len(rc.TxtStrings) - 1) + if sum > 512 { + return fmt.Errorf("encoded txt too long") } return nil } diff --git a/providers/netcup/auditrecords.go b/providers/netcup/auditrecords.go index e93e0187b..2571b99cf 100644 --- a/providers/netcup/auditrecords.go +++ b/providers/netcup/auditrecords.go @@ -2,12 +2,16 @@ package netcup import ( "github.com/StackExchange/dnscontrol/v3/models" - "github.com/StackExchange/dnscontrol/v3/pkg/recordaudit" + "github.com/StackExchange/dnscontrol/v3/pkg/rejectif" ) -// AuditRecords returns an error if any records are not -// supportable by this provider. -func AuditRecords(records []*models.RecordConfig) error { - return recordaudit.TxtNotEmpty(records) - // Still needed as of 2021-03-01 +// AuditRecords returns a list of errors corresponding to the records +// that aren't supported by this provider. If all records are +// supported, an empty list is returned. +func AuditRecords(records []*models.RecordConfig) []error { + a := rejectif.Auditor{} + + a.Add("TXT", rejectif.TxtIsEmpty) // Last verified 2021-03-01 + + return a.Audit(records) } diff --git a/providers/ns1/auditrecords.go b/providers/ns1/auditrecords.go index cac395ab4..d302017f2 100644 --- a/providers/ns1/auditrecords.go +++ b/providers/ns1/auditrecords.go @@ -2,17 +2,16 @@ package ns1 import ( "github.com/StackExchange/dnscontrol/v3/models" - "github.com/StackExchange/dnscontrol/v3/pkg/recordaudit" + "github.com/StackExchange/dnscontrol/v3/pkg/rejectif" ) -// AuditRecords returns an error if any records are not -// supportable by this provider. -func AuditRecords(records []*models.RecordConfig) error { +// AuditRecords returns a list of errors corresponding to the records +// that aren't supported by this provider. If all records are +// supported, an empty list is returned. +func AuditRecords(records []*models.RecordConfig) []error { + a := rejectif.Auditor{} - if err := recordaudit.TxtNoMultipleStrings(records); err != nil { - return err - } - // Still needed as of 2021-03-01 + a.Add("TXT", rejectif.TxtHasMultipleSegments) - return nil + return a.Audit(records) } diff --git a/providers/octodns/auditrecords.go b/providers/octodns/auditrecords.go index ab572f670..4dd078981 100644 --- a/providers/octodns/auditrecords.go +++ b/providers/octodns/auditrecords.go @@ -1,11 +1,10 @@ package octodns -import ( - "github.com/StackExchange/dnscontrol/v3/models" -) +import "github.com/StackExchange/dnscontrol/v3/models" -// AuditRecords returns an error if any records are not -// supportable by this provider. -func AuditRecords(records []*models.RecordConfig) error { +// AuditRecords returns a list of errors corresponding to the records +// that aren't supported by this provider. If all records are +// supported, an empty list is returned. +func AuditRecords(records []*models.RecordConfig) []error { return nil } diff --git a/providers/opensrs/auditrecords.go b/providers/opensrs/auditrecords.go index ef7bbf441..e26fd0465 100644 --- a/providers/opensrs/auditrecords.go +++ b/providers/opensrs/auditrecords.go @@ -1,11 +1,10 @@ package opensrs -import ( - "github.com/StackExchange/dnscontrol/v3/models" -) +import "github.com/StackExchange/dnscontrol/v3/models" -// AuditRecords returns an error if any records are not -// supportable by this provider. -func AuditRecords(records []*models.RecordConfig) error { +// AuditRecords returns a list of errors corresponding to the records +// that aren't supported by this provider. If all records are +// supported, an empty list is returned. +func AuditRecords(records []*models.RecordConfig) []error { return nil } diff --git a/providers/oracle/auditrecords.go b/providers/oracle/auditrecords.go index 697fa7184..3ad3e998b 100644 --- a/providers/oracle/auditrecords.go +++ b/providers/oracle/auditrecords.go @@ -1,11 +1,10 @@ package oracle -import ( - "github.com/StackExchange/dnscontrol/v3/models" -) +import "github.com/StackExchange/dnscontrol/v3/models" -// AuditRecords returns an error if any records are not -// supportable by this provider. -func AuditRecords(records []*models.RecordConfig) error { +// AuditRecords returns a list of errors corresponding to the records +// that aren't supported by this provider. If all records are +// supported, an empty list is returned. +func AuditRecords(records []*models.RecordConfig) []error { return nil } diff --git a/providers/ovh/auditrecords.go b/providers/ovh/auditrecords.go index c3ee7dd92..612694ad2 100644 --- a/providers/ovh/auditrecords.go +++ b/providers/ovh/auditrecords.go @@ -1,11 +1,10 @@ package ovh -import ( - "github.com/StackExchange/dnscontrol/v3/models" -) +import "github.com/StackExchange/dnscontrol/v3/models" -// AuditRecords returns an error if any records are not -// supportable by this provider. -func AuditRecords(records []*models.RecordConfig) error { +// AuditRecords returns a list of errors corresponding to the records +// that aren't supported by this provider. If all records are +// supported, an empty list is returned. +func AuditRecords(records []*models.RecordConfig) []error { return nil } diff --git a/providers/packetframe/auditrecords.go b/providers/packetframe/auditrecords.go index df0823c18..7d092f96a 100644 --- a/providers/packetframe/auditrecords.go +++ b/providers/packetframe/auditrecords.go @@ -1,11 +1,10 @@ package packetframe -import ( - "github.com/StackExchange/dnscontrol/v3/models" -) +import "github.com/StackExchange/dnscontrol/v3/models" -// AuditRecords returns an error if any records are not -// supportable by this provider. -func AuditRecords(records []*models.RecordConfig) error { +// AuditRecords returns a list of errors corresponding to the records +// that aren't supported by this provider. If all records are +// supported, an empty list is returned. +func AuditRecords(records []*models.RecordConfig) []error { return nil } diff --git a/providers/powerdns/auditrecords.go b/providers/powerdns/auditrecords.go index 4c350ac83..fc3b2fae4 100644 --- a/providers/powerdns/auditrecords.go +++ b/providers/powerdns/auditrecords.go @@ -1,11 +1,10 @@ package powerdns -import ( - "github.com/StackExchange/dnscontrol/v3/models" -) +import "github.com/StackExchange/dnscontrol/v3/models" -// AuditRecords returns an error if any records are not -// supportable by this provider. -func AuditRecords(records []*models.RecordConfig) error { +// AuditRecords returns a list of errors corresponding to the records +// that aren't supported by this provider. If all records are +// supported, an empty list is returned. +func AuditRecords(records []*models.RecordConfig) []error { return nil } diff --git a/providers/providers.go b/providers/providers.go index e30ae34f8..42d850748 100644 --- a/providers/providers.go +++ b/providers/providers.go @@ -41,9 +41,9 @@ var RegistrarTypes = map[string]RegistrarInitializer{} type DspInitializer func(map[string]string, json.RawMessage) (DNSServiceProvider, error) // RecordAuditor is a function that verifies that all the records -// are supportable by this provider. It returns an error related to -// the first record that this provider can not support. -type RecordAuditor func([]*models.RecordConfig) error +// are supportable by this provider. It returns a list of errors +// detailing records that this provider can not support. +type RecordAuditor func([]*models.RecordConfig) []error // DspFuncs lists functions registered with a provider. type DspFuncs struct { @@ -132,13 +132,13 @@ func beCompatible(n string, config map[string]string) (string, error) { } // AuditRecords calls the RecordAudit function for a provider. -func AuditRecords(dType string, rcs models.Records) error { +func AuditRecords(dType string, rcs models.Records) []error { p, ok := DNSProviderTypes[dType] if !ok { - return fmt.Errorf("unknown DNS service provider type: %q", dType) + return []error{fmt.Errorf("unknown DNS service provider type: %q", dType)} } if p.RecordAuditor == nil { - return fmt.Errorf("DNS service provider type %q has no RecordAuditor", dType) + return []error{fmt.Errorf("DNS service provider type %q has no RecordAuditor", dType)} } return p.RecordAuditor(rcs) } diff --git a/providers/route53/auditrecords.go b/providers/route53/auditrecords.go index ee3bc20bd..be1eb8839 100644 --- a/providers/route53/auditrecords.go +++ b/providers/route53/auditrecords.go @@ -1,11 +1,10 @@ package route53 -import ( - "github.com/StackExchange/dnscontrol/v3/models" -) +import "github.com/StackExchange/dnscontrol/v3/models" -// AuditRecords returns an error if any records are not -// supportable by this provider. -func AuditRecords(records []*models.RecordConfig) error { +// AuditRecords returns a list of errors corresponding to the records +// that aren't supported by this provider. If all records are +// supported, an empty list is returned. +func AuditRecords(records []*models.RecordConfig) []error { return nil } diff --git a/providers/rwth/auditrecords.go b/providers/rwth/auditrecords.go index 6e83f9466..0ab2db054 100644 --- a/providers/rwth/auditrecords.go +++ b/providers/rwth/auditrecords.go @@ -2,24 +2,20 @@ package rwth import ( "github.com/StackExchange/dnscontrol/v3/models" - "github.com/StackExchange/dnscontrol/v3/pkg/recordaudit" + "github.com/StackExchange/dnscontrol/v3/pkg/rejectif" ) -// AuditRecords returns an error if any records are not -// supportable by this provider. -func AuditRecords(records []*models.RecordConfig) error { +// AuditRecords returns a list of errors corresponding to the records +// that aren't supported by this provider. If all records are +// supported, an empty list is returned. +func AuditRecords(records []*models.RecordConfig) []error { + a := rejectif.Auditor{} - if err := recordaudit.TxtNoMultipleStrings(records); err != nil { - return err - } + a.Add("TXT", rejectif.TxtHasMultipleSegments) - if err := recordaudit.TxtNoTrailingSpace(records); err != nil { - return err - } + a.Add("TXT", rejectif.TxtHasTrailingSpace) - if err := recordaudit.TxtNotEmpty(records); err != nil { - return err - } + a.Add("TXT", rejectif.TxtIsEmpty) - return nil + return a.Audit(records) } diff --git a/providers/softlayer/auditrecords.go b/providers/softlayer/auditrecords.go index 5af343d2c..8acbabb8f 100644 --- a/providers/softlayer/auditrecords.go +++ b/providers/softlayer/auditrecords.go @@ -1,11 +1,10 @@ package softlayer -import ( - "github.com/StackExchange/dnscontrol/v3/models" -) +import "github.com/StackExchange/dnscontrol/v3/models" -// AuditRecords returns an error if any records are not -// supportable by this provider. -func AuditRecords(records []*models.RecordConfig) error { +// AuditRecords returns a list of errors corresponding to the records +// that aren't supported by this provider. If all records are +// supported, an empty list is returned. +func AuditRecords(records []*models.RecordConfig) []error { return nil } diff --git a/providers/transip/auditrecords.go b/providers/transip/auditrecords.go index d79841f95..bd3052b43 100644 --- a/providers/transip/auditrecords.go +++ b/providers/transip/auditrecords.go @@ -1,11 +1,10 @@ package transip -import ( - "github.com/StackExchange/dnscontrol/v3/models" -) +import "github.com/StackExchange/dnscontrol/v3/models" -// AuditRecords returns an error if any records are not -// supportable by this provider. -func AuditRecords(records []*models.RecordConfig) error { +// AuditRecords returns a list of errors corresponding to the records +// that aren't supported by this provider. If all records are +// supported, an empty list is returned. +func AuditRecords(records []*models.RecordConfig) []error { return nil } diff --git a/providers/vultr/auditrecords.go b/providers/vultr/auditrecords.go index 4efe22900..82838c1de 100644 --- a/providers/vultr/auditrecords.go +++ b/providers/vultr/auditrecords.go @@ -2,23 +2,20 @@ package vultr import ( "github.com/StackExchange/dnscontrol/v3/models" - "github.com/StackExchange/dnscontrol/v3/pkg/recordaudit" + "github.com/StackExchange/dnscontrol/v3/pkg/rejectif" ) -// AuditRecords returns an error if any records are not -// supportable by this provider. -func AuditRecords(records []*models.RecordConfig) error { +// AuditRecords returns a list of errors corresponding to the records +// that aren't supported by this provider. If all records are +// supported, an empty list is returned. +func AuditRecords(records []*models.RecordConfig) []error { + a := rejectif.Auditor{} - // TODO(tlim) Needs investigation. Could be a dnscontrol issue or + a.Add("TXT", rejectif.TxtHasDoubleQuotes) // Last verified 2021-03-02 + // Needs investigation. Could be a dnscontrol issue or // the provider doesn't support double quotes. - if err := recordaudit.TxtNoDoubleQuotes(records); err != nil { - return err - } - // Still needed as of 2021-03-02 - if err := recordaudit.TxtNoMultipleStrings(records); err != nil { - return err - } + a.Add("TXT", rejectif.TxtHasMultipleSegments) - return nil + return a.Audit(records) }