From 5dbe5e84c914e5a6e437dba1e4116d63e6492d8f Mon Sep 17 00:00:00 2001 From: Tom Limoncelli Date: Mon, 13 Jan 2025 11:33:12 -0500 Subject: [PATCH] CHORE: Fix lint warnings from golangci-lint (#3311) --- build/generate/dtsFile.go | 3 +- build/generate/featureMatrix.go | 7 +- build/generate/functionTypes.go | 3 +- build/generate/ownersFile.go | 3 +- commands/commands.go | 5 +- commands/completion.go | 4 +- commands/completion_test.go | 9 +- commands/fmt.go | 2 +- commands/getCerts.go | 11 +- commands/getZones.go | 10 +- commands/gz_test.go | 4 +- commands/ppreviewPush.go | 41 +-- commands/previewPush.go | 25 +- commands/previewPush_test.go | 1 - commands/printIR.go | 6 +- commands/r53_test.go | 16 +- commands/writeTypes.go | 16 +- integrationTest/integration_test.go | 313 +++++++++--------- models/dns.go | 3 +- models/domain.go | 10 +- models/quotes_test.go | 46 ++- models/record.go | 16 +- models/record_test.go | 6 +- models/recorddb.go | 2 +- models/t_caa.go | 4 +- models/t_loc.go | 11 +- models/t_mx.go | 4 +- models/t_naptr.go | 4 +- models/t_parse.go | 2 +- models/t_soa.go | 6 +- models/t_srv.go | 4 +- models/t_sshfp.go | 4 +- models/t_svcb.go | 6 +- models/t_tlsa.go | 4 +- models/t_txt.go | 4 +- models/target.go | 16 +- pkg/acme/acme.go | 27 +- pkg/acme/directoryStorage.go | 12 +- pkg/acme/vaultStorage.go | 3 +- pkg/credsfile/providerConfig.go | 8 +- pkg/diff/diff.go | 3 +- pkg/diff2/analyze.go | 8 +- pkg/diff2/analyze_test.go | 108 +++--- pkg/diff2/compareconfig.go | 8 +- pkg/diff2/compareconfig_test.go | 3 - pkg/diff2/handsoff.go | 27 +- pkg/diff2/handsoff_test.go | 9 +- pkg/diff2/min.go | 10 - pkg/dnsgraph/dnsgraph.go | 1 - pkg/dnsgraph/dnsgraph_test.go | 2 +- pkg/dnssort/graphsort.go | 1 - pkg/dnssort/graphsort_test.go | 1 - pkg/dnstree/dnstree_test.go | 1 - pkg/js/hash.go | 2 +- pkg/js/js.go | 36 +- pkg/js/js_test.go | 24 +- pkg/nameservers/nameservers.go | 6 +- pkg/normalize/capabilities_test.go | 9 +- pkg/normalize/flatten.go | 11 +- pkg/normalize/importTransform_test.go | 3 +- pkg/normalize/validate.go | 53 +-- pkg/normalize/validate_test.go | 130 +++++--- pkg/notifications/bonfire.go | 2 +- pkg/notifications/notifications.go | 2 +- pkg/notifications/notifications_test.go | 2 - pkg/notifications/shoutrrr.go | 2 +- pkg/notifications/slack.go | 2 +- pkg/notifications/teams.go | 2 +- pkg/notifications/telegram.go | 3 +- pkg/powershell/backend/ssh.go | 10 +- pkg/powershell/middleware/session.go | 2 +- pkg/powershell/middleware/session_config.go | 2 +- pkg/powershell/shell.go | 8 +- pkg/prettyzone/prettyzone.go | 5 +- pkg/prettyzone/prettyzone_test.go | 55 ++- pkg/prettyzone/sorting.go | 18 +- pkg/printer/printer.go | 26 +- pkg/recorddb/recorddb.go | 2 +- pkg/rejectif/caa.go | 6 +- pkg/rejectif/label.go | 4 +- pkg/rejectif/mx.go | 4 +- pkg/rejectif/srv.go | 4 +- pkg/rejectif/txt.go | 19 +- pkg/rfc4183/ipv6.go | 6 +- pkg/rfc4183/mode.go | 9 +- pkg/rfc4183/reverse.go | 2 - pkg/rfc4183/reverse_test.go | 4 +- pkg/rtypecontrol/pave.go | 3 - pkg/rtypes/postprocess.go | 5 +- pkg/spflib/flatten.go | 16 +- pkg/spflib/parse.go | 6 +- pkg/spflib/parse_test.go | 30 +- pkg/spflib/resolver.go | 3 +- pkg/transform/arpa.go | 1 - pkg/transform/arpa_test.go | 2 +- pkg/transform/ptr.go | 1 - pkg/transform/ptr_test.go | 6 +- pkg/transform/transform.go | 14 +- pkg/transform/transform_test.go | 36 +- pkg/txtutil/txtcode.go | 17 +- pkg/txtutil/txtcode_test.go | 42 ++- pkg/txtutil/txtutil.go | 2 +- pkg/zonerecs/zonerecords.go | 5 +- providers/_all/all.go | 2 +- .../akamaiedgedns/akamaiEdgeDnsProvider.go | 14 +- .../akamaiedgedns/akamaiEdgeDnsService.go | 8 +- providers/autodns/api.go | 13 +- providers/autodns/autoDnsProvider.go | 41 ++- providers/autodns/types.go | 3 - providers/axfrddns/axfrddnsProvider.go | 25 +- providers/azuredns/azureDnsProvider.go | 13 +- .../azurePrivateDnsProvider.go | 14 +- providers/bind/bindProvider.go | 7 +- providers/bind/fnames.go | 7 +- providers/bind/fnames_test.go | 1 - providers/bind/serial_test.go | 2 +- providers/bind/soa.go | 5 +- providers/bind/soa_test.go | 5 +- providers/bunnydns/api.go | 8 +- providers/bunnydns/bunnydnsProvider.go | 4 +- providers/bunnydns/records.go | 7 +- providers/capabilities.go | 5 +- providers/cloudflare/cloudflareProvider.go | 55 ++- providers/cloudflare/preprocess_test.go | 9 +- providers/cloudflare/rest.go | 48 +-- .../cfsingleredirect/cfsingleredirect.go | 5 +- .../rtypes/cfsingleredirect/convert.go | 20 +- .../rtypes/cfsingleredirect/convert_test.go | 5 +- .../rtypes/cfsingleredirect/from.go | 26 +- providers/cloudns/api.go | 59 ++-- providers/cloudns/cloudnsProvider.go | 35 +- providers/cnr/cnrProvider.go | 6 +- providers/cnr/domains.go | 2 +- providers/cnr/records.go | 28 +- providers/cscglobal/api.go | 103 +++--- providers/cscglobal/convert.go | 30 +- providers/cscglobal/cscglobalProvider.go | 4 +- providers/cscglobal/dns.go | 11 +- providers/cscglobal/listzones.go | 1 - providers/cscglobal/registrar.go | 3 +- providers/desec/convert.go | 4 +- providers/desec/desecProvider.go | 19 +- providers/desec/protocol.go | 48 +-- providers/digitalocean/auditrecords.go | 6 +- .../digitalocean/digitaloceanProvider.go | 24 +- providers/dnsimple/dnsimpleProvider.go | 7 +- providers/dnsmadeeasy/api.go | 6 +- providers/dnsmadeeasy/dnsMadeEasyProvider.go | 6 +- providers/dnsmadeeasy/restApi.go | 7 +- providers/doh/api.go | 2 +- providers/domainnameshop/api.go | 27 +- providers/domainnameshop/convert.go | 12 +- providers/domainnameshop/dns.go | 26 +- .../domainnameshop/domainnameshopProvider.go | 6 +- providers/dynadot/api.go | 22 +- providers/dynadot/dynadotProvider.go | 3 +- providers/easyname/api.go | 8 +- providers/easyname/easynameProvider.go | 3 +- providers/exoscale/exoscaleProvider.go | 14 +- providers/gandiv5/convert.go | 4 +- providers/gandiv5/convert_test.go | 12 +- providers/gandiv5/gandi_v5Provider.go | 10 +- providers/gcloud/gcloudProvider.go | 19 +- providers/gcore/convert.go | 4 - providers/gcore/convertMetadata.go | 2 +- providers/gcore/gcoreExtend.go | 6 +- providers/gcore/gcoreProvider.go | 7 +- providers/hedns/hednsProvider.go | 10 +- providers/hetzner/api.go | 2 +- providers/hetzner/hetznerProvider.go | 4 +- providers/hexonet/domains.go | 2 +- providers/hexonet/hexonetProvider.go | 6 +- providers/hexonet/records.go | 18 +- providers/hostingde/hostingdeProvider.go | 24 +- providers/hostingde/types.go | 18 +- providers/huaweicloud/convert.go | 7 +- providers/internetbs/api.go | 12 +- providers/internetbs/internetbsProvider.go | 3 +- providers/inwx/inwxProvider.go | 19 +- providers/linode/api.go | 4 +- providers/linode/auditrecords.go | 1 - providers/linode/linodeProvider.go | 28 +- providers/loopia/client.go | 30 +- providers/loopia/client_test.go | 2 +- providers/loopia/convert.go | 6 +- providers/loopia/convert_test.go | 4 +- providers/loopia/loopiaProvider.go | 43 ++- providers/loopia/types.go | 6 +- providers/luadns/api.go | 56 ++-- providers/luadns/luadnsProvider.go | 13 +- providers/msdns/convert.go | 31 +- providers/msdns/msdnsProvider.go | 2 - providers/msdns/naptr.go | 9 +- providers/msdns/naptr_test.go | 8 +- providers/msdns/powershell.go | 58 ++-- providers/msdns/powershell_test.go | 27 +- providers/msdns/types.go | 10 +- .../mythicbeasts/mythicbeastsProvider.go | 5 +- providers/namecheap/namecheapProvider.go | 26 +- providers/namedotcom/auditrecords.go | 4 +- providers/namedotcom/namedotcomProvider.go | 4 +- providers/namedotcom/records.go | 35 +- providers/netcup/api.go | 24 +- providers/netcup/netcupProvider.go | 5 +- providers/netlify/api.go | 18 +- providers/netlify/netlifyProvider.go | 5 +- providers/ns1/ns1Provider.go | 28 +- providers/opensrs/opensrsProvider.go | 4 +- providers/oracle/oracleProvider.go | 9 +- providers/ovh/ovhProvider.go | 5 +- providers/ovh/protocol.go | 6 +- providers/packetframe/api.go | 4 +- providers/packetframe/packetframeProvider.go | 25 +- providers/porkbun/api.go | 17 +- providers/porkbun/porkbunProvider.go | 34 +- providers/powerdns/dns.go | 1 - providers/powerdns/powerdnsProvider.go | 11 +- providers/providers.go | 5 +- providers/realtimeregister/api.go | 11 +- .../realtimeregisterProvider.go | 6 +- .../realtimeregisterProvider_test.go | 3 +- providers/route53/auditrecords.go | 4 +- providers/route53/route53Provider.go | 17 +- providers/route53/route53Provider_test.go | 6 +- providers/rwth/api.go | 7 +- providers/rwth/convert.go | 3 +- providers/rwth/dns.go | 4 +- providers/rwth/rwthProvider.go | 4 +- providers/sakuracloud/api.go | 3 +- providers/sakuracloud/convert.go | 10 +- providers/sakuracloud/records.go | 5 +- providers/sakuracloud/sakuracloudProvider.go | 5 +- providers/softlayer/softlayerProvider.go | 34 +- providers/transip/transipProvider.go | 17 +- providers/vultr/vultrProvider.go | 11 +- 235 files changed, 1774 insertions(+), 1589 deletions(-) delete mode 100644 pkg/diff2/min.go diff --git a/build/generate/dtsFile.go b/build/generate/dtsFile.go index a0e20a6b6..20c6aa2d6 100644 --- a/build/generate/dtsFile.go +++ b/build/generate/dtsFile.go @@ -68,6 +68,5 @@ func generateDTSFile(funcs string) error { fileContent += strings.TrimRight(line, " \t") + "\n" } fileContent = strings.TrimRight(fileContent, "\n") - os.WriteFile(join("commands", "types", "dnscontrol.d.ts"), []byte(fileContent+"\n"), 0644) - return nil + return os.WriteFile(join("commands", "types", "dnscontrol.d.ts"), []byte(fileContent+"\n"), 0o644) } diff --git a/build/generate/featureMatrix.go b/build/generate/featureMatrix.go index d92afc4e6..78562c11d 100644 --- a/build/generate/featureMatrix.go +++ b/build/generate/featureMatrix.go @@ -13,7 +13,6 @@ import ( func generateFeatureMatrix() error { matrix := matrixData() markdownTable, err := markdownTable(matrix) - if err != nil { return err } @@ -45,7 +44,7 @@ func markdownTable(matrix *FeatureMatrix) (string, error) { tableData = append(tableData, tableDataRow) } - var markdownTable, err = markdown.NewTableFormatterBuilder(). + markdownTable, err := markdown.NewTableFormatterBuilder(). Build(tableHeaders...). Format(tableData) if err != nil { @@ -123,7 +122,7 @@ func matrixData() *FeatureMatrix { DomainModifierDnskey, DualHost, CreateDomains, - //NoPurge, + // NoPurge, GetZones, }, } @@ -346,7 +345,7 @@ func replaceInlineContent( contentBytes = []byte(content) contentBytes = append(contentBytes[:start], append(newContentBytes, contentBytes[end+len(endMarker):]...)...) - err = os.WriteFile(file, contentBytes, 0644) + err = os.WriteFile(file, contentBytes, 0o644) if err != nil { panic(err) } diff --git a/build/generate/functionTypes.go b/build/generate/functionTypes.go index 65194f2fa..2b0794b10 100644 --- a/build/generate/functionTypes.go +++ b/build/generate/functionTypes.go @@ -64,7 +64,7 @@ func readDocFile(fPath string) (map[string]interface{}, string, error) { func parseFrontMatter(content string) (map[string]interface{}, string, error) { delimiterIndices := delimiterRegex.FindAllStringIndex(content, 2) if len(delimiterIndices) < 1 { - return nil, "", fmt.Errorf("failed to parse file. Remove it and try again") + return nil, "", errors.New("failed to parse file. Remove it and try again") } startIndex := delimiterIndices[0][0] endIndex := delimiterIndices[1][0] @@ -126,7 +126,6 @@ func generateFunctionTypes() (string, error) { if err != nil { println("Error parsing front matter in", fPath, "error: ", err.Error()) continue - } if frontMatter["ts_ignore"] == true { continue diff --git a/build/generate/ownersFile.go b/build/generate/ownersFile.go index b9c9009ea..9de10f2c4 100644 --- a/build/generate/ownersFile.go +++ b/build/generate/ownersFile.go @@ -1,10 +1,11 @@ package main import ( - "github.com/StackExchange/dnscontrol/v4/providers" "os" "sort" "strings" + + "github.com/StackExchange/dnscontrol/v4/providers" ) func generateOwnersFile() error { diff --git a/commands/commands.go b/commands/commands.go index 23e46d0a7..752fc8e10 100644 --- a/commands/commands.go +++ b/commands/commands.go @@ -11,9 +11,8 @@ import ( "github.com/StackExchange/dnscontrol/v4/pkg/diff2" "github.com/StackExchange/dnscontrol/v4/pkg/js" "github.com/StackExchange/dnscontrol/v4/pkg/printer" - "github.com/urfave/cli/v2" - "github.com/fatih/color" + "github.com/urfave/cli/v2" ) // categories of commands @@ -165,7 +164,7 @@ func GetDNSConfig(args GetDNSConfigArgs) (*models.DNSConfig, error) { // convenient access patterns. Does everything we need to prepare for the validation phase, but // cannot do anything that requires the credentials file yet. func preloadProviders(cfg *models.DNSConfig) (*models.DNSConfig, error) { - //build name to type maps + // build name to type maps cfg.RegistrarsByName = map[string]*models.RegistrarConfig{} cfg.DNSProvidersByName = map[string]*models.DNSProviderConfig{} for _, reg := range cfg.Registrars { diff --git a/commands/completion.go b/commands/completion.go index 7f94348b4..f328afe90 100644 --- a/commands/completion.go +++ b/commands/completion.go @@ -30,7 +30,9 @@ func shellCompletionCommand() *cli.Command { BashComplete: func(ctx *cli.Context) { for _, shell := range supportedShells { if strings.HasPrefix(shell, ctx.Args().First()) { - ctx.App.Writer.Write([]byte(shell + "\n")) + if _, err := ctx.App.Writer.Write([]byte(shell + "\n")); err != nil { + panic(err) + } } } }, diff --git a/commands/completion_test.go b/commands/completion_test.go index 07ba8436c..81f59f3d3 100644 --- a/commands/completion_test.go +++ b/commands/completion_test.go @@ -3,14 +3,13 @@ package commands import ( "bytes" "fmt" + "slices" "strings" "testing" "text/template" "github.com/google/go-cmp/cmp" - "github.com/urfave/cli/v2" - "golang.org/x/exp/slices" ) type shellTestDataItem struct { @@ -99,7 +98,7 @@ func TestShellCompletionCommand(t *testing.T) { t.Fatal("expected error, but didn't get one") } - want := fmt.Sprintf("unknown shell: %s", invalidShellTestDataItem.shellName) + want := "unknown shell: " + invalidShellTestDataItem.shellName got := strings.TrimSpace(appErrWriterBuffer.String()) if diff := cmp.Diff(got, want); diff != "" { t.Errorf("mismatch (-want +got):\n%s", diff) @@ -153,7 +152,7 @@ func TestShellCompletionCommand(t *testing.T) { t.Fatal("expected error, but didn't get one") } - want := fmt.Sprintf("unknown shell: %s", invalidShellTestDataItem.shellPath) + want := "unknown shell: " + invalidShellTestDataItem.shellPath got := strings.TrimSpace(appErrWriterBuffer.String()) if diff := cmp.Diff(got, want); diff != "" { t.Errorf("mismatch (-want +got):\n%s", diff) @@ -230,7 +229,7 @@ func testHelperGetShellsAndCompletionScripts() ([]shellTestDataItem, error) { shellsAndValues, shellTestDataItem{ shellName: shellName, - shellPath: fmt.Sprintf("/bin/%s", shellName), + shellPath: "/bin/" + shellName, completionScriptTemplate: t, }, ) diff --git a/commands/fmt.go b/commands/fmt.go index 6a3c7b3a7..9491572b9 100644 --- a/commands/fmt.go +++ b/commands/fmt.go @@ -66,7 +66,7 @@ func FmtFile(args FmtArgs) error { if args.OutputFile == "" { fmt.Print(beautified) } else { - if err := os.WriteFile(args.OutputFile, []byte(beautified), 0744); err != nil { + if err := os.WriteFile(args.OutputFile, []byte(beautified), 0o744); err != nil { return err } fmt.Fprintf(os.Stderr, "File %s successfully written\n", args.OutputFile) diff --git a/commands/getCerts.go b/commands/getCerts.go index 2e63b1479..37dd7eaab 100644 --- a/commands/getCerts.go +++ b/commands/getCerts.go @@ -2,6 +2,7 @@ package commands import ( "encoding/json" + "errors" "fmt" "os" "regexp" @@ -129,10 +130,10 @@ func GetCerts(args GetCertsArgs) error { fmt.Println(args.JSFile) // check agree flag if !args.AgreeTOS { - return fmt.Errorf("you must agree to the Let's Encrypt Terms of Service by using -agreeTOS") + return errors.New("you must agree to the Let's Encrypt Terms of Service by using -agreeTOS") } if args.Email == "" { - return fmt.Errorf("must provide email to use for Let's Encrypt registration") + return errors.New("must provide email to use for Let's Encrypt registration") } // load dns config @@ -142,7 +143,7 @@ func GetCerts(args GetCertsArgs) error { } errs := normalize.ValidateAndNormalizeConfig(cfg) if PrintValidationErrors(errs) { - return fmt.Errorf("exiting due to validation errors") + return errors.New("exiting due to validation errors") } providerConfigs, err := credsfile.LoadProviderConfigs(args.CredsFile) if err != nil { @@ -170,7 +171,7 @@ func GetCerts(args GetCertsArgs) error { return err } if len(certList) == 0 { - return fmt.Errorf("must provide at least one certificate to issue in cert configuration") + return errors.New("must provide at least one certificate to issue in cert configuration") } if err = validateCertificateList(certList, cfg); err != nil { return err @@ -207,7 +208,7 @@ func GetCerts(args GetCertsArgs) error { if manyerr == nil { manyerr = err } else { - manyerr = fmt.Errorf("%w; %v", manyerr, err) + manyerr = fmt.Errorf("%w; %w", manyerr, err) } } } diff --git a/commands/getZones.go b/commands/getZones.go index 4ae28443b..27882a751 100644 --- a/commands/getZones.go +++ b/commands/getZones.go @@ -26,7 +26,7 @@ var _ = cmd(catUtils, func() *cli.Command { args.CredName = ctx.Args().Get(0) arg1 := ctx.Args().Get(1) args.ProviderName = arg1 - // In v4.0, skip the first args.ZoneNames if it it equals "-". + // In v4.0, skip the first args.ZoneNames if it equals "-". args.ZoneNames = ctx.Args().Slice()[2:] if arg1 != "" && arg1 != "-" { @@ -212,7 +212,6 @@ func GetZone(args GetZoneArgs) error { dspVariableName := "DSP_" + strings.ToUpper(args.CredName) if args.OutputFormat == "js" || args.OutputFormat == "djs" { - if args.ProviderName == "-" { fmt.Fprintf(w, `var %s = NewDnsProvider("%s");`+"\n", dspVariableName, args.CredName) @@ -229,10 +228,11 @@ func GetZone(args GetZoneArgs) error { z := prettyzone.PrettySort(recs, zoneName, 0, nil) switch args.OutputFormat { - case "zone": fmt.Fprintf(w, "$ORIGIN %s.\n", zoneName) - prettyzone.WriteZoneFileRC(w, z.Records, zoneName, uint32(args.DefaultTTL), nil) + if err := prettyzone.WriteZoneFileRC(w, z.Records, zoneName, uint32(args.DefaultTTL), nil); err != nil { + return err + } fmt.Fprintln(w) case "js", "djs": @@ -281,7 +281,6 @@ func GetZone(args GetZoneArgs) error { case "tsv": for _, rec := range recs { - cfproxy := "" if cp, ok := rec.Metadata["cloudflare_proxy"]; ok { if cp == "true" { @@ -315,7 +314,6 @@ func jsonQuoted(i string) string { } func formatDsl(rec *models.RecordConfig, defaultTTL uint32) string { - target := rec.GetTargetCombined() ttl := uint32(0) diff --git a/commands/gz_test.go b/commands/gz_test.go index 594debb83..9eb123de3 100644 --- a/commands/gz_test.go +++ b/commands/gz_test.go @@ -32,7 +32,7 @@ func testFormat(t *testing.T, domain, format string) { expectedFilename := fmt.Sprintf("test_data/%s.zone.%s", domain, format) outputFiletmpl := fmt.Sprintf("%s.zone.%s.*.txt", domain, format) - outfile, err := os.CreateTemp("", outputFiletmpl) + outfile, err := os.CreateTemp(t.TempDir(), outputFiletmpl) if err != nil { log.Fatal(fmt.Errorf("gz can't TempFile %q: %w", outputFiletmpl, err)) } @@ -68,7 +68,7 @@ func testFormat(t *testing.T, domain, format string) { if w, g := string(want), string(got); w != g { // If the test fails, output a file showing "got" - err = os.WriteFile(expectedFilename+".ACTUAL", got, 0644) + err = os.WriteFile(expectedFilename+".ACTUAL", got, 0o644) if err != nil { log.Fatal(err) } diff --git a/commands/ppreviewPush.go b/commands/ppreviewPush.go index e8a16dca9..535ffcc68 100644 --- a/commands/ppreviewPush.go +++ b/commands/ppreviewPush.go @@ -3,6 +3,7 @@ package commands import ( "cmp" "encoding/json" + "errors" "fmt" "os" "strings" @@ -88,7 +89,7 @@ type PPreviewArgs struct { } // ReportItem is a record of corrections for a particular domain/provider/registrar. -//type ReportItem struct { +// type ReportItem struct { // Domain string `json:"domain"` // Corrections int `json:"corrections"` // Provider string `json:"provider,omitempty"` @@ -140,8 +141,8 @@ func (args *PPreviewArgs) flags() []cli.Flag { Name: "reportmax", Hidden: true, Usage: `Limit the IGNORE/NO_PURGE report to this many lines (Expermental. Will change in the future.)`, - Action: func(ctx *cli.Context, max int) error { - printer.MaxReport = max + Action: func(ctx *cli.Context, maxreport int) error { + printer.MaxReport = maxreport return nil }, }) @@ -220,7 +221,6 @@ var pobsoleteDiff2FlagUsed = false // run is the main routine common to preview/push func prun(args PPreviewArgs, push bool, interactive bool, out printer.CLI, report string) error { - // This is a hack until we have the new printer replacement. printer.SkinnyReport = !args.Full fullMode := args.Full @@ -250,7 +250,7 @@ func prun(args PPreviewArgs, push bool, interactive bool, out printer.CLI, repor out.PrintfIf(fullMode, "Normalizing and validating 'desired'..\n") errs := normalize.ValidateAndNormalizeConfig(cfg) if PrintValidationErrors(errs) { - return fmt.Errorf("exiting due to validation errors") + return errors.New("exiting due to validation errors") } zcache := NewZoneCache() @@ -312,7 +312,6 @@ func prun(args PPreviewArgs, push bool, interactive bool, out printer.CLI, repor reportItems = append(reportItems, genReportItem(zone.Name, corrections, zone.RegistrarName)) anyErrors = cmp.Or(anyErrors, pprintOrRunCorrections(zone.Name, zone.RegistrarInstance.Name, corrections, out, push, interactive, notifier, report)) } - } if os.Getenv("TEAMCITY_VERSION") != "" { @@ -323,18 +322,18 @@ func prun(args PPreviewArgs, push bool, interactive bool, out printer.CLI, repor out.Printf("Done. %d corrections.\n", totalCorrections) err = writeReport(report, reportItems) if err != nil { - return fmt.Errorf("could not write report") + return errors.New("could not write report") } if anyErrors { - return fmt.Errorf("completed with errors") + return errors.New("completed with errors") } if totalCorrections != 0 && args.WarnChanges { - return fmt.Errorf("there are pending changes") + return errors.New("there are pending changes") } return nil } -//func countActions(corrections []*models.Correction) int { +// func countActions(corrections []*models.Correction) int { // r := 0 // for _, c := range corrections { // if c.F != nil { @@ -382,12 +381,12 @@ func splitConcurrent(domains []*models.DomainConfig, filter string) (serial []*m // concurrency. Otherwise false is returned. func allConcur(dc *models.DomainConfig) bool { if !providers.ProviderHasCapability(dc.RegistrarInstance.ProviderType, providers.CanConcur) { - //fmt.Printf("WHY? %q: %+v\n", dc.Name, dc.RegistrarInstance) + // fmt.Printf("WHY? %q: %+v\n", dc.Name, dc.RegistrarInstance) return false } for _, p := range dc.DNSProviderInstances { if !providers.ProviderHasCapability(p.ProviderType, providers.CanConcur) { - //fmt.Printf("WHY? %q: %+v\n", dc.Name, p) + // fmt.Printf("WHY? %q: %+v\n", dc.Name, p) return false } } @@ -421,7 +420,6 @@ func oneZone(zone *models.DomainConfig, args PPreviewArgs, zc *zoneCache) { // Loop over the (selected) providers configured for that zone: providersToProcess := whichProvidersToProcess(zone.DNSProviderInstances, args.Providers) for _, provider := range providersToProcess { - // Populate the zones at the provider (if desired/needed/able): if !args.NoPopulate { populateCorrections := generatePopulateCorrections(provider, zone.Name, zc) @@ -441,7 +439,6 @@ func oneZone(zone *models.DomainConfig, args PPreviewArgs, zc *zoneCache) { } func whichProvidersToProcess(providers []*models.DNSProviderInstance, filter string) []*models.DNSProviderInstance { - if filter == "all" { // all return providers } @@ -477,7 +474,6 @@ func skipProvider(name string, providers []*models.DNSProviderInstance) bool { } func genReportItem(zname string, corrections []*models.Correction, pname string) *ReportItem { - // Only count the actions, not the messages. cnt := 0 for _, cor := range corrections { @@ -502,7 +498,6 @@ func pprintOrRunCorrections(zoneName string, providerName string, corrections [] cc := 0 cn := 0 for _, correction := range corrections { - // Print what we're about to do. if correction.F == nil { out.PrintReport(cn, correction) @@ -514,7 +509,6 @@ func pprintOrRunCorrections(zoneName string, providerName string, corrections [] var err error if push { - // If interactive, ask "are you sure?" and skip if not. if interactive && !out.PromptToRun() { continue @@ -542,7 +536,7 @@ func writeReport(report string, reportItems []*ReportItem) error { return nil } - f, err := os.OpenFile(report, os.O_CREATE|os.O_WRONLY|os.O_TRUNC, 0644) + f, err := os.OpenFile(report, os.O_CREATE|os.O_WRONLY|os.O_TRUNC, 0o644) if err != nil { return err } @@ -558,7 +552,6 @@ func writeReport(report string, reportItems []*ReportItem) error { } func generatePopulateCorrections(provider *models.DNSProviderInstance, zoneName string, zcache *zoneCache) []*models.Correction { - lister, ok := provider.Driver.(providers.ZoneLister) if !ok { return nil // We can't generate a list. No corrections are possible. @@ -595,7 +588,7 @@ func generateZoneCorrections(zone *models.DomainConfig, provider *models.DNSProv } func generateDelegationCorrections(zone *models.DomainConfig, providers []*models.DNSProviderInstance, _ *models.RegistrarInstance) ([]*models.Correction, int) { - //fmt.Printf("DEBUG: generateDelegationCorrections start zone=%q nsList = %v\n", zone.Name, zone.Nameservers) + // fmt.Printf("DEBUG: generateDelegationCorrections start zone=%q nsList = %v\n", zone.Name, zone.Nameservers) nsList, err := nameservers.DetermineNameserversForProviders(zone, providers, true) if err != nil { return msg(fmt.Sprintf("DetermineNS: zone %q; Error: %s", zone.Name, err)), 0 @@ -645,7 +638,7 @@ func PInitializeProviders(cfg *models.DNSConfig, providerConfigs map[string]map[ fmt.Fprintln(os.Stderr, strings.Join(msgs, "\n")) } if err != nil { - return + return notify, err } registrars := map[string]providers.Registrar{} @@ -674,7 +667,7 @@ func PInitializeProviders(cfg *models.DNSConfig, providerConfigs map[string]map[ pInst.IsDefault = !isNonDefault[pInst.Name] } } - return + return notify, err } // pproviderTypeFieldName is the name of the field in creds.json that specifies the provider type id. @@ -765,7 +758,6 @@ func puniqueStrings(stringSlice []string) []string { } func prefineProviderType(credEntryName string, t string, credFields map[string]string, source string) (replacementType string, warnMsg string, err error) { - // t="" and t="-" are processed the same. Standardize on "-" to reduce the number of cases to check. if t == "" { t = "-" @@ -778,7 +770,7 @@ func prefineProviderType(credEntryName string, t string, credFields map[string]s // - or "" GANDI lookup worked. Nothing to say. // - or "" - or "" ERROR "creds.json has invalid or missing data" // GANDI "" WARNING "Working but.... Please fix as follows..." - // GANDI GANDI INFO "working but unneeded: clean up as follows..." + // GANDI INFO "working but unneeded: clean up as follows..." // GANDI NAMEDOT ERROR "error mismatched: please fix as follows..." // ERROR: Invalid. @@ -869,5 +861,4 @@ func prefineProviderType(credEntryName string, t string, credFields map[string]s // use the value in creds.json (this should be the normal case) return ct, "", nil } - } diff --git a/commands/previewPush.go b/commands/previewPush.go index 2a2e176cd..410ae47f1 100644 --- a/commands/previewPush.go +++ b/commands/previewPush.go @@ -2,13 +2,12 @@ package commands import ( "encoding/json" + "errors" "fmt" "os" "strings" "sync" - "golang.org/x/net/idna" - "github.com/StackExchange/dnscontrol/v4/models" "github.com/StackExchange/dnscontrol/v4/pkg/credsfile" "github.com/StackExchange/dnscontrol/v4/pkg/nameservers" @@ -19,6 +18,7 @@ import ( "github.com/StackExchange/dnscontrol/v4/pkg/zonerecs" "github.com/StackExchange/dnscontrol/v4/providers" "golang.org/x/exp/slices" + "golang.org/x/net/idna" ) // ReportItem is a record of corrections for a particular domain/provider/registrar. @@ -67,7 +67,7 @@ func run(args PPreviewArgs, push bool, interactive bool, out printer.CLI, report errs := normalize.ValidateAndNormalizeConfig(cfg) if PrintValidationErrors(errs) { - return fmt.Errorf("exiting due to validation errors") + return errors.New("exiting due to validation errors") } anyErrors := false totalCorrections := 0 @@ -112,8 +112,8 @@ func run(args PPreviewArgs, push bool, interactive bool, out printer.CLI, report aceZoneName, _ := idna.ToASCII(domain.Name) if !slices.Contains(zones, aceZoneName) { - //out.Warnf("DEBUG: zones: %v\n", zones) - //out.Warnf("DEBUG: Name: %v\n", domain.Name) + // out.Warnf("DEBUG: zones: %v\n", zones) + // out.Warnf("DEBUG: Name: %v\n", domain.Name) out.Warnf("Zone '%s' does not exist in the '%s' profile and will be added automatically.\n", domain.Name, provider.Name) continue // continue with next provider, as we can not determine corrections without an existing zone @@ -141,7 +141,6 @@ func run(args PPreviewArgs, push bool, interactive bool, out printer.CLI, report nameservers.AddNSRecords(domain) for _, provider := range providersWithExistingZone { - shouldrun := args.shouldRunProvider(provider.Name, domain) out.StartDNSProvider(provider.Name, !shouldrun) if !shouldrun { @@ -199,13 +198,13 @@ func run(args PPreviewArgs, push bool, interactive bool, out printer.CLI, report notifier.Done() out.Printf("Done. %d corrections.\n", totalCorrections) if anyErrors { - return fmt.Errorf("completed with errors") + return errors.New("completed with errors") } if totalCorrections != 0 && args.WarnChanges { - return fmt.Errorf("there are pending changes") + return errors.New("there are pending changes") } if report != nil && *report != "" { - f, err := os.OpenFile(*report, os.O_CREATE|os.O_WRONLY|os.O_TRUNC, 0644) + f, err := os.OpenFile(*report, os.O_CREATE|os.O_WRONLY|os.O_TRUNC, 0o644) if err != nil { return err } @@ -245,7 +244,7 @@ func InitializeProviders(cfg *models.DNSConfig, providerConfigs map[string]map[s fmt.Fprintln(os.Stderr, strings.Join(msgs, "\n")) } if err != nil { - return + return notify, err } registrars := map[string]providers.Registrar{} @@ -274,7 +273,7 @@ func InitializeProviders(cfg *models.DNSConfig, providerConfigs map[string]map[s pInst.IsDefault = !isNonDefault[pInst.Name] } } - return + return notify, err } // providerTypeFieldName is the name of the field in creds.json that specifies the provider type id. @@ -364,7 +363,6 @@ func uniqueStrings(stringSlice []string) []string { } func refineProviderType(credEntryName string, t string, credFields map[string]string, source string) (replacementType string, warnMsg string, err error) { - // t="" and t="-" are processed the same. Standardize on "-" to reduce the number of cases to check. if t == "" { t = "-" @@ -377,7 +375,7 @@ func refineProviderType(credEntryName string, t string, credFields map[string]st // - or "" GANDI lookup worked. Nothing to say. // - or "" - or "" ERROR "creds.json has invalid or missing data" // GANDI "" WARNING "Working but.... Please fix as follows..." - // GANDI GANDI INFO "working but unneeded: clean up as follows..." + // GANDI INFO "working but unneeded: clean up as follows..." // GANDI NAMEDOT ERROR "error mismatched: please fix as follows..." // ERROR: Invalid. @@ -468,7 +466,6 @@ func refineProviderType(credEntryName string, t string, credFields map[string]st // use the value in creds.json (this should be the normal case) return ct, "", nil } - } func printOrRunCorrections(domain string, provider string, corrections []*models.Correction, out printer.CLI, push bool, interactive bool, notifier notifications.Notifier) (anyErrors bool) { diff --git a/commands/previewPush_test.go b/commands/previewPush_test.go index 92a95fbe5..b00622d7e 100644 --- a/commands/previewPush_test.go +++ b/commands/previewPush_test.go @@ -6,7 +6,6 @@ import ( ) func Test_refineProviderType(t *testing.T) { - var mapEmpty map[string]string mapTypeMissing := map[string]string{"otherfield": "othervalue"} mapTypeFoo := map[string]string{"TYPE": "FOO"} diff --git a/commands/printIR.go b/commands/printIR.go index cb463504f..17ccd63e7 100644 --- a/commands/printIR.go +++ b/commands/printIR.go @@ -2,6 +2,7 @@ package commands import ( "encoding/json" + "errors" "fmt" "log" "os" @@ -42,7 +43,6 @@ var _ = cmd(catDebug, func() *cli.Command { Name: "check", Usage: "Check and validate dnsconfig.js. Output to stdout. Do not access providers.", Action: func(c *cli.Context) error { - // Create a PrintIRArgs struct and copy our args to the // appropriate fields. var pargs PrintIRArgs @@ -96,7 +96,7 @@ func PrintIR(args PrintIRArgs) error { if !args.Raw { errs := normalize.ValidateAndNormalizeConfig(cfg) if PrintValidationErrors(errs) { - return fmt.Errorf("exiting due to validation errors") + return errors.New("exiting due to validation errors") } } return PrintJSON(args.PrintJSONArgs, cfg) @@ -122,7 +122,7 @@ func PrintValidationErrors(errs []error) (fatal bool) { // ExecuteDSL executes the dnsconfig.js contents. func ExecuteDSL(args ExecuteDSLArgs) (*models.DNSConfig, error) { if args.JSFile == "" { - return nil, fmt.Errorf("no config specified") + return nil, errors.New("no config specified") } dnsConfig, err := js.ExecuteJavaScript(args.JSFile, args.DevMode, stringSliceToMap(args.Variable)) diff --git a/commands/r53_test.go b/commands/r53_test.go index 27772bc3c..05a9141f0 100644 --- a/commands/r53_test.go +++ b/commands/r53_test.go @@ -13,7 +13,7 @@ func TestR53Test_1(t *testing.T) { Name: "foo", NameFQDN: "foo.domain.tld", } - rec.SetTarget("bar") + rec.MustSetTarget("bar") rec.R53Alias = make(map[string]string) rec.R53Alias["type"] = "A" w := `R53_ALIAS("foo", "A", "bar")` @@ -28,7 +28,7 @@ func TestR53Test_1ttl(t *testing.T) { Name: "foo", NameFQDN: "foo.domain.tld", } - rec.SetTarget("bar") + rec.MustSetTarget("bar") rec.R53Alias = make(map[string]string) rec.R53Alias["type"] = "A" w := `R53_ALIAS("foo", "A", "bar", TTL(321))` @@ -43,7 +43,7 @@ func TestR53Test_2(t *testing.T) { Name: "foo", NameFQDN: "foo.domain.tld", } - rec.SetTarget("bar") + rec.MustSetTarget("bar") rec.R53Alias = make(map[string]string) rec.R53Alias["type"] = "A" rec.R53Alias["zone_id"] = "blarg" @@ -59,7 +59,7 @@ func TestR53Test_2ttl(t *testing.T) { Name: "foo", NameFQDN: "foo.domain.tld", } - rec.SetTarget("bar") + rec.MustSetTarget("bar") rec.R53Alias = make(map[string]string) rec.R53Alias["type"] = "A" rec.R53Alias["zone_id"] = "blarg" @@ -75,7 +75,7 @@ func TestR53Test_3(t *testing.T) { Name: "foo", NameFQDN: "foo.domain.tld", } - rec.SetTarget("bar") + rec.MustSetTarget("bar") rec.R53Alias = make(map[string]string) rec.R53Alias["type"] = "A" rec.R53Alias["evaluate_target_health"] = "true" @@ -91,7 +91,7 @@ func TestR53Test_3ttl(t *testing.T) { Name: "foo", NameFQDN: "foo.domain.tld", } - rec.SetTarget("bar") + rec.MustSetTarget("bar") rec.R53Alias = make(map[string]string) rec.R53Alias["type"] = "A" rec.R53Alias["evaluate_target_health"] = "true" @@ -107,7 +107,7 @@ func TestR53Test_4(t *testing.T) { Name: "foo", NameFQDN: "foo.domain.tld", } - rec.SetTarget("bar") + rec.MustSetTarget("bar") rec.R53Alias = make(map[string]string) rec.R53Alias["type"] = "A" rec.R53Alias["zone_id"] = "blarg" @@ -124,7 +124,7 @@ func TestR53Test_4ttl(t *testing.T) { Name: "foo", NameFQDN: "foo.domain.tld", } - rec.SetTarget("bar") + rec.MustSetTarget("bar") rec.R53Alias = make(map[string]string) rec.R53Alias["type"] = "A" rec.R53Alias["zone_id"] = "blarg" diff --git a/commands/writeTypes.go b/commands/writeTypes.go index ef0a6100f..2e067d83f 100644 --- a/commands/writeTypes.go +++ b/commands/writeTypes.go @@ -52,10 +52,18 @@ func WriteTypes(args TypesArgs) error { } defer file.Close() - file.WriteString("// This file was automatically generated by DNSControl. Do not edit it directly.\n") - file.WriteString("// To update it, run `dnscontrol write-types`.\n\n") - file.WriteString("// " + version + "\n") - file.WriteString(dtsContent) + if _, err := file.WriteString("// This file was automatically generated by DNSControl. Do not edit it directly.\n"); err != nil { + return err + } + if _, err := file.WriteString("// To update it, run `dnscontrol write-types`.\n\n"); err != nil { + return err + } + if _, err := file.WriteString("// " + version + "\n"); err != nil { + return err + } + if _, err := file.WriteString(dtsContent); err != nil { + return err + } print("Successfully wrote " + args.DTSFile + "\n") return nil diff --git a/integrationTest/integration_test.go b/integrationTest/integration_test.go index b98de7092..d00247b6f 100644 --- a/integrationTest/integration_test.go +++ b/integrationTest/integration_test.go @@ -2,6 +2,7 @@ package main import ( "encoding/json" + "errors" "flag" "fmt" "os" @@ -20,14 +21,16 @@ import ( "github.com/miekg/dns/dnsutil" ) -var providerFlag = flag.String("provider", "", "Provider to run (if empty, deduced from -profile)") -var profileFlag = flag.String("profile", "", "Entry in profiles.json to use (if empty, copied from -provider)") -var startIdx = flag.Int("start", -1, "Test number to begin with") -var endIdx = flag.Int("end", -1, "Test index to stop after") -var verbose = flag.Bool("verbose", false, "Print corrections as you run them") -var printElapsed = flag.Bool("elapsed", false, "Print elapsed time for each testgroup") -var enableCFWorkers = flag.Bool("cfworkers", true, "Set false to disable CF worker tests") -var enableCFRedirectMode = flag.String("cfredirect", "", "cloudflare pagerule tests: default=page_rules, c=convert old to enw, n=new-style, o=none") +var ( + providerFlag = flag.String("provider", "", "Provider to run (if empty, deduced from -profile)") + profileFlag = flag.String("profile", "", "Entry in profiles.json to use (if empty, copied from -provider)") + startIdx = flag.Int("start", -1, "Test number to begin with") + endIdx = flag.Int("end", -1, "Test index to stop after") + verbose = flag.Bool("verbose", false, "Print corrections as you run them") + printElapsed = flag.Bool("elapsed", false, "Print elapsed time for each testgroup") + enableCFWorkers = flag.Bool("cfworkers", true, "Set false to disable CF worker tests") + enableCFRedirectMode = flag.String("cfredirect", "", "cloudflare pagerule tests: default=page_rules, c=convert old to enw, n=new-style, o=none") +) func init() { testing.Init() @@ -47,6 +50,12 @@ func CfCProxyFull() *TestCase { return tc("cproxyf", cfProxyCNAME("cproxy", "exa // --- +func panicOnErr(err error) { + if err != nil { + panic(err) + } +} + func getProvider(t *testing.T) (providers.DNSServiceProvider, string, map[string]string) { if *providerFlag == "" && *profileFlag == "" { t.Log("No -provider or -profile specified") @@ -97,7 +106,7 @@ func getProvider(t *testing.T) (providers.DNSServiceProvider, string, map[string *providerFlag = profileType } - //fmt.Printf("DEBUG flag=%q Profile=%q TYPE=%q\n", *providerFlag, profileName, profileType) + // fmt.Printf("DEBUG flag=%q Profile=%q TYPE=%q\n", *providerFlag, profileName, profileType) fmt.Printf("Testing Profile=%q TYPE=%q\n", profileName, profileType) var metadata json.RawMessage @@ -152,7 +161,6 @@ func TestDNSProviders(t *testing.T) { t.Run(domain, func(t *testing.T) { runTests(t, provider, domain, cfg) }) - } func getDomainConfigWithNameservers(t *testing.T, prv providers.DNSServiceProvider, domainName string) *models.DomainConfig { @@ -174,10 +182,9 @@ func getDomainConfigWithNameservers(t *testing.T, prv providers.DNSServiceProvid // testPermitted returns nil if the test is permitted, otherwise an // error explaining why it is not. func testPermitted(p string, f TestGroup) error { - // not() and only() can't be mixed. if len(f.only) != 0 && len(f.not) != 0 { - return fmt.Errorf("invalid filter: can't mix not() and only()") + return errors.New("invalid filter: can't mix not() and only()") } // TODO(tlim): Have a separate validation pass so that such mistakes // are more visible? @@ -205,7 +212,7 @@ func testPermitted(p string, f TestGroup) error { return nil } } - return fmt.Errorf("disabled by only") + return errors.New("disabled by only") } // If there are any "not" items, you must NOT be one of them. @@ -238,7 +245,7 @@ func makeChanges(t *testing.T, prv providers.DNSServiceProvider, dc *models.Doma if strings.Contains(rc.GetLabelFQDN(), "**current-domain**") { rc.SetLabelFromFQDN(strings.Replace(rc.GetLabelFQDN(), "**current-domain**", domainName, 1), domainName) } - //if providers.ProviderHasCapability(*providerToRun, providers.CanUseAzureAlias) { + // if providers.ProviderHasCapability(*providerToRun, providers.CanUseAzureAlias) { if strings.Contains(rc.GetTargetField(), "**subscription-id**") { _ = rc.SetTarget(strings.Replace(rc.GetTargetField(), "**subscription-id**", origConfig["SubscriptionID"], 1)) } @@ -315,7 +322,6 @@ func makeChanges(t *testing.T, prv providers.DNSServiceProvider, dc *models.Doma } t.FailNow() } - }) } @@ -334,7 +340,6 @@ func runTests(t *testing.T, prv providers.DNSServiceProvider, domainName string, curGroup := -1 for gIdx, group := range testGroups { - // Abide by -start -end flags curGroup++ if curGroup < firstGroup || curGroup > lastGroup { @@ -342,9 +347,9 @@ func runTests(t *testing.T, prv providers.DNSServiceProvider, domainName string, } // Abide by filter - //fmt.Printf("DEBUG testPermitted: prov=%q profile=%q\n", *providerFlag, *profileFlag) + // fmt.Printf("DEBUG testPermitted: prov=%q profile=%q\n", *providerFlag, *profileFlag) if err := testPermitted(*profileFlag, *group); err != nil { - //t.Logf("%s: ***SKIPPED(%v)***", group.Desc, err) + // t.Logf("%s: ***SKIPPED(%v)***", group.Desc, err) makeChanges(t, prv, dc, tc("Empty"), fmt.Sprintf("%02d:%s ***SKIPPED(%v)***", gIdx, group.Desc, err), false, origConfig) continue } @@ -356,7 +361,6 @@ func runTests(t *testing.T, prv providers.DNSServiceProvider, domainName string, start := time.Now() for _, tst := range group.tests { - // TODO(tlim): This is the old version. It skipped the remaining tc() statements if one failed. // The new code continues to test the remaining tc() statements. Keeping this as a comment // in case we ever want to do something similar. @@ -368,16 +372,13 @@ func runTests(t *testing.T, prv providers.DNSServiceProvider, domainName string, if ok := makeChanges(t, prv, dc, tst, fmt.Sprintf("%02d:%s", gIdx, group.Desc), true, origConfig); !ok { break } - } elapsed := time.Since(start) if *printElapsed { fmt.Printf("ELAPSED %02d %7.2f %q\n", gIdx, elapsed.Seconds(), group.Desc) } - } - } func TestDualProviders(t *testing.T) { @@ -474,7 +475,7 @@ func TestNameserverDots(t *testing.T) { t.Run("No trailing dot in nameserver", func(t *testing.T) { for _, nameserver := range dc.Nameservers { - //fmt.Printf("DEBUG: nameserver.Name = %q\n", nameserver.Name) + // fmt.Printf("DEBUG: nameserver.Name = %q\n", nameserver.Name) if strings.HasSuffix(nameserver.Name, ".") { t.Errorf("Provider returned nameserver with trailing dot: %q", nameserver) } @@ -543,7 +544,7 @@ func azureAlias(name, aliasType, target string) *models.RecordConfig { func caa(name string, tag string, flag uint8, target string) *models.RecordConfig { r := makeRec(name, target, "CAA") - r.SetTargetCAA(flag, tag, target) + panicOnErr(r.SetTargetCAA(flag, tag, target)) return r } @@ -567,10 +568,7 @@ func cfSingleRedirectEnabled() bool { func cfSingleRedirect(name string, code any, when, then string) *models.RecordConfig { r := makeRec("@", name, cfsingleredirect.SINGLEREDIRECT) - err := cfsingleredirect.FromRaw(r, []any{name, code, when, then}) - if err != nil { - panic("Should not happen... cfSingleRedirect") - } + panicOnErr(cfsingleredirect.FromRaw(r, []any{name, code, when, then})) // Should not happen return r } @@ -606,13 +604,13 @@ func dname(name, target string) *models.RecordConfig { func ds(name string, keyTag uint16, algorithm, digestType uint8, digest string) *models.RecordConfig { r := makeRec(name, "", "DS") - r.SetTargetDS(keyTag, algorithm, digestType, digest) + panicOnErr(r.SetTargetDS(keyTag, algorithm, digestType, digest)) return r } func dnskey(name string, flags uint16, protocol, algorithm uint8, publicKey string) *models.RecordConfig { r := makeRec(name, "", "DNSKEY") - r.SetTargetDNSKEY(flags, protocol, algorithm, publicKey) + panicOnErr(r.SetTargetDNSKEY(flags, protocol, algorithm, publicKey)) return r } @@ -644,9 +642,10 @@ func ignore(labelSpec string, typeSpec string, targetSpec string) *models.Record } func loc(name string, d1 uint8, m1 uint8, s1 float32, ns string, - d2 uint8, m2 uint8, s2 float32, ew string, al float32, sz float32, hp float32, vp float32) *models.RecordConfig { + d2 uint8, m2 uint8, s2 float32, ew string, al float32, sz float32, hp float32, vp float32, +) *models.RecordConfig { r := makeRec(name, "", "LOC") - r.SetLOCParams(d1, m1, s1, ns, d2, m2, s2, ew, al, sz, hp, vp) + panicOnErr(r.SetLOCParams(d1, m1, s1, ns, d2, m2, s2, ew, al, sz, hp, vp)) return r } @@ -656,13 +655,13 @@ func makeRec(name, target, typ string) *models.RecordConfig { TTL: 300, } SetLabel(r, name, "**current-domain**") - r.SetTarget(target) + r.MustSetTarget(target) return r } func manyA(namePattern, target string, n int) []*models.RecordConfig { recs := []*models.RecordConfig{} - for i := 0; i < n; i++ { + for i := range n { recs = append(recs, makeRec(fmt.Sprintf(namePattern, i), target, "A")) } return recs @@ -680,7 +679,7 @@ func ns(name, target string) *models.RecordConfig { func naptr(name string, order uint16, preference uint16, flags string, service string, regexp string, target string) *models.RecordConfig { r := makeRec(name, target, "NAPTR") - r.SetTargetNAPTR(order, preference, flags, service, regexp, target) + panicOnErr(r.SetTargetNAPTR(order, preference, flags, service, regexp, target)) return r } @@ -699,19 +698,19 @@ func r53alias(name, aliasType, target, evalTargetHealth string) *models.RecordCo func soa(name string, ns, mbox string, serial, refresh, retry, expire, minttl uint32) *models.RecordConfig { r := makeRec(name, "", "SOA") - r.SetTargetSOA(ns, mbox, serial, refresh, retry, expire, minttl) + panicOnErr(r.SetTargetSOA(ns, mbox, serial, refresh, retry, expire, minttl)) return r } func srv(name string, priority, weight, port uint16, target string) *models.RecordConfig { r := makeRec(name, target, "SRV") - r.SetTargetSRV(priority, weight, port, target) + panicOnErr(r.SetTargetSRV(priority, weight, port, target)) return r } func sshfp(name string, algorithm uint8, fingerprint uint8, target string) *models.RecordConfig { r := makeRec(name, target, "SSHFP") - r.SetTargetSSHFP(algorithm, fingerprint, target) + panicOnErr(r.SetTargetSSHFP(algorithm, fingerprint, target)) return r } @@ -738,7 +737,7 @@ func makeOvhNativeRecord(name, target, rType string) *models.RecordConfig { r := makeRec(name, "", "TXT") r.Metadata = make(map[string]string) r.Metadata["create_ovh_native_record"] = rType - r.SetTarget(target) + r.MustSetTarget(target) return r } @@ -807,7 +806,7 @@ func tc(desc string, recs ...*models.RecordConfig) *TestCase { func txt(name, target string) *models.RecordConfig { r := makeRec(name, "", "TXT") - r.SetTargetTXT(target) + panicOnErr(r.SetTargetTXT(target)) return r } @@ -819,7 +818,7 @@ func ttl(r *models.RecordConfig, t uint32) *models.RecordConfig { func tlsa(name string, usage, selector, matchingtype uint8, target string) *models.RecordConfig { r := makeRec(name, target, "TLSA") - r.SetTargetTLSA(usage, selector, matchingtype, target) + panicOnErr(r.SetTargetTLSA(usage, selector, matchingtype, target)) return r } @@ -832,7 +831,7 @@ func porkbunUrlfwd(name, target, t, includePath, wildcard string) *models.Record return r } -func clear() *TestCase { +func tcEmptyZone() *TestCase { return tc("Empty") } @@ -871,7 +870,6 @@ func alltrue(f ...bool) alltrueFilter { // func makeTests() []*TestGroup { - sha256hash := strings.Repeat("0123456789abcdef", 4) sha512hash := strings.Repeat("0123456789abcdef", 8) reversedSha512 := strings.Repeat("fedcba9876543210", 8) @@ -906,12 +904,11 @@ func makeTests() []*TestGroup { // whether or not a certain kind of record can be created and // deleted. - // clear() is the same as tc("Empty"). It removes all records. - // Each testgroup() begins with clear() automagically. You do not - // have to include the clear() in each testgroup(). + // emptyzone() is the same as tc("Empty"). It removes all records. + // Each testgroup() begins with tcEmptyZone() automagically. You do not + // have to include the tcEmptyZone() in each testgroup(). tests := []*TestGroup{ - // START HERE // Narrative: Hello friend! Are you adding a new DNS provider to @@ -1040,7 +1037,7 @@ func makeTests() []*TestGroup { testgroup("ManyAtOnce", tc("CreateManyAtLabel", a("www", "1.1.1.1"), a("www", "2.2.2.2"), a("www", "3.3.3.3")), - clear(), + tcEmptyZone(), tc("Create an A record", a("www", "1.1.1.1")), tc("Add at label1", a("www", "1.1.1.1"), a("www", "2.2.2.2")), tc("Add at label2", a("www", "1.1.1.1"), a("www", "2.2.2.2"), a("www", "3.3.3.3")), @@ -1048,7 +1045,7 @@ func makeTests() []*TestGroup { testgroup("manyTypesAtOnce", tc("CreateManyTypesAtLabel", a("www", "1.1.1.1"), mx("testmx", 5, "foo.com."), mx("testmx", 100, "bar.com.")), - clear(), + tcEmptyZone(), tc("Create an A record", a("www", "1.1.1.1")), tc("Add Type At Label", a("www", "1.1.1.1"), mx("testmx", 5, "foo.com.")), tc("Add Type At Label", a("www", "1.1.1.1"), mx("testmx", 5, "foo.com."), mx("testmx", 100, "bar.com.")), @@ -1286,7 +1283,7 @@ func makeTests() []*TestGroup { tc("a 764-byte TXT", txt("foo764", strings.Repeat("G", 764))), // 255*3-1 tc("a 765-byte TXT", txt("foo765", strings.Repeat("H", 765))), // 255*3 tc("a 766-byte TXT", txt("foo766", strings.Repeat("J", 766))), // 255*3+1 - //clear(), + // tcEmptyZone(), tc("TXT with 1 single-quote", txt("foosq", "quo'te")), tc("TXT with 1 backtick", txt("foobt", "blah`blah")), @@ -1301,14 +1298,14 @@ func makeTests() []*TestGroup { tc("TXT with semicolon ws", txt("foosc2", `wssemi ; colon`)), tc("TXT interior ws", txt("foosp", "with spaces")), - //tc("TXT leading ws", txt("foowsb", " leadingspace")), + // tc("TXT leading ws", txt("foowsb", " leadingspace")), tc("TXT trailing ws", txt("foows1", "trailingws ")), // Vultr syntax-checks TXT records with SPF contents. tc("Create a TXT/SPF", txt("foo", "v=spf1 ip4:99.99.99.99 -all")), // Nobody needs this and many APIs don't allow it. - //tc("Create TXT with frequently difficult characters", txt("fooex", `!^.*$@#%^&()([][{}{<>1000 corrections. See https://github.com/StackExchange/dnscontrol/issues/1440 //"CSCGLOBAL", // Doesn't page. Works fine. Due to the slow API we skip. @@ -1537,20 +1534,20 @@ func makeTests() []*TestGroup { // LOCation records. // No.47 testgroup("LOC", requires(providers.CanUseLOC), - //42 21 54 N 71 06 18 W -24m 30m + // 42 21 54 N 71 06 18 W -24m 30m tc("Single LOC record", loc("@", 42, 21, 54, "N", 71, 6, 18, "W", -24.05, 30, 0, 0)), - //42 21 54 N 71 06 18 W -24m 30m + // 42 21 54 N 71 06 18 W -24m 30m tc("Update single LOC record", loc("@", 42, 21, 54, "N", 71, 6, 18, "W", -24.06, 30, 10, 0)), - tc("Multiple LOC records-create a-d modify apex", //create a-d, modify @ - //42 21 54 N 71 06 18 W -24m 30m + tc("Multiple LOC records-create a-d modify apex", // create a-d, modify @ + // 42 21 54 N 71 06 18 W -24m 30m loc("@", 42, 21, 54, "N", 71, 6, 18, "W", -24, 30, 0, 0), - //42 21 43.952 N 71 5 6.344 W -24m 1m 200m + // 42 21 43.952 N 71 5 6.344 W -24m 1m 200m loc("a", 42, 21, 43.952, "N", 71, 5, 6.344, "W", -24.33, 1, 200, 10), - //52 14 05 N 00 08 50 E 10m + // 52 14 05 N 00 08 50 E 10m loc("b", 52, 14, 5, "N", 0, 8, 50, "E", 10.22, 0, 0, 0), - //32 7 19 S 116 2 25 E 10m + // 32 7 19 S 116 2 25 E 10m loc("c", 32, 7, 19, "S", 116, 2, 25, "E", 10, 0, 0, 0), - //42 21 28.764 N 71 00 51.617 W -44m 2000m + // 42 21 28.764 N 71 00 51.617 W -44m 2000m loc("d", 42, 21, 28.764, "N", 71, 0, 51.617, "W", -44, 2000, 0, 0), ), ), @@ -1590,7 +1587,7 @@ func makeTests() []*TestGroup { // SOA testgroup("SOA", requires(providers.CanUseSOA), - clear(), // Extra clear required or only the first run passes. + tcEmptyZone(), // Required or only the first run passes. tc("Create SOA record", soa("@", "kim.ns.cloudflare.com.", "dns.cloudflare.com.", 2037190000, 10000, 2400, 604800, 3600)), tc("Modify SOA ns ", soa("@", "mmm.ns.cloudflare.com.", "dns.cloudflare.com.", 2037190000, 10000, 2400, 604800, 3600)), tc("Modify SOA mbox ", soa("@", "mmm.ns.cloudflare.com.", "eee.cloudflare.com.", 2037190000, 10000, 2400, 604800, 3600)), @@ -1610,7 +1607,7 @@ func makeTests() []*TestGroup { tc("Change Priority", srv("_sip._tcp", 52, 6, 7, "foo.com."), srv("_sip._tcp", 15, 65, 75, "foo4.com.")), tc("Change Weight", srv("_sip._tcp", 52, 62, 7, "foo.com."), srv("_sip._tcp", 15, 65, 75, "foo4.com.")), tc("Change Port", srv("_sip._tcp", 52, 62, 72, "foo.com."), srv("_sip._tcp", 15, 65, 75, "foo4.com.")), - clear(), + tcEmptyZone(), tc("Null Target", srv("_sip._tcp", 15, 65, 75, ".")), ), @@ -1713,7 +1710,7 @@ func makeTests() []*TestGroup { ds("child", 63909, 3, 4, "EEC7FA02E6788DA889B2CE41D43D92F948AB126EDCF83B7037E73CE9531C8E7E45653ABBAA76C2D6E42F98316EDE599B"), ns("child", "ns101.cloudns.net."), ), - //tc("modify field 2", ds("child", 65535, 254, 4, "0123456789ABCDEF")), + // tc("modify field 2", ds("child", 65535, 254, 4, "0123456789ABCDEF")), tc("delete 1, create 1", ds("another-child", 35632, 13, 4, "F5F32ABCA6B01AA7A9963012F90B7C8523A1D946185A3AD70B67F3C9F18E7312FA9DD6AB2F7D8382F789213DB173D429"), ns("another-child", "ns101.cloudns.net."), @@ -1726,7 +1723,7 @@ func makeTests() []*TestGroup { ), // in CLouDNS we must delete DS Record before deleting NS record // should no longer be necessary, provider should handle order correctly - //tc("delete all DS", + // tc("delete all DS", // ns("another-child", "ns101.cloudns.net."), //), ), @@ -1938,12 +1935,12 @@ func makeTests() []*TestGroup { // Removed these for speed. They tested if order matters, // which it doesn't seem to. Re-add if needed. - clear(), + tcEmptyZone(), tc("multipleA", cfRedir("cnn.**current-domain-no-trailing**/*", "https://www.cnn.com/$1"), cfRedir("msnbc.**current-domain-no-trailing**/*", "https://msnbc.cnn.com/$1"), ), - clear(), + tcEmptyZone(), tc("multipleB", cfRedir("msnbc.**current-domain-no-trailing**/*", "https://msnbc.cnn.com/$1"), cfRedir("cnn.**current-domain-no-trailing**/*", "https://www.cnn.com/$1"), @@ -1958,7 +1955,7 @@ func makeTests() []*TestGroup { ), // NB(tlim): This test case used to fail but mysteriously started working. - clear(), + tcEmptyZone(), tc("multiple3", cfRedir("msnbc.**current-domain-no-trailing**/*", "https://msnbc.cnn.com/$1"), cfRedir("cnn.**current-domain-no-trailing**/*", "https://www.cnn.com/$1"), @@ -1966,16 +1963,16 @@ func makeTests() []*TestGroup { ), // Repeat the above tests using CF_TEMP_REDIR instead - clear(), + tcEmptyZone(), tc("tempredir", cfRedirTemp("cnn.**current-domain-no-trailing**/*", "https://www.cnn.com/$1")), tc("tempchange", cfRedirTemp("cnn.**current-domain-no-trailing**/*", "https://change.cnn.com/$1")), tc("tempchangelabel", cfRedirTemp("cable.**current-domain-no-trailing**/*", "https://change.cnn.com/$1")), - clear(), + tcEmptyZone(), tc("tempmultipleA", cfRedirTemp("cnn.**current-domain-no-trailing**/*", "https://www.cnn.com/$1"), cfRedirTemp("msnbc.**current-domain-no-trailing**/*", "https://msnbc.cnn.com/$1"), ), - clear(), + tcEmptyZone(), tc("tempmultipleB", cfRedirTemp("msnbc.**current-domain-no-trailing**/*", "https://msnbc.cnn.com/$1"), cfRedirTemp("cnn.**current-domain-no-trailing**/*", "https://www.cnn.com/$1"), @@ -2018,10 +2015,10 @@ func makeTests() []*TestGroup { testgroup("CF_PROXY A create", only("CLOUDFLAREAPI"), - CfProxyOff(), clear(), - CfProxyOn(), clear(), - CfProxyFull1(), clear(), - CfProxyFull2(), clear(), + CfProxyOff(), tcEmptyZone(), + CfProxyOn(), tcEmptyZone(), + CfProxyFull1(), tcEmptyZone(), + CfProxyFull2(), tcEmptyZone(), ), // These next testgroups attempt every possible transition between off, on, full1 and full2. @@ -2030,62 +2027,62 @@ func makeTests() []*TestGroup { testgroup("CF_PROXY A off to X", only("CLOUDFLAREAPI"), - //CF_PROXY_OFF(), CF_PROXY_OFF(), clear(), // redundant - CfProxyOff(), CfProxyOn(), clear(), - CfProxyOff(), CfProxyFull1(), clear(), - CfProxyOff(), CfProxyFull2(), clear(), + // CF_PROXY_OFF(), CF_PROXY_OFF(), tcEmptyZone(), // redundant + CfProxyOff(), CfProxyOn(), tcEmptyZone(), + CfProxyOff(), CfProxyFull1(), tcEmptyZone(), + CfProxyOff(), CfProxyFull2(), tcEmptyZone(), ), testgroup("CF_PROXY A on to X", only("CLOUDFLAREAPI"), - CfProxyOn(), CfProxyOff(), clear(), - //CF_PROXY_ON(), CF_PROXY_ON(), clear(), // redundant - //CF_PROXY_ON(), CF_PROXY_FULL1().ExpectNoChanges(), clear(), // Removed for speed - CfProxyOn(), CfProxyFull2(), clear(), + CfProxyOn(), CfProxyOff(), tcEmptyZone(), + // CF_PROXY_ON(), CF_PROXY_ON(), tcEmptyZone(), // redundant + // CF_PROXY_ON(), CF_PROXY_FULL1().ExpectNoChanges(), tcEmptyZone(), // Removed for speed + CfProxyOn(), CfProxyFull2(), tcEmptyZone(), ), testgroup("CF_PROXY A full1 to X", only("CLOUDFLAREAPI"), - CfProxyFull1(), CfProxyOff(), clear(), - //CF_PROXY_FULL1(), CF_PROXY_ON().ExpectNoChanges(), clear(), // Removed for speed - //CF_PROXY_FULL1(), CF_PROXY_FULL1(), clear(), // redundant - CfProxyFull1(), CfProxyFull2(), clear(), + CfProxyFull1(), CfProxyOff(), tcEmptyZone(), + // CF_PROXY_FULL1(), CF_PROXY_ON().ExpectNoChanges(), tcEmptyZone(), // Removed for speed + // CF_PROXY_FULL1(), tcEmptyZone(), // redundant + CfProxyFull1(), CfProxyFull2(), tcEmptyZone(), ), testgroup("CF_PROXY A full2 to X", only("CLOUDFLAREAPI"), - CfProxyFull2(), CfProxyOff(), clear(), - CfProxyFull2(), CfProxyOn(), clear(), - CfProxyFull2(), CfProxyFull1(), clear(), - //CF_PROXY_FULL2(), CF_PROXY_FULL2(), clear(), // redundant + CfProxyFull2(), CfProxyOff(), tcEmptyZone(), + CfProxyFull2(), CfProxyOn(), tcEmptyZone(), + CfProxyFull2(), CfProxyFull1(), tcEmptyZone(), + // CF_PROXY_FULL2(), CF_PROXY_FULL2(), tcEmptyZone(), // redundant ), testgroup("CF_PROXY CNAME create", only("CLOUDFLAREAPI"), - CfCProxyOff(), clear(), - CfCProxyOn(), clear(), - CfCProxyFull(), clear(), + CfCProxyOff(), tcEmptyZone(), + CfCProxyOn(), tcEmptyZone(), + CfCProxyFull(), tcEmptyZone(), ), testgroup("CF_PROXY CNAME off to X", only("CLOUDFLAREAPI"), - //CF_CPROXY_OFF(), CF_CPROXY_OFF(), clear(), // redundant - CfCProxyOff(), CfCProxyOn(), clear(), - CfCProxyOff(), CfCProxyFull(), clear(), + // CF_CPROXY_OFF(), CF_CPROXY_OFF(), tcEmptyZone(), // redundant + CfCProxyOff(), CfCProxyOn(), tcEmptyZone(), + CfCProxyOff(), CfCProxyFull(), tcEmptyZone(), ), testgroup("CF_PROXY CNAME on to X", only("CLOUDFLAREAPI"), - CfCProxyOn(), CfCProxyOff(), clear(), - //CF_CPROXY_ON(), CF_CPROXY_ON(), clear(), // redundant - //CF_CPROXY_ON(), CF_CPROXY_FULL().ExpectNoChanges(), clear(), // Removed for speed + CfCProxyOn(), CfCProxyOff(), tcEmptyZone(), + // CF_CPROXY_ON(), CF_CPROXY_ON(), tcEmptyZone(), // redundant + // CF_CPROXY_ON(), CF_CPROXY_FULL().ExpectNoChanges(), tcEmptyZone(), // Removed for speed ), testgroup("CF_PROXY CNAME full to X", only("CLOUDFLAREAPI"), - CfCProxyFull(), CfCProxyOff(), clear(), - //CF_CPROXY_FULL(), CF_CPROXY_ON().ExpectNoChanges(), clear(), // Removed for speed - //CF_CPROXY_FULL(), CF_CPROXY_FULL(), clear(), // redundant + CfCProxyFull(), CfCProxyOff(), tcEmptyZone(), + // CF_CPROXY_FULL(), CF_CPROXY_ON().ExpectNoChanges(), tcEmptyZone(), // Removed for speed + // CF_CPROXY_FULL(), tcEmptyZone(), // redundant ), testgroup("CF_WORKER_ROUTE", @@ -2095,7 +2092,7 @@ func makeTests() []*TestGroup { tc("simple", cfWorkerRoute("cnn.**current-domain-no-trailing**/*", "dnscontrol_integrationtest_cnn")), tc("changeScript", cfWorkerRoute("cnn.**current-domain-no-trailing**/*", "dnscontrol_integrationtest_msnbc")), tc("changePattern", cfWorkerRoute("cable.**current-domain-no-trailing**/*", "dnscontrol_integrationtest_msnbc")), - clear(), + tcEmptyZone(), tc("createMultiple", cfWorkerRoute("cnn.**current-domain-no-trailing**/*", "dnscontrol_integrationtest_cnn"), cfWorkerRoute("msnbc.**current-domain-no-trailing**/*", "dnscontrol_integrationtest_msnbc"), @@ -2137,9 +2134,9 @@ func makeTests() []*TestGroup { // NB(tlim): This ignores 1 record of a recordSet. This should // fail for diff2.ByRecordSet() providers if diff2 is not // implemented correctly. - //a("foo", "1.2.3.4"), - //a("foo", "2.3.4.5"), - //txt("foo", "simple"), + // a("foo", "1.2.3.4"), + // a("foo", "2.3.4.5"), + // txt("foo", "simple"), a("bar", "5.5.5.5"), cname("mail", "ghs.googlehosted.com."), ignore("foo", "", ""), @@ -2153,8 +2150,8 @@ func makeTests() []*TestGroup { ).ExpectNoChanges(), tc("ignore label,type", - //a("foo", "1.2.3.4"), - //a("foo", "2.3.4.5"), + // a("foo", "1.2.3.4"), + // a("foo", "2.3.4.5"), txt("foo", "simple"), a("bar", "5.5.5.5"), cname("mail", "ghs.googlehosted.com."), @@ -2169,7 +2166,7 @@ func makeTests() []*TestGroup { ).ExpectNoChanges(), tc("ignore label,type,target", - //a("foo", "1.2.3.4"), + // a("foo", "1.2.3.4"), a("foo", "2.3.4.5"), txt("foo", "simple"), a("bar", "5.5.5.5"), @@ -2185,10 +2182,10 @@ func makeTests() []*TestGroup { ).ExpectNoChanges(), tc("ignore type", - //a("foo", "1.2.3.4"), - //a("foo", "2.3.4.5"), + // a("foo", "1.2.3.4"), + // a("foo", "2.3.4.5"), txt("foo", "simple"), - //a("bar", "5.5.5.5"), + // a("bar", "5.5.5.5"), cname("mail", "ghs.googlehosted.com."), ignore("", "A", ""), ).ExpectNoChanges(), @@ -2202,7 +2199,7 @@ func makeTests() []*TestGroup { tc("ignore type,target", a("foo", "1.2.3.4"), - //a("foo", "2.3.4.5"), + // a("foo", "2.3.4.5"), txt("foo", "simple"), a("bar", "5.5.5.5"), cname("mail", "ghs.googlehosted.com."), @@ -2218,7 +2215,7 @@ func makeTests() []*TestGroup { tc("ignore target", a("foo", "1.2.3.4"), - //a("foo", "2.3.4.5"), + // a("foo", "2.3.4.5"), txt("foo", "simple"), a("bar", "5.5.5.5"), cname("mail", "ghs.googlehosted.com."), @@ -2234,10 +2231,10 @@ func makeTests() []*TestGroup { // Many types: tc("ignore manytypes", - //a("foo", "1.2.3.4"), - //a("foo", "2.3.4.5"), - //txt("foo", "simple"), - //a("bar", "5.5.5.5"), + // a("foo", "1.2.3.4"), + // a("foo", "2.3.4.5"), + // txt("foo", "simple"), + // a("bar", "5.5.5.5"), cname("mail", "ghs.googlehosted.com."), ignore("", "A,TXT", ""), ).ExpectNoChanges(), @@ -2255,7 +2252,7 @@ func makeTests() []*TestGroup { a("foo", "2.3.4.5"), txt("foo", "simple"), a("bar", "5.5.5.5"), - //cname("mail", "ghs.googlehosted.com."), + // cname("mail", "ghs.googlehosted.com."), ignore("", "CNAME", "*.googlehosted.com."), ).ExpectNoChanges(), tc("VERIFY PREVIOUS", @@ -2281,13 +2278,13 @@ func makeTests() []*TestGroup { // NB(tlim): This ignores 1 record of a recordSet. This should // fail for diff2.ByRecordSet() providers if diff2 is not // implemented correctly. - //a("@", "1.2.3.4"), - //a("@", "2.3.4.5"), - //txt("@", "simple"), + // a("@", "1.2.3.4"), + // a("@", "2.3.4.5"), + // txt("@", "simple"), a("bar", "5.5.5.5"), cname("mail", "ghs.googlehosted.com."), ignore("@", "", ""), - //ignore("", "NS", ""), + // ignore("", "NS", ""), // NB(tlim): .UnsafeIgnore is needed because the NS records // that providers injects into zones are treated like input // from dnsconfig.js. @@ -2301,8 +2298,8 @@ func makeTests() []*TestGroup { ).ExpectNoChanges(), tc("apex label,type", - //a("@", "1.2.3.4"), - //a("@", "2.3.4.5"), + // a("@", "1.2.3.4"), + // a("@", "2.3.4.5"), txt("@", "simple"), a("bar", "5.5.5.5"), cname("mail", "ghs.googlehosted.com."), @@ -2317,7 +2314,7 @@ func makeTests() []*TestGroup { ).ExpectNoChanges(), tc("apex label,type,target", - //a("@", "1.2.3.4"), + // a("@", "1.2.3.4"), a("@", "2.3.4.5"), txt("@", "simple"), a("bar", "5.5.5.5"), @@ -2336,10 +2333,10 @@ func makeTests() []*TestGroup { ).ExpectNoChanges(), tc("apex type", - //a("@", "1.2.3.4"), - //a("@", "2.3.4.5"), + // a("@", "1.2.3.4"), + // a("@", "2.3.4.5"), txt("@", "simple"), - //a("bar", "5.5.5.5"), + // a("bar", "5.5.5.5"), cname("mail", "ghs.googlehosted.com."), ignore("", "A", ""), ).ExpectNoChanges(), @@ -2353,7 +2350,7 @@ func makeTests() []*TestGroup { tc("apex type,target", a("@", "1.2.3.4"), - //a("@", "2.3.4.5"), + // a("@", "2.3.4.5"), txt("@", "simple"), a("bar", "5.5.5.5"), cname("mail", "ghs.googlehosted.com."), @@ -2369,7 +2366,7 @@ func makeTests() []*TestGroup { tc("apex target", a("@", "1.2.3.4"), - //a("@", "2.3.4.5"), + // a("@", "2.3.4.5"), txt("@", "simple"), a("bar", "5.5.5.5"), cname("mail", "ghs.googlehosted.com."), @@ -2385,10 +2382,10 @@ func makeTests() []*TestGroup { // Many types: tc("apex manytypes", - //a("@", "1.2.3.4"), - //a("@", "2.3.4.5"), - //txt("@", "simple"), - //a("bar", "5.5.5.5"), + // a("@", "1.2.3.4"), + // a("@", "2.3.4.5"), + // txt("@", "simple"), + // a("bar", "5.5.5.5"), cname("mail", "ghs.googlehosted.com."), ignore("", "A,TXT", ""), ).ExpectNoChanges(), @@ -2452,9 +2449,9 @@ func makeTests() []*TestGroup { ), tc("ignore label=foo.*", - //a("foo.bat", "1.2.3.4"), - //a("foo.bat", "2.3.4.5"), - //txt("foo.bat", "simple"), + // a("foo.bat", "1.2.3.4"), + // a("foo.bat", "2.3.4.5"), + // txt("foo.bat", "simple"), a("bar.bat", "5.5.5.5"), cname("mail.bat", "ghs.googlehosted.com."), ignore("foo.*", "", ""), @@ -2468,10 +2465,10 @@ func makeTests() []*TestGroup { ).ExpectNoChanges(), tc("ignore label=foo.bat,type", - //a("foo.bat", "1.2.3.4"), - //a("foo.bat", "2.3.4.5"), + // a("foo.bat", "1.2.3.4"), + // a("foo.bat", "2.3.4.5"), txt("foo.bat", "simple"), - //a("bar.bat", "5.5.5.5"), + // a("bar.bat", "5.5.5.5"), cname("mail.bat", "ghs.googlehosted.com."), ignore("*.bat", "A", ""), ).ExpectNoChanges(), @@ -2488,7 +2485,7 @@ func makeTests() []*TestGroup { a("foo.bat", "2.3.4.5"), txt("foo.bat", "simple"), a("bar.bat", "5.5.5.5"), - //cname("mail.bat", "ghs.googlehosted.com."), + // cname("mail.bat", "ghs.googlehosted.com."), ignore("", "", "*.googlehosted.com."), ).ExpectNoChanges(), tc("VERIFY PREVIOUS", @@ -2521,8 +2518,8 @@ func makeTests() []*TestGroup { aaaa("foo", "2003:dd:d7ff::fe71:aaaa"), mx("foo", 10, "aspmx.l.google.com."), mx("foo", 20, "alt1.aspmx.l.google.com."), - //a("zzz", "3.3.3.3"), - //a("zzz", "4.4.4.4"), + // a("zzz", "3.3.3.3"), + // a("zzz", "4.4.4.4"), aaaa("zzz", "2003:dd:d7ff::fe71:cccc"), ), tc("VERIFY PREVIOUS", @@ -2542,8 +2539,8 @@ func makeTests() []*TestGroup { a("foo", "1.1.1.1"), a("foo", "12.12.12.12"), // CHANGE aaaa("foo", "2003:dd:d7ff::fe71:aaaa"), - //mx("foo", 10, "aspmx.l.google.com."), - //mx("foo", 20, "alt1.aspmx.l.google.com"), + // mx("foo", 10, "aspmx.l.google.com."), + // mx("foo", 20, "alt1.aspmx.l.google.com"), a("zzz", "3.3.3.3"), a("zzz", "4.4.4.4"), aaaa("zzz", "2003:dd:d7ff::fe71:cccc"), @@ -2564,9 +2561,9 @@ func makeTests() []*TestGroup { ignore("foo", "MX,AAAA", ""), a("foo", "1.1.1.1"), a("foo", "13.13.13.13"), // CHANGE - //aaaa("foo", "2003:dd:d7ff::fe71:aaaa"), - //mx("foo", 10, "aspmx.l.google.com."), - //mx("foo", 20, "alt1.aspmx.l.google.com"), + // aaaa("foo", "2003:dd:d7ff::fe71:aaaa"), + // mx("foo", 10, "aspmx.l.google.com."), + // mx("foo", 20, "alt1.aspmx.l.google.com"), a("zzz", "3.3.3.3"), a("zzz", "4.4.4.4"), aaaa("zzz", "2003:dd:d7ff::fe71:cccc"), @@ -2585,7 +2582,7 @@ func makeTests() []*TestGroup { // Change within a (name+type+data) ("ByRecord") tc("IGNORE change ByRecord", ignore("foo", "A", "1.1.1.1"), - //a("foo", "1.1.1.1"), + // a("foo", "1.1.1.1"), a("foo", "14.14.14.14"), aaaa("foo", "2003:dd:d7ff::fe71:aaaa"), mx("foo", 10, "aspmx.l.google.com."), @@ -2658,7 +2655,7 @@ func makeTests() []*TestGroup { a("testdefined", "9.9.9.9"), ), tc("ignore", - //a("testignore", "8.8.8.8"), + // a("testignore", "8.8.8.8"), a("testdefined", "9.9.9.9"), ignore("testignore", "", ""), ).ExpectNoChanges(), @@ -2677,7 +2674,7 @@ func makeTests() []*TestGroup { ).ExpectNoChanges(), tc("ignore with change", - //a("testignore", "8.8.8.8"), + // a("testignore", "8.8.8.8"), a("testdefined", "2.2.2.2"), ignore("testignore", "", ""), ), diff --git a/models/dns.go b/models/dns.go index a2ed16f62..524a3e007 100644 --- a/models/dns.go +++ b/models/dns.go @@ -2,6 +2,7 @@ package models import ( "encoding/json" + "errors" "fmt" "strings" ) @@ -67,7 +68,7 @@ func ToNameservers(nss []string) ([]*Nameserver, error) { nservers := []*Nameserver{} for _, ns := range nss { if strings.HasSuffix(ns, ".") { - return nil, fmt.Errorf("provider code leaves trailing dot on nameserver") + return nil, errors.New("provider code leaves trailing dot on nameserver") // If you see this error, maybe the provider should call // ToNameserversStripTD instead. } diff --git a/models/domain.go b/models/domain.go index 3054a443d..e583fd614 100644 --- a/models/domain.go +++ b/models/domain.go @@ -36,7 +36,7 @@ type DomainConfig struct { UnmanagedUnsafe bool `json:"unmanaged_disable_safety_check,omitempty"` // DISABLE_IGNORE_SAFETY_CHECK AutoDNSSEC string `json:"auto_dnssec,omitempty"` // "", "on", "off" - //DNSSEC bool `json:"dnssec,omitempty"` + // DNSSEC bool `json:"dnssec,omitempty"` // These fields contain instantiated provider instances once everything is linked up. // This linking is in two phases: @@ -130,9 +130,13 @@ func (dc *DomainConfig) Punycode() error { if err != nil { return err } - rec.SetTarget(t) + if err := rec.SetTarget(t); err != nil { + return err + } case "CLOUDFLAREAPI_SINGLE_REDIRECT", "CF_REDIRECT", "CF_TEMP_REDIRECT", "CF_WORKER_ROUTE": - rec.SetTarget(rec.GetTargetField()) + if err := rec.SetTarget(rec.GetTargetField()); err != nil { + return err + } case "A", "AAAA", "CAA", "DHCID", "DNSKEY", "DS", "HTTPS", "LOC", "NAPTR", "SOA", "SSHFP", "SVCB", "TXT", "TLSA", "AZURE_ALIAS": // Nothing to do. default: diff --git a/models/quotes_test.go b/models/quotes_test.go index 595bdb124..2cf214552 100644 --- a/models/quotes_test.go +++ b/models/quotes_test.go @@ -65,23 +65,37 @@ func TestParseQuotedTxt(t *testing.T) { {`"aaa" "bbb"`, []string{`aaa`, `bbb`}}, {`"a"a" "bbb"`, []string{`a"a`, `bbb`}}, // Seen in live traffic: - {"\"BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB\"", - []string{r("B", 254)}}, - {"\"CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC\"", - []string{r("C", 255)}}, - {"\"DDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDD\" \"D\"", - []string{r("D", 255), "D"}}, - {"\"EEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE\" \"EEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE\"", - []string{r("E", 255), r("E", 255)}}, - {"\"FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF\" \"FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF\" \"F\"", - []string{r("F", 255), r("F", 255), "F"}}, - {"\"GGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGG\" \"GGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGG\" \"GGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGG\"", - []string{r("G", 255), r("G", 255), r("G", 255)}}, - {"\"HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH\" \"HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH\" \"HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH\" \"H\"", - []string{r("H", 255), r("H", 255), r("H", 255), "H"}}, + { + "\"BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB\"", + []string{r("B", 254)}, + }, + { + "\"CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC\"", + []string{r("C", 255)}, + }, + { + "\"DDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDD\" \"D\"", + []string{r("D", 255), "D"}, + }, + { + "\"EEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE\" \"EEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE\"", + []string{r("E", 255), r("E", 255)}, + }, + { + "\"FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF\" \"FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF\" \"F\"", + []string{r("F", 255), r("F", 255), "F"}, + }, + { + "\"GGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGG\" \"GGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGG\" \"GGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGG\"", + []string{r("G", 255), r("G", 255), r("G", 255)}, + }, + { + "\"HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH\" \"HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH\" \"HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH\" \"H\"", + []string{r("H", 255), r("H", 255), r("H", 255), "H"}, + }, {"\"quo'te\"", []string{`quo'te`}}, {"\"blah`blah\"", []string{"blah`blah"}}, - //{"\"quo\\\"te\"", []string{`quo"te`}}, + // {"\"quo\\\"te\"", []string{`quo"te`}}, //{"\"q\\\"uo\\\"te\"", []string{`q"uo"te`}}, //{"\"backs\\\\lash\"", []string{`back\slash`}}, } @@ -111,7 +125,7 @@ func TestParseQuotedFields(t *testing.T) { } for i, test := range tests { ls, _ := ParseQuotedFields(test.d1) - //fmt.Printf("%v: expected TxtStrings:\nWANT: %v\n GOT: %v\n", i, test.e1, ls) + // fmt.Printf("%v: expected TxtStrings:\nWANT: %v\n GOT: %v\n", i, test.e1, ls) if len(ls) != len(test.e1) { t.Errorf("%v: expected TxtStrings=(%v) got (%v)", i, test.e1, ls) } diff --git a/models/record.go b/models/record.go index d83a11d7d..3d977b925 100644 --- a/models/record.go +++ b/models/record.go @@ -253,9 +253,13 @@ func (rc *RecordConfig) UnmarshalJSON(b []byte) error { } // Copy the exported fields. - copier.CopyWithOption(&rc, &recj, copier.Option{IgnoreEmpty: true, DeepCopy: true}) + if err := copier.CopyWithOption(&rc, &recj, copier.Option{IgnoreEmpty: true, DeepCopy: true}); err != nil { + return err + } // Set each unexported field. - rc.SetTarget(recj.Target) + if err := rc.SetTarget(recj.Target); err != nil { + return err + } // Some sanity checks: if recj.Type != rc.Type { @@ -288,7 +292,6 @@ func (rc *RecordConfig) Copy() (*RecordConfig, error) { // short must not have a training dot: That would mean you have a FQDN, and // shouldn't be using SetLabel(). Maybe SetLabelFromFQDN()? func (rc *RecordConfig) SetLabel(short, origin string) { - // Assertions that make sure the function is being used correctly: if strings.HasSuffix(origin, ".") { panic(fmt.Errorf("origin (%s) is not supposed to end with a dot", origin)) @@ -317,7 +320,6 @@ func (rc *RecordConfig) SetLabel(short, origin string) { // fqdn may have a trailing "." but it is not required. // origin may not have a trailing dot. func (rc *RecordConfig) SetLabelFromFQDN(fqdn, origin string) { - // Assertions that make sure the function is being used correctly: if strings.HasSuffix(origin, ".") { panic(fmt.Errorf("origin (%s) is not supposed to end with a dot", origin)) @@ -360,9 +362,9 @@ func (rc *RecordConfig) ToComparableNoTTL() string { return fmt.Sprintf("%s %v %d %d %d %d", rc.target, rc.SoaMbox, rc.SoaRefresh, rc.SoaRetry, rc.SoaExpire, rc.SoaMinttl) // SoaSerial is not included because it isn't used in comparisons. case "TXT": - //fmt.Fprintf(os.Stdout, "DEBUG: ToComNoTTL raw txts=%s q=%q\n", rc.target, rc.target) + // fmt.Fprintf(os.Stdout, "DEBUG: ToComNoTTL raw txts=%s q=%q\n", rc.target, rc.target) r := txtutil.EncodeQuoted(rc.target) - //fmt.Fprintf(os.Stdout, "DEBUG: ToComNoTTL cmp txts=%s q=%q\n", r, r) + // fmt.Fprintf(os.Stdout, "DEBUG: ToComNoTTL cmp txts=%s q=%q\n", r, r) return r case "UNKNOWN": return fmt.Sprintf("rtype=%s rdata=%s", rc.UnknownTypeName, rc.target) @@ -372,7 +374,6 @@ func (rc *RecordConfig) ToComparableNoTTL() string { // ToRR converts a RecordConfig to a dns.RR. func (rc *RecordConfig) ToRR() dns.RR { - // Don't call this on fake types. rdtype, ok := dns.StringToType[rc.Type] if !ok { @@ -486,7 +487,6 @@ func (rc *RecordConfig) ToRR() dns.RR { // GetDependencies returns the FQDNs on which this record dependents func (rc *RecordConfig) GetDependencies() []string { - switch rc.Type { // #rtype_variations case "NS", "SRV", "CNAME", "DNAME", "MX", "ALIAS", "AZURE_ALIAS", "R53_ALIAS": diff --git a/models/record_test.go b/models/record_test.go index e654bd33a..3a324013d 100644 --- a/models/record_test.go +++ b/models/record_test.go @@ -24,7 +24,7 @@ func TestHasRecordTypeName(t *testing.T) { } func TestKey(t *testing.T) { - var tests = []struct { + tests := []struct { rc RecordConfig expected RecordKey }{ @@ -136,7 +136,7 @@ func TestRecordConfig_Copy(t *testing.T) { TlsaMatchingType: 3, R53Alias: map[string]string{"a": "eh", "b": "bee"}, AzureAlias: map[string]string{"az": "az", "ure": "your"}, - //Original interface{}, + // Original interface{}, }, want: &RecordConfig{ Type: "type", @@ -174,7 +174,7 @@ func TestRecordConfig_Copy(t *testing.T) { TlsaMatchingType: 3, R53Alias: map[string]string{"a": "eh", "b": "bee"}, AzureAlias: map[string]string{"az": "az", "ure": "your"}, - //Original interface{}, + // Original interface{}, }, }, } diff --git a/models/recorddb.go b/models/recorddb.go index 72cc350ae..95d8e6828 100644 --- a/models/recorddb.go +++ b/models/recorddb.go @@ -16,7 +16,7 @@ func NewRecordDBFromRecords(recs Records, zone string) *RecordDB { for _, rec := range recs { result.labelAndTypeMap[rec.Key()] = struct{}{} } - //fmt.Printf("DEBUG: BUILDING RecordDB: DONE!\n") + // fmt.Printf("DEBUG: BUILDING RecordDB: DONE!\n") return result } diff --git a/models/t_caa.go b/models/t_caa.go index 9086da534..b3743e68f 100644 --- a/models/t_caa.go +++ b/models/t_caa.go @@ -9,7 +9,9 @@ import ( func (rc *RecordConfig) SetTargetCAA(flag uint8, tag string, target string) error { rc.CaaTag = tag rc.CaaFlag = flag - rc.SetTarget(target) + if err := rc.SetTarget(target); err != nil { + return err + } if rc.Type == "" { rc.Type = "CAA" } diff --git a/models/t_loc.go b/models/t_loc.go index 4a4ad639a..a8f1a7596 100644 --- a/models/t_loc.go +++ b/models/t_loc.go @@ -31,8 +31,8 @@ func (rc *RecordConfig) SetTargetLOC(ver uint8, lat uint32, lon uint32, alt uint // for further processing to the LOC native 7 input binary format: // LocVersion (0), LocLatitude, LocLongitude, LocAltitude, LocSize, LocVertPre, LocHorizPre func (rc *RecordConfig) SetLOCParams(d1 uint8, m1 uint8, s1 float32, ns string, - d2 uint8, m2 uint8, s2 float32, ew string, al float32, sz float32, hp float32, vp float32) error { - + d2 uint8, m2 uint8, s2 float32, ew string, al float32, sz float32, hp float32, vp float32, +) error { err := rc.calculateLOCFields(d1, m1, s1, ns, d2, m2, s2, ew, al, sz, hp, vp) return err @@ -90,14 +90,13 @@ func (rc *RecordConfig) extractLOCFieldsFromStringInput(input string) error { } // fmt.Printf("\ngot: %d %d %g %s %d %d %g %s %0.2fm %0.2fm %0.2fm %0.2fm \n", d1, m1, s1, ns, d2, m2, s2, ew, al, sz, hp, vp) - rc.calculateLOCFields(d1, m1, s1, ns, d2, m2, s2, ew, al, sz, hp, vp) - - return nil + return rc.calculateLOCFields(d1, m1, s1, ns, d2, m2, s2, ew, al, sz, hp, vp) } // calculateLOCFields converts from 12 user inputs to the LOC 7 binary fields func (rc *RecordConfig) calculateLOCFields(d1 uint8, m1 uint8, s1 float32, ns string, - d2 uint8, m2 uint8, s2 float32, ew string, al float32, sz float32, hp float32, vp float32) error { + d2 uint8, m2 uint8, s2 float32, ew string, al float32, sz float32, hp float32, vp float32, +) error { // Crazy hairy shit happens here. // We already got the useful "string" version earlier. ¯\_(ツ)_/¯ code golf... const LOCEquator uint64 = 0x80000000 // 1 << 31 // RFC 1876, Section 2. diff --git a/models/t_mx.go b/models/t_mx.go index eabc85a81..174d98cf7 100644 --- a/models/t_mx.go +++ b/models/t_mx.go @@ -9,7 +9,9 @@ import ( // SetTargetMX sets the MX fields. func (rc *RecordConfig) SetTargetMX(pref uint16, target string) error { rc.MxPreference = pref - rc.SetTarget(target) + if err := rc.SetTarget(target); err != nil { + return err + } if rc.Type == "" { rc.Type = "MX" } diff --git a/models/t_naptr.go b/models/t_naptr.go index 24517dc62..ed1a21b75 100644 --- a/models/t_naptr.go +++ b/models/t_naptr.go @@ -16,7 +16,9 @@ func (rc *RecordConfig) SetTargetNAPTR(order uint16, preference uint16, flags st rc.NaptrFlags = flags rc.NaptrService = service rc.NaptrRegexp = regexp - rc.SetTarget(target) + if err := rc.SetTarget(target); err != nil { + return err + } if rc.Type == "" { rc.Type = "NAPTR" diff --git a/models/t_parse.go b/models/t_parse.go index e224f8c60..fbbc95196 100644 --- a/models/t_parse.go +++ b/models/t_parse.go @@ -110,7 +110,7 @@ func (rc *RecordConfig) PopulateFromStringFunc(rtype, contents, origin string, t case "TLSA": return rc.SetTargetTLSAString(contents) default: - //return fmt.Errorf("unknown rtype (%s) when parsing (%s) domain=(%s)", rtype, contents, origin) + // return fmt.Errorf("unknown rtype (%s) when parsing (%s) domain=(%s)", rtype, contents, origin) return MakeUnknown(rc, rtype, contents, origin) } } diff --git a/models/t_soa.go b/models/t_soa.go index d095fc580..053cad4e5 100644 --- a/models/t_soa.go +++ b/models/t_soa.go @@ -19,7 +19,10 @@ work that providers do. // SetTargetSOA sets the SOA fields. func (rc *RecordConfig) SetTargetSOA(ns, mbox string, serial, refresh, retry, expire, minttl uint32) error { - rc.SetTarget(ns) // The NS field is stored as the .Target + // The NS field is stored as the .Target + if err := rc.SetTarget(ns); err != nil { + return err + } rc.SoaMbox = mbox rc.SoaSerial = serial rc.SoaRefresh = refresh @@ -39,7 +42,6 @@ func (rc *RecordConfig) SetTargetSOA(ns, mbox string, serial, refresh, retry, ex // SetTargetSOAStrings is like SetTargetSOA but accepts strings. func (rc *RecordConfig) SetTargetSOAStrings(ns, mbox, serial, refresh, retry, expire, minttl string) error { - u32serial, err := strconv.ParseUint(serial, 10, 32) if err != nil { return fmt.Errorf("SOA serial '%v' is invalid: %w", serial, err) diff --git a/models/t_srv.go b/models/t_srv.go index 6672b7f65..f335e772c 100644 --- a/models/t_srv.go +++ b/models/t_srv.go @@ -11,7 +11,9 @@ func (rc *RecordConfig) SetTargetSRV(priority, weight, port uint16, target strin rc.SrvPriority = priority rc.SrvWeight = weight rc.SrvPort = port - rc.SetTarget(target) + if err := rc.SetTarget(target); err != nil { + return err + } if rc.Type == "" { rc.Type = "SRV" } diff --git a/models/t_sshfp.go b/models/t_sshfp.go index 8f046c6ba..3331814c7 100644 --- a/models/t_sshfp.go +++ b/models/t_sshfp.go @@ -10,7 +10,9 @@ import ( func (rc *RecordConfig) SetTargetSSHFP(algorithm uint8, fingerprint uint8, target string) error { rc.SshfpAlgorithm = algorithm rc.SshfpFingerprint = fingerprint - rc.SetTarget(target) + if err := rc.SetTarget(target); err != nil { + return err + } if rc.Type == "" { rc.Type = "SSHFP" } diff --git a/models/t_svcb.go b/models/t_svcb.go index fd8b82cbb..ba29d9ce7 100644 --- a/models/t_svcb.go +++ b/models/t_svcb.go @@ -10,7 +10,9 @@ import ( // SetTargetSVCB sets the SVCB fields. func (rc *RecordConfig) SetTargetSVCB(priority uint16, target string, params []dns.SVCBKeyValue) error { rc.SvcPriority = priority - rc.SetTarget(target) + if err := rc.SetTarget(target); err != nil { + return err + } paramsStr := []string{} for _, kv := range params { paramsStr = append(paramsStr, fmt.Sprintf("%s=%s", kv.Key(), kv.String())) @@ -32,7 +34,7 @@ func (rc *RecordConfig) SetTargetSVCBString(origin, contents string) error { } record, err := dns.NewRR(fmt.Sprintf("%s. %s %s", origin, rc.Type, contents)) if err != nil { - return fmt.Errorf("could not parse SVCB record: %s", err) + return fmt.Errorf("could not parse SVCB record: %w", err) } switch r := record.(type) { case *dns.HTTPS: diff --git a/models/t_tlsa.go b/models/t_tlsa.go index 90ef6114d..eaf38ae65 100644 --- a/models/t_tlsa.go +++ b/models/t_tlsa.go @@ -11,7 +11,9 @@ func (rc *RecordConfig) SetTargetTLSA(usage, selector, matchingtype uint8, targe rc.TlsaUsage = usage rc.TlsaSelector = selector rc.TlsaMatchingType = matchingtype - rc.SetTarget(target) + if err := rc.SetTarget(target); err != nil { + return err + } if rc.Type == "" { rc.Type = "TLSA" } diff --git a/models/t_txt.go b/models/t_txt.go index c8937121e..53796a9b1 100644 --- a/models/t_txt.go +++ b/models/t_txt.go @@ -17,7 +17,7 @@ represented by the provider, which could be a single string, a series of smaller strings, or a single string that is quoted/escaped. This created tons of edge-cases and other distractions. -If a provider doesn't support certain charactors in a TXT record, use +If a provider doesn't support certain characters in a TXT record, use the providers/$PROVIDER/auditrecords.go file to indicate this. DNSControl uses this information to warn users of unsupporrted input, and to skip related integration tests. @@ -87,7 +87,7 @@ func splitChunks(buf string, lim int) []string { chunks = append(chunks, chunk) } if len(buf) > 0 { - chunks = append(chunks, buf[:]) + chunks = append(chunks, buf) } return chunks } diff --git a/models/target.go b/models/target.go index 62fbedc17..b298a1028 100644 --- a/models/target.go +++ b/models/target.go @@ -45,7 +45,6 @@ func (rc *RecordConfig) GetTargetCombinedFunc(encodeFn func(s string) string) st // WARNING: How TXT records are handled is buggy but we can't change it because // code depends on the bugs. Use Get GetTargetCombinedFunc() instead. func (rc *RecordConfig) GetTargetCombined() string { - // Pseudo records: if _, ok := dns.StringToType[rc.Type]; !ok { switch rc.Type { // #rtype_variations @@ -82,7 +81,7 @@ func (rc *RecordConfig) zoneFileQuoted() string { // TODO(tlim): Request the dns project add a function that returns // the string without the header. if rc.Type == "NAPTR" && rc.GetTargetField() == "" { - rc.SetTarget(".") + rc.MustSetTarget(".") } rr := rc.ToRR() header := rr.Header().String() @@ -112,7 +111,7 @@ func (rc *RecordConfig) GetTargetDebug() string { case "A", "AAAA", "AKAMAICDN", "CNAME", "DHCID", "NS", "PTR", "TXT": // Nothing special. case "AZURE_ALIAS": - content += fmt.Sprintf(" type=%s", rc.AzureAlias["type"]) + content += " type=" + rc.AzureAlias["type"] case "CAA": content += fmt.Sprintf(" caatag=%s caaflag=%d", rc.CaaTag, rc.CaaFlag) case "DS": @@ -153,9 +152,16 @@ func (rc *RecordConfig) SetTarget(target string) error { return nil } +// MustSetTarget is like SetTarget, but panics if an error occurs. +// It should only be used in _test.go files and in the init() function. +func (rc *RecordConfig) MustSetTarget(target string) { + if err := rc.SetTarget(target); err != nil { + panic(err) + } +} + // SetTargetIP sets the target to an IP, verifying this is an appropriate rtype. func (rc *RecordConfig) SetTargetIP(ip net.IP) error { // TODO(tlim): Verify the rtype is appropriate for an IP. - rc.SetTarget(ip.String()) - return nil + return rc.SetTarget(ip.String()) } diff --git a/pkg/acme/acme.go b/pkg/acme/acme.go index c2c4e6f76..782b1f22f 100644 --- a/pkg/acme/acme.go +++ b/pkg/acme/acme.go @@ -4,6 +4,7 @@ package acme import ( "crypto/x509" "encoding/pem" + "errors" "fmt" "io" "log" @@ -104,7 +105,7 @@ func (c *certManager) IssueOrRenewCert(cfg *CertConfig, renewUnder int, verbose if !verbose { acmelog.Logger = log.New(io.Discard, "", 0) } - defer c.finalCleanUp() + defer c.finalCleanUp() //nolint:errcheck log.Printf("Checking certificate [%s]", cfg.CertName) existing, err := c.storage.GetCertificate(cfg.CertName) @@ -114,7 +115,7 @@ func (c *certManager) IssueOrRenewCert(cfg *CertConfig, renewUnder int, verbose var client *lego.Client - var action = func() (*certificate.Resource, error) { + action := func() (*certificate.Resource, error) { return client.Certificate.Obtain(certificate.ObtainRequest{ Bundle: true, Domains: cfg.Names, @@ -133,7 +134,7 @@ func (c *certManager) IssueOrRenewCert(cfg *CertConfig, renewUnder int, verbose namesOK := dnsNamesEqual(cfg.Names, names) if daysLeft >= float64(renewUnder) && namesOK { log.Println("Nothing to do") - //nothing to do + // nothing to do return false, nil } if !namesOK { @@ -159,7 +160,7 @@ func (c *certManager) IssueOrRenewCert(cfg *CertConfig, renewUnder int, verbose } client.Challenge.Remove(challenge.HTTP01) client.Challenge.Remove(challenge.TLSALPN01) - client.Challenge.SetDNS01Provider(c, dns01.WrapPreCheck(c.preCheckDNS)) + client.Challenge.SetDNS01Provider(c, dns01.WrapPreCheck(c.preCheckDNS)) //nolint:errcheck certResource, err := action() if err != nil { @@ -176,7 +177,7 @@ func (c *certManager) IssueOrRenewCert(cfg *CertConfig, renewUnder int, verbose func getCertInfo(pemBytes []byte) (names []string, remaining float64, err error) { block, _ := pem.Decode(pemBytes) if block == nil { - return nil, 0, fmt.Errorf("invalid certificate PEM data") + return nil, 0, errors.New("invalid certificate PEM data") } cert, err := x509.ParseCertificate(block.Bytes) if err != nil { @@ -187,7 +188,7 @@ func getCertInfo(pemBytes []byte) (names []string, remaining float64, err error) // may be decommed eventually, and since there are no unit tests, // I'm not excited about making this change. // var daysLeft = float64(time.Until(cert.NotAfter)) / float64(time.Hour*24) - var daysLeft = float64(cert.NotAfter.Sub(time.Now())) / float64(time.Hour*24) + daysLeft := float64(time.Until(cert.NotAfter)) / float64(time.Hour*24) return cert.DNSNames, daysLeft, nil } @@ -225,24 +226,26 @@ func (c *certManager) Present(domain, token, keyAuth string) (e error) { nameservers.AddNSRecords(d) // make sure we have the latest config before we change anything. - // alternately, we could avoid a lot of this trouble if we really really trusted no-purge in all cases + // alternately, we could avoid a lot of this trouble if we really trusted no-purge in all cases if err := c.ensureNoPendingCorrections(d); err != nil { return err } - // copy domain and work from copy from now on. That way original config can be used to "restore" when we are all done. - copy, err := d.Copy() + // Copy domain and work from cpy from now on. That way original config can be used to "restore" when we are all done. + cpy, err := d.Copy() if err != nil { return err } c.originalDomains = append(c.originalDomains, d) - c.domains[name] = copy - d = copy + c.domains[name] = cpy + d = cpy } fqdn, val := dns01.GetRecord(domain, keyAuth) txt := &models.RecordConfig{Type: "TXT"} - txt.SetTargetTXT(val) + if err := txt.SetTargetTXT(val); err != nil { + return err + } txt.SetLabelFromFQDN(fqdn, d.Name) d.Records = append(d.Records, txt) return c.getAndRunCorrections(d) diff --git a/pkg/acme/directoryStorage.go b/pkg/acme/directoryStorage.go index ef6471820..cddfed974 100644 --- a/pkg/acme/directoryStorage.go +++ b/pkg/acme/directoryStorage.go @@ -4,7 +4,7 @@ import ( "crypto/x509" "encoding/json" "encoding/pem" - "fmt" + "errors" "os" "path/filepath" @@ -18,6 +18,7 @@ type directoryStorage string func (d directoryStorage) certFile(name, ext string) string { return filepath.Join(d.certDir(name), name+"."+ext) } + func (d directoryStorage) certDir(name string) string { return filepath.Join(string(d), "certificates", name) } @@ -29,12 +30,15 @@ func (d directoryStorage) accountDirectory(acmeHost string) string { func (d directoryStorage) accountFile(acmeHost string) string { return filepath.Join(d.accountDirectory(acmeHost), "account.json") } + func (d directoryStorage) accountKeyFile(acmeHost string) string { return filepath.Join(d.accountDirectory(acmeHost), "account.key") } -const perms os.FileMode = 0600 -const dirPerms os.FileMode = 0700 +const ( + perms os.FileMode = 0o600 + dirPerms os.FileMode = 0o700 +) func (d directoryStorage) GetCertificate(name string) (*certificate.Resource, error) { f, err := os.Open(d.certFile(name, "json")) @@ -106,7 +110,7 @@ func (d directoryStorage) GetAccount(acmeHost string) (*Account, error) { } keyBlock, _ := pem.Decode(keyBytes) if keyBlock == nil { - return nil, fmt.Errorf("error decoding account private key") + return nil, errors.New("error decoding account private key") } acct.key, err = x509.ParseECPrivateKey(keyBlock.Bytes) if err != nil { diff --git a/pkg/acme/vaultStorage.go b/pkg/acme/vaultStorage.go index aa01b5d9b..7efca7810 100644 --- a/pkg/acme/vaultStorage.go +++ b/pkg/acme/vaultStorage.go @@ -5,6 +5,7 @@ import ( "crypto/x509" "encoding/json" "encoding/pem" + "errors" "fmt" "strings" @@ -123,7 +124,7 @@ func (v *vaultStorage) GetAccount(acmeHost string) (*Account, error) { if dat, err = v.getString("tls.key", secret.Data, path); err != nil { return nil, err } else if block, _ = pem.Decode(dat); block == nil { - return nil, fmt.Errorf("error decoding account private key") + return nil, errors.New("error decoding account private key") } else if key, err = x509.ParseECPrivateKey(block.Bytes); err != nil { return nil, err } diff --git a/pkg/credsfile/providerConfig.go b/pkg/credsfile/providerConfig.go index 34c751065..c34391947 100644 --- a/pkg/credsfile/providerConfig.go +++ b/pkg/credsfile/providerConfig.go @@ -21,7 +21,7 @@ import ( // LoadProviderConfigs will open or execute the specified file name, and parse its contents. It will replace environment variables it finds if any value matches $[A-Za-z_-0-9]+ func LoadProviderConfigs(fname string) (map[string]map[string]string, error) { - var results = map[string]map[string]string{} + results := map[string]map[string]string{} var dat []byte var err error @@ -45,7 +45,7 @@ func LoadProviderConfigs(fname string) (map[string]map[string]string, error) { r := JsonConfigReader.New(strings.NewReader(s)) err = json.NewDecoder(r).Decode(&results) if err != nil { - return nil, fmt.Errorf("failed parsing provider credentials file %v: %v", fname, err) + return nil, fmt.Errorf("failed parsing provider credentials file %v: %w", fname, err) } if err = replaceEnvVars(results); err != nil { return nil, err @@ -66,7 +66,7 @@ func LoadProviderConfigs(fname string) (map[string]map[string]string, error) { func isExecutable(filename string) bool { if stat, statErr := os.Stat(filename); statErr == nil { - if mode := stat.Mode(); mode&0111 == 0111 { + if mode := stat.Mode(); mode&0o111 == 0o111 { return true } } @@ -81,7 +81,7 @@ func readCredsFile(filename string) ([]byte, error) { fmt.Printf("INFO: Config file %q does not exist. Skipping.\n", filename) return []byte{}, nil } - return nil, fmt.Errorf("failed reading provider credentials file %v: %v", filename, err) + return nil, fmt.Errorf("failed reading provider credentials file %v: %w", filename, err) } return dat, nil } diff --git a/pkg/diff/diff.go b/pkg/diff/diff.go index d572afcd3..110dec927 100644 --- a/pkg/diff/diff.go +++ b/pkg/diff/diff.go @@ -26,8 +26,7 @@ type Differ interface { ChangedGroups(existing []*models.RecordConfig) (map[models.RecordKey][]string, []string, int, error) } -type differ struct { -} +type differ struct{} // get normalized content for record. target, ttl, mxprio, and specified metadata func (d *differ) content(r *models.RecordConfig) string { diff --git a/pkg/diff2/analyze.go b/pkg/diff2/analyze.go index 6201db7c4..2904e91dd 100644 --- a/pkg/diff2/analyze.go +++ b/pkg/diff2/analyze.go @@ -89,7 +89,6 @@ func analyzeByLabel(cc *CompareConfig) (ChangeList, int) { } func analyzeByRecord(cc *CompareConfig) (ChangeList, int) { - var instructions ChangeList var actualChangeCount int // For each label, for each type at that label, see if there are any changes. @@ -136,7 +135,6 @@ func mkDelete(l string, t string, msgs []string, oldRecs models.Records) Change } func removeCommon(existing, desired []targetConfig) ([]targetConfig, []targetConfig) { - // Sort by comparableFull. sort.Slice(existing, func(i, j int) bool { return existing[i].comparableFull < existing[j].comparableFull }) sort.Slice(desired, func(i, j int) bool { return desired[i].comparableFull < desired[j].comparableFull }) @@ -159,7 +157,6 @@ func removeCommon(existing, desired []targetConfig) ([]targetConfig, []targetCon // findTTLChanges finds the records that ONLY change their TTL. For those, generate a Change. // Remove such items from the list. func findTTLChanges(existing, desired []targetConfig) ([]targetConfig, []targetConfig, ChangeList) { - if (len(existing) == 0) || (len(desired) == 0) { return existing, desired, nil } @@ -251,8 +248,7 @@ func humanDiff(a, b targetConfig) string { } func diffTargets(existing, desired []targetConfig) ChangeList { - - //fmt.Printf("DEBUG: diffTargets(\nexisting=%v\ndesired=%v\nDEBUG.\n", existing, desired) + // fmt.Printf("DEBUG: diffTargets(\nexisting=%v\ndesired=%v\nDEBUG.\n", existing, desired) // Nothing to do? if len(existing) == 0 && len(desired) == 0 { @@ -277,7 +273,7 @@ func diffTargets(existing, desired []targetConfig) ChangeList { // the remaining chunks are changes (regardless of TTL) mi := min(len(existing), len(desired)) - for i := 0; i < mi; i++ { + for i := range mi { er := existing[i].rec dr := desired[i].rec diff --git a/pkg/diff2/analyze_test.go b/pkg/diff2/analyze_test.go index a4bc83b2c..5bf4271a5 100644 --- a/pkg/diff2/analyze_test.go +++ b/pkg/diff2/analyze_test.go @@ -60,48 +60,55 @@ func makeRec(label, rtype, content string) *models.RecordConfig { origin := "f.com" r := models.RecordConfig{TTL: 300} r.SetLabel(label, origin) - r.PopulateFromString(rtype, content, origin) + if err := r.PopulateFromString(rtype, content, origin); err != nil { + panic(err) + } return &r } + func makeRecTTL(label, rtype, content string, ttl uint32) *models.RecordConfig { r := makeRec(label, rtype, content) r.TTL = ttl return r } -var testDataAA1234 = makeRec("laba", "A", "1.2.3.4") // [ 0] -var testDataAA5678 = makeRec("laba", "A", "5.6.7.8") // -var testDataAA1234ttl700 = makeRecTTL("laba", "A", "1.2.3.4", 700) // -var testDataAA5678ttl700 = makeRecTTL("laba", "A", "5.6.7.8", 700) // -var testDataAMX10a = makeRec("laba", "MX", "10 laba") // [ 1] -var testDataCCa = makeRec("labc", "CNAME", "laba") // [ 2] -var testDataEA15 = makeRec("labe", "A", "10.10.10.15") // [ 3] -var e4 = makeRec("labe", "A", "10.10.10.16") // [ 4] -var e5 = makeRec("labe", "A", "10.10.10.17") // [ 5] -var e6 = makeRec("labe", "A", "10.10.10.18") // [ 6] -var e7 = makeRec("labg", "NS", "laba") // [ 7] -var e8 = makeRec("labg", "NS", "labb") // [ 8] -var e9 = makeRec("labg", "NS", "labc") // [ 9] -var e10 = makeRec("labg", "NS", "labe") // [10] -var e11mx = makeRec("labh", "MX", "22 ttt") // [11] -var e11 = makeRec("labh", "CNAME", "labd") // [11] -var testDataApexMX1aaa = makeRec("", "MX", "1 aaa") +var ( + testDataAA1234 = makeRec("laba", "A", "1.2.3.4") // [ 0] + testDataAA5678 = makeRec("laba", "A", "5.6.7.8") // + testDataAA1234ttl700 = makeRecTTL("laba", "A", "1.2.3.4", 700) // + testDataAA5678ttl700 = makeRecTTL("laba", "A", "5.6.7.8", 700) // + testDataAMX10a = makeRec("laba", "MX", "10 laba") // [ 1] + testDataCCa = makeRec("labc", "CNAME", "laba") // [ 2] + testDataEA15 = makeRec("labe", "A", "10.10.10.15") // [ 3] + e4 = makeRec("labe", "A", "10.10.10.16") // [ 4] + e5 = makeRec("labe", "A", "10.10.10.17") // [ 5] + e6 = makeRec("labe", "A", "10.10.10.18") // [ 6] + e7 = makeRec("labg", "NS", "laba") // [ 7] + e8 = makeRec("labg", "NS", "labb") // [ 8] + e9 = makeRec("labg", "NS", "labc") // [ 9] + e10 = makeRec("labg", "NS", "labe") // [10] + e11mx = makeRec("labh", "MX", "22 ttt") // [11] + e11 = makeRec("labh", "CNAME", "labd") // [11] + testDataApexMX1aaa = makeRec("", "MX", "1 aaa") +) -var testDataAA1234clone = makeRec("laba", "A", "1.2.3.4") // [ 0'] -var testDataAA12345 = makeRec("laba", "A", "1.2.3.5") // [ 1'] -var testDataAMX20b = makeRec("laba", "MX", "20 labb") // [ 2'] -var d3 = makeRec("labe", "A", "10.10.10.95") // [ 3'] -var d4 = makeRec("labe", "A", "10.10.10.96") // [ 4'] -var d5 = makeRec("labe", "A", "10.10.10.97") // [ 5'] -var d6 = makeRec("labe", "A", "10.10.10.98") // [ 6'] -var d7 = makeRec("labf", "TXT", "foo") // [ 7'] -var d8 = makeRec("labg", "NS", "labf") // [ 8'] -var d9 = makeRec("labg", "NS", "laba") // [ 9'] -var d10 = makeRec("labg", "NS", "labe") // [10'] -var d11 = makeRec("labg", "NS", "labb") // [11'] -var d12 = makeRec("labh", "A", "1.2.3.4") // [12'] -var d13 = makeRec("labc", "CNAME", "labe") // [13'] -var testDataApexMX22bbb = makeRec("", "MX", "22 bbb") +var ( + testDataAA1234clone = makeRec("laba", "A", "1.2.3.4") // [ 0'] + testDataAA12345 = makeRec("laba", "A", "1.2.3.5") // [ 1'] + testDataAMX20b = makeRec("laba", "MX", "20 labb") // [ 2'] + d3 = makeRec("labe", "A", "10.10.10.95") // [ 3'] + d4 = makeRec("labe", "A", "10.10.10.96") // [ 4'] + d5 = makeRec("labe", "A", "10.10.10.97") // [ 5'] + d6 = makeRec("labe", "A", "10.10.10.98") // [ 6'] + d7 = makeRec("labf", "TXT", "foo") // [ 7'] + d8 = makeRec("labg", "NS", "labf") // [ 8'] + d9 = makeRec("labg", "NS", "laba") // [ 9'] + d10 = makeRec("labg", "NS", "labe") // [10'] + d11 = makeRec("labg", "NS", "labb") // [11'] + d12 = makeRec("labh", "A", "1.2.3.4") // [12'] + d13 = makeRec("labc", "CNAME", "labe") // [13'] + testDataApexMX22bbb = makeRec("", "MX", "22 bbb") +) func justMsgString(cl ChangeList) string { msgs := justMsgs(cl) @@ -158,7 +165,6 @@ func Test_analyzeByRecordSet(t *testing.T) { wantChangeZone string wantChangeCount int }{ - { name: "oneequal", args: args{ @@ -559,7 +565,6 @@ ChangeList: len=11 }) // NB(tlim): There is no analyzeByZone(). diff2.ByZone() uses analyzeByRecord(). - } } @@ -586,15 +591,15 @@ func mkTargetConfig(x ...*models.RecordConfig) []targetConfig { } func mkTargetConfigMap(x ...*models.RecordConfig) map[string]*targetConfig { - var m = map[string]*targetConfig{} + m := map[string]*targetConfig{} for _, v := range mkTargetConfig(x...) { + v := v m[v.comparableFull] = &v } return m } func Test_diffTargets(t *testing.T) { - type args struct { existing []targetConfig desired []targetConfig @@ -604,7 +609,6 @@ func Test_diffTargets(t *testing.T) { args args want ChangeList }{ - { name: "add1changettl", args: args{ @@ -612,9 +616,10 @@ func Test_diffTargets(t *testing.T) { desired: mkTargetConfig(testDataAA5678ttl700, testDataAA1234ttl700), }, want: ChangeList{ - Change{Type: CHANGE, - Key: models.RecordKey{NameFQDN: "laba.f.com", Type: "A"}, - New: models.Records{testDataAA5678ttl700, testDataAA1234ttl700}, + Change{ + Type: CHANGE, + Key: models.RecordKey{NameFQDN: "laba.f.com", Type: "A"}, + New: models.Records{testDataAA5678ttl700, testDataAA1234ttl700}, Msgs: []string{ "± MODIFY-TTL laba.f.com A 5.6.7.8 ttl=(300->700)", "+ CREATE laba.f.com A 1.2.3.4 ttl=700", @@ -629,7 +634,7 @@ func Test_diffTargets(t *testing.T) { existing: mkTargetConfig(testDataAA1234), desired: mkTargetConfig(testDataAA1234), }, - //want: , + // want: , }, { @@ -639,7 +644,8 @@ func Test_diffTargets(t *testing.T) { desired: mkTargetConfig(testDataAA1234, testDataAMX10a), }, want: ChangeList{ - Change{Type: CREATE, + Change{ + Type: CREATE, Key: models.RecordKey{NameFQDN: "laba.f.com", Type: "MX"}, New: models.Records{makeRec("laba", "MX", "10 laba.f.com.")}, Msgs: []string{"+ CREATE laba.f.com MX 10 laba.f.com. ttl=300"}, @@ -654,7 +660,8 @@ func Test_diffTargets(t *testing.T) { desired: mkTargetConfig(testDataAA1234), }, want: ChangeList{ - Change{Type: DELETE, + Change{ + Type: DELETE, Key: models.RecordKey{NameFQDN: "laba.f.com", Type: "MX"}, Old: models.Records{makeRec("laba", "MX", "10 laba.f.com.")}, Msgs: []string{"- DELETE laba.f.com MX 10 laba.f.com. ttl=300"}, @@ -669,7 +676,8 @@ func Test_diffTargets(t *testing.T) { desired: mkTargetConfig(testDataAA1234, testDataAMX20b), }, want: ChangeList{ - Change{Type: CHANGE, + Change{ + Type: CHANGE, Key: models.RecordKey{NameFQDN: "laba.f.com", Type: "MX"}, Old: models.Records{testDataAMX10a}, New: models.Records{testDataAMX20b}, @@ -685,7 +693,8 @@ func Test_diffTargets(t *testing.T) { desired: mkTargetConfig(testDataAA1234), }, want: ChangeList{ - Change{Type: CHANGE, + Change{ + Type: CHANGE, Key: models.RecordKey{NameFQDN: "laba.f.com", Type: "A"}, Old: models.Records{testDataAA1234, testDataAA5678}, New: models.Records{testDataAA1234}, @@ -696,13 +705,13 @@ func Test_diffTargets(t *testing.T) { } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { - //fmt.Printf("DEBUG: Test %02d\n", i) + // fmt.Printf("DEBUG: Test %02d\n", i) got := diffTargets(tt.args.existing, tt.args.desired) g := strings.TrimSpace(justMsgString(got)) w := strings.TrimSpace(justMsgString(tt.want)) d := diff.Diff(g, w) if d != "" { - //fmt.Printf("DEBUG: fail %q %q\n", g, w) + // fmt.Printf("DEBUG: fail %q %q\n", g, w) t.Errorf("diffTargets()\n diff=%s", d) } }) @@ -720,7 +729,6 @@ func Test_removeCommon(t *testing.T) { want []targetConfig want1 []targetConfig }{ - { name: "same", args: args{ @@ -772,7 +780,6 @@ func Test_filterBy(t *testing.T) { args args want []targetConfig }{ - { name: "removeall", args: args{ @@ -821,7 +828,6 @@ func Test_splitTTLOnly(t *testing.T) { wantDesireDiff []targetConfig wantChanges string }{ - { name: "simple", args: args{ diff --git a/pkg/diff2/compareconfig.go b/pkg/diff2/compareconfig.go index 91d6c86f7..35b61a45b 100644 --- a/pkg/diff2/compareconfig.go +++ b/pkg/diff2/compareconfig.go @@ -113,7 +113,6 @@ func NewCompareConfig(origin string, existing, desired models.Records, compFn Co // verifyCNAMEAssertions verifies assertions about CNAME updates ordering. func (cc *CompareConfig) verifyCNAMEAssertions() { - // According to the RFCs if a label has a CNAME, it can not have any other // records at that label... even other CNAMEs. Therefore, we need to be // careful with changes at a label that involve a CNAME. @@ -121,7 +120,7 @@ func (cc *CompareConfig) verifyCNAMEAssertions() { // OLD: a.example.com CNAME b // NEW: a.example.com A 1.2.3.4 // We must delete the CNAME record THEN create the A record. If we - // blindly create the the A first, most APIs will reply with an error + // blindly create the A first, most APIs will reply with an error // because there is already a CNAME at that label. // Example 2: // OLD: a.example.com A 1.2.3.4 @@ -141,9 +140,7 @@ func (cc *CompareConfig) verifyCNAMEAssertions() { for _, ld := range cc.ldata { for j, td := range ld.tdata { - if td.rType == "CNAME" { - // This assertion doesn't hold for a site that permits a // recordset with both CNAMEs and other records, such as // Cloudflare. @@ -167,13 +164,11 @@ func (cc *CompareConfig) verifyCNAMEAssertions() { } } } - } // Generate a string that can be used to compare this record to others // for equality. func mkCompareBlobs(rc *models.RecordConfig, f func(*models.RecordConfig) string) (string, string) { - // Start with the comparable string comp := rc.ToComparableNoTTL() @@ -204,7 +199,6 @@ func (cc *CompareConfig) addRecords(recs models.Records, storeInExisting bool) { z := prettyzone.PrettySort(recs, cc.origin, 0, nil) for _, rec := range z.Records { - key := rec.Key() label := key.NameFQDN rtype := key.Type diff --git a/pkg/diff2/compareconfig_test.go b/pkg/diff2/compareconfig_test.go index 0c221a815..c0ced24a0 100644 --- a/pkg/diff2/compareconfig_test.go +++ b/pkg/diff2/compareconfig_test.go @@ -51,7 +51,6 @@ func TestNewCompareConfig(t *testing.T) { args args want string }{ - { name: "one", args: args{ @@ -227,7 +226,6 @@ compFn: for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { - models.CanonicalizeTargets(tt.args.desired, "f.com") models.CanonicalizeTargets(tt.args.existing, "f.com") @@ -264,7 +262,6 @@ func Test_mkCompareBlobs(t *testing.T) { } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { - got, got1 := mkCompareBlobs(tt.args.rc, tt.args.f) if got != tt.want { t.Errorf("mkCompareBlobs() got = %q, want %q", got, tt.want) diff --git a/pkg/diff2/handsoff.go b/pkg/diff2/handsoff.go index 7e2b4f649..e22669b13 100644 --- a/pkg/diff2/handsoff.go +++ b/pkg/diff2/handsoff.go @@ -5,6 +5,7 @@ package diff2 // NO_PURGE, ENSURE_ABSENT and IGNORE*() features. import ( + "errors" "fmt" "strings" @@ -56,7 +57,7 @@ As a result, the diff2 algorithm won't delete them because they are desired! (Of course "desired" can't have duplicate records. Check before you add.) This is different than in the old implementation (pkg/diff) which would generate the -diff but but then do a bunch of checking to see if the record was one that +diff but then do a bunch of checking to see if the record was one that shouldn't be deleted. Or, in the case of NO_PURGE, would simply not do the deletions. This was complex because there were many edge cases to deal with. It was often also wrong. For example, if a provider updates all records in a @@ -114,13 +115,16 @@ func handsoff( return nil, nil, err } - var punct = ":" + punct := ":" if printer.MaxReport == 0 { punct = "." } // Process IGNORE*() and NO_PURGE features: - ignorable, foreign := processIgnoreAndNoPurge(domain, existing, desired, absences, unmanagedConfigs, noPurge) + ignorable, foreign, err := processIgnoreAndNoPurge(domain, existing, desired, absences, unmanagedConfigs, noPurge) + if err != nil { + return nil, nil, err + } if len(foreign) != 0 { msgs = append(msgs, fmt.Sprintf("%d records not being deleted because of NO_PURGE%s", len(foreign), punct)) msgs = append(msgs, reportSkips(foreign, !printer.SkinnyReport)...) @@ -138,7 +142,7 @@ func handsoff( msgs = append(msgs, fmt.Sprintf(" %s %s %s", r.GetLabelFQDN(), r.Type, r.GetTargetCombined())) } if !unmanagedSafely { - return nil, nil, fmt.Errorf(strings.Join(msgs, "\n") + + return nil, nil, errors.New(strings.Join(msgs, "\n") + "\nERROR: Unsafe to continue. Add DISABLE_IGNORE_SAFETY_CHECK to D() to override") } } @@ -172,14 +176,16 @@ func reportSkips(recs models.Records, full bool) []string { } // processIgnoreAndNoPurge processes the IGNORE_*() and NO_PURGE/ENSURE_ABSENT() features. -func processIgnoreAndNoPurge(domain string, existing, desired, absences models.Records, unmanagedConfigs []*models.UnmanagedConfig, noPurge bool) (models.Records, models.Records) { +func processIgnoreAndNoPurge(domain string, existing, desired, absences models.Records, unmanagedConfigs []*models.UnmanagedConfig, noPurge bool) (models.Records, models.Records, error) { var ignorable, foreign models.Records desiredDB := models.NewRecordDBFromRecords(desired, domain) absentDB := models.NewRecordDBFromRecords(absences, domain) - compileUnmanagedConfigs(unmanagedConfigs) + if err := compileUnmanagedConfigs(unmanagedConfigs); err != nil { + return nil, nil, err + } for _, rec := range existing { isMatch := matchAny(unmanagedConfigs, rec) - //fmt.Printf("DEBUG: matchAny returned: %v\n", isMatch) + // fmt.Printf("DEBUG: matchAny returned: %v\n", isMatch) if isMatch { ignorable = append(ignorable, rec) } else { @@ -194,7 +200,7 @@ func processIgnoreAndNoPurge(domain string, existing, desired, absences models.R } } } - return ignorable, foreign + return ignorable, foreign, nil } // findConflicts takes a list of recs and a list of (compiled) UnmanagedConfigs @@ -247,7 +253,7 @@ func compileUnmanagedConfigs(configs []*models.UnmanagedConfig) error { // matchAny returns true if rec matches any of the uconfigs. func matchAny(uconfigs []*models.UnmanagedConfig, rec *models.RecordConfig) bool { - //fmt.Printf("DEBUG: matchAny(%s, %q, %q, %q)\n", models.DebugUnmanagedConfig(uconfigs), rec.NameFQDN, rec.Type, rec.GetTargetField()) + // fmt.Printf("DEBUG: matchAny(%s, %q, %q, %q)\n", models.DebugUnmanagedConfig(uconfigs), rec.NameFQDN, rec.Type, rec.GetTargetField()) for _, uc := range uconfigs { if matchLabel(uc.LabelGlob, rec.GetLabel()) && matchType(uc.RTypeMap, rec.Type) && @@ -257,12 +263,14 @@ func matchAny(uconfigs []*models.UnmanagedConfig, rec *models.RecordConfig) bool } return false } + func matchLabel(labelGlob glob.Glob, labelName string) bool { if labelGlob == nil { return true } return labelGlob.Match(labelName) } + func matchType(typeMap map[string]struct{}, typeName string) bool { if len(typeMap) == 0 { return true @@ -270,6 +278,7 @@ func matchType(typeMap map[string]struct{}, typeName string) bool { _, ok := typeMap[typeName] return ok } + func matchTarget(targetGlob glob.Glob, targetName string) bool { if targetGlob == nil { return true diff --git a/pkg/diff2/handsoff_test.go b/pkg/diff2/handsoff_test.go index 4b2863739..565ab2a94 100644 --- a/pkg/diff2/handsoff_test.go +++ b/pkg/diff2/handsoff_test.go @@ -11,7 +11,7 @@ import ( testifyrequire "github.com/stretchr/testify/require" ) -// parseZoneContents is copied verbatium from providers/bind/bindProvider.go +// parseZoneContents is copied verbatim from providers/bind/bindProvider.go // because import cycles and... tests shouldn't depend on huge modules. func parseZoneContents(content string, zoneName string, zonefileName string) (models.Records, error) { zp := dns.NewZoneParser(strings.NewReader(content), zoneName, zonefileName) @@ -47,7 +47,7 @@ func handsoffHelper(t *testing.T, existingZone, desiredJs string, noPurge bool, existing, err := parseZoneContents(existingZone, "f.com", "no_file_name") if err != nil { - panic(err) + t.Fatal(err) } dnsconfig, err := js.ExecuteJavascriptString([]byte(desiredJs), false, nil) @@ -68,13 +68,16 @@ func handsoffHelper(t *testing.T, existingZone, desiredJs string, noPurge bool, absences[i].SetLabel(j.GetLabel(), "f.com") } - ignored, purged := processIgnoreAndNoPurge( + ignored, purged, err := processIgnoreAndNoPurge( "f.com", existing, desired, absences, unmanagedConfigs, noPurge, ) + if err != nil { + t.Fatal(err) + } ignoredRecs := showRecs(ignored) purgedRecs := showRecs(purged) diff --git a/pkg/diff2/min.go b/pkg/diff2/min.go deleted file mode 100644 index 402b27cc8..000000000 --- a/pkg/diff2/min.go +++ /dev/null @@ -1,10 +0,0 @@ -package diff2 - -import "golang.org/x/exp/constraints" - -func min[T constraints.Ordered](a, b T) T { - if a < b { - return a - } - return b -} diff --git a/pkg/dnsgraph/dnsgraph.go b/pkg/dnsgraph/dnsgraph.go index ef69b22f0..12292b9e2 100644 --- a/pkg/dnsgraph/dnsgraph.go +++ b/pkg/dnsgraph/dnsgraph.go @@ -145,7 +145,6 @@ func (edges Edges[T]) RemoveNode(toRemove *Node[T]) Edges[T] { // Contains returns true if a node is in the graph AND is in that direction. func (edges Edges[T]) Contains(toFind *Node[T], direction edgeDirection) bool { - for _, edge := range edges { if edge.Node == toFind && edge.Direction == direction { return true diff --git a/pkg/dnsgraph/dnsgraph_test.go b/pkg/dnsgraph/dnsgraph_test.go index 719f92a9e..c90ae3105 100644 --- a/pkg/dnsgraph/dnsgraph_test.go +++ b/pkg/dnsgraph/dnsgraph_test.go @@ -58,7 +58,7 @@ func Test_RemoveNode(t *testing.T) { // example.com change has been removed nodes := graph.Tree.Get("example.com") - assert.Len(t, nodes, 0) + assert.Empty(t, nodes) nodes = graph.Tree.Get("a.hq.example.com") assert.Len(t, nodes, 1) diff --git a/pkg/dnssort/graphsort.go b/pkg/dnssort/graphsort.go index 3c8c1a37c..c4dd34688 100644 --- a/pkg/dnssort/graphsort.go +++ b/pkg/dnssort/graphsort.go @@ -22,7 +22,6 @@ func SortUsingGraph[T dnsgraph.Graphable](records []T) SortResult[T] { sortState := createDirectedSortState(records) for sortState.hasWork() { - for _, node := range sortState.graph.All { sortState.hasResolvedLastRound = false diff --git a/pkg/dnssort/graphsort_test.go b/pkg/dnssort/graphsort_test.go index 2736a9fc5..8d72b41c7 100644 --- a/pkg/dnssort/graphsort_test.go +++ b/pkg/dnssort/graphsort_test.go @@ -9,7 +9,6 @@ import ( ) func Test_graphsort(t *testing.T) { - t.Run("Direct dependency", executeGraphSort( []testutils.StubRecord{ diff --git a/pkg/dnstree/dnstree_test.go b/pkg/dnstree/dnstree_test.go index 5e1957491..1f2c8ecfd 100644 --- a/pkg/dnstree/dnstree_test.go +++ b/pkg/dnstree/dnstree_test.go @@ -7,7 +7,6 @@ import ( ) func Test_domaintree(t *testing.T) { - t.Run("Single FQDN", executeTreeTest( []string{ diff --git a/pkg/js/hash.go b/pkg/js/hash.go index 1bf8ba317..70aef08c8 100644 --- a/pkg/js/hash.go +++ b/pkg/js/hash.go @@ -18,7 +18,7 @@ func hashFunc(call otto.FunctionCall) otto.Value { algorithm := call.Argument(0).String() // The algorithm to use for hashing value := call.Argument(1).String() // The value to hash //lint:ignore SA4006 work around bug in staticcheck. This value is needed if the switch statement follows the default path. - result := otto.Value{} + result := otto.Value{} //nolint:staticcheck fmt.Printf("%s\n", value) switch algorithm { diff --git a/pkg/js/js.go b/pkg/js/js.go index 06d9a7d30..6c614d4c5 100644 --- a/pkg/js/js.go +++ b/pkg/js/js.go @@ -51,7 +51,6 @@ func ExecuteJavaScript(file string, devMode bool, variables map[string]string) ( // ExecuteJavascriptString accepts a string containing javascript and runs it, returning the resulting dnsConfig. func ExecuteJavascriptString(script []byte, devMode bool, variables map[string]string) (*models.DNSConfig, error) { - vm := otto.New() l := loop.New(vm) @@ -69,16 +68,26 @@ func ExecuteJavascriptString(script []byte, devMode bool, variables map[string]s } } - vm.Set("require", require) - vm.Set("REV", reverse) - vm.Set("REVCOMPAT", reverseCompat) - vm.Set("glob", listFiles) // used for require_glob() - vm.Set("PANIC", jsPanic) - vm.Set("HASH", hashFunc) + // add functions to otto + functions := map[string]interface{}{ + "require": require, + "REV": reverse, + "REVCOMPAT": reverseCompat, + "glob": listFiles, // used for require_glob() + "PANIC": jsPanic, + "HASH": hashFunc, + } + for name, fn := range functions { + if err := vm.Set(name, fn); err != nil { + return nil, err + } + } // add cli variables to otto for key, value := range variables { - vm.Set(key, value) + if err := vm.Set(key, value); err != nil { + return nil, err + } } helperJs := GetHelpers(devMode) @@ -150,15 +159,14 @@ func require(call otto.FunctionCall) otto.Value { printer.Debugf("requiring: %s (%s)\n", file, relFile) // quick fix, by replacing to linux slashes, to make it work with windows paths too. data, err := os.ReadFile(filepath.ToSlash(relFile)) - if err != nil { throw(call.Otto, err.Error()) } - var value = otto.TrueValue() + value := otto.TrueValue() // If its a json file return the json value, else default to true - var ext = strings.ToLower(filepath.Ext(relFile)) + ext := strings.ToLower(filepath.Ext(relFile)) if strings.HasSuffix(ext, "json") || strings.HasSuffix(ext, "json5") { cmd := fmt.Sprintf(`JSON.parse(JSON.stringify(%s))`, string(data)) value, err = call.Otto.Run(cmd) @@ -201,7 +209,7 @@ func listFiles(call otto.FunctionCall) otto.Value { } // Second: Recursive? - var recursive = true + recursive := true if call.Argument(1).IsDefined() && !call.Argument(1).IsNull() { if call.Argument(1).IsBoolean() { recursive, _ = call.Argument(1).ToBoolean() // If it should be recursive @@ -211,7 +219,7 @@ func listFiles(call otto.FunctionCall) otto.Value { } // Third: File extension filter. - var fileExtension = ".js" + fileExtension := ".js" if call.Argument(2).IsDefined() && !call.Argument(2).IsNull() { if call.Argument(2).IsString() { fileExtension = call.Argument(2).String() // Which file extension to filter for. @@ -247,7 +255,7 @@ func listFiles(call otto.FunctionCall) otto.Value { // ONLY skip, when the file extension is NOT matching, or when filter is NOT disabled. return nil } - //dirPath := filepath.ToSlash(filepath.Dir(path)) + "/" + // dirPath := filepath.ToSlash(filepath.Dir(path)) + "/" files = append(files, path) return err }) diff --git a/pkg/js/js_test.go b/pkg/js/js_test.go index 5ff379b47..6982251d8 100644 --- a/pkg/js/js_test.go +++ b/pkg/js/js_test.go @@ -23,7 +23,10 @@ const ( ) func init() { - os.Chdir("../..") // go up a directory so we helpers.js is in a consistent place. + // go up a directory so we helpers.js is in a consistent place. + if err := os.Chdir("../.."); err != nil { + panic(err) + } } func TestParsedFiles(t *testing.T) { @@ -56,8 +59,8 @@ func TestParsedFiles(t *testing.T) { } for _, dc := range conf.Domains { - //fmt.Printf("DEBUG: PrettySort: domain=%q #rec=%d\n", dc.Name, len(dc.Records)) - //fmt.Printf("DEBUG: records = %d %v\n", len(dc.Records), dc.Records) + // fmt.Printf("DEBUG: PrettySort: domain=%q #rec=%d\n", dc.Name, len(dc.Records)) + // fmt.Printf("DEBUG: records = %d %v\n", len(dc.Records), dc.Records) ps := prettyzone.PrettySort(dc.Records, dc.Name, 0, nil) dc.Records = ps.Records if len(dc.Records) == 0 { @@ -67,7 +70,7 @@ func TestParsedFiles(t *testing.T) { // Initialize any DNS providers mentioned. for _, dProv := range conf.DNSProviders { - var pcfg = map[string]string{} + pcfg := map[string]string{} if dProv.Type == "-" { // Pretend any "look up provider type in creds.json" results @@ -101,8 +104,10 @@ func TestParsedFiles(t *testing.T) { es := string(expectedJSON) as := string(actualJSON) _, _ = es, as - // When debugging, leave behind the actual result: - os.WriteFile(expectedFile+".ACTUAL", []byte(as), 0644) // Leave behind the actual result: + // Leave behind the actual result: + if err := os.WriteFile(expectedFile+".ACTUAL", []byte(as), 0o644); err != nil { + t.Fatal(err) + } testifyrequire.JSONEqf(t, es, as, "EXPECTING %q = \n```\n%s\n```", expectedFile, as) // For each domain, if there is a zone file, test against it: @@ -128,16 +133,16 @@ func TestParsedFiles(t *testing.T) { as := actualZone if es != as { // On failure, leave behind the .ACTUAL file. - os.WriteFile(zoneFile+".ACTUAL", []byte(actualZone), 0644) + if err := os.WriteFile(zoneFile+".ACTUAL", []byte(actualZone), 0o644); err != nil { + t.Fatal(err) + } } testifyrequire.Equal(t, es, as, "EXPECTING %q =\n```\n%s```", zoneFile, as) } if dCount > 0 && (len(conf.Domains) != dCount) { t.Fatal(fmt.Errorf("only %d of %d domains in %q have zonefiles", dCount, len(conf.Domains), name)) } - }) - } } @@ -160,6 +165,5 @@ func TestErrors(t *testing.T) { t.Fatal("Expected error but found none") } }) - } } diff --git a/pkg/nameservers/nameservers.go b/pkg/nameservers/nameservers.go index 56faabd72..c6c2a76f7 100644 --- a/pkg/nameservers/nameservers.go +++ b/pkg/nameservers/nameservers.go @@ -49,7 +49,7 @@ func DetermineNameserversForProviders(dc *models.DomainConfig, providers []*mode if n > 0 && n < take { take = n } - for i := 0; i < take; i++ { + for i := range take { ns = append(ns, nss[i]) } } @@ -78,7 +78,9 @@ func AddNSRecords(dc *models.DomainConfig) { if !strings.HasSuffix(t, ".") { t += "." } - rc.SetTarget(t) + if err := rc.SetTarget(t); err != nil { + fmt.Printf("failed AddNSRecords rc.SetTarget(%q): %s\n", t, err) + } dc.Records = append(dc.Records, rc) } diff --git a/pkg/normalize/capabilities_test.go b/pkg/normalize/capabilities_test.go index 622a8b9c3..c8ccf28fa 100644 --- a/pkg/normalize/capabilities_test.go +++ b/pkg/normalize/capabilities_test.go @@ -9,14 +9,16 @@ import ( "testing" ) -const providersImportDir = "../../providers" -const providersPackageName = "providers" +const ( + providersImportDir = "../../providers" + providersPackageName = "providers" +) func TestCapabilitiesAreFiltered(t *testing.T) { // Any capabilities which we wish to whitelist because it's not directly // something we can test against. skipCheckCapabilities := make(map[string]struct{}) - //skipCheckCapabilities["CanUseBlahBlahBlah"] = struct{}{} + // skipCheckCapabilities["CanUseBlahBlahBlah"] = struct{}{} fset := token.NewFileSet() pkgs, err := parser.ParseDir(fset, providersImportDir, nil, 0) @@ -70,5 +72,4 @@ func TestCapabilitiesAreFiltered(t *testing.T) { t.Errorf("MISSING: providers.%s (%d) is not checked by checkProviderCapabilities", capName, capInt) } } - } diff --git a/pkg/normalize/flatten.go b/pkg/normalize/flatten.go index 48d848e21..a9c046ed8 100644 --- a/pkg/normalize/flatten.go +++ b/pkg/normalize/flatten.go @@ -56,7 +56,6 @@ func flattenSPFs(cfg *models.DNSConfig) []error { } // now split if needed if split, ok := txt.Metadata["split"]; ok { - overhead1 := 0 // overhead1: The first segment of the SPF record // needs to be shorter than the others due to the overhead of @@ -91,10 +90,14 @@ func flattenSPFs(cfg *models.DNSConfig) []error { for _, k := range sortedKeys(recs) { v := recs[k] if k == "@" { - txt.SetTargetTXTs(v) + if err := txt.SetTargetTXTs(v); err != nil { + errs = append(errs, err) + } } else { cp, _ := txt.Copy() - cp.SetTargetTXTs(v) + if err := cp.SetTargetTXTs(v); err != nil { + errs = append(errs, err) + } cp.SetLabelFromFQDN(k, domain.Name) domain.Records = append(domain.Records, cp) } @@ -107,7 +110,7 @@ func flattenSPFs(cfg *models.DNSConfig) []error { } // check if cache is stale for _, e := range cache.ResolveErrors() { - errs = append(errs, Warning{fmt.Errorf("problem resolving SPF record: %s", e)}) + errs = append(errs, Warning{fmt.Errorf("problem resolving SPF record: %w", e)}) } if len(cache.ResolveErrors()) == 0 { changed := cache.ChangedRecords() diff --git a/pkg/normalize/importTransform_test.go b/pkg/normalize/importTransform_test.go index 089e137cd..4e2c3bb8b 100644 --- a/pkg/normalize/importTransform_test.go +++ b/pkg/normalize/importTransform_test.go @@ -8,12 +8,11 @@ import ( func makeRC(label, domain, target string, rc models.RecordConfig) *models.RecordConfig { rc.SetLabel(label, domain) - rc.SetTarget(target) + rc.MustSetTarget(target) return &rc } func TestImportTransform(t *testing.T) { - const transformDouble = "0.0.0.0~1.1.1.1~~9.0.0.0,10.0.0.0" const transformSingle = "0.0.0.0~1.1.1.1~~8.0.0.0" src := &models.DomainConfig{ diff --git a/pkg/normalize/validate.go b/pkg/normalize/validate.go index 1094f1127..e92dd40bb 100644 --- a/pkg/normalize/validate.go +++ b/pkg/normalize/validate.go @@ -5,6 +5,7 @@ import ( "fmt" "net" "sort" + "strconv" "strings" "github.com/StackExchange/dnscontrol/v4/models" @@ -35,7 +36,7 @@ func checkTarget(target string) error { return nil } if target == "" { - return fmt.Errorf("empty target") + return errors.New("empty target") } if strings.ContainsAny(target, `'" +,|!£$%&()=?^*ç°§;:<>[]()@`) { return fmt.Errorf("target (%v) includes invalid char", target) @@ -53,7 +54,7 @@ func checkTarget(target string) error { // validateRecordTypes list of valid rec.Type values. Returns true if this is a real DNS record type, false means it is a pseudo-type used internally. func validateRecordTypes(rec *models.RecordConfig, domain string, pTypes []string) error { // #rtype_variations - var validTypes = map[string]bool{ + validTypes := map[string]bool{ "A": true, "AAAA": true, "ALIAS": false, @@ -230,12 +231,12 @@ func checkTargets(rec *models.RecordConfig, domain string) (errs []error) { default: if rec.Metadata["orig_custom_type"] != "" { // it is a valid custom type. We perform no validation on target - return + return errs } errs = append(errs, fmt.Errorf("checkTargets: Unimplemented record type (%v) domain=%v name=%v", rec.Type, domain, rec.GetLabel())) } - return + return errs } func transformCNAME(target, oldDomain, newDomain, suffixstrip string) string { @@ -270,7 +271,8 @@ func transformLabel(label, suffixstrip string) (string, error) { // import_transform imports the records of one zone into another, modifying records along the way. func importTransform(srcDomain, dstDomain *models.DomainConfig, - transforms []transform.IPConversion, ttl uint32, suffixstrip string) error { + transforms []transform.IPConversion, ttl uint32, suffixstrip string, +) error { // Read srcDomain.Records, transform, and append to dstDomain.Records: // 1. Skip any that aren't A or CNAMEs. // 2. Append destDomainname to the end of the label. @@ -290,7 +292,7 @@ func importTransform(srcDomain, dstDomain *models.DomainConfig, case "A": trs, err := transform.IPToList(net.ParseIP(rec.GetTargetField()), transforms) if err != nil { - return fmt.Errorf("import_transform: TransformIP(%v, %v) returned err=%s", rec.GetTargetField(), transforms, err) + return fmt.Errorf("import_transform: TransformIP(%v, %v) returned err=%w", rec.GetTargetField(), transforms, err) } for _, tr := range trs { r := newRec(rec, ttl) @@ -299,7 +301,9 @@ func importTransform(srcDomain, dstDomain *models.DomainConfig, return err } r.SetLabel(l, dstDomain.Name) - r.SetTarget(tr.String()) + if err := r.SetTarget(tr.String()); err != nil { + return err + } dstDomain.Records = append(dstDomain.Records, r) } case "CNAME": @@ -309,7 +313,9 @@ func importTransform(srcDomain, dstDomain *models.DomainConfig, return err } r.SetLabel(l, dstDomain.Name) - r.SetTarget(transformCNAME(r.GetTargetField(), srcDomain.Name, dstDomain.Name, suffixstrip)) + if err := r.SetTarget(transformCNAME(r.GetTargetField(), srcDomain.Name, dstDomain.Name, suffixstrip)); err != nil { + return err + } dstDomain.Records = append(dstDomain.Records, r) default: // Anything else is ignored. @@ -376,7 +382,6 @@ func ValidateAndNormalizeConfig(config *models.DNSConfig) (errs []error) { // Normalize Records. models.PostProcessRecords(domain.Records) for _, rec := range domain.Records { - if rec.TTL == 0 { rec.TTL = models.DefaultTTL } @@ -425,9 +430,13 @@ func ValidateAndNormalizeConfig(config *models.DNSConfig) (errs []error) { if rec.SubDomain != "" { origin = rec.SubDomain + "." + origin } - rec.SetTarget(dnsutil.AddOrigin(rec.GetTargetField(), origin)) + if err := rec.SetTarget(dnsutil.AddOrigin(rec.GetTargetField(), origin)); err != nil { + errs = append(errs, err) + } } else if rec.Type == "A" || rec.Type == "AAAA" { - rec.SetTarget(net.ParseIP(rec.GetTargetField()).String()) + if err := rec.SetTarget(net.ParseIP(rec.GetTargetField()).String()); err != nil { + errs = append(errs, err) + } } else if rec.Type == "PTR" { var err error var name string @@ -460,7 +469,6 @@ func ValidateAndNormalizeConfig(config *models.DNSConfig) (errs []error) { if _, ok := rec.Metadata["ignore_name_disable_safety_check"]; ok { errs = append(errs, errors.New("IGNORE_NAME_DISABLE_SAFETY_CHECK no longer supported. Please use DISABLE_IGNORE_SAFETY_CHECK for the entire domain")) } - } } @@ -481,7 +489,7 @@ func ValidateAndNormalizeConfig(config *models.DNSConfig) (errs []error) { } c := config.FindDomain(rec.GetTargetField()) if c == nil { - err = fmt.Errorf("IMPORT_TRANSFORM mentions non-existant domain %q", rec.GetTargetField()) + err = fmt.Errorf("IMPORT_TRANSFORM mentions non-existent domain %q", rec.GetTargetField()) errs = append(errs, err) } err = importTransform(c, domain, table, rec.TTL, suffixstrip) @@ -677,7 +685,6 @@ func checkRecordSetHasMultipleTTLs(records []*models.RecordConfig) (errs []error func formatInconsistency(r map[string]map[uint32]bool) string { var rtypeResult []string for rtype, ttlsMap := range r { - ttlList := make([]int, len(ttlsMap)) i := 0 for k := range ttlsMap { @@ -696,7 +703,7 @@ func formatInconsistency(r map[string]map[uint32]bool) string { func commaSepInts(list []int) string { slist := make([]string, len(list)) for i, v := range list { - slist[i] = fmt.Sprintf("%d", v) + slist[i] = strconv.Itoa(v) } return strings.Join(slist, ",") } @@ -707,7 +714,7 @@ func commaSepInts(list []int) string { var providerCapabilityChecks = []pairTypeCapability{ // #rtype_variations // If a zone uses rType X, the provider must support capability Y. - //{"X", providers.Y}, + // {"X", providers.Y}, capabilityCheck("AKAMAICDN", providers.CanUseAKAMAICDN), capabilityCheck("ALIAS", providers.CanUseAlias), capabilityCheck("AUTODNSSEC", providers.CanAutoDNSSEC), @@ -803,7 +810,6 @@ func checkProviderCapabilities(dc *models.DomainConfig) error { break } } - } if !hasAny { continue @@ -854,15 +860,20 @@ func applyRecordTransforms(domain *models.DomainConfig) error { } for i, newIP := range newIPs { if i == 0 && !newIP.Equal(ip) { - rec.SetTarget(newIP.String()) // replace target of first record if different + // replace target of first record if different + if err := rec.SetTarget(newIP.String()); err != nil { + return err + } } else if i > 0 { // any additional ips need identical records with the alternate ip added to the domain - copy, err := rec.Copy() + cpy, err := rec.Copy() if err != nil { return err } - copy.SetTarget(newIP.String()) - domain.Records = append(domain.Records, copy) + if err := cpy.SetTarget(newIP.String()); err != nil { + return err + } + domain.Records = append(domain.Records, cpy) } } } diff --git a/pkg/normalize/validate_test.go b/pkg/normalize/validate_test.go index 68076822a..7664c3393 100644 --- a/pkg/normalize/validate_test.go +++ b/pkg/normalize/validate_test.go @@ -9,7 +9,7 @@ import ( ) func TestSoaLabelAndTarget(t *testing.T) { - var tests = []struct { + tests := []struct { isError bool label string target string @@ -22,8 +22,10 @@ func TestSoaLabelAndTarget(t *testing.T) { } for _, test := range tests { experiment := fmt.Sprintf("%s %s", test.label, test.target) - rc := makeRC(test.label, "foo.com", test.target, models.RecordConfig{Type: "SOA", - SoaExpire: 1, SoaMinttl: 1, SoaRefresh: 1, SoaRetry: 1, SoaSerial: 1, SoaMbox: "bar.foo.com"}) + rc := makeRC(test.label, "foo.com", test.target, models.RecordConfig{ + Type: "SOA", + SoaExpire: 1, SoaMinttl: 1, SoaRefresh: 1, SoaRetry: 1, SoaSerial: 1, SoaMbox: "bar.foo.com", + }) err := checkTargets(rc, "foo.com") if err != nil && !test.isError { t.Errorf("%v: Error (%v)\n", experiment, err) @@ -35,7 +37,7 @@ func TestSoaLabelAndTarget(t *testing.T) { } func TestCheckSoa(t *testing.T) { - var tests = []struct { + tests := []struct { isError bool expire uint32 minttl uint32 @@ -75,7 +77,7 @@ func TestCheckSoa(t *testing.T) { } func TestCheckLabel(t *testing.T) { - var tests = []struct { + tests := []struct { label string rType string target string @@ -109,7 +111,6 @@ func TestCheckLabel(t *testing.T) { t.Errorf("%02d: Expected error but got none", i) } }) - } } @@ -123,7 +124,7 @@ func checkError(t *testing.T, err error, shouldError bool, experiment string) { } func Test_assert_valid_ipv4(t *testing.T) { - var tests = []struct { + tests := []struct { experiment string isError bool }{ @@ -140,7 +141,7 @@ func Test_assert_valid_ipv4(t *testing.T) { } func Test_assert_valid_target(t *testing.T) { - var tests = []struct { + tests := []struct { experiment string isError bool }{ @@ -162,7 +163,7 @@ func Test_assert_valid_target(t *testing.T) { } func Test_transform_cname(t *testing.T) { - var tests = []struct { + tests := []struct { experiment string expected string }{ @@ -182,41 +183,71 @@ func Test_transform_cname(t *testing.T) { } func Test_transform_cname_strip(t *testing.T) { - var tests = []struct { + tests := []struct { p []string expected string }{ - {[]string{"ai.meta.stackexchange.com.", "stackexchange.com", "com.internal", "com"}, - "ai.meta.stackexchange.com.internal."}, - {[]string{"askubuntu.com.", "askubuntu.com", "com.internal", "com"}, - "askubuntu.com.internal."}, - {[]string{"blogoverflow.com.", "stackoverflow.com", "com.internal", "com"}, - "blogoverflow.com.internal."}, - {[]string{"careers.stackoverflow.com.", "stackoverflow.com", "com.internal", "com"}, - "careers.stackoverflow.com.internal."}, - {[]string{"chat.stackexchange.com.", "askubuntu.com", "com.internal", "com"}, - "chat.stackexchange.com.internal."}, - {[]string{"chat.stackexchange.com.", "stackoverflow.com", "com.internal", "com"}, - "chat.stackexchange.com.internal."}, - {[]string{"chat.stackexchange.com.", "superuser.com", "com.internal", "com"}, - "chat.stackexchange.com.internal."}, - {[]string{"sstatic.net.", "sstatic.net", "net.internal", "net"}, - "sstatic.net.internal."}, - {[]string{"stackapps.com.", "stackapps.com", "com.internal", "com"}, - "stackapps.com.internal."}, - {[]string{"stackexchange.com.", "stackexchange.com", "com.internal", "com"}, - "stackexchange.com.internal."}, - {[]string{"stackoverflow.com.", "stackoverflow.com", "com.internal", "com"}, - "stackoverflow.com.internal."}, - {[]string{"superuser.com.", "superuser.com", "com.internal", "com"}, - "superuser.com.internal."}, - {[]string{"teststackoverflow.com.", "teststackoverflow.com", "com.internal", "com"}, - "teststackoverflow.com.internal."}, - {[]string{"webapps.stackexchange.com.", "stackexchange.com", "com.internal", "com"}, - "webapps.stackexchange.com.internal."}, + { + []string{"ai.meta.stackexchange.com.", "stackexchange.com", "com.internal", "com"}, + "ai.meta.stackexchange.com.internal.", + }, + { + []string{"askubuntu.com.", "askubuntu.com", "com.internal", "com"}, + "askubuntu.com.internal.", + }, + { + []string{"blogoverflow.com.", "stackoverflow.com", "com.internal", "com"}, + "blogoverflow.com.internal.", + }, + { + []string{"careers.stackoverflow.com.", "stackoverflow.com", "com.internal", "com"}, + "careers.stackoverflow.com.internal.", + }, + { + []string{"chat.stackexchange.com.", "askubuntu.com", "com.internal", "com"}, + "chat.stackexchange.com.internal.", + }, + { + []string{"chat.stackexchange.com.", "stackoverflow.com", "com.internal", "com"}, + "chat.stackexchange.com.internal.", + }, + { + []string{"chat.stackexchange.com.", "superuser.com", "com.internal", "com"}, + "chat.stackexchange.com.internal.", + }, + { + []string{"sstatic.net.", "sstatic.net", "net.internal", "net"}, + "sstatic.net.internal.", + }, + { + []string{"stackapps.com.", "stackapps.com", "com.internal", "com"}, + "stackapps.com.internal.", + }, + { + []string{"stackexchange.com.", "stackexchange.com", "com.internal", "com"}, + "stackexchange.com.internal.", + }, + { + []string{"stackoverflow.com.", "stackoverflow.com", "com.internal", "com"}, + "stackoverflow.com.internal.", + }, + { + []string{"superuser.com.", "superuser.com", "com.internal", "com"}, + "superuser.com.internal.", + }, + { + []string{"teststackoverflow.com.", "teststackoverflow.com", "com.internal", "com"}, + "teststackoverflow.com.internal.", + }, + { + []string{"webapps.stackexchange.com.", "stackexchange.com", "com.internal", "com"}, + "webapps.stackexchange.com.internal.", + }, // - {[]string{"sstatic.net.", "sstatic.net", "com.internal", "com"}, - "sstatic.net.internal."}, + { + []string{"sstatic.net.", "sstatic.net", "com.internal", "com"}, + "sstatic.net.internal.", + }, } for _, test := range tests { @@ -231,7 +262,7 @@ func TestNSAtRoot(t *testing.T) { // do not allow ns records for @ rec := &models.RecordConfig{Type: "NS"} rec.SetLabel("test", "foo.com") - rec.SetTarget("ns1.name.com.") + rec.MustSetTarget("ns1.name.com.") errs := checkTargets(rec, "foo.com") if len(errs) > 0 { t.Error("Expect no error with ns record on subdomain") @@ -246,7 +277,7 @@ func TestNSAtRoot(t *testing.T) { func TestNS1URLFWDValid(t *testing.T) { rec := &models.RecordConfig{Type: "NS1_URLFWD"} rec.SetLabel("test1", "foo.com") - rec.SetTarget("/ http://example.com 302 2 0") + rec.MustSetTarget("/ http://example.com 302 2 0") errs := checkTargets(rec, "foo.com") if len(errs) > 0 { @@ -257,7 +288,7 @@ func TestNS1URLFWDValid(t *testing.T) { func TestNS1URLFWDInvalid(t *testing.T) { rec := &models.RecordConfig{Type: "NS1_URLFWD"} rec.SetLabel("test2", "foo.com") - rec.SetTarget("/ http://example.com 302 2") + rec.MustSetTarget("/ http://example.com 302 2") errs := checkTargets(rec, "foo.com") if len(errs) == 0 { @@ -266,7 +297,7 @@ func TestNS1URLFWDInvalid(t *testing.T) { } func TestTransforms(t *testing.T) { - var tests = []struct { + tests := []struct { givenIP string expectedRecords []string }{ @@ -300,9 +331,9 @@ func TestTransforms(t *testing.T) { } func TestCNAMEMutex(t *testing.T) { - var recA = &models.RecordConfig{Type: "CNAME"} + recA := &models.RecordConfig{Type: "CNAME"} recA.SetLabel("foo", "foo.example.com") - recA.SetTarget("example.com.") + recA.MustSetTarget("example.com.") tests := []struct { rType string name string @@ -315,9 +346,9 @@ func TestCNAMEMutex(t *testing.T) { } for _, tst := range tests { t.Run(fmt.Sprintf("%s %s", tst.rType, tst.name), func(t *testing.T) { - var recB = &models.RecordConfig{Type: tst.rType} + recB := &models.RecordConfig{Type: tst.rType} recB.SetLabel(tst.name, "example.com") - recB.SetTarget("example2.com.") + recB.MustSetTarget("example2.com.") dc := &models.DomainConfig{ Name: "example.com", Records: []*models.RecordConfig{recA, recB}, @@ -479,7 +510,8 @@ func TestTLSAValidation(t *testing.T) { RegistrarName: "BIND", Records: []*models.RecordConfig{ makeRC("_443._tcp", "_443._tcp.example.com", "abcdef0", models.RecordConfig{ - Type: "TLSA", TlsaUsage: 4, TlsaSelector: 1, TlsaMatchingType: 1}), + Type: "TLSA", TlsaUsage: 4, TlsaSelector: 1, TlsaMatchingType: 1, + }), }, }, }, diff --git a/pkg/notifications/bonfire.go b/pkg/notifications/bonfire.go index 542977df9..d96e62430 100644 --- a/pkg/notifications/bonfire.go +++ b/pkg/notifications/bonfire.go @@ -30,7 +30,7 @@ func (b bonfireNotifier) Notify(domain, provider, msg string, err error, preview // chat doesn't markdownify multiline messages. Split in two so the first line can have markdown parts := strings.SplitN(payload, "\n", 2) for _, p := range parts { - http.Post(string(b), "text/markdown", strings.NewReader(p)) + _, _ = http.Post(string(b), "text/markdown", strings.NewReader(p)) } } diff --git a/pkg/notifications/notifications.go b/pkg/notifications/notifications.go index c454cfd74..3e86dde80 100644 --- a/pkg/notifications/notifications.go +++ b/pkg/notifications/notifications.go @@ -40,7 +40,6 @@ func stripAnsiColors(colored string) string { } func (m multiNotifier) Notify(domain, provider string, message string, err error, preview bool) { - // force-remove ansi colors that might come with the message from dnscontrol. // These usually don't render well in notifiers, outputting escape codes. // If a notifier wants to output colors, they should probably implement @@ -50,6 +49,7 @@ func (m multiNotifier) Notify(domain, provider string, message string, err error n.Notify(domain, provider, nMsg, err, preview) } } + func (m multiNotifier) Done() { for _, n := range m { n.Done() diff --git a/pkg/notifications/notifications_test.go b/pkg/notifications/notifications_test.go index 456302f68..a155bf07f 100644 --- a/pkg/notifications/notifications_test.go +++ b/pkg/notifications/notifications_test.go @@ -3,7 +3,6 @@ package notifications import "testing" func Test_stripAnsiColorsValid(t *testing.T) { - coloredStr := "\x1b[0133myellow\x1b[0m" // 33 == yellow nonColoredStr := "yellow" @@ -14,7 +13,6 @@ func Test_stripAnsiColorsValid(t *testing.T) { } func Test_stripAnsiColorsInvalid(t *testing.T) { - coloredStr := "\x1b[01AAmyellow\x1b[0m" // AA not a real color nonColoredStr := "yellow" diff --git a/pkg/notifications/shoutrrr.go b/pkg/notifications/shoutrrr.go index a8c362bbe..1ed0c5d6b 100644 --- a/pkg/notifications/shoutrrr.go +++ b/pkg/notifications/shoutrrr.go @@ -26,7 +26,7 @@ func (b shoutrrrNotifier) Notify(domain, provider, msg string, err error, previe } else { payload = fmt.Sprintf("DNSControl successfully ran correction for %s[%s]:\n%s", domain, provider, msg) } - shoutrrr.Send(string(b), payload) + _ = shoutrrr.Send(string(b), payload) } func (b shoutrrrNotifier) Done() {} diff --git a/pkg/notifications/slack.go b/pkg/notifications/slack.go index 275c2e44a..a2fcf60f6 100644 --- a/pkg/notifications/slack.go +++ b/pkg/notifications/slack.go @@ -40,7 +40,7 @@ func (s *slackNotifier) Notify(domain, provider, msg string, err error, preview } json, _ := json.Marshal(payload) - http.Post(s.URL, "text/json", bytes.NewReader(json)) + _, _ = http.Post(s.URL, "text/json", bytes.NewReader(json)) } func (s *slackNotifier) Done() {} diff --git a/pkg/notifications/teams.go b/pkg/notifications/teams.go index 7f97d6441..62698722a 100644 --- a/pkg/notifications/teams.go +++ b/pkg/notifications/teams.go @@ -46,7 +46,7 @@ func (s *teamsNotifier) Notify(domain, provider, msg string, err error, preview } json, _ := json.Marshal(payload) - http.Post(s.URL, "text/json", bytes.NewReader(json)) + _, _ = http.Post(s.URL, "text/json", bytes.NewReader(json)) } func (s *teamsNotifier) Done() {} diff --git a/pkg/notifications/telegram.go b/pkg/notifications/telegram.go index bdadda38a..48cf21fe6 100644 --- a/pkg/notifications/telegram.go +++ b/pkg/notifications/telegram.go @@ -35,7 +35,7 @@ func (s *telegramNotifier) Notify(domain, provider, msg string, err error, previ Text string `json:"text"` } - var url = fmt.Sprintf("https://api.telegram.org/bot%s/sendMessage", s.BotToken) + url := fmt.Sprintf("https://api.telegram.org/bot%s/sendMessage", s.BotToken) payload.ChatID, _ = strconv.ParseInt(s.ChatID, 10, 64) @@ -50,7 +50,6 @@ func (s *telegramNotifier) Notify(domain, provider, msg string, err error, previ marshaledPayload, _ := json.Marshal(payload) _, _ = http.Post(url, "application/json", bytes.NewBuffer(marshaledPayload)) - } func (s *telegramNotifier) Done() {} diff --git a/pkg/powershell/backend/ssh.go b/pkg/powershell/backend/ssh.go index bdaa6fdd7..3e8231b0d 100644 --- a/pkg/powershell/backend/ssh.go +++ b/pkg/powershell/backend/ssh.go @@ -20,25 +20,25 @@ type SSH struct { Session sshSession } -// func (b *SSH) StartProcess(cmd string, args ...string) (Waiter, io.Writer, io.Reader, io.Reader, error) { +// func (b *SSH) StartProcess(cmd string, args ...string) (Waiter, io.Writer, io.Reader, error) // stdin, err := b.Session.StdinPipe() // if err != nil { -// return nil, nil, nil, nil, errors.Annotate(err, "Could not get hold of the SSH session's stdin stream") +// return nil, errors.Annotate(err, "Could not get hold of the SSH session's stdin stream") // } // stdout, err := b.Session.StdoutPipe() // if err != nil { -// return nil, nil, nil, nil, errors.Annotate(err, "Could not get hold of the SSH session's stdout stream") +// return nil, errors.Annotate(err, "Could not get hold of the SSH session's stdout stream") // } // stderr, err := b.Session.StderrPipe() // if err != nil { -// return nil, nil, nil, nil, errors.Annotate(err, "Could not get hold of the SSH session's stderr stream") +// return nil, errors.Annotate(err, "Could not get hold of the SSH session's stderr stream") // } // err = b.Session.Start(b.createCmd(cmd, args)) // if err != nil { -// return nil, nil, nil, nil, errors.Annotate(err, "Could not spawn process via SSH") +// return nil, errors.Annotate(err, "Could not spawn process via SSH") // } // return b.Session, stdin, stdout, stderr, nil diff --git a/pkg/powershell/middleware/session.go b/pkg/powershell/middleware/session.go index d96a2e0cb..1c89db86c 100644 --- a/pkg/powershell/middleware/session.go +++ b/pkg/powershell/middleware/session.go @@ -42,6 +42,6 @@ func (s *session) Execute(cmd string) (string, string, error) { } func (s *session) Exit() { - s.upstream.Execute(fmt.Sprintf("Disconnect-PSSession -Session $%s", s.name)) + _, _, _ = s.upstream.Execute("Disconnect-PSSession -Session $" + s.name) s.upstream.Exit() } diff --git a/pkg/powershell/middleware/session_config.go b/pkg/powershell/middleware/session_config.go index f9f47421b..5f4dfbbf0 100644 --- a/pkg/powershell/middleware/session_config.go +++ b/pkg/powershell/middleware/session_config.go @@ -91,5 +91,5 @@ func (c *UserPasswordCredential) prepare(s Middleware) (interface{}, error) { return nil, errors.Annotate(err, "Could not create PSCredential object") } - return fmt.Sprintf("$%s", name), nil + return "$" + name, nil } diff --git a/pkg/powershell/shell.go b/pkg/powershell/shell.go index 2215f596c..d4a8131a7 100644 --- a/pkg/powershell/shell.go +++ b/pkg/powershell/shell.go @@ -59,8 +59,8 @@ func (s *shell) Execute(cmd string) (string, string, error) { waiter := &sync.WaitGroup{} waiter.Add(2) - go streamReader(s.stdout, outBoundary, &sout, waiter) - go streamReader(s.stderr, errBoundary, &serr, waiter) + go streamReader(s.stdout, outBoundary, &sout, waiter) //nolint:errcheck + go streamReader(s.stdout, outBoundary, &sout, waiter) //nolint:errcheck waiter.Wait() @@ -72,7 +72,7 @@ func (s *shell) Execute(cmd string) (string, string, error) { } func (s *shell) Exit() { - s.stdin.Write([]byte("exit" + newline)) + _, _ = s.stdin.Write([]byte("exit" + newline)) // if it's possible to close stdin, do so (some backends, like the local one, // do support it) @@ -81,7 +81,7 @@ func (s *shell) Exit() { closer.Close() } - s.handle.Wait() + _ = s.handle.Wait() s.handle = nil s.stdin = nil diff --git a/pkg/prettyzone/prettyzone.go b/pkg/prettyzone/prettyzone.go index cb91babf2..17d6bfb0c 100644 --- a/pkg/prettyzone/prettyzone.go +++ b/pkg/prettyzone/prettyzone.go @@ -7,6 +7,7 @@ import ( "fmt" "io" "sort" + "strconv" "strings" "github.com/StackExchange/dnscontrol/v4/models" @@ -87,7 +88,6 @@ func PrettySort(records models.Records, origin string, defaultTTL uint32, commen // generateZoneFileHelper creates a pretty zonefile. func (z *ZoneGenData) generateZoneFileHelper(w io.Writer) error { - nameShortPrevious := "" sort.Sort(z) @@ -103,7 +103,6 @@ func (z *ZoneGenData) generateZoneFileHelper(w io.Writer) error { } } for i, rr := range z.Records { - // Fake types are commented out. prefix := "" _, ok := dns.StringToType[rr.Type] @@ -122,7 +121,7 @@ func (z *ZoneGenData) generateZoneFileHelper(w io.Writer) error { // ttl ttl := "" if rr.TTL != z.DefaultTTL && rr.TTL != 0 { - ttl = fmt.Sprint(rr.TTL) + ttl = strconv.FormatUint(uint64(rr.TTL), 10) } // type diff --git a/pkg/prettyzone/prettyzone_test.go b/pkg/prettyzone/prettyzone_test.go index 4c98cacf8..a344d13e0 100644 --- a/pkg/prettyzone/prettyzone_test.go +++ b/pkg/prettyzone/prettyzone_test.go @@ -30,7 +30,9 @@ func parseAndRegen(t *testing.T, buf *bytes.Buffer, expected string) { // Generate it back: buf2 := &bytes.Buffer{} - writeZoneFileRR(buf2, parsed, "bosun.org") + if err := writeZoneFileRR(buf2, parsed, "bosun.org"); err != nil { + t.Fatal(err) + } // Compare: if buf2.String() != expected { @@ -61,6 +63,7 @@ func writeZoneFileRR(w io.Writer, records []dns.RR, origin string) error { return WriteZoneFileRC(w, rcs, origin, 0, nil) } + func TestMostCommonTtl(t *testing.T) { var records []dns.RR var g, e uint32 @@ -117,7 +120,6 @@ func TestMostCommonTtl(t *testing.T) { if e != g { t.Fatalf("expected %d; got %d\n", e, g) } - } // func WriteZoneFile @@ -127,7 +129,9 @@ func TestWriteZoneFileSimple(t *testing.T) { r2, _ := dns.NewRR("bosun.org. 300 IN A 192.30.252.154") r3, _ := dns.NewRR("www.bosun.org. 300 IN CNAME bosun.org.") buf := &bytes.Buffer{} - writeZoneFileRR(buf, []dns.RR{r1, r2, r3}, "bosun.org") + if err := writeZoneFileRR(buf, []dns.RR{r1, r2, r3}, "bosun.org"); err != nil { + t.Fatal(err) + } expected := `$TTL 300 @ IN A 192.30.252.153 IN A 192.30.252.154 @@ -148,7 +152,9 @@ func TestWriteZoneFileSimpleTtl(t *testing.T) { r3, _ := dns.NewRR("bosun.org. 100 IN A 192.30.252.155") r4, _ := dns.NewRR("www.bosun.org. 300 IN CNAME bosun.org.") buf := &bytes.Buffer{} - writeZoneFileRR(buf, []dns.RR{r1, r2, r3, r4}, "bosun.org") + if err := writeZoneFileRR(buf, []dns.RR{r1, r2, r3, r4}, "bosun.org"); err != nil { + t.Fatal(err) + } expected := `$TTL 100 @ IN A 192.30.252.153 IN A 192.30.252.154 @@ -178,7 +184,9 @@ func TestWriteZoneFileMx(t *testing.T) { r8, _ := dns.NewRR("ccc.bosun.org. IN MX 40 aaa.example.com.") r9, _ := dns.NewRR("ccc.bosun.org. IN MX 1 ttt.example.com.") buf := &bytes.Buffer{} - writeZoneFileRR(buf, []dns.RR{r1, r2, r3, r4, r5, r6, r7, r8, r9}, "bosun.org") + if err := writeZoneFileRR(buf, []dns.RR{r1, r2, r3, r4, r5, r6, r7, r8, r9}, "bosun.org"); err != nil { + t.Fatal(err) + } if buf.String() != testdataZFMX { t.Log(buf.String()) t.Log(testdataZFMX) @@ -207,7 +215,9 @@ func TestWriteZoneFileSrv(t *testing.T) { r4, _ := dns.NewRR(`bosun.org. 300 IN SRV 20 10 5050 foo.com.`) r5, _ := dns.NewRR(`bosun.org. 300 IN SRV 10 10 5050 foo.com.`) buf := &bytes.Buffer{} - writeZoneFileRR(buf, []dns.RR{r1, r2, r3, r4, r5}, "bosun.org") + if err := writeZoneFileRR(buf, []dns.RR{r1, r2, r3, r4, r5}, "bosun.org"); err != nil { // 5 + t.Fatal(err) + } if buf.String() != testdataZFSRV { t.Log(buf.String()) t.Log(testdataZFSRV) @@ -230,7 +240,9 @@ func TestWriteZoneFilePtr(t *testing.T) { r2, _ := dns.NewRR(`bosun.org. 300 IN PTR barney.bosun.org.`) r3, _ := dns.NewRR(`bosun.org. 300 IN PTR alex.bosun.org.`) buf := &bytes.Buffer{} - writeZoneFileRR(buf, []dns.RR{r1, r2, r3}, "bosun.org") + if err := writeZoneFileRR(buf, []dns.RR{r1, r2, r3}, "bosun.org"); err != nil { + t.Fatal(err) + } if buf.String() != testdataZFPTR { t.Log(buf.String()) t.Log(testdataZFPTR) @@ -254,7 +266,9 @@ func TestWriteZoneFileCaa(t *testing.T) { r5, _ := dns.NewRR(`bosun.org. 300 IN CAA 0 iodef "https://example.net"`) r6, _ := dns.NewRR(`bosun.org. 300 IN CAA 1 iodef "mailto:example.com"`) buf := &bytes.Buffer{} - writeZoneFileRR(buf, []dns.RR{r1, r2, r3, r4, r5, r6}, "bosun.org") + if err := writeZoneFileRR(buf, []dns.RR{r1, r2, r3, r4, r5, r6}, "bosun.org"); err != nil { + t.Fatal(err) + } if buf.String() != testdataZFCAA { t.Log(buf.String()) t.Log(testdataZFCAA) @@ -298,7 +312,9 @@ func TestWriteZoneFileTxt(t *testing.T) { // Generate the zonefile: buf := &bytes.Buffer{} - writeZoneFileRR(buf, []dns.RR{rr}, "bosun.org") + if err := writeZoneFileRR(buf, []dns.RR{rr}, "bosun.org"); err != nil { + t.Fatal(err) + } gz := buf.String() if gz != ez { t.Log("got: " + gz) @@ -309,7 +325,6 @@ func TestWriteZoneFileTxt(t *testing.T) { // Reverse the process. Turn the zonefile into a list of records parseAndRegen(t, buf, ez) } - } // Test 1 of each record type @@ -344,7 +359,9 @@ func TestWriteZoneFileEach(t *testing.T) { d = append(d, mustNewRR(`bosun.org. 300 IN HTTPS 1 . alpn="h3,h2"`)) d = append(d, mustNewRR(`bosun.org. 300 IN SVCB 1 . alpn="h3,h2"`)) buf := &bytes.Buffer{} - writeZoneFileRR(buf, d, "bosun.org") + if err := writeZoneFileRR(buf, d, "bosun.org"); err != nil { + t.Fatal(err) + } if buf.String() != testdataZFEach { t.Log(buf.String()) t.Log(testdataZFEach) @@ -390,7 +407,9 @@ func TestWriteZoneFileSynth(t *testing.T) { recs = append(recs, rsynz) buf := &bytes.Buffer{} - WriteZoneFileRC(buf, recs, "bosun.org", 0, []string{"c1", "c2", "c3\nc4"}) + if err := WriteZoneFileRC(buf, recs, "bosun.org", 0, []string{"c1", "c2", "c3\nc4"}); err != nil { + t.Fatal(err) + } expected := `$TTL 300 ; c1 ; c2 @@ -438,7 +457,9 @@ func TestWriteZoneFileOrder(t *testing.T) { } buf := &bytes.Buffer{} - writeZoneFileRR(buf, records, "stackoverflow.com") + if err := writeZoneFileRR(buf, records, "stackoverflow.com"); err != nil { + t.Fatal(err) + } // Compare if buf.String() != testdataOrder { t.Log("Found:") @@ -458,7 +479,9 @@ func TestWriteZoneFileOrder(t *testing.T) { } // Generate buf := &bytes.Buffer{} - writeZoneFileRR(buf, records, "stackoverflow.com") + if err := writeZoneFileRR(buf, records, "stackoverflow.com"); err != nil { + t.Fatal(err) + } // Compare if buf.String() != testdataOrder { t.Log(buf.String()) @@ -532,7 +555,7 @@ func TestZoneLabelLess(t *testing.T) { zap */ - var tests = []struct { + tests := []struct { e1, e2 string expected bool }{ @@ -584,7 +607,7 @@ func TestZoneRrtypeLess(t *testing.T) { In zonefiles we want to list SOAs, then NSs, then all others. */ - var tests = []struct { + tests := []struct { e1, e2 string expected bool }{ diff --git a/pkg/prettyzone/sorting.go b/pkg/prettyzone/sorting.go index 160421dcc..e7095e5bd 100644 --- a/pkg/prettyzone/sorting.go +++ b/pkg/prettyzone/sorting.go @@ -29,7 +29,7 @@ func (z *ZoneGenData) Less(i, j int) bool { //fmt.Printf("DEBUG: LabelLess(%q, %q) = %v %q %q\n", compA, compB, LabelLess(compA, compB), a.Name, b.Name) compA, compB := a.NameFQDN, b.NameFQDN - // If we are at the apex, pass "@" to the Less function. + // Unify FQDNs to "@". LabelLess needs FQDNs to be "@" to work properly. if a.Name == "@" { compA = "@" } @@ -68,7 +68,7 @@ func (z *ZoneGenData) Less(i, j int) bool { } return a.MxPreference < b.MxPreference case "SRV": - //ta2, tb2 := a.(*dns.SRV), b.(*dns.SRV) + // ta2, tb2 := a.(*dns.SRV), b.(*dns.SRV) pa, pb := a.SrvPort, b.SrvPort if pa != pb { return pa < pb @@ -88,13 +88,13 @@ func (z *ZoneGenData) Less(i, j int) bool { } return a.SvcPriority < b.SvcPriority case "PTR": - //ta2, tb2 := a.(*dns.PTR), b.(*dns.PTR) + // ta2, tb2 := a.(*dns.PTR), b.(*dns.PTR) pa, pb := a.GetTargetField(), b.GetTargetField() if pa != pb { return pa < pb } case "CAA": - //ta2, tb2 := a.(*dns.CAA), b.(*dns.CAA) + // ta2, tb2 := a.(*dns.CAA), b.(*dns.CAA) // sort by tag pa, pb := a.CaaTag, b.CaaTag if pa != pb { @@ -123,7 +123,7 @@ func (z *ZoneGenData) Less(i, j int) bool { default: // pass through. String comparison is sufficient. } - //fmt.Printf("DEBUG: Less %q < %q == %v\n", a.String(), b.String(), a.String() < b.String()) + // fmt.Printf("DEBUG: Less %q < %q == %v\n", a.String(), b.String(), a.String() < b.String()) return a.String() < b.String() } @@ -138,7 +138,7 @@ func LabelLess(a, b string) bool { } // Sort @ at the top, then *, then everything else lexigraphically. - // i.e. @ always is less. * is is less than everything but @. + // i.e. @ always is less. * is less than everything but @. if a == "@" { return true } @@ -171,11 +171,10 @@ func LabelLess(a, b string) bool { for i, j := ia, ib; minIdx >= 0; i, j, minIdx = i-1, j-1, minIdx-1 { // Compare as[i] < bs[j] // Sort @ at the top, then *, then everything else. - // i.e. @ always is less. * is is less than everything but @. + // i.e. @ always is less. * is less than everything but @. // If both are numeric, compare as integers, otherwise as strings. if as[i] != bs[j] { - // If the first element is *, it is always less. if i == 0 && as[i] == "*" { return true @@ -207,7 +206,8 @@ func zoneRrtypeLess(a, b string) bool { // List SOAs, NSs, etc. then all others alphabetically. - for _, t := range []string{"SOA", "NS", "CNAME", + for _, t := range []string{ + "SOA", "NS", "CNAME", "A", "AAAA", "MX", "SRV", "TXT", } { if a == t { diff --git a/pkg/printer/printer.go b/pkg/printer/printer.go index 0686a5ea0..9826b4eed 100644 --- a/pkg/printer/printer.go +++ b/pkg/printer/printer.go @@ -32,7 +32,7 @@ type Printer interface { Println(lines ...string) Warnf(fmt string, args ...interface{}) Errorf(fmt string, args ...interface{}) - PrintfIf(print bool, fmt string, args ...interface{}) + PrintfIf(prnt bool, fmt string, args ...interface{}) } // Debugf is called to print/format debug information. @@ -61,20 +61,18 @@ func Warnf(fmt string, args ...interface{}) { // } // PrintfIf is called to optionally print something. -func PrintfIf(print bool, fmt string, args ...interface{}) { - DefaultPrinter.PrintfIf(print, fmt, args...) +func PrintfIf(prnt bool, fmt string, args ...interface{}) { + DefaultPrinter.PrintfIf(prnt, fmt, args...) } -var ( - // DefaultPrinter is the default Printer, used by Debugf, Printf, and Warnf. - DefaultPrinter = &ConsolePrinter{ - Reader: bufio.NewReader(os.Stdin), - Writer: os.Stdout, - Verbose: false, - } -) +// DefaultPrinter is the default Printer, used by Debugf, Printf, and Warnf. +var DefaultPrinter = &ConsolePrinter{ + Reader: bufio.NewReader(os.Stdin), + Writer: os.Stdout, + Verbose: false, +} -// SkinnyReport is true to to disable certain print statements. +// SkinnyReport is true to disable certain print statements. // This is a hack until we have the new printer replacement. The long // variable name is easy to grep for when we make the conversion. var SkinnyReport = true @@ -211,8 +209,8 @@ func (c ConsolePrinter) Errorf(format string, args ...interface{}) { } // PrintfIf is called to optionally print/format a message. -func (c ConsolePrinter) PrintfIf(print bool, format string, args ...interface{}) { - if print { +func (c ConsolePrinter) PrintfIf(prnt bool, format string, args ...interface{}) { + if prnt { fmt.Fprintf(c.Writer, format, args...) } } diff --git a/pkg/recorddb/recorddb.go b/pkg/recorddb/recorddb.go index 7e9665a0d..786c492e5 100644 --- a/pkg/recorddb/recorddb.go +++ b/pkg/recorddb/recorddb.go @@ -25,7 +25,7 @@ func NewFromRecords(recs models.Records) *RecordDB { // ContainsLT returns true if recdb contains rec. Matching is done // on the record's label and type (i.e. the RecordKey) -//func (recdb RecordDB) ContainsLT(rec *models.RecordConfig) bool { +// func (recdb RecordDB) ContainsLT(rec *models.RecordConfig) bool { // _, ok := recdb.labelAndTypeMap[rec.Key()] // return ok //} diff --git a/pkg/rejectif/caa.go b/pkg/rejectif/caa.go index f11d6a271..3c21eb138 100644 --- a/pkg/rejectif/caa.go +++ b/pkg/rejectif/caa.go @@ -1,7 +1,7 @@ package rejectif import ( - "fmt" + "errors" "strings" "github.com/StackExchange/dnscontrol/v4/models" @@ -12,7 +12,7 @@ import ( // CaaFlagIsNonZero identifies CAA records where tag is no zero. func CaaFlagIsNonZero(rc *models.RecordConfig) error { if rc.CaaFlag != 0 { - return fmt.Errorf("caa flag is non-zero") + return errors.New("caa flag is non-zero") } return nil } @@ -22,7 +22,7 @@ func CaaFlagIsNonZero(rc *models.RecordConfig) error { // See https://github.com/StackExchange/dnscontrol/issues/1374 func CaaTargetContainsWhitespace(rc *models.RecordConfig) error { if strings.ContainsAny(rc.GetTargetField(), " \t\r\n") { - return fmt.Errorf("caa target contains whitespace") + return errors.New("caa target contains whitespace") } return nil } diff --git a/pkg/rejectif/label.go b/pkg/rejectif/label.go index f82d02575..f4304b792 100644 --- a/pkg/rejectif/label.go +++ b/pkg/rejectif/label.go @@ -1,7 +1,7 @@ package rejectif import ( - "fmt" + "errors" "github.com/StackExchange/dnscontrol/v4/models" ) @@ -12,7 +12,7 @@ import ( // is only permitted at the apex. func LabelNotApex(rc *models.RecordConfig) error { if rc.GetLabel() != "@" { - return fmt.Errorf("use not at apex") + return errors.New("use not at apex") } return nil } diff --git a/pkg/rejectif/mx.go b/pkg/rejectif/mx.go index 61b96aba0..7b0fa0a70 100644 --- a/pkg/rejectif/mx.go +++ b/pkg/rejectif/mx.go @@ -1,7 +1,7 @@ package rejectif import ( - "fmt" + "errors" "github.com/StackExchange/dnscontrol/v4/models" ) @@ -12,7 +12,7 @@ import ( // This is needed by providers that don't support RFC 7505. func MxNull(rc *models.RecordConfig) error { if rc.GetTargetField() == "." { - return fmt.Errorf("mx has null target") + return errors.New("mx has null target") } return nil } diff --git a/pkg/rejectif/srv.go b/pkg/rejectif/srv.go index 822b9ac19..8071ed6b9 100644 --- a/pkg/rejectif/srv.go +++ b/pkg/rejectif/srv.go @@ -1,7 +1,7 @@ package rejectif import ( - "fmt" + "errors" "github.com/StackExchange/dnscontrol/v4/models" ) @@ -11,7 +11,7 @@ import ( // SrvHasNullTarget detects SRV records that has a null target. func SrvHasNullTarget(rc *models.RecordConfig) error { if rc.GetTargetField() == "." { - return fmt.Errorf("srv has null target") + return errors.New("srv has null target") } return nil } diff --git a/pkg/rejectif/txt.go b/pkg/rejectif/txt.go index 0df3be196..7f3f2ef31 100644 --- a/pkg/rejectif/txt.go +++ b/pkg/rejectif/txt.go @@ -1,6 +1,7 @@ package rejectif import ( + "errors" "fmt" "strings" @@ -12,7 +13,7 @@ import ( // TxtHasBackslash audits TXT records for strings that contains one or more backslashes. func TxtHasBackslash(rc *models.RecordConfig) error { if strings.Contains(rc.GetTargetTXTJoined(), `\`) { - return fmt.Errorf("txtstring contains backslashes") + return errors.New("txtstring contains backslashes") } return nil } @@ -20,7 +21,7 @@ func TxtHasBackslash(rc *models.RecordConfig) error { // TxtHasBackticks audits TXT records for strings that contain backticks. func TxtHasBackticks(rc *models.RecordConfig) error { if strings.Contains(rc.GetTargetTXTJoined(), "`") { - return fmt.Errorf("txtstring contains backtick") + return errors.New("txtstring contains backtick") } return nil } @@ -28,7 +29,7 @@ func TxtHasBackticks(rc *models.RecordConfig) error { // TxtHasDoubleQuotes audits TXT records for strings that contain doublequotes. func TxtHasDoubleQuotes(rc *models.RecordConfig) error { if strings.Contains(rc.GetTargetTXTJoined(), `"`) { - return fmt.Errorf("txtstring contains doublequotes") + return errors.New("txtstring contains doublequotes") } return nil } @@ -36,7 +37,7 @@ func TxtHasDoubleQuotes(rc *models.RecordConfig) error { // TxtHasSemicolon audits TXT records for strings that contain backticks. func TxtHasSemicolon(rc *models.RecordConfig) error { if strings.Contains(rc.GetTargetTXTJoined(), ";") { - return fmt.Errorf("txtstring contains semicolon") + return errors.New("txtstring contains semicolon") } return nil } @@ -44,7 +45,7 @@ func TxtHasSemicolon(rc *models.RecordConfig) error { // TxtHasSingleQuotes audits TXT records for strings that contain single-quotes. func TxtHasSingleQuotes(rc *models.RecordConfig) error { if strings.Contains(rc.GetTargetTXTJoined(), "'") { - return fmt.Errorf("txtstring contains single-quotes") + return errors.New("txtstring contains single-quotes") } return nil } @@ -53,7 +54,7 @@ func TxtHasSingleQuotes(rc *models.RecordConfig) error { func TxtHasTrailingSpace(rc *models.RecordConfig) error { txt := rc.GetTargetTXTJoined() if txt != "" && txt[ultimate(txt)] == ' ' { - return fmt.Errorf("txtstring ends with space") + return errors.New("txtstring ends with space") } return nil } @@ -61,7 +62,7 @@ func TxtHasTrailingSpace(rc *models.RecordConfig) error { // TxtHasUnpairedDoubleQuotes audits TXT records for strings that contain unpaired doublequotes. func TxtHasUnpairedDoubleQuotes(rc *models.RecordConfig) error { if strings.Count(rc.GetTargetTXTJoined(), `"`)%2 == 1 { - return fmt.Errorf("txtstring contains unpaired doublequotes") + return errors.New("txtstring contains unpaired doublequotes") } return nil } @@ -69,7 +70,7 @@ func TxtHasUnpairedDoubleQuotes(rc *models.RecordConfig) error { // TxtIsEmpty audits TXT records for empty strings. func TxtIsEmpty(rc *models.RecordConfig) error { if len(rc.GetTargetTXTJoined()) == 0 { - return fmt.Errorf("txtstring is empty") + return errors.New("txtstring is empty") } return nil } @@ -90,7 +91,7 @@ func TxtLongerThan(maxLength int) func(rc *models.RecordConfig) error { func TxtStartsOrEndsWithSpaces(rc *models.RecordConfig) error { txt := rc.GetTargetTXTJoined() if len(txt) > 0 && (txt[0] == ' ' || txt[len(txt)-1] == ' ') { - return fmt.Errorf("txtstring starts or ends with spaces") + return errors.New("txtstring starts or ends with spaces") } return nil } diff --git a/pkg/rfc4183/ipv6.go b/pkg/rfc4183/ipv6.go index d6595413e..c3233e215 100644 --- a/pkg/rfc4183/ipv6.go +++ b/pkg/rfc4183/ipv6.go @@ -1,14 +1,12 @@ package rfc4183 -import ( - "fmt" -) +import "errors" // reverseIPv6 returns the ipv6.arpa string suitable for reverse DNS lookups. func reverseIPv6(ip []byte, maskbits int) (arpa string, err error) { // Must be IPv6 if len(ip) != 16 { - return "", fmt.Errorf("not IPv6") + return "", errors.New("not IPv6") } buf := []byte("x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.ip6.arpa") diff --git a/pkg/rfc4183/mode.go b/pkg/rfc4183/mode.go index 587171c8c..a9b175338 100644 --- a/pkg/rfc4183/mode.go +++ b/pkg/rfc4183/mode.go @@ -1,17 +1,20 @@ package rfc4183 import ( + "errors" "fmt" "strings" ) -var newmode bool -var modeset bool +var ( + newmode bool + modeset bool +) // SetCompatibilityMode sets REV() compatibility mode. func SetCompatibilityMode(m string) error { if modeset { - return fmt.Errorf("ERROR: REVCOMPAT() already set") + return errors.New("ERROR: REVCOMPAT() already set") } modeset = true diff --git a/pkg/rfc4183/reverse.go b/pkg/rfc4183/reverse.go index 25b2c9587..87f17536b 100644 --- a/pkg/rfc4183/reverse.go +++ b/pkg/rfc4183/reverse.go @@ -10,7 +10,6 @@ import ( // a in-addr name. IP addresses are assumed to be /32 or /128 CIDR blocks. // CIDR host bits are changed to 0s. func ReverseDomainName(cidr string) (string, error) { - // Mask missing? Add it. if !strings.Contains(cidr, "/") { a, err := netip.ParseAddr(cidr) @@ -75,5 +74,4 @@ func ReverseDomainName(cidr string) (string, error) { return fmt.Sprintf("%d-%d.%d.in-addr.arpa", y, m, x), nil } return "", fmt.Errorf("fewer than 8 mask bits is not reasonable: %v", cidr) - } diff --git a/pkg/rfc4183/reverse_test.go b/pkg/rfc4183/reverse_test.go index 4c53bced3..b93821418 100644 --- a/pkg/rfc4183/reverse_test.go +++ b/pkg/rfc4183/reverse_test.go @@ -6,7 +6,7 @@ import ( ) func TestReverse(t *testing.T) { - var tests = []struct { + tests := []struct { in string out string }{ @@ -106,7 +106,7 @@ func TestReverse(t *testing.T) { } func TestReverseErrors(t *testing.T) { - var tests = []struct { + tests := []struct { in string }{ {"0.0.0.0/0"}, diff --git a/pkg/rtypecontrol/pave.go b/pkg/rtypecontrol/pave.go index 871eaab65..b30ae3f6d 100644 --- a/pkg/rtypecontrol/pave.go +++ b/pkg/rtypecontrol/pave.go @@ -10,7 +10,6 @@ import ( // 'i': uinet16 (will convert strings, truncate floats, etc) // 's': Valid only if string. func PaveArgs(args []any, argTypes string) error { - if len(args) != len(argTypes) { return fmt.Errorf("wrong number of arguments. Expected %v, got %v", len(argTypes), len(args)) } @@ -18,7 +17,6 @@ func PaveArgs(args []any, argTypes string) error { for i, at := range argTypes { arg := args[i] switch at { - case 'i': // uint16 if s, ok := arg.(string); ok { // Is this a string-encoded int? ni, err := strconv.Atoi(s) @@ -42,7 +40,6 @@ func PaveArgs(args []any, argTypes string) error { } else { args[i] = fmt.Sprintf("%v", arg) } - } } diff --git a/pkg/rtypes/postprocess.go b/pkg/rtypes/postprocess.go index 91a14ddad..1631ab42d 100644 --- a/pkg/rtypes/postprocess.go +++ b/pkg/rtypes/postprocess.go @@ -8,11 +8,9 @@ import ( ) func PostProcess(domains []*models.DomainConfig) error { - var err error for _, dc := range domains { - for _, rawRec := range dc.RawRecords { rec := &models.RecordConfig{ Type: rawRec.Type, @@ -33,9 +31,8 @@ func PostProcess(domains []*models.DomainConfig) error { } // Call the proper initialize function. - // TODO(tlim): Good candiate for an interface or a lookup table. + // TODO(tlim): Good candidate for an interface or a lookup table. switch rawRec.Type { - case "CLOUDFLAREAPI_SINGLE_REDIRECT": err = cfsingleredirect.FromRaw(rec, rawRec.Args) rec.SetLabel("@", dc.Name) diff --git a/pkg/spflib/flatten.go b/pkg/spflib/flatten.go index 2268e8d87..7cc3fcc9a 100644 --- a/pkg/spflib/flatten.go +++ b/pkg/spflib/flatten.go @@ -9,23 +9,24 @@ import ( // use this to split TXT records into 255 sized chunks for RFC 4408 // https://tools.ietf.org/html/rfc4408#section-3.1.3 // Borrowed from https://stackoverflow.com/a/61469854/11477663 +// TODO(tlim): Consider replacing with https://pkg.go.dev/slices#Chunk func Chunks(s string, chunkSize int) []string { if chunkSize >= len(s) { return []string{s} } var chunks []string chunk := make([]rune, chunkSize) - len := 0 + lngth := 0 for _, r := range s { - chunk[len] = r - len++ - if len == chunkSize { + chunk[lngth] = r + lngth++ + if lngth == chunkSize { chunks = append(chunks, string(chunk)) - len = 0 + lngth = 0 } } - if len > 0 { - chunks = append(chunks, string(chunk[:len])) + if lngth > 0 { + chunks = append(chunks, string(chunk[:lngth])) } return chunks } @@ -58,7 +59,6 @@ func (s *SPFRecord) TXTSplit(pattern string, overhead int, txtMaxSize int) map[s m := map[string][]string{} s.split("@", pattern, 1, m, overhead, txtMaxSize) return m - } func (s *SPFRecord) split(thisfqdn string, pattern string, nextIdx int, m map[string][]string, overhead int, txtMaxSize int) { diff --git a/pkg/spflib/parse.go b/pkg/spflib/parse.go index b48f9d6b3..2f75d230d 100644 --- a/pkg/spflib/parse.go +++ b/pkg/spflib/parse.go @@ -1,6 +1,7 @@ package spflib import ( + "errors" "fmt" "strings" ) @@ -28,7 +29,7 @@ var qualifiers = map[byte]bool{ // Parse parses a raw SPF record. func Parse(text string, dnsres Resolver) (*SPFRecord, error) { if !strings.HasPrefix(text, "v=spf1 ") { - return nil, fmt.Errorf("not an SPF record") + return nil, errors.New("not an SPF record") } parts := strings.Split(text, " ") rec := &SPFRecord{} @@ -73,7 +74,7 @@ func Parse(text string, dnsres Resolver) (*SPFRecord, error) { } p.IncludeRecord, err = Parse(subRecord, dnsres) if err != nil { - return nil, fmt.Errorf("in included SPF: %s", err) + return nil, fmt.Errorf("in included SPF: %w", err) } } } else if strings.HasPrefix(part, "exists:") || strings.HasPrefix(part, "ptr:") { @@ -81,7 +82,6 @@ func Parse(text string, dnsres Resolver) (*SPFRecord, error) { } else { return nil, fmt.Errorf("unsupported SPF part %s", part) } - } return rec, nil } diff --git a/pkg/spflib/parse_test.go b/pkg/spflib/parse_test.go index 098e4f779..b90ad9e2b 100644 --- a/pkg/spflib/parse_test.go +++ b/pkg/spflib/parse_test.go @@ -9,7 +9,6 @@ import ( ) func dump(rec *SPFRecord, indent string, w io.Writer) { - fmt.Fprintf(w, "%sTotal Lookups: %d\n", indent, rec.Lookups()) fmt.Fprint(w, indent+"v=spf1") for _, p := range rec.Parts { @@ -53,19 +52,21 @@ func TestParse(t *testing.T) { if err != nil { t.Fatal(err) } - rec, err := Parse(strings.Join([]string{"v=spf1", + rec, err := Parse(strings.Join([]string{ + "v=spf1", "ip4:198.252.206.0/24", "ip4:192.111.0.0/24", "include:_spf.google.com", "include:mailgun.org", - //"include:spf-basic.fogcreek.com", + // "include:spf-basic.fogcreek.com", "include:mail.zendesk.com", "include:servers.mcsv.net", "include:sendgrid.net", "include:spf.mtasv.net", "exists:%{i}._spf.sparkpostmail.com", "ptr:sparkpostmail.com", - "~all"}, " "), dnsres) + "~all", + }, " "), dnsres) if err != nil { t.Fatal(err) } @@ -90,9 +91,11 @@ func TestParseRedirectNotLast(t *testing.T) { if err != nil { t.Fatal(err) } - _, err = Parse(strings.Join([]string{"v=spf1", + _, err = Parse(strings.Join([]string{ + "v=spf1", "redirect=servers.mcsv.net", - "~all"}, " "), dnsres) + "~all", + }, " "), dnsres) if err == nil { t.Fatal("should fail") } @@ -104,7 +107,8 @@ func TestParseRedirectColon(t *testing.T) { if err != nil { t.Fatal(err) } - _, err = Parse(strings.Join([]string{"v=spf1", + _, err = Parse(strings.Join([]string{ + "v=spf1", "redirect:servers.mcsv.net", }, " "), dnsres) if err == nil { @@ -117,8 +121,10 @@ func TestParseRedirectOnly(t *testing.T) { if err != nil { t.Fatal(err) } - rec, err := Parse(strings.Join([]string{"v=spf1", - "redirect=servers.mcsv.net"}, " "), dnsres) + rec, err := Parse(strings.Join([]string{ + "v=spf1", + "redirect=servers.mcsv.net", + }, " "), dnsres) if err != nil { t.Fatal(err) } @@ -130,9 +136,11 @@ func TestParseRedirectLast(t *testing.T) { if err != nil { t.Fatal(err) } - rec, err := Parse(strings.Join([]string{"v=spf1", + rec, err := Parse(strings.Join([]string{ + "v=spf1", "ip4:198.252.206.0/24", - "redirect=servers.mcsv.net"}, " "), dnsres) + "redirect=servers.mcsv.net", + }, " "), dnsres) if err != nil { t.Fatal(err) } diff --git a/pkg/spflib/resolver.go b/pkg/spflib/resolver.go index cf1cadf1e..16d72a31f 100644 --- a/pkg/spflib/resolver.go +++ b/pkg/spflib/resolver.go @@ -125,6 +125,7 @@ func (c *cache) ResolveErrors() (errs []error) { } return } + func (c *cache) Save(filename string) error { outRecs := make(map[string]*cacheEntry, len(c.records)) for k, entry := range c.records { @@ -136,5 +137,5 @@ func (c *cache) Save(filename string) error { } } dat, _ := json.MarshalIndent(outRecs, "", " ") - return os.WriteFile(filename, dat, 0644) + return os.WriteFile(filename, dat, 0o644) } diff --git a/pkg/transform/arpa.go b/pkg/transform/arpa.go index 704222bbe..b82f827b7 100644 --- a/pkg/transform/arpa.go +++ b/pkg/transform/arpa.go @@ -12,7 +12,6 @@ import ( // For cases not covered by RFC2317, implement RFC4183 // The host bits must all be zeros. func ReverseDomainName(cidr string) (string, error) { - if rfc4183.IsRFC4183Mode() { return rfc4183.ReverseDomainName(cidr) } diff --git a/pkg/transform/arpa_test.go b/pkg/transform/arpa_test.go index a1486a936..b209c1322 100644 --- a/pkg/transform/arpa_test.go +++ b/pkg/transform/arpa_test.go @@ -6,7 +6,7 @@ import ( ) func TestReverse(t *testing.T) { - var tests = []struct { + tests := []struct { in string isError bool out string diff --git a/pkg/transform/ptr.go b/pkg/transform/ptr.go index 15b320718..53b71d9bc 100644 --- a/pkg/transform/ptr.go +++ b/pkg/transform/ptr.go @@ -63,7 +63,6 @@ var isRfc2317Format1 = regexp.MustCompile(`(\d{1,3})/(\d{1,3})\.(\d{1,3})\.(\d{1 // ipMatchesClasslessDomain returns true if ip is appropriate for domain. // domain is a reverse DNS lookup zone (in-addr.arpa) as described in RFC2317. func ipMatchesClasslessDomain(ip net.IP, domain string) bool { - // The unofficial but preferred format in RFC2317: m := isRfc2317Format1.FindStringSubmatch(domain) if m != nil { diff --git a/pkg/transform/ptr_test.go b/pkg/transform/ptr_test.go index a0112e808..93a1d3a91 100644 --- a/pkg/transform/ptr_test.go +++ b/pkg/transform/ptr_test.go @@ -56,8 +56,10 @@ func TestPtrMagic(t *testing.T) { // User manually reversed addresses: {"1.1.1.1.in-addr.arpa.", "1.1.in-addr.arpa", "1.1", false}, - {"1.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.8.b.d.0.1.0.0.2.ip6.arpa.", - "0.2.ip6.arpa", "1.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.8.b.d.0.1.0", false}, + { + "1.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.8.b.d.0.1.0.0.2.ip6.arpa.", + "0.2.ip6.arpa", "1.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.8.b.d.0.1.0", false, + }, // Error cases: {"1.1.1.1.in-addr.arpa.", "2.2.in-addr.arpa", "", true}, diff --git a/pkg/transform/transform.go b/pkg/transform/transform.go index 5f0fdab6e..a4c41d97b 100644 --- a/pkg/transform/transform.go +++ b/pkg/transform/transform.go @@ -1,6 +1,7 @@ package transform import ( + "errors" "fmt" "net" "strings" @@ -22,7 +23,7 @@ func ipToUint(i net.IP) (uint32, error) { return r, nil } -// UintToIP convert a 32-bit into into a net.IP. +// UintToIP convert a 32-bit into a net.IP. func UintToIP(u uint32) net.IP { return net.IPv4( byte((u>>24)&255), @@ -51,7 +52,6 @@ func DecodeTransformTable(transforms string) ([]IPConversion, error) { parseList := func(s string) ([]net.IP, error) { ips := []net.IP{} for _, ip := range strings.Split(s, ",") { - if ip == "" { continue } @@ -77,7 +77,7 @@ func DecodeTransformTable(transforms string) ([]IPConversion, error) { return nil, fmt.Errorf("transform_table Low should be less than High. row (%v) %v>%v (%v)", ri, con.Low, con.High, transforms) } if len(con.NewBases) > 0 && len(con.NewIPs) > 0 { - return nil, fmt.Errorf("transform_table_rows should only specify one of NewBases or NewIPs, Not both") + return nil, errors.New("transform_table_rows should only specify one of NewBases or NewIPs, Not both") } result = append(result, con) } @@ -104,15 +104,15 @@ func IPToList(address net.IP, transforms []IPConversion) ([]net.IP, error) { return nil, err } for _, conv := range transforms { - min, err := ipToUint(conv.Low) + min_, err := ipToUint(conv.Low) if err != nil { return nil, err } - max, err := ipToUint(conv.High) + max_, err := ipToUint(conv.High) if err != nil { return nil, err } - if (thisIP >= min) && (thisIP <= max) { + if (thisIP >= min_) && (thisIP <= max_) { if len(conv.NewIPs) > 0 { return conv.NewIPs, nil } @@ -122,7 +122,7 @@ func IPToList(address net.IP, transforms []IPConversion) ([]net.IP, error) { if err != nil { return nil, err } - list = append(list, UintToIP(newbase+(thisIP-min))) + list = append(list, UintToIP(newbase+(thisIP-min_))) } return list, nil } diff --git a/pkg/transform/transform_test.go b/pkg/transform/transform_test.go index c2b070a81..b11631920 100644 --- a/pkg/transform/transform_test.go +++ b/pkg/transform/transform_test.go @@ -68,6 +68,7 @@ func Test_DecodeTransformTable_1(t *testing.T) { testIP(t, "NewBase[1]", "7.6.5.4", result[1].NewBases[0]) // test_ip(t, "newIP[1]", "", result[0].NewIP) } + func Test_DecodeTransformTable_NewIP(t *testing.T) { result, err := DecodeTransformTable("1.2.3.4 ~ 2.3.4.5 ~ ~ 3.4.5.6 ") if err != nil { @@ -104,8 +105,7 @@ func Test_DecodeTransformTable_Base_and_IP(t *testing.T) { } func Test_IP(t *testing.T) { - - var transforms1 = []IPConversion{{ + transforms1 := []IPConversion{{ Low: net.ParseIP("11.11.11.0"), High: net.ParseIP("11.11.11.20"), NewBases: []net.IP{net.ParseIP("99.99.99.0")}, @@ -128,7 +128,7 @@ func Test_IP(t *testing.T) { }} // NO TRANSFORMS ON 99.x.x.x PLZ - var tests = []struct { + tests := []struct { experiment string expected string }{ @@ -172,23 +172,23 @@ func Test_IP(t *testing.T) { } func Test_IP_NewIP(t *testing.T) { - - var transforms1 = []IPConversion{{ - Low: net.ParseIP("11.11.11.0"), - High: net.ParseIP("11.11.11.20"), - NewIPs: []net.IP{net.ParseIP("1.1.1.1")}, - }, { - Low: net.ParseIP("22.22.22.0"), - High: net.ParseIP("22.22.22.40"), - NewIPs: []net.IP{net.ParseIP("2.2.2.2")}, - }, { - Low: net.ParseIP("33.33.33.20"), - High: net.ParseIP("33.33.35.40"), - NewIPs: []net.IP{net.ParseIP("3.3.3.3")}, - }, + transforms1 := []IPConversion{ + { + Low: net.ParseIP("11.11.11.0"), + High: net.ParseIP("11.11.11.20"), + NewIPs: []net.IP{net.ParseIP("1.1.1.1")}, + }, { + Low: net.ParseIP("22.22.22.0"), + High: net.ParseIP("22.22.22.40"), + NewIPs: []net.IP{net.ParseIP("2.2.2.2")}, + }, { + Low: net.ParseIP("33.33.33.20"), + High: net.ParseIP("33.33.35.40"), + NewIPs: []net.IP{net.ParseIP("3.3.3.3")}, + }, } - var tests = []struct { + tests := []struct { experiment string expected string }{ diff --git a/pkg/txtutil/txtcode.go b/pkg/txtutil/txtcode.go index b125cac4f..c20ec6340 100644 --- a/pkg/txtutil/txtcode.go +++ b/pkg/txtutil/txtcode.go @@ -70,10 +70,10 @@ func txtDecode(s string) (string, error) { /* BNF: - txttarget := `""`` | item | item ` ` item* + txttarget := `""`` | item | item ` item* item := quoteditem | unquoteditem quoteditem := quote innertxt quote - quote := `"` + := `"` innertxt := (escaped | printable )* escaped := `\\` | `\"` printable := (printable ASCII chars) @@ -81,16 +81,14 @@ func txtDecode(s string) (string, error) { */ - //printer.Printf("DEBUG: txtDecode txt inboundv=%v\n", s) + // printer.Printf("DEBUG: txtDecode txt inboundv=%v\n", s) b := &bytes.Buffer{} state := StateStart for i, c := range s { - - //printer.Printf("DEBUG: state=%v rune=%v\n", state, string(c)) + // printer.Printf("DEBUG: state=%v rune=%v\n", state, string(c)) switch state { - case StateStart: if c == ' ' { // skip whitespace @@ -133,18 +131,17 @@ func txtDecode(s string) (string, error) { } else { return "", fmt.Errorf("txtDecode expected whitespace after close quote q(%q)", s) } - } } r := b.String() - //printer.Printf("DEBUG: txtDecode txt decodedv=%v\n", r) + // printer.Printf("DEBUG: txtDecode txt decodedv=%v\n", r) return r, nil } // txtEncode encodes TXT strings in RFC1035 format as interpreted by Tom. func txtEncode(ts []string) string { - //printer.Printf("DEBUG: txtEncode txt outboundv=%v\n", ts) + // printer.Printf("DEBUG: txtEncode txt outboundv=%v\n", ts) if (len(ts) == 0) || (strings.Join(ts, "") == "") { return `""` } @@ -160,6 +157,6 @@ func txtEncode(ts []string) string { } t := strings.Join(r, ` `) - //printer.Printf("DEBUG: txtEncode txt encodedv=%v\n", t) + // printer.Printf("DEBUG: txtEncode txt encodedv=%v\n", t) return t } diff --git a/pkg/txtutil/txtcode_test.go b/pkg/txtutil/txtcode_test.go index d8375ba40..6fd4c8955 100644 --- a/pkg/txtutil/txtcode_test.go +++ b/pkg/txtutil/txtcode_test.go @@ -21,20 +21,34 @@ func TestTxtDecode(t *testing.T) { {`"aaa" "bbb"`, []string{`aaa`, `bbb`}}, {`"a\"a" "bbb"`, []string{`a"a`, `bbb`}}, // Seen in live traffic: - {"\"BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB\"", - []string{r("B", 254)}}, - {"\"CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC\"", - []string{r("C", 255)}}, - {"\"DDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDD\" \"D\"", - []string{r("D", 255), "D"}}, - {"\"EEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE\" \"EEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE\"", - []string{r("E", 255), r("E", 255)}}, - {"\"FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF\" \"FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF\" \"F\"", - []string{r("F", 255), r("F", 255), "F"}}, - {"\"GGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGG\" \"GGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGG\" \"GGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGG\"", - []string{r("G", 255), r("G", 255), r("G", 255)}}, - {"\"HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH\" \"HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH\" \"HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH\" \"H\"", - []string{r("H", 255), r("H", 255), r("H", 255), "H"}}, + { + "\"BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB\"", + []string{r("B", 254)}, + }, + { + "\"CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC\"", + []string{r("C", 255)}, + }, + { + "\"DDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDD\" \"D\"", + []string{r("D", 255), "D"}, + }, + { + "\"EEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE\" \"EEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE\"", + []string{r("E", 255), r("E", 255)}, + }, + { + "\"FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF\" \"FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF\" \"F\"", + []string{r("F", 255), r("F", 255), "F"}, + }, + { + "\"GGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGG\" \"GGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGG\" \"GGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGG\"", + []string{r("G", 255), r("G", 255), r("G", 255)}, + }, + { + "\"HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH\" \"HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH\" \"HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH\" \"H\"", + []string{r("H", 255), r("H", 255), r("H", 255), "H"}, + }, {"\"quo'te\"", []string{`quo'te`}}, {"\"blah`blah\"", []string{"blah`blah"}}, {"\"quo\\\"te\"", []string{`quo"te`}}, diff --git a/pkg/txtutil/txtutil.go b/pkg/txtutil/txtutil.go index a6caf5e05..4a859b1bb 100644 --- a/pkg/txtutil/txtutil.go +++ b/pkg/txtutil/txtutil.go @@ -13,7 +13,7 @@ func splitChunks(buf string, lim int) []string { chunks = append(chunks, chunk) } if len(buf) > 0 { - chunks = append(chunks, buf[:]) + chunks = append(chunks, buf) } return chunks } diff --git a/pkg/zonerecs/zonerecords.go b/pkg/zonerecs/zonerecords.go index b43f06b8a..7904ee99c 100644 --- a/pkg/zonerecs/zonerecords.go +++ b/pkg/zonerecs/zonerecords.go @@ -8,7 +8,6 @@ import ( // post-processing, and then calls GetZoneRecordsCorrections. The // name sucks because all the good names were taken. func CorrectZoneRecords(driver models.DNSProvider, dc *models.DomainConfig) ([]*models.Correction, []*models.Correction, int, error) { - existingRecords, err := driver.GetZoneRecords(dc.Name, dc.Metadata) if err != nil { return nil, nil, 0, err @@ -30,7 +29,9 @@ func CorrectZoneRecords(driver models.DNSProvider, dc *models.DomainConfig) ([]* } // punycode - dc.Punycode() + if err := dc.Punycode(); err != nil { + return nil, nil, 0, err + } // FIXME(tlim) It is a waste to PunyCode every iteration. // This should be moved to where the JavaScript is processed. diff --git a/providers/_all/all.go b/providers/_all/all.go index 617697fa1..c4f4820ff 100644 --- a/providers/_all/all.go +++ b/providers/_all/all.go @@ -10,9 +10,9 @@ import ( _ "github.com/StackExchange/dnscontrol/v4/providers/azureprivatedns" _ "github.com/StackExchange/dnscontrol/v4/providers/bind" _ "github.com/StackExchange/dnscontrol/v4/providers/bunnydns" - _ "github.com/StackExchange/dnscontrol/v4/providers/cnr" _ "github.com/StackExchange/dnscontrol/v4/providers/cloudflare" _ "github.com/StackExchange/dnscontrol/v4/providers/cloudns" + _ "github.com/StackExchange/dnscontrol/v4/providers/cnr" _ "github.com/StackExchange/dnscontrol/v4/providers/cscglobal" _ "github.com/StackExchange/dnscontrol/v4/providers/desec" _ "github.com/StackExchange/dnscontrol/v4/providers/digitalocean" diff --git a/providers/akamaiedgedns/akamaiEdgeDnsProvider.go b/providers/akamaiedgedns/akamaiEdgeDnsProvider.go index 64c5a673a..c991dec1f 100644 --- a/providers/akamaiedgedns/akamaiEdgeDnsProvider.go +++ b/providers/akamaiedgedns/akamaiEdgeDnsProvider.go @@ -11,7 +11,7 @@ https://www.akamai.com/us/en/multimedia/documents/product-brief/edge-dns-product import ( "encoding/json" - "fmt" + "errors" "strings" "github.com/StackExchange/dnscontrol/v4/models" @@ -70,22 +70,22 @@ func newEdgeDNSDSP(config map[string]string, metadata json.RawMessage) (provider groupID := config["group_id"] if clientSecret == "" { - return nil, fmt.Errorf("creds.json: client_secret must not be empty") + return nil, errors.New("creds.json: client_secret must not be empty") } if host == "" { - return nil, fmt.Errorf("creds.json: host must not be empty") + return nil, errors.New("creds.json: host must not be empty") } if accessToken == "" { - return nil, fmt.Errorf("creds.json: accessToken must not be empty") + return nil, errors.New("creds.json: accessToken must not be empty") } if clientToken == "" { - return nil, fmt.Errorf("creds.json: clientToken must not be empty") + return nil, errors.New("creds.json: clientToken must not be empty") } if contractID == "" { - return nil, fmt.Errorf("creds.json: contractID must not be empty") + return nil, errors.New("creds.json: contractID must not be empty") } if groupID == "" { - return nil, fmt.Errorf("creds.json: groupID must not be empty") + return nil, errors.New("creds.json: groupID must not be empty") } initialize(clientSecret, host, accessToken, clientToken) diff --git a/providers/akamaiedgedns/akamaiEdgeDnsService.go b/providers/akamaiedgedns/akamaiEdgeDnsService.go index e47b1c20f..377dea5fd 100644 --- a/providers/akamaiedgedns/akamaiEdgeDnsService.go +++ b/providers/akamaiedgedns/akamaiEdgeDnsService.go @@ -9,6 +9,7 @@ https://github.com/akamai/AkamaiOPEN-edgegrid-golang */ import ( + "errors" "fmt" "github.com/StackExchange/dnscontrol/v4/models" @@ -19,7 +20,6 @@ import ( // initialize initializes the "Akamai OPEN EdgeGrid" library func initialize(clientSecret string, host string, accessToken string, clientToken string) { - eg := edgegrid.Config{ ClientSecret: clientSecret, Host: host, @@ -68,7 +68,7 @@ func createZone(zonename string, contractID string, groupID string) error { // Indirectly create NS and SOA records err = zone.SaveChangelist() if err != nil { - return fmt.Errorf("zone initialization failed. SOA and NS records need to be created") + return errors.New("zone initialization failed. SOA and NS records need to be created") } err = zone.SubmitChangelist() if err != nil { @@ -188,7 +188,7 @@ func getAuthorities(contractID string) ([]string, error) { // rcToRs converts DNSControl RecordConfig records to an AkamaiEdgeDNS recordset. func rcToRs(records []*models.RecordConfig) (*dnsv2.RecordBody, error) { if len(records) == 0 { - return nil, fmt.Errorf("no records to replace") + return nil, errors.New("no records to replace") } akaRecord := &dnsv2.RecordBody{ @@ -242,7 +242,7 @@ func deleteRecordset(records []*models.RecordConfig, zonename string) error { err = akaRecord.Delete(zonename, true) if err != nil { if dnsv2.IsConfigDNSError(err) && err.(dnsv2.ConfigDNSError).NotFound() { - return fmt.Errorf("recordset not found") + return errors.New("recordset not found") } return fmt.Errorf("failed to delete recordset. error: %s", err.Error()) } diff --git a/providers/autodns/api.go b/providers/autodns/api.go index 076a8866f..0a6cbf588 100644 --- a/providers/autodns/api.go +++ b/providers/autodns/api.go @@ -43,14 +43,14 @@ func (api *autoDNSProvider) request(method string, requestPath string, data inte request.Body = io.NopCloser(buffer) } - response, error := client.Do(request) - if error != nil { - return nil, error + response, err := client.Do(request) + if err != nil { + return nil, err } defer response.Body.Close() responseText, _ := io.ReadAll(response.Body) - if response.StatusCode != 200 { + if response.StatusCode != http.StatusOK { return nil, errors.New("Request to " + requestURL.Path + " failed: " + string(responseText)) } @@ -89,7 +89,7 @@ func (api *autoDNSProvider) getZone(domain string) (*Zone, error) { } // if resolving of a systemNameServer succeeds the system contains this zone - var responseData, _ = api.request("GET", "zone/"+domain+"/"+systemNameServer.Name, nil) + responseData, _ := api.request("GET", "zone/"+domain+"/"+systemNameServer.Name, nil) var responseObject JSONResponseDataZone // make sure that the response is valid, the zone is in AutoDNS but we're not sure the returned data meets our expectation unmErr := json.Unmarshal(responseData, &responseObject) @@ -102,7 +102,6 @@ func (api *autoDNSProvider) getZone(domain string) (*Zone, error) { func (api *autoDNSProvider) updateZone(domain string, resourceRecords []*ResourceRecord, nameServers []*models.Nameserver, zoneTTL uint32) error { systemNameServer, err := api.findZoneSystemNameServer(domain) - if err != nil { return err } @@ -129,7 +128,7 @@ func (api *autoDNSProvider) updateZone(domain string, resourceRecords []*Resourc zone.NameServers = append(zone.NameServers, nameServers...) - var _, putErr = api.request("PUT", "zone/"+domain+"/"+systemNameServer.Name, zone) + _, putErr := api.request("PUT", "zone/"+domain+"/"+systemNameServer.Name, zone) if putErr != nil { return putErr diff --git a/providers/autodns/autoDnsProvider.go b/providers/autodns/autoDnsProvider.go index 87795e091..5496f54fe 100644 --- a/providers/autodns/autoDnsProvider.go +++ b/providers/autodns/autoDnsProvider.go @@ -84,7 +84,6 @@ func (api *autoDNSProvider) GetZoneRecordsCorrections(dc *models.DomainConfig, e msgs, changed, actualChangeCount := result.Msgs, result.HasChanges, result.ActualChangeCount if changed { - msgs = append(msgs, "Zone update for "+domain) msg := strings.Join(msgs, "\n") @@ -94,7 +93,6 @@ func (api *autoDNSProvider) GetZoneRecordsCorrections(dc *models.DomainConfig, e &models.Correction{ Msg: msg, F: func() error { - nameServers := nameServers zoneTTL := zoneTTL resourceRecords := resourceRecords @@ -107,7 +105,6 @@ func (api *autoDNSProvider) GetZoneRecordsCorrections(dc *models.DomainConfig, e return nil }, }) - } return corrections, actualChangeCount, nil @@ -119,7 +116,6 @@ func recordsToNative(recs models.Records) ([]*models.Nameserver, uint32, []*Reso var resourceRecords []*ResourceRecord for _, record := range recs { - if record.Type == "NS" && record.Name == "@" { // NS records for the APEX should be handled differently nameServers = append(nameServers, &models.Nameserver{ @@ -169,7 +165,6 @@ func recordsToNative(recs models.Records) ([]*models.Nameserver, uint32, []*Reso // GetNameservers returns the nameservers for a domain. func (api *autoDNSProvider) GetNameservers(domain string) ([]*models.Nameserver, error) { zone, err := api.getZone(domain) - if err != nil { return nil, err } @@ -182,8 +177,11 @@ func (api *autoDNSProvider) GetZoneRecords(domain string, meta map[string]string zone, _ := api.getZone(domain) existingRecords := make([]*models.RecordConfig, len(zone.ResourceRecords)) for i, resourceRecord := range zone.ResourceRecords { - existingRecords[i] = toRecordConfig(domain, resourceRecord) - + var err error + existingRecords[i], err = toRecordConfig(domain, resourceRecord) + if err != nil { + return nil, err + } // If TTL is not set for an individual RR AutoDNS defaults to the zone TTL defined in SOA if existingRecords[i].TTL == 0 { existingRecords[i].TTL = zone.Soa.TTL @@ -241,7 +239,7 @@ func (api *autoDNSProvider) GetZoneRecords(domain string, meta map[string]string return existingRecords, nil } -func toRecordConfig(domain string, record *ResourceRecord) *models.RecordConfig { +func toRecordConfig(domain string, record *ResourceRecord) (*models.RecordConfig, error) { rc := &models.RecordConfig{ Type: record.Type, TTL: uint32(record.TTL), @@ -249,11 +247,15 @@ func toRecordConfig(domain string, record *ResourceRecord) *models.RecordConfig } rc.SetLabel(record.Name, domain) - _ = rc.PopulateFromString(record.Type, record.Value, domain) + if err := rc.PopulateFromString(record.Type, record.Value, domain); err != nil { + return nil, err + } if record.Type == "MX" { rc.MxPreference = uint16(record.Pref) - rc.SetTarget(record.Value) + if err := rc.SetTarget(record.Value); err != nil { + return nil, err + } } if record.Type == "SRV" { @@ -261,8 +263,14 @@ func toRecordConfig(domain string, record *ResourceRecord) *models.RecordConfig re := regexp.MustCompile(`(\d+) (\d+) (.+)$`) found := re.FindStringSubmatch(record.Value) + if len(found) != 4 { + return nil, fmt.Errorf("invalid SRV record value: %s", record.Value) + } - weight, _ := strconv.Atoi(found[1]) + weight, err := strconv.Atoi(found[1]) + if err != nil { + return nil, err + } if weight < 0 { rc.SrvWeight = 0 } else if weight > 65535 { @@ -271,7 +279,10 @@ func toRecordConfig(domain string, record *ResourceRecord) *models.RecordConfig rc.SrvWeight = uint16(weight) } - port, _ := strconv.Atoi(found[2]) + port, err := strconv.Atoi(found[2]) + if err != nil { + return nil, err + } if port < 0 { rc.SrvPort = 0 } else if port > 65535 { @@ -280,8 +291,10 @@ func toRecordConfig(domain string, record *ResourceRecord) *models.RecordConfig rc.SrvPort = uint16(port) } - rc.SetTarget(found[3]) + if err := rc.SetTarget(found[3]); err != nil { + return nil, err + } } - return rc + return rc, nil } diff --git a/providers/autodns/types.go b/providers/autodns/types.go index 4ba1f5f75..220b5bc7d 100644 --- a/providers/autodns/types.go +++ b/providers/autodns/types.go @@ -7,7 +7,6 @@ import ( // ResourceRecord represents DNS records in API calls. type ResourceRecord struct { - // The name of the record. // Required: true Name string `json:"name"` @@ -32,7 +31,6 @@ type ResourceRecord struct { // MainAddressRecord represents an address record in API calls. type MainAddressRecord struct { - // TTL of the record (Optionally if not set then Default SOA TTL is used) TTL int64 `json:"ttl,omitempty"` @@ -65,7 +63,6 @@ type Zone struct { // JSONResponseDataZone represents the response to the DataZone call. type JSONResponseDataZone struct { - // The data for the response. The type of the objects are depending on the request and are also specified in the responseObject value of the response. Data []*Zone `json:"data"` } diff --git a/providers/axfrddns/axfrddnsProvider.go b/providers/axfrddns/axfrddnsProvider.go index 2183306ab..dd08d8c53 100644 --- a/providers/axfrddns/axfrddnsProvider.go +++ b/providers/axfrddns/axfrddnsProvider.go @@ -15,6 +15,7 @@ import ( "crypto/tls" "encoding/base64" "encoding/json" + "errors" "fmt" "net" "strings" @@ -103,8 +104,7 @@ func initAxfrDdns(config map[string]string, providermeta json.RawMessage) (provi } if config["update-mode"] != "" { switch config["update-mode"] { - case "tcp", - "tcp-tls": + case "tcp", "tcp-tls": api.updateMode = config["update-mode"] case "udp": api.updateMode = "" @@ -116,8 +116,7 @@ func initAxfrDdns(config map[string]string, providermeta json.RawMessage) (provi } if config["transfer-mode"] != "" { switch config["transfer-mode"] { - case "tcp", - "tcp-tls": + case "tcp", "tcp-tls": api.transferMode = config["transfer-mode"] default: printer.Printf("[Warning] AXFRDDNS: Unknown transfer-mode in `creds.json` (%s)\n", config["transfer-mode"]) @@ -133,7 +132,7 @@ func initAxfrDdns(config map[string]string, providermeta json.RawMessage) (provi } else if len(api.nameservers) != 0 { api.master = api.nameservers[0].Name + ":53" } else { - return nil, fmt.Errorf("nameservers list is empty: creds.json needs a default `nameservers` or an explicit `master`") + return nil, errors.New("nameservers list is empty: creds.json needs a default `nameservers` or an explicit `master`") } if config["transfer-server"] != "" { api.transferServer = config["transfer-server"] @@ -237,8 +236,8 @@ func (c *axfrddnsProvider) GetNameservers(domain string) ([]*models.Nameserver, } func (c *axfrddnsProvider) getAxfrConnection() (*dns.Transfer, error) { - var con net.Conn = nil - var err error = nil + var con net.Conn + var err error if c.transferMode == "tcp-tls" { con, err = tls.Dial("tcp", c.transferServer, &tls.Config{}) } else { @@ -265,8 +264,7 @@ func (c *axfrddnsProvider) FetchZoneRecords(domain string) ([]dns.RR, error) { request.SetAxfr(domain + ".") if c.transferKey != nil { - transfer.TsigSecret = - map[string]string{c.transferKey.id: c.transferKey.secret} + transfer.TsigSecret = map[string]string{c.transferKey.id: c.transferKey.secret} request.SetTsig(c.transferKey.id, c.transferKey.algo, 300, time.Now().Unix()) if c.transferKey.algo == dns.HmacMD5 { transfer.TsigProvider = md5Provider(c.transferKey.secret) @@ -291,12 +289,10 @@ func (c *axfrddnsProvider) FetchZoneRecords(domain string) ([]dns.RR, error) { rawRecords = append(rawRecords, msg.RR...) } return rawRecords, nil - } // GetZoneRecords gets the records of a zone and returns them in RecordConfig format. func (c *axfrddnsProvider) GetZoneRecords(domain string, meta map[string]string) (models.Records, error) { - rawRecords, err := c.FetchZoneRecords(domain) if err != nil { return nil, err @@ -360,7 +356,6 @@ func (c *axfrddnsProvider) GetZoneRecords(domain string, meta map[string]string) } return foundRecords, nil - } // BuildCorrection return a Correction for a given set of DDNS update and the corresponding message. @@ -373,13 +368,11 @@ func (c *axfrddnsProvider) BuildCorrection(dc *models.DomainConfig, msgs []strin return &models.Correction{ Msg: fmt.Sprintf("DDNS UPDATES to '%s' (primary master: '%s'). Changes:\n%s", dc.Name, c.master, strings.Join(msgs, "\n")), F: func() error { - client := new(dns.Client) client.Net = c.updateMode client.Timeout = dnsTimeout if c.updateKey != nil { - client.TsigSecret = - map[string]string{c.updateKey.id: c.updateKey.secret} + client.TsigSecret = map[string]string{c.updateKey.id: c.updateKey.secret} update.SetTsig(c.updateKey.id, c.updateKey.algo, 300, time.Now().Unix()) if c.updateKey.algo == dns.HmacMD5 { client.TsigProvider = md5Provider(c.updateKey.secret) @@ -474,7 +467,7 @@ func (c *axfrddnsProvider) GetZoneRecordsCorrections(dc *models.DomainConfig, fo // the last NS record of a zone. Since modifying a record is // implemented by successively a deletion of the old record and an // insertion of the new one, then modifying all the NS record of a - // zone might will fail (even if the the deletion and insertion + // zone might will fail (even if the deletion and insertion // are grouped in a single batched update). // // To avoid this case, we will first insert a dummy NS record, diff --git a/providers/azuredns/azureDnsProvider.go b/providers/azuredns/azureDnsProvider.go index 856077ba7..d243a4ab6 100644 --- a/providers/azuredns/azureDnsProvider.go +++ b/providers/azuredns/azureDnsProvider.go @@ -4,6 +4,7 @@ import ( "context" "encoding/json" "fmt" + "net/http" "strings" "time" @@ -201,7 +202,6 @@ func (a *azurednsProvider) GetZoneRecordsCorrections(dc *models.DomainConfig, ex } for _, change := range changes { - // Copy all param values to local variables to avoid overwrites msgs := change.MsgsJoined dcn := dc.Name @@ -234,7 +234,6 @@ func (a *azurednsProvider) GetZoneRecordsCorrections(dc *models.DomainConfig, ex } func (a *azurednsProvider) recordCreate(zoneName string, reckey models.RecordKey, recs models.Records) error { - rrset, azRecType, err := a.recordToNativeDiff2(reckey, recs) if err != nil { return err @@ -256,7 +255,7 @@ retry: _, err = a.recordsClient.CreateOrUpdate(ctx, *a.resourceGroup, zoneName, recordName, azRecType, *rrset, nil) if e, ok := err.(*azcore.ResponseError); ok { - if e.StatusCode == 429 { + if e.StatusCode == http.StatusTooManyRequests { waitTime = waitTime * 2 if waitTime > 300 { return err @@ -271,7 +270,6 @@ retry: } func (a *azurednsProvider) recordDelete(zoneName string, reckey models.RecordKey) error { - shortName := strings.TrimSuffix(reckey.NameFQDN, "."+zoneName) if shortName == zoneName { shortName = "@" @@ -290,7 +288,7 @@ retry: _, err = a.recordsClient.Delete(ctx, *a.resourceGroup, zoneName, shortName, azRecType, nil) if e, ok := err.(*azcore.ResponseError); ok { - if e.StatusCode == 429 { + if e.StatusCode == http.StatusTooManyRequests { waitTime = waitTime * 2 if waitTime > 300 { return err @@ -485,7 +483,6 @@ func nativeToRecords(set *adns.RecordSet, origin string) []*models.RecordConfig // NOTE recordToNativeDiff2 is really "convert []RecordConfig to rrset". func (a *azurednsProvider) recordToNativeDiff2(recordKey models.RecordKey, recordConfig []*models.RecordConfig) (*adns.RecordSet, adns.RecordType, error) { - recordKeyType := recordKey.Type // if recordKeyType == "AZURE_ALIAS" { // fmt.Fprintf(os.Stderr, "DEBUG: XXXXXXXXXXXXXXXXXXXXXXX %v\n", recordKeyType) @@ -572,7 +569,6 @@ func (a *azurednsProvider) fetchRecordSets(zoneName string) ([]*adns.RecordSet, recordsPager := a.recordsClient.NewListAllByDNSZonePager(*a.resourceGroup, zoneName, nil) for recordsPager.More() { - waitTime := 1 retry: @@ -581,8 +577,7 @@ func (a *azurednsProvider) fetchRecordSets(zoneName string) ([]*adns.RecordSet, if recordsErr != nil { err := recordsErr if e, ok := err.(*azcore.ResponseError); ok { - - if e.StatusCode == 429 { + if e.StatusCode == http.StatusTooManyRequests { waitTime = waitTime * 2 if waitTime > 300 { return nil, err diff --git a/providers/azureprivatedns/azurePrivateDnsProvider.go b/providers/azureprivatedns/azurePrivateDnsProvider.go index 2e2b05fe6..c0f6c2cfb 100644 --- a/providers/azureprivatedns/azurePrivateDnsProvider.go +++ b/providers/azureprivatedns/azurePrivateDnsProvider.go @@ -4,6 +4,7 @@ import ( "context" "encoding/json" "fmt" + "net/http" "strings" "time" @@ -196,7 +197,6 @@ func (a *azurednsProvider) GetZoneRecordsCorrections(dc *models.DomainConfig, ex } for _, change := range changes { - // Copy all param values to local variables to avoid overwrites msgs := change.MsgsJoined dcn := dc.Name @@ -229,7 +229,6 @@ func (a *azurednsProvider) GetZoneRecordsCorrections(dc *models.DomainConfig, ex } func (a *azurednsProvider) recordCreate(zoneName string, reckey models.RecordKey, recs models.Records) error { - rrset, azRecType, err := a.recordToNativeDiff2(reckey, recs) if err != nil { return err @@ -251,7 +250,7 @@ retry: _, err = a.recordsClient.CreateOrUpdate(ctx, *a.resourceGroup, zoneName, azRecType, recordName, *rrset, nil) if e, ok := err.(*azcore.ResponseError); ok { - if e.StatusCode == 429 { + if e.StatusCode == http.StatusTooManyRequests { waitTime = waitTime * 2 if waitTime > 300 { return err @@ -266,7 +265,6 @@ retry: } func (a *azurednsProvider) recordDelete(zoneName string, reckey models.RecordKey) error { - shortName := strings.TrimSuffix(reckey.NameFQDN, "."+zoneName) if shortName == zoneName { shortName = "@" @@ -285,7 +283,7 @@ retry: _, err = a.recordsClient.Delete(ctx, *a.resourceGroup, zoneName, azRecType, shortName, nil) if e, ok := err.(*azcore.ResponseError); ok { - if e.StatusCode == 429 { + if e.StatusCode == http.StatusTooManyRequests { waitTime = waitTime * 2 if waitTime > 300 { return err @@ -345,7 +343,6 @@ func nativeToRecords(set *adns.RecordSet, origin string) []*models.RecordConfig } } else { panic(fmt.Errorf("nativeToRecords rtype %v unimplemented", *set.Type)) - } case "Microsoft.Network/privateDnsZones/AAAA": if set.Properties.AaaaRecords != nil { @@ -427,7 +424,6 @@ func nativeToRecords(set *adns.RecordSet, origin string) []*models.RecordConfig // NOTE recordToNativeDiff2 is really "convert []RecordConfig to rrset". func (a *azurednsProvider) recordToNativeDiff2(recordKey models.RecordKey, recordConfig []*models.RecordConfig) (*adns.RecordSet, adns.RecordType, error) { - recordKeyType := recordKey.Type // if recordKeyType == "AZURE_ALIAS" { // fmt.Fprintf(os.Stderr, "DEBUG: XXXXXXXXXXXXXXXXXXXXXXX %v\n", recordKeyType) @@ -501,7 +497,6 @@ func (a *azurednsProvider) fetchRecordSets(zoneName string) ([]*adns.RecordSet, recordsPager := a.recordsClient.NewListPager(*a.resourceGroup, zoneName, nil) for recordsPager.More() { - waitTime := 1 retry: @@ -510,8 +505,7 @@ func (a *azurednsProvider) fetchRecordSets(zoneName string) ([]*adns.RecordSet, if recordsErr != nil { err := recordsErr if e, ok := err.(*azcore.ResponseError); ok { - - if e.StatusCode == 429 { + if e.StatusCode == http.StatusTooManyRequests { waitTime = waitTime * 2 if waitTime > 300 { return nil, err diff --git a/providers/bind/bindProvider.go b/providers/bind/bindProvider.go index 0c853f95b..81cd9abb6 100644 --- a/providers/bind/bindProvider.go +++ b/providers/bind/bindProvider.go @@ -260,7 +260,7 @@ func (c *bindProvider) GetZoneRecordsCorrections(dc *models.DomainConfig, foundR comments := make([]string, 0, 5) comments = append(comments, - fmt.Sprintf("generated with dnscontrol %s", time.Now().Format(time.RFC3339)), + "generated with dnscontrol "+time.Now().Format(time.RFC3339), ) if dc.AutoDNSSEC == "on" { // This does nothing but reminds the user to add the correct @@ -300,7 +300,6 @@ func (c *bindProvider) GetZoneRecordsCorrections(dc *models.DomainConfig, foundR // be commented out on write, but we don't reverse that when // reading, so there will be a diff on every invocation. err = prettyzone.WriteZoneFileRC(zf, result.DesiredPlus, dc.Name, 0, comments) - if err != nil { return fmt.Errorf("failed WriteZoneFile: %w", err) } @@ -316,7 +315,7 @@ func (c *bindProvider) GetZoneRecordsCorrections(dc *models.DomainConfig, foundR } // preprocessFilename pre-processes a filename we're about to os.Create() -// * On Windows systems, it translates the seperator. +// * On Windows systems, it translates the separator. // * It attempts to mkdir the directories leading up to the filename. // * If running on Linux as root, it does not attempt to create directories. func preprocessFilename(name string) (string, error) { @@ -326,7 +325,7 @@ func preprocessFilename(name string) (string, error) { // Create the parent directories dir := filepath.Dir(name) universalDir := filepath.FromSlash(dir) - if err := os.MkdirAll(universalDir, 0750); err != nil { + if err := os.MkdirAll(universalDir, 0o750); err != nil { return "", err } } diff --git a/providers/bind/fnames.go b/providers/bind/fnames.go index 0803174a8..51ab58c89 100644 --- a/providers/bind/fnames.go +++ b/providers/bind/fnames.go @@ -11,7 +11,7 @@ import ( // makeFileName uses format to generate a zone's filename. See the func makeFileName(format, uniquename, domain, tag string) string { - //fmt.Printf("DEBUG: makeFileName(%q, %q, %q, %q)\n", format, uniquename, domain, tag) + // fmt.Printf("DEBUG: makeFileName(%q, %q, %q, %q)\n", format, uniquename, domain, tag) if format == "" { fmt.Fprintf(os.Stderr, "BUG: makeFileName called with null format\n") return uniquename @@ -56,7 +56,7 @@ func makeFileName(format, uniquename, domain, tag string) string { } } - //fmt.Printf("DEBUG: makeFileName returns= %q\n", b.String()) + // fmt.Printf("DEBUG: makeFileName returns= %q\n", b.String()) return b.String() } @@ -97,7 +97,6 @@ func extractZonesFromFilenames(format string, names []string) []string { // filenames. It is mathematically impossible to do this correctly for all // format strings, but typical format strings are supported. func makeExtractor(format string) (string, error) { - // The algorithm works as follows. // We generate a regex that is A or A|B. @@ -123,7 +122,6 @@ func makeExtractor(format string) (string, error) { generateB := false for pass := range []int{0, 1} { - for pos := 0; pos < len(tokens); pos++ { tok := tokens[pos] @@ -188,7 +186,6 @@ func makeExtractor(format string) (string, error) { break } } - } return b.String(), nil diff --git a/providers/bind/fnames_test.go b/providers/bind/fnames_test.go index 0f3f101ff..34306cc28 100644 --- a/providers/bind/fnames_test.go +++ b/providers/bind/fnames_test.go @@ -6,7 +6,6 @@ import ( ) func Test_makeFileName(t *testing.T) { - uu := "uni" dd := "domy" tt := "tagy" diff --git a/providers/bind/serial_test.go b/providers/bind/serial_test.go index 2a47e307c..a992b23ad 100644 --- a/providers/bind/serial_test.go +++ b/providers/bind/serial_test.go @@ -9,7 +9,7 @@ func Test_generate_serial_1(t *testing.T) { d1, _ := time.Parse("20060102", "20150108") d4, _ := time.Parse("20060102", "40150108") d12, _ := time.Parse("20060102", "20151231") - var tests = []struct { + tests := []struct { Given uint32 Today time.Time Expected uint32 diff --git a/providers/bind/soa.go b/providers/bind/soa.go index be6302df2..0ca17f57c 100644 --- a/providers/bind/soa.go +++ b/providers/bind/soa.go @@ -30,7 +30,7 @@ func makeSoa(origin string, defSoa *SoaDefaults, existing, desired *models.Recor } soaRec.TTL = firstNonZero(desired.TTL, defSoa.TTL, existing.TTL, models.DefaultTTL) - soaRec.SetTargetSOA( + err := soaRec.SetTargetSOA( firstNonNull(desired.GetTargetField(), existing.GetTargetField(), defSoa.Ns, "DEFAULT_NOT_SET."), soaMail, firstNonZero(desired.SoaSerial, existing.SoaSerial, defSoa.Serial, 1), @@ -39,6 +39,9 @@ func makeSoa(origin string, defSoa *SoaDefaults, existing, desired *models.Recor firstNonZero(desired.SoaExpire, existing.SoaExpire, defSoa.Expire, 604800), firstNonZero(desired.SoaMinttl, existing.SoaMinttl, defSoa.Minttl, 1440), ) + if err != nil { + panic(err) // Should never happen. + } return &soaRec, generateSerial(soaRec.SoaSerial) } diff --git a/providers/bind/soa_test.go b/providers/bind/soa_test.go index 447670c73..f0b1aaed1 100644 --- a/providers/bind/soa_test.go +++ b/providers/bind/soa_test.go @@ -9,13 +9,13 @@ import ( ) func mkRC(target string, rec *models.RecordConfig) *models.RecordConfig { - rec.SetTarget(target) + rec.MustSetTarget(target) return rec } func Test_makeSoa(t *testing.T) { origin := "example.com" - var tests = []struct { + tests := []struct { def *SoaDefaults existing *models.RecordConfig desired *models.RecordConfig @@ -88,7 +88,6 @@ func Test_makeSoa(t *testing.T) { } for i, tst := range tests { - if tst.existing != nil { tst.existing.SetLabel("@", origin) tst.existing.Type = "SOA" diff --git a/providers/bunnydns/api.go b/providers/bunnydns/api.go index f7c262988..18656d5e7 100644 --- a/providers/bunnydns/api.go +++ b/providers/bunnydns/api.go @@ -4,12 +4,13 @@ import ( "bytes" "encoding/json" "fmt" - "github.com/StackExchange/dnscontrol/v4/models" - "github.com/StackExchange/dnscontrol/v4/pkg/printer" - "golang.org/x/exp/slices" "io" "net/http" "strconv" + + "github.com/StackExchange/dnscontrol/v4/models" + "github.com/StackExchange/dnscontrol/v4/pkg/printer" + "golang.org/x/exp/slices" ) const ( @@ -128,7 +129,6 @@ func (b *bunnydnsProvider) createZone(domain string) (*zone, error) { zone := &zone{} body := map[string]string{"domain": domain} err := b.request("POST", "/dnszone", nil, body, &zone, []int{http.StatusCreated}) - if err != nil { return nil, err } diff --git a/providers/bunnydns/bunnydnsProvider.go b/providers/bunnydns/bunnydnsProvider.go index aa797b288..cd83b7a44 100644 --- a/providers/bunnydns/bunnydnsProvider.go +++ b/providers/bunnydns/bunnydnsProvider.go @@ -2,7 +2,7 @@ package bunnydns import ( "encoding/json" - "fmt" + "errors" "github.com/StackExchange/dnscontrol/v4/models" "github.com/StackExchange/dnscontrol/v4/providers" @@ -50,7 +50,7 @@ func init() { func newBunnydns(settings map[string]string, _ json.RawMessage) (providers.DNSServiceProvider, error) { apiKey := settings["api_key"] if apiKey == "" { - return nil, fmt.Errorf("missing BUNNY_DNS api_key") + return nil, errors.New("missing BUNNY_DNS api_key") } return &bunnydnsProvider{ diff --git a/providers/bunnydns/records.go b/providers/bunnydns/records.go index 34e247bc0..9b305940b 100644 --- a/providers/bunnydns/records.go +++ b/providers/bunnydns/records.go @@ -1,12 +1,13 @@ package bunnydns import ( + "errors" "fmt" + "slices" "github.com/StackExchange/dnscontrol/v4/models" "github.com/StackExchange/dnscontrol/v4/pkg/diff2" "github.com/StackExchange/dnscontrol/v4/pkg/printer" - "golang.org/x/exp/slices" ) func (b *bunnydnsProvider) GetZoneRecords(domain string, meta map[string]string) (models.Records, error) { @@ -124,7 +125,7 @@ func (b *bunnydnsProvider) mkChangeCorrection(zoneID int64, oldRec, newRec *mode F: func() error { existingID := oldRec.Original.(*record).ID if existingID == 0 { - return fmt.Errorf("BUNNY_DNS: cannot change implicit records") + return errors.New("BUNNY_DNS: cannot change implicit records") } desired, err := fromRecordConfig(newRec) @@ -143,7 +144,7 @@ func (b *bunnydnsProvider) mkDeleteCorrection(zoneID int64, oldRec *models.Recor F: func() error { existingID := oldRec.Original.(*record).ID if existingID == 0 { - return fmt.Errorf("BUNNY_DNS: cannot delete implicit records") + return errors.New("BUNNY_DNS: cannot delete implicit records") } return b.deleteRecord(zoneID, existingID) diff --git a/providers/capabilities.go b/providers/capabilities.go index 72f451985..b72c9fa5c 100644 --- a/providers/capabilities.go +++ b/providers/capabilities.go @@ -100,11 +100,11 @@ const ( var providerCapabilities = map[string]map[Capability]bool{} // ProviderHasCapability returns true if provider has capability. -func ProviderHasCapability(pType string, cap Capability) bool { +func ProviderHasCapability(pType string, capa Capability) bool { if providerCapabilities[pType] == nil { return false } - return providerCapabilities[pType][cap] + return providerCapabilities[pType][capa] } // DocumentationNote is a way for providers to give more detail about what features they support. @@ -143,7 +143,6 @@ func unwrapProviderCapabilities(pName string, meta []ProviderMetadata) { default: log.Fatalf("Unrecognized ProviderMetadata type: %T", pm) } - } } diff --git a/providers/cloudflare/cloudflareProvider.go b/providers/cloudflare/cloudflareProvider.go index 89b090b0c..b1d8d7d6b 100644 --- a/providers/cloudflare/cloudflareProvider.go +++ b/providers/cloudflare/cloudflareProvider.go @@ -3,6 +3,7 @@ package cloudflare import ( "context" "encoding/json" + "errors" "fmt" "net" "os" @@ -10,8 +11,6 @@ import ( "strings" "sync" - "golang.org/x/net/idna" - "github.com/StackExchange/dnscontrol/v4/models" "github.com/StackExchange/dnscontrol/v4/pkg/diff2" "github.com/StackExchange/dnscontrol/v4/pkg/printer" @@ -20,6 +19,7 @@ import ( "github.com/StackExchange/dnscontrol/v4/providers/cloudflare/rtypes/cfsingleredirect" "github.com/cloudflare/cloudflare-go" "github.com/fatih/color" + "golang.org/x/net/idna" ) /* @@ -100,7 +100,6 @@ type cloudflareProvider struct { // GetNameservers returns the nameservers for a domain. func (c *cloudflareProvider) GetNameservers(domain string) ([]*models.Nameserver, error) { - c.Lock() defer c.Unlock() if err := c.cacheDomainList(); err != nil { @@ -116,7 +115,6 @@ func (c *cloudflareProvider) GetNameservers(domain string) ([]*models.Nameserver // ListZones returns a list of the DNS zones. func (c *cloudflareProvider) ListZones() ([]string, error) { - c.Lock() defer c.Unlock() if err := c.cacheDomainList(); err != nil { @@ -132,7 +130,6 @@ func (c *cloudflareProvider) ListZones() ([]string, error) { // GetZoneRecords gets the records of a zone and returns them in RecordConfig format. func (c *cloudflareProvider) GetZoneRecords(domain string, meta map[string]string) (models.Records, error) { - domainID, err := c.getDomainID(domain) if err != nil { return nil, err @@ -189,7 +186,6 @@ func (c *cloudflareProvider) GetZoneRecords(domain string, meta map[string]strin } func (c *cloudflareProvider) getDomainID(name string) (string, error) { - c.Lock() defer c.Unlock() if err := c.cacheDomainList(); err != nil { @@ -205,7 +201,6 @@ func (c *cloudflareProvider) getDomainID(name string) (string, error) { // GetZoneRecordsCorrections returns a list of corrections that will turn existing records into dc.Records. func (c *cloudflareProvider) GetZoneRecordsCorrections(dc *models.DomainConfig, records models.Records) ([]*models.Correction, int, error) { - for _, rec := range dc.Records { if rec.Type == "ALIAS" { rec.Type = "CNAME" @@ -243,7 +238,6 @@ func (c *cloudflareProvider) GetZoneRecordsCorrections(dc *models.DomainConfig, } for _, inst := range instructions { - addToFront := false var corrs []*models.Correction @@ -335,7 +329,6 @@ func (c *cloudflareProvider) mkCreateCorrection(newrec *models.RecordConfig, dom } func (c *cloudflareProvider) mkChangeCorrection(oldrec, newrec *models.RecordConfig, domainID string, msg string) []*models.Correction { - var idTxt string switch oldrec.Type { case "PAGE_RULE": @@ -374,7 +367,7 @@ func (c *cloudflareProvider) mkChangeCorrection(oldrec, newrec *models.RecordCon default: e := oldrec.Original.(cloudflare.DNSRecord) proxy := e.Proxiable && newrec.Metadata[metaProxy] != "off" - //fmt.Fprintf(os.Stderr, "DEBUG: proxy := %v && %v != off is... %v\n", e.Proxiable, newrec.Metadata[metaProxy], proxy) + // fmt.Fprintf(os.Stderr, "DEBUG: proxy := %v && %v != off is... %v\n", e.Proxiable, newrec.Metadata[metaProxy], proxy) return []*models.Correction{{ Msg: msg, F: func() error { return c.modifyRecord(domainID, e.ID, proxy, newrec) }, @@ -383,7 +376,6 @@ func (c *cloudflareProvider) mkChangeCorrection(oldrec, newrec *models.RecordCon } func (c *cloudflareProvider) mkDeleteCorrection(recType string, origRec *models.RecordConfig, domainID string, msg string) []*models.Correction { - var idTxt string switch recType { case "PAGE_RULE": @@ -437,7 +429,7 @@ func checkNSModifications(dc *models.DomainConfig) { func (c *cloudflareProvider) checkUniversalSSL(dc *models.DomainConfig, id string) (changed bool, newState bool, err error) { expectedStr := dc.Metadata[metaUniversalSSL] if expectedStr == "" { - return false, false, fmt.Errorf("metadata not set") + return false, false, errors.New("metadata not set") } if actual, err := c.getUniversalSSL(id); err == nil { @@ -454,7 +446,7 @@ func (c *cloudflareProvider) checkUniversalSSL(dc *models.DomainConfig, id strin } return false, expected, nil } - return false, false, fmt.Errorf("error receiving universal ssl state") + return false, false, errors.New("error receiving universal ssl state") } const ( @@ -474,7 +466,6 @@ func checkProxyVal(v string) (string, error) { } func (c *cloudflareProvider) preprocessConfig(dc *models.DomainConfig) error { - // Determine the default proxy setting. var defProxy string var err error @@ -536,7 +527,7 @@ func (c *cloudflareProvider) preprocessConfig(dc *models.DomainConfig) error { // CF_REDIRECT record types: if rec.Type == "CF_REDIRECT" || rec.Type == "CF_TEMP_REDIRECT" { if !c.manageRedirects && !c.manageSingleRedirects { - return fmt.Errorf("you must add 'manage_single_redirects: true' metadata to cloudflare provider to use CF_REDIRECT/CF_TEMP_REDIRECT records") + return errors.New("you must add 'manage_single_redirects: true' metadata to cloudflare provider to use CF_REDIRECT/CF_TEMP_REDIRECT records") } code := uint16(301) if rec.Type == "CF_TEMP_REDIRECT" { @@ -548,19 +539,21 @@ func (c *cloudflareProvider) preprocessConfig(dc *models.DomainConfig) error { prPriority++ // Convert this record to a PAGE_RULE. - cfsingleredirect.MakePageRule(rec, prPriority, code, prWhen, prThen) + if err := cfsingleredirect.MakePageRule(rec, prPriority, code, prWhen, prThen); err != nil { + return err + } rec.SetLabel("@", dc.Name) if c.manageRedirects && !c.manageSingleRedirects { // Old-Style only. No additional work needed. - } else if !c.manageRedirects && c.manageSingleRedirects { // New-Style only. Convert PAGE_RULE to SINGLEREDIRECT. - cfsingleredirect.TranscodePRtoSR(rec) + if err := cfsingleredirect.TranscodePRtoSR(rec); err != nil { + return err + } if err := c.LogTranscode(dc.Name, rec.CloudflareRedirect); err != nil { return err } - } else { // Both old-style and new-style enabled! // Retain the PAGE_RULE and append an additional SINGLEREDIRECT. @@ -571,7 +564,9 @@ func (c *cloudflareProvider) preprocessConfig(dc *models.DomainConfig) error { return err } // The copy becomes the CF SingleRedirect - cfsingleredirect.TranscodePRtoSR(rec) + if err := cfsingleredirect.TranscodePRtoSR(rec); err != nil { + return err + } if err := c.LogTranscode(dc.Name, rec.CloudflareRedirect); err != nil { return err } @@ -580,18 +575,16 @@ func (c *cloudflareProvider) preprocessConfig(dc *models.DomainConfig) error { // The original PAGE_RULE remains untouched. } - } else if rec.Type == cfsingleredirect.SINGLEREDIRECT { // SINGLEREDIRECT record types. Verify they are enabled. if !c.manageSingleRedirects { - return fmt.Errorf("you must add 'manage_single_redirects: true' metadata to cloudflare provider to use CF_SINGLE__REDIRECT records") + return errors.New("you must add 'manage_single_redirects: true' metadata to cloudflare provider to use CF_SINGLE__REDIRECT records") } - } else if rec.Type == "CF_WORKER_ROUTE" { // CF_WORKER_ROUTE record types. Encode target as $PATTERN,$SCRIPT parts := strings.Split(rec.GetTargetField(), ",") if len(parts) != 2 { - return fmt.Errorf("invalid data specified for cloudflare worker record") + return errors.New("invalid data specified for cloudflare worker record") } rec.TTL = 1 rec.Type = "WORKER_ROUTE" @@ -617,7 +610,9 @@ func (c *cloudflareProvider) preprocessConfig(dc *models.DomainConfig) error { return err } rec.Metadata[metaOriginalIP] = rec.GetTargetField() - rec.SetTarget(newIP.String()) + if err := rec.SetTarget(newIP.String()); err != nil { + return err + } } return nil @@ -632,7 +627,7 @@ func (c *cloudflareProvider) LogTranscode(zone string, redirect *models.Cloudfla // File not opened already? Open it. if c.tcLogFh == nil { - f, err := os.OpenFile(filename, os.O_APPEND|os.O_WRONLY|os.O_CREATE, 0600) + f, err := os.OpenFile(filename, os.O_APPEND|os.O_WRONLY|os.O_CREATE, 0o600) if err != nil { return err } @@ -659,10 +654,10 @@ func newCloudflare(m map[string]string, metadata json.RawMessage) (providers.DNS api := &cloudflareProvider{} // check api keys from creds json file if m["apitoken"] == "" && (m["apikey"] == "" || m["apiuser"] == "") { - return nil, fmt.Errorf("if cloudflare apitoken is not set, apikey and apiuser must be provided") + return nil, errors.New("if cloudflare apitoken is not set, apikey and apiuser must be provided") } if m["apitoken"] != "" && (m["apikey"] != "" || m["apiuser"] != "") { - return nil, fmt.Errorf("if cloudflare apitoken is set, apikey and apiuser should not be provided") + return nil, errors.New("if cloudflare apitoken is set, apikey and apiuser should not be provided") } optRP := cloudflare.UsingRetryPolicy(20, 1, 120) @@ -838,7 +833,6 @@ func stringDefault(value interface{}, def string) string { } func (c *cloudflareProvider) nativeToRecord(domain string, cr cloudflare.DNSRecord) (*models.RecordConfig, error) { - // normalize cname,mx,ns records with dots to be consistent with our config format. if cr.Type == "ALIAS" || cr.Type == "CNAME" || cr.Type == "MX" || cr.Type == "NS" || cr.Type == "PTR" { if cr.Content != "." { @@ -907,13 +901,12 @@ func getProxyMetadata(r *models.RecordConfig) map[string]string { proxied = r.Metadata[metaProxy] != "off" } return map[string]string{ - "proxy": fmt.Sprint(proxied), + "proxy": strconv.FormatBool(proxied), } } // EnsureZoneExists creates a zone if it does not exist func (c *cloudflareProvider) EnsureZoneExists(domain string) error { - c.Lock() defer c.Unlock() if err := c.cacheDomainList(); err != nil { diff --git a/providers/cloudflare/preprocess_test.go b/providers/cloudflare/preprocess_test.go index d0d933147..a41a3b3c4 100644 --- a/providers/cloudflare/preprocess_test.go +++ b/providers/cloudflare/preprocess_test.go @@ -22,7 +22,7 @@ func makeRCmeta(meta map[string]string) *models.RecordConfig { Metadata: meta, } rc.SetLabel("foo", "example.tld") - rc.SetTarget("1.2.3.4") + rc.MustSetTarget("1.2.3.4") return &rc } @@ -88,7 +88,7 @@ func TestPreprocess_DefaultProxy_Validation(t *testing.T) { } func TestIpRewriting(t *testing.T) { - var tests = []struct { + tests := []struct { Given, Expected string Proxy string }{ @@ -106,10 +106,11 @@ func TestIpRewriting(t *testing.T) { Low: net.ParseIP("1.2.3.0"), High: net.ParseIP("1.2.3.40"), NewBases: []net.IP{net.ParseIP("255.255.255.0")}, - NewIPs: nil}} + NewIPs: nil, + }} for _, tst := range tests { rec := &models.RecordConfig{Type: "A", Metadata: map[string]string{metaProxy: tst.Proxy}} - rec.SetTarget(tst.Given) + rec.MustSetTarget(tst.Given) domain.Records = append(domain.Records, rec) } err := cf.preprocessConfig(domain) diff --git a/providers/cloudflare/rest.go b/providers/cloudflare/rest.go index 860d8cc5c..cbe0e8207 100644 --- a/providers/cloudflare/rest.go +++ b/providers/cloudflare/rest.go @@ -6,11 +6,10 @@ import ( "fmt" "strings" - "golang.org/x/net/idna" - "github.com/StackExchange/dnscontrol/v4/models" "github.com/StackExchange/dnscontrol/v4/providers/cloudflare/rtypes/cfsingleredirect" "github.com/cloudflare/cloudflare-go" + "golang.org/x/net/idna" ) // get list of domains for account. Cache so the ids can be looked up from domain name @@ -20,10 +19,10 @@ func (c *cloudflareProvider) cacheDomainList() error { return nil } - //fmt.Printf("DEBUG: CLOUDFLARE POPULATING CACHE\n") + // fmt.Printf("DEBUG: CLOUDFLARE POPULATING CACHE\n") zones, err := c.cfClient.ListZones(context.Background()) if err != nil { - return fmt.Errorf("failed fetching domain list from cloudflare(%q): %s", c.cfClient.APIEmail, err) + return fmt.Errorf("failed fetching domain list from cloudflare(%q): %w", c.cfClient.APIEmail, err) } c.domainIndex = map[string]string{} @@ -150,7 +149,6 @@ func cfNaptrData(rec *models.RecordConfig) *cfNaptrRecData { } func (c *cloudflareProvider) createRecDiff2(rec *models.RecordConfig, domainID string, msg string) []*models.Correction { - content := rec.GetTargetField() if rec.Metadata[metaOriginalIP] != "" { content = rec.Metadata[metaOriginalIP] @@ -222,7 +220,7 @@ func (c *cloudflareProvider) createRecDiff2(rec *models.RecordConfig, domainID s func (c *cloudflareProvider) modifyRecord(domainID, recID string, proxied bool, rec *models.RecordConfig) error { if domainID == "" || recID == "" { - return fmt.Errorf("cannot modify record if domain or record id are empty") + return errors.New("cannot modify record if domain or record id are empty") } r := cloudflare.UpdateDNSRecordParams{ @@ -285,13 +283,12 @@ func (c *cloudflareProvider) getSingleRedirects(id string, domain string) ([]*mo if errors.As(err, &e) { return []*models.RecordConfig{}, nil } - return nil, fmt.Errorf("failed fetching redirect rule list cloudflare: %s (%T)", err, err) + return nil, fmt.Errorf("failed fetching redirect rule list cloudflare: %w (%T)", err, err) } recs := []*models.RecordConfig{} for _, pr := range rules.Rules { - - var thisPr = pr + thisPr := pr r := &models.RecordConfig{ Original: thisPr, } @@ -302,7 +299,9 @@ func (c *cloudflareProvider) getSingleRedirects(id string, domain string) ([]*mo srThen := pr.ActionParameters.FromValue.TargetURL.Expression code := uint16(pr.ActionParameters.FromValue.StatusCode) - cfsingleredirect.MakeSingleRedirectFromAPI(r, code, srName, srWhen, srThen) + if err := cfsingleredirect.MakeSingleRedirectFromAPI(r, code, srName, srWhen, srThen); err != nil { + return nil, err + } r.SetLabel("@", domain) // Store the IDs @@ -317,7 +316,6 @@ func (c *cloudflareProvider) getSingleRedirects(id string, domain string) ([]*mo } func (c *cloudflareProvider) createSingleRedirect(domainID string, cfr models.CloudflareSingleRedirectConfig) error { - newSingleRedirectRulesActionParameters := cloudflare.RulesetRuleActionParameters{} newSingleRedirectRule := cloudflare.RulesetRule{} newSingleRedirectRules := []cloudflare.RulesetRule{} @@ -350,7 +348,7 @@ func (c *cloudflareProvider) createSingleRedirect(domainID string, cfr models.Cl rules, err := c.cfClient.GetEntrypointRuleset(context.Background(), cloudflare.ZoneIdentifier(domainID), "http_request_dynamic_redirect") var e *cloudflare.NotFoundError if err != nil && !errors.As(err, &e) { - return fmt.Errorf("failed fetching redirect rule list cloudflare: %s", err) + return fmt.Errorf("failed fetching redirect rule list cloudflare: %w", err) } newSingleRedirect.Rules = newSingleRedirectRules newSingleRedirect.Rules = append(newSingleRedirect.Rules, rules.Rules...) @@ -361,7 +359,6 @@ func (c *cloudflareProvider) createSingleRedirect(domainID string, cfr models.Cl } func (c *cloudflareProvider) deleteSingleRedirects(domainID string, cfr models.CloudflareSingleRedirectConfig) error { - // This block should delete rules using the as is Cloudflare Golang lib in theory, need to debug why it isn't // updatedRuleset := cloudflare.UpdateEntrypointRulesetParams{} // updatedRulesetRules := []cloudflare.RulesetRule{} @@ -387,11 +384,12 @@ func (c *cloudflareProvider) deleteSingleRedirects(domainID string, cfr models.C // if err != nil { // return err // } - //printer.Printf("DEBUG: CALLING API DeleteRulesetRule: SRRRulesetID=%v, cfr.SRRRulesetRuleID=%v\n", cfr.SRRRulesetID, cfr.SRRRulesetRuleID) + // printer.Printf("DEBUG: CALLING API DeleteRulesetRule: SRRRulesetID=%v, cfr.SRRRulesetRuleID=%v\n", cfr.SRRRulesetID, cfr.SRRRulesetRuleID) err := c.cfClient.DeleteRulesetRule(context.Background(), cloudflare.ZoneIdentifier(domainID), cloudflare.DeleteRulesetRuleParams{ RulesetID: cfr.SRRRulesetID, - RulesetRuleID: cfr.SRRRulesetRuleID}, + RulesetRuleID: cfr.SRRRulesetRuleID, + }, ) // NB(tlim): Yuck. This returns an error even when it is successful. Dig into the JSON for the real status. if strings.Contains(err.Error(), `"success": true,`) { @@ -411,7 +409,7 @@ func (c *cloudflareProvider) updateSingleRedirect(domainID string, oldrec, newre func (c *cloudflareProvider) getPageRules(id string, domain string) ([]*models.RecordConfig, error) { rules, err := c.cfClient.ListPageRules(context.Background(), id) if err != nil { - return nil, fmt.Errorf("failed fetching page rule list cloudflare: %s", err) + return nil, fmt.Errorf("failed fetching page rule list cloudflare: %w", err) } recs := []*models.RecordConfig{} for _, pr := range rules { @@ -423,7 +421,7 @@ func (c *cloudflareProvider) getPageRules(id string, domain string) ([]*models.R continue } value := pr.Actions[0].Value.(map[string]interface{}) - var thisPr = pr + thisPr := pr r := &models.RecordConfig{ Original: thisPr, } @@ -434,7 +432,9 @@ func (c *cloudflareProvider) getPageRules(id string, domain string) ([]*models.R then := value["url"].(string) currentPrPrio := pr.Priority - cfsingleredirect.MakePageRule(r, currentPrPrio, code, when, then) + if err := cfsingleredirect.MakePageRule(r, currentPrPrio, code, when, then); err != nil { + return nil, err + } r.SetLabel("@", domain) recs = append(recs, r) @@ -448,7 +448,7 @@ func (c *cloudflareProvider) deletePageRule(recordID, domainID string) error { func (c *cloudflareProvider) updatePageRule(recordID, domainID string, cfr models.CloudflareSingleRedirectConfig) error { // maybe someday? - //c.apiProvider.UpdatePageRule(context.Background(), domainId, recordID, ) + // c.apiProvider.UpdatePageRule(context.Background(), domainId, recordID, ) if err := c.deletePageRule(recordID, domainID); err != nil { return err } @@ -480,21 +480,25 @@ func (c *cloudflareProvider) createPageRule(domainID string, cfr models.Cloudfla func (c *cloudflareProvider) getWorkerRoutes(id string, domain string) ([]*models.RecordConfig, error) { res, err := c.cfClient.ListWorkerRoutes(context.Background(), cloudflare.ZoneIdentifier(id), cloudflare.ListWorkerRoutesParams{}) if err != nil { - return nil, fmt.Errorf("failed fetching worker route list cloudflare: %s", err) + return nil, fmt.Errorf("failed fetching worker route list cloudflare: %w", err) } recs := []*models.RecordConfig{} for _, pr := range res.Routes { - var thisPr = pr + thisPr := pr r := &models.RecordConfig{ Type: "WORKER_ROUTE", Original: thisPr, TTL: 1, } r.SetLabel("@", domain) - r.SetTarget(fmt.Sprintf("%s,%s", // $PATTERN,$SCRIPT + err := r.SetTarget(fmt.Sprintf("%s,%s", // $PATTERN,$SCRIPT pr.Pattern, pr.ScriptName)) + if err != nil { + return nil, err + } + recs = append(recs, r) } return recs, nil diff --git a/providers/cloudflare/rtypes/cfsingleredirect/cfsingleredirect.go b/providers/cloudflare/rtypes/cfsingleredirect/cfsingleredirect.go index a00ca4a5d..fe8489dec 100644 --- a/providers/cloudflare/rtypes/cfsingleredirect/cfsingleredirect.go +++ b/providers/cloudflare/rtypes/cfsingleredirect/cfsingleredirect.go @@ -16,7 +16,6 @@ func init() { // FromRaw convert RecordConfig using data from a RawRecordConfig's parameters. func FromRaw(rc *models.RecordConfig, items []any) error { - // Validate types. if err := rtypecontrol.PaveArgs(items, "siss"); err != nil { return err @@ -34,7 +33,5 @@ func FromRaw(rc *models.RecordConfig, items []any) error { when = items[2].(string) then = items[3].(string) - makeSingleRedirectFromRawRec(rc, code, name, when, then) - - return nil + return makeSingleRedirectFromRawRec(rc, code, name, when, then) } diff --git a/providers/cloudflare/rtypes/cfsingleredirect/convert.go b/providers/cloudflare/rtypes/cfsingleredirect/convert.go index 40ada4986..ce0014884 100644 --- a/providers/cloudflare/rtypes/cfsingleredirect/convert.go +++ b/providers/cloudflare/rtypes/cfsingleredirect/convert.go @@ -27,18 +27,15 @@ func TranscodePRtoSR(rec *models.RecordConfig) error { } // Fix the RecordConfig - makeSingleRedirectFromConvert(rec, + return makeSingleRedirectFromConvert(rec, sr.PRPriority, prWhen, prThen, code, srName, srWhen, srThen) - - return nil } // makeRuleFromPattern compile old-style patterns and replacements into new-style rules and expressions. func makeRuleFromPattern(pattern, replacement string) (string, string, error) { - var srWhen, srThen string var err error @@ -68,34 +65,27 @@ func makeRuleFromPattern(pattern, replacement string) (string, string, error) { if !strings.Contains(phost, `*`) && (ppath == `/` || ppath == "") { // https://i.sstatic.net/ (No Wildcards) srWhen = fmt.Sprintf(`http.host eq "%s" and http.request.uri.path eq "%s"`, phost, "/") - } else if !strings.Contains(phost, `*`) && (ppath == `/*`) { // https://i.stack.imgur.com/* srWhen = fmt.Sprintf(`http.host eq "%s"`, phost) - } else if !strings.Contains(phost, `*`) && !strings.Contains(ppath, "*") { // https://insights.stackoverflow.com/trends srWhen = fmt.Sprintf(`http.host eq "%s" and http.request.uri.path eq "%s"`, phost, ppath) - } else if phost[0] == '*' && strings.Count(phost, `*`) == 1 && !strings.Contains(ppath, "*") { // *stackoverflow.careers/ (wildcard at beginning only) srWhen = fmt.Sprintf(`( http.host eq "%s" or ends_with(http.host, ".%s") ) and http.request.uri.path eq "%s"`, phost[1:], phost[1:], ppath) - } else if phost[0] == '*' && strings.Count(phost, `*`) == 1 && ppath == "/*" { // *stackoverflow.careers/* (wildcard at beginning and end) srWhen = fmt.Sprintf(`http.host eq "%s" or ends_with(http.host, ".%s")`, phost[1:], phost[1:]) - } else if strings.Contains(phost, `*`) && ppath == "/*" { // meta.*yodeya.com/* (wildcard in host) h := simpleGlobToRegex(phost) srWhen = fmt.Sprintf(`http.host matches r###"%s"###`, h) - } else if !strings.Contains(phost, `*`) && strings.Count(ppath, `*`) == 1 && strings.HasSuffix(ppath, "*") { // domain.tld/.well-known* (wildcard in path) srWhen = fmt.Sprintf(`(starts_with(http.request.uri.path, "%s") and http.host eq "%s")`, ppath[0:len(ppath)-1], phost) - } // replacement @@ -103,38 +93,31 @@ func makeRuleFromPattern(pattern, replacement string) (string, string, error) { if !strings.Contains(replacement, `$`) { // https://stackexchange.com/ (no substitutions) srThen = fmt.Sprintf(`concat("%s", "")`, replacement) - } else if phost[0] == '*' && strings.Count(phost, `*`) == 1 && strings.Count(replacement, `$`) == 1 && len(rpath) > 3 && strings.HasSuffix(rpath, "/$2") { // *stackoverflowenterprise.com/* -> https://www.stackoverflowbusiness.com/enterprise/$2 srThen = fmt.Sprintf(`concat("https://%s", "%s", http.request.uri.path)`, rhost, rpath[0:len(rpath)-3], ) - } else if phost[0] == '*' && strings.Count(phost, `*`) == 1 && strings.Count(replacement, `$`) == 1 && len(rpath) > 3 && strings.HasSuffix(rpath, "/$2") { // *stackoverflowenterprise.com/* -> https://www.stackoverflowbusiness.com/enterprise/$2 srThen = fmt.Sprintf(`concat("https://%s", "%s", http.request.uri.path)`, rhost, rpath[0:len(rpath)-3], ) - } else if strings.Count(replacement, `$`) == 1 && rpath == `/$1` { // https://i.sstatic.net/$1 ($1 at end) srThen = fmt.Sprintf(`concat("https://%s", http.request.uri.path)`, rhost) - } else if strings.Count(phost, `*`) == 1 && strings.Count(ppath, `*`) == 1 && strings.Count(replacement, `$`) == 1 && strings.HasSuffix(rpath, `/$2`) { // https://careers.stackoverflow.com/$2 srThen = fmt.Sprintf(`concat("https://%s", http.request.uri.path)`, rhost) - } else if strings.Count(replacement, `$`) == 1 && strings.HasSuffix(replacement, `$1`) { // https://social.domain.tld/.well-known$1 srThen = fmt.Sprintf(`concat("https://%s", http.request.uri.path)`, rhost) - } else if strings.Count(replacement, `$`) == 1 && strings.HasSuffix(replacement, `$1`) { // https://social.domain.tld/.well-known$1 srThen = fmt.Sprintf(`concat("https://%s", http.request.uri.path)`, rhost) - } // Not implemented @@ -177,7 +160,6 @@ func normalizeURL(s string) (string, string, string, error) { // simpleGlobToRegex translates very simple Glob patterns into regexp-compatible expressions. // It only handles `.` and `*` currently. See singleredirect_test.go for supported patterns. func simpleGlobToRegex(g string) string { - if g == "" { return `.*` } diff --git a/providers/cloudflare/rtypes/cfsingleredirect/convert_test.go b/providers/cloudflare/rtypes/cfsingleredirect/convert_test.go index 54e9bef7e..1a9c78f4c 100644 --- a/providers/cloudflare/rtypes/cfsingleredirect/convert_test.go +++ b/providers/cloudflare/rtypes/cfsingleredirect/convert_test.go @@ -226,7 +226,7 @@ func Test_makeSingleDirectRule(t *testing.T) { if gotExpr != tt.wantExpr { t.Errorf("makeSingleDirectRule() EXPR = %v\n want %v", gotExpr, tt.wantExpr) } - //_ = gotType + // _ = gotType }) } } @@ -330,7 +330,6 @@ func Test_simpleGlobToRegex(t *testing.T) { // Make sure the regex compiles and gets the same result when matching against strings in data. for i, d := range data { - rm, err := regexp.MatchString(got, d) if err != nil { t.Errorf("simpleGlobToRegex() = %003d can not compile: %v", i, err) @@ -342,9 +341,7 @@ func Test_simpleGlobToRegex(t *testing.T) { if gm != rm { t.Errorf("simpleGlobToRegex() = %003d glob: %v '%v' regexp: %v '%v'", i, gm, tt.pattern, rm, got) } - } }) - } } diff --git a/providers/cloudflare/rtypes/cfsingleredirect/from.go b/providers/cloudflare/rtypes/cfsingleredirect/from.go index f1bd3f71f..d2f8c8bb1 100644 --- a/providers/cloudflare/rtypes/cfsingleredirect/from.go +++ b/providers/cloudflare/rtypes/cfsingleredirect/from.go @@ -1,13 +1,21 @@ package cfsingleredirect import ( + "errors" "fmt" "github.com/StackExchange/dnscontrol/v4/models" ) // MakePageRule updates a RecordConfig to be a PAGE_RULE using PAGE_RULE data. -func MakePageRule(rc *models.RecordConfig, priority int, code uint16, when, then string) { +func MakePageRule(rc *models.RecordConfig, priority int, code uint16, when, then string) error { + if rc == nil { + return errors.New("RecordConfig cannot be nil") + } + if when == "" || then == "" { + return errors.New("when and then parameters cannot be empty") + } + display := mkPageRuleBlob(priority, code, when, then) rc.Type = "PAGE_RULE" @@ -20,7 +28,7 @@ func MakePageRule(rc *models.RecordConfig, priority int, code uint16, when, then PRPriority: priority, PRDisplay: display, } - rc.SetTarget(display) + return rc.SetTarget(display) } // mkPageRuleBlob creates the 1,301,when,then string used in displays. @@ -30,7 +38,7 @@ func mkPageRuleBlob(priority int, code uint16, when, then string) string { // makeSingleRedirectFromRawRec updates a RecordConfig to be a // SINGLEREDIRECT using the data from a RawRecord. -func makeSingleRedirectFromRawRec(rc *models.RecordConfig, code uint16, name, when, then string) { +func makeSingleRedirectFromRawRec(rc *models.RecordConfig, code uint16, name, when, then string) error { target := targetFromRaw(name, code, when, then) rc.Type = SINGLEREDIRECT @@ -48,7 +56,7 @@ func makeSingleRedirectFromRawRec(rc *models.RecordConfig, code uint16, name, wh SRThen: then, SRDisplay: target, } - rc.SetTarget(rc.CloudflareRedirect.SRDisplay) + return rc.SetTarget(rc.CloudflareRedirect.SRDisplay) } // targetFromRaw create the display text used for a normal Redirect. @@ -62,7 +70,7 @@ func targetFromRaw(name string, code uint16, when, then string) string { } // MakeSingleRedirectFromAPI updatese a RecordConfig to be a SINGLEREDIRECT using data downloaded via the API. -func MakeSingleRedirectFromAPI(rc *models.RecordConfig, code uint16, name, when, then string) { +func MakeSingleRedirectFromAPI(rc *models.RecordConfig, code uint16, name, when, then string) error { // The target is the same as the name. It is the responsibility of the record creator to name it something diffable. target := targetFromAPIData(name, code, when, then) @@ -81,7 +89,7 @@ func MakeSingleRedirectFromAPI(rc *models.RecordConfig, code uint16, name, when, SRThen: then, SRDisplay: target, } - rc.SetTarget(rc.CloudflareRedirect.SRDisplay) + return rc.SetTarget(rc.CloudflareRedirect.SRDisplay) } // targetFromAPIData creates the display text used for a Redirect as received from Cloudflare's API. @@ -99,8 +107,8 @@ func makeSingleRedirectFromConvert(rc *models.RecordConfig, priority int, prWhen, prThen string, code uint16, - srName, srWhen, srThen string) { - + srName, srWhen, srThen string, +) error { srDisplay := targetFromConverted(priority, code, prWhen, prThen, srWhen, srThen) rc.Type = SINGLEREDIRECT @@ -113,7 +121,7 @@ func makeSingleRedirectFromConvert(rc *models.RecordConfig, sr.SRThen = srThen sr.SRDisplay = srDisplay - rc.SetTarget(rc.CloudflareRedirect.SRDisplay) + return rc.SetTarget(rc.CloudflareRedirect.SRDisplay) } // targetFromConverted makes the display text used when a redirect was the result of converting a PAGE_RULE. diff --git a/providers/cloudns/api.go b/providers/cloudns/api.go index 00d4e5153..1681961bd 100644 --- a/providers/cloudns/api.go +++ b/providers/cloudns/api.go @@ -95,20 +95,20 @@ func (c *cloudnsProvider) fetchAvailableNameservers() ([]string, error) { defer c.Unlock() if c.nameserversNames == nil { - - var bodyString, err = c.get("/dns/available-name-servers.json", requestParams{}) + bodyString, err := c.get("/dns/available-name-servers.json", requestParams{}) if err != nil { - return nil, fmt.Errorf("failed fetching available nameservers list from ClouDNS: %s", err) + return nil, fmt.Errorf("failed fetching available nameservers list from ClouDNS: %w", err) } var nr nameserverResponse - json.Unmarshal(bodyString, &nr) + if err := json.Unmarshal(bodyString, &nr); err != nil { + return nil, fmt.Errorf("failed to unmarshal available nameservers list from ClouDNS: %w", err) + } for _, nameserver := range nr { if nameserver.Type == "premium" { c.nameserversNames = append(c.nameserversNames, nameserver.Name) } - } } return c.nameserversNames, nil @@ -120,12 +120,14 @@ func (c *cloudnsProvider) fetchAvailableTTLValues(domain string) ([]uint32, erro "domain-name": domain, } - var bodyString, err = c.get("/dns/get-available-ttl.json", params) + bodyString, err := c.get("/dns/get-available-ttl.json", params) if err != nil { - return nil, fmt.Errorf("failed fetching available TTL values list from ClouDNS: %s", err) + return nil, fmt.Errorf("failed fetching available TTL values list from ClouDNS: %w", err) } - json.Unmarshal(bodyString, &allowedTTLValues) + if err := json.Unmarshal(bodyString, &allowedTTLValues); err != nil { + return nil, fmt.Errorf("failed to unmarshal available TTL values list from ClouDNS: %w", err) + } return allowedTTLValues, nil } @@ -143,11 +145,13 @@ func (c *cloudnsProvider) fetchDomainIndex(name string) (string, bool, error) { "rows-per-page": strconv.Itoa(rowsPerPage), } endpoint := "/dns/list-zones.json" - var bodyString, err = c.get(endpoint, params) + bodyString, err := c.get(endpoint, params) if err != nil { - return "", false, fmt.Errorf("failed fetching domain list from ClouDNS: %s", err) + return "", false, fmt.Errorf("failed fetching domain list from ClouDNS: %w", err) + } + if err := json.Unmarshal(bodyString, &dr); err != nil { + return "", false, fmt.Errorf("failed to unmarshal domain list from ClouDNS: %w", err) } - json.Unmarshal(bodyString, &dr) if c.domainIndex == nil { c.domainIndex = map[string]string{} @@ -173,7 +177,7 @@ func (c *cloudnsProvider) createDomain(domain string) error { "zone-type": "master", } if _, err := c.get("/dns/register.json", params); err != nil { - return fmt.Errorf("failed create domain (ClouDNS): %s", err) + return fmt.Errorf("failed create domain (ClouDNS): %w", err) } return nil } @@ -181,7 +185,7 @@ func (c *cloudnsProvider) createDomain(domain string) error { func (c *cloudnsProvider) createRecord(domainID string, rec requestParams) error { rec["domain-name"] = domainID if _, err := c.get("/dns/add-record.json", rec); err != nil { // here we add record - return fmt.Errorf("failed create record (ClouDNS): %s", err) + return fmt.Errorf("failed create record (ClouDNS): %w", err) } return nil } @@ -192,7 +196,7 @@ func (c *cloudnsProvider) deleteRecord(domainID string, recordID string) error { "record-id": recordID, } if _, err := c.get("/dns/delete-record.json", params); err != nil { - return fmt.Errorf("failed delete record (ClouDNS): %s", err) + return fmt.Errorf("failed delete record (ClouDNS): %w", err) } return nil } @@ -201,7 +205,7 @@ func (c *cloudnsProvider) modifyRecord(domainID string, recordID string, rec req rec["domain-name"] = domainID rec["record-id"] = recordID if _, err := c.get("/dns/mod-record.json", rec); err != nil { - return fmt.Errorf("failed update (ClouDNS): %s", err) + return fmt.Errorf("failed update (ClouDNS): %w", err) } return nil } @@ -209,13 +213,15 @@ func (c *cloudnsProvider) modifyRecord(domainID string, recordID string, rec req func (c *cloudnsProvider) getRecords(id string) ([]domainRecord, error) { params := requestParams{"domain-name": id} - var bodyString, err = c.get("/dns/records.json", params) + bodyString, err := c.get("/dns/records.json", params) if err != nil { - return nil, fmt.Errorf("failed fetching record list from ClouDNS: %s", err) + return nil, fmt.Errorf("failed fetching record list from ClouDNS: %w", err) } var dr recordResponse - json.Unmarshal(bodyString, &dr) + if err := json.Unmarshal(bodyString, &dr); err != nil { + return nil, fmt.Errorf("failed to unmarshal record list from ClouDNS: %w", err) + } var records []domainRecord for _, rec := range dr { @@ -227,7 +233,7 @@ func (c *cloudnsProvider) getRecords(id string) ([]domainRecord, error) { func (c *cloudnsProvider) isDnssecEnabled(id string) (bool, error) { params := requestParams{"domain-name": id} - var bodyString, err = c.get("/dns/get-dnssec-ds-records.json", params) + bodyString, err := c.get("/dns/get-dnssec-ds-records.json", params) if err != nil { // DNSSEC disabled is indicated by an error fetching the DS records. var errResp errorResponse @@ -236,7 +242,7 @@ func (c *cloudnsProvider) isDnssecEnabled(id string) (bool, error) { if errResp.Description == "The DNSSEC is not active." { return false, nil } - return false, fmt.Errorf("failed fetching DS records from ClouDNS: %s", err) + return false, fmt.Errorf("failed fetching DS records from ClouDNS: %w", err) } } @@ -253,9 +259,9 @@ func (c *cloudnsProvider) setDnssec(id string, enabled bool) error { endpoint = "/dns/deactivate-dnssec.json" } - var _, err = c.get(endpoint, params) + _, err := c.get(endpoint, params) if err != nil { - return fmt.Errorf("failed setting DNSSEC at ClouDNS: %s", err) + return fmt.Errorf("failed setting DNSSEC at ClouDNS: %w", err) } return nil @@ -263,10 +269,10 @@ func (c *cloudnsProvider) setDnssec(id string, enabled bool) error { func (c *cloudnsProvider) get(endpoint string, params requestParams) ([]byte, error) { client := &http.Client{} - req, _ := http.NewRequest("GET", "https://api.cloudns.net"+endpoint, nil) + req, _ := http.NewRequest(http.MethodGet, "https://api.cloudns.net"+endpoint, nil) q := req.URL.Query() - //TODO: Support sub-auth-user https://asia.cloudns.net/wiki/article/42/ + // TODO: Support sub-auth-user https://asia.cloudns.net/wiki/article/42/ // Add auth params q.Add("auth-id", c.creds.id) q.Add("auth-password", c.creds.password) @@ -279,9 +285,10 @@ func (c *cloudnsProvider) get(endpoint string, params requestParams) ([]byte, er req.URL.RawQuery = q.Encode() // ClouDNS has a rate limit (not documented) of 10 request/second - c.requestLimit.Wait(context.Background()) + if err := c.requestLimit.Wait(context.Background()); err != nil { + return nil, err + } resp, err := client.Do(req) - if err != nil { return []byte{}, err } diff --git a/providers/cloudns/cloudnsProvider.go b/providers/cloudns/cloudnsProvider.go index 16af5263a..d218925fa 100644 --- a/providers/cloudns/cloudnsProvider.go +++ b/providers/cloudns/cloudnsProvider.go @@ -2,6 +2,7 @@ package cloudns import ( "encoding/json" + "errors" "fmt" "strconv" "strings" @@ -28,7 +29,7 @@ func NewCloudns(m map[string]string, metadata json.RawMessage) (providers.DNSSer c.creds.id, c.creds.password, c.creds.subid = m["auth-id"], m["auth-password"], m["sub-auth-id"] if (c.creds.id == "" && c.creds.subid == "") || c.creds.password == "" { - return nil, fmt.Errorf("missing ClouDNS auth-id or sub-auth-id and auth-password") + return nil, errors.New("missing ClouDNS auth-id or sub-auth-id and auth-password") } return c, nil @@ -228,7 +229,6 @@ func (c *cloudnsProvider) GetZoneRecordsCorrections(dc *models.DomainConfig, exi } return corrections, actualChangeCount, nil - } // getDNSSECCorrections returns corrections that update a domain's DNSSEC state. @@ -267,7 +267,10 @@ func (c *cloudnsProvider) GetZoneRecords(domain string, meta map[string]string) } existingRecords := make([]*models.RecordConfig, len(records)) for i := range records { - existingRecords[i] = toRc(domain, &records[i]) + existingRecords[i], err = toRc(domain, &records[i]) + if err != nil { + return nil, err + } } return existingRecords, nil } @@ -283,8 +286,7 @@ func (c *cloudnsProvider) EnsureZoneExists(domain string) error { } // parses the ClouDNS format into our standard RecordConfig -func toRc(domain string, r *domainRecord) *models.RecordConfig { - +func toRc(domain string, r *domainRecord) (*models.RecordConfig, error) { ttl, _ := strconv.ParseUint(r.TTL, 10, 32) priority, _ := strconv.ParseUint(r.Priority, 10, 16) weight, _ := strconv.ParseUint(r.Weight, 10, 16) @@ -301,16 +303,19 @@ func toRc(domain string, r *domainRecord) *models.RecordConfig { } rc.SetLabel(r.Host, domain) + var err error switch rtype := r.Type; rtype { // #rtype_variations case "TXT": - rc.SetTargetTXT(r.Target) + err = rc.SetTargetTXT(r.Target) case "CNAME", "DNAME", "MX", "NS", "SRV", "ALIAS", "PTR": - rc.SetTarget(dnsutil.AddOrigin(r.Target+".", domain)) + if err := rc.SetTarget(dnsutil.AddOrigin(r.Target+".", domain)); err != nil { + return nil, err + } case "CAA": caaFlag, _ := strconv.ParseUint(r.CaaFlag, 10, 8) rc.CaaFlag = uint8(caaFlag) rc.CaaTag = r.CaaTag - rc.SetTarget(r.CaaValue) + err = rc.SetTarget(r.CaaValue) case "TLSA": tlsaUsage, _ := strconv.ParseUint(r.TlsaUsage, 10, 8) rc.TlsaUsage = uint8(tlsaUsage) @@ -318,13 +323,13 @@ func toRc(domain string, r *domainRecord) *models.RecordConfig { rc.TlsaSelector = uint8(tlsaSelector) tlsaMatchingType, _ := strconv.ParseUint(r.TlsaMatchingType, 10, 8) rc.TlsaMatchingType = uint8(tlsaMatchingType) - rc.SetTarget(r.Target) + err = rc.SetTarget(r.Target) case "SSHFP": sshfpAlgorithm, _ := strconv.ParseUint(r.SshfpAlgorithm, 10, 8) rc.SshfpAlgorithm = uint8(sshfpAlgorithm) sshfpFingerprint, _ := strconv.ParseUint(r.SshfpFingerprint, 10, 8) rc.SshfpFingerprint = uint8(sshfpFingerprint) - rc.SetTarget(r.Target) + err = rc.SetTarget(r.Target) case "DS": dsKeyTag, _ := strconv.ParseUint(r.DsKeyTag, 10, 16) rc.DsKeyTag = uint16(dsKeyTag) @@ -333,21 +338,21 @@ func toRc(domain string, r *domainRecord) *models.RecordConfig { dsDigestType, _ := strconv.ParseUint(r.DsDigestType, 10, 8) rc.DsDigestType = uint8(dsDigestType) rc.DsDigest = r.Target - rc.SetTarget(r.Target) + err = rc.SetTarget(r.Target) case "CLOUD_WR": rc.Type = "WR" - rc.SetTarget(r.Target) + err = rc.SetTarget(r.Target) case "LOC": loc := fmt.Sprintf("%s %s %s %s %s %s %s %s %s %s %s %s", r.LocLatDeg, r.LocLatMin, r.LocLatSec, r.LocLatDir, r.LocLongDeg, r.LocLongMin, r.LocLongSec, r.LocLongDir, r.LocAltitude, r.LocSize, r.LocHPrecision, r.LocVPrecision) - rc.SetTargetLOCString(r.Target, loc) + err = rc.SetTargetLOCString(r.Target, loc) default: - rc.SetTarget(r.Target) + err = rc.SetTarget(r.Target) } - return rc + return rc, err } func formatLocParam(param string) string { diff --git a/providers/cnr/cnrProvider.go b/providers/cnr/cnrProvider.go index 5debd3f08..dfb5472e5 100644 --- a/providers/cnr/cnrProvider.go +++ b/providers/cnr/cnrProvider.go @@ -4,7 +4,7 @@ package cnr import ( "encoding/json" - "fmt" + "errors" "github.com/StackExchange/dnscontrol/v4/providers" cnrcl "github.com/centralnicgroup-opensource/rtldev-middleware-go-sdk/v5/apiclient" @@ -67,13 +67,13 @@ func newProvider(conf map[string]string) (*CNRClient, error) { api.client.EnableDebugMode() } if api.APIEntity != "OTE" && api.APIEntity != "LIVE" { - return nil, fmt.Errorf("wrong api system entity used. use \"OTE\" for OT&E system or \"LIVE\" for Live system") + return nil, errors.New("wrong api system entity used. use \"OTE\" for OT&E system or \"LIVE\" for Live system") } if api.APIEntity == "OTE" { api.client.UseOTESystem() } if api.APILogin == "" || api.APIPassword == "" { - return nil, fmt.Errorf("missing login credentials apilogin or apipassword") + return nil, errors.New("missing login credentials apilogin or apipassword") } api.client.SetCredentials(api.APILogin, api.APIPassword) return api, nil diff --git a/providers/cnr/domains.go b/providers/cnr/domains.go index fed530407..7991536c0 100644 --- a/providers/cnr/domains.go +++ b/providers/cnr/domains.go @@ -46,7 +46,7 @@ func (n *CNRClient) ListZones() ([]string, error) { } zoneColumn := r.GetColumn("DNSZONE") if zoneColumn != nil { - //return nil, fmt.Errorf("failed getting DNSZONE BASIC column") + // return nil, fmt.Errorf("failed getting DNSZONE BASIC column") zones = append(zones, zoneColumn.GetData()...) } } diff --git a/providers/cnr/records.go b/providers/cnr/records.go index 5a931b5f1..b21693968 100644 --- a/providers/cnr/records.go +++ b/providers/cnr/records.go @@ -2,6 +2,7 @@ package cnr import ( "bytes" + "errors" "fmt" "os" "regexp" @@ -46,7 +47,6 @@ func (n *CNRClient) GetZoneRecords(domain string, meta map[string]string) (model } return actual, nil - } // GetZoneRecordsCorrections returns a list of corrections that will turn existing records into dc.Records. @@ -215,7 +215,7 @@ func (n *CNRClient) getRecords(domain string) ([]*CNRRecord, error) { totalRecords += limitation // finally request all resource records available for the zone - cmd["LIMIT"] = fmt.Sprintf("%d", totalRecords) + cmd["LIMIT"] = strconv.Itoa(totalRecords) cmd["WIDE"] = "1" r = n.client.Request(cmd) @@ -227,7 +227,7 @@ func (n *CNRClient) getRecords(domain string) ([]*CNRRecord, error) { // loop over the records array rrs := r.GetRecords() - for i := 0; i < len(rrs); i++ { + for i := range len(rrs) { data := rrs[i].GetData() // fmt.Printf("Data: %+v\n", data) if _, exists := data["NAME"]; !exists { @@ -253,14 +253,14 @@ func (n *CNRClient) getRecords(domain string) ([]*CNRRecord, error) { pattern := `^CNAME|MX|NS|SRV|PTR$` re, err := regexp.Compile(pattern) if err != nil { - return nil, fmt.Errorf("error compiling regex in getRecords: %s", err) + return nil, fmt.Errorf("error compiling regex in getRecords: %w", err) } if re.MatchString(data["TYPE"]) && !strings.HasSuffix(data["CONTENT"], ".") { - data["CONTENT"] = fmt.Sprintf("%s.", data["CONTENT"]) + data["CONTENT"] = data["CONTENT"] + "." } // Only append domain if it's not already a fully qualified domain name - fqdn := fmt.Sprintf("%s.", domain) + fqdn := domain + "." if data["NAME"] != "@" && !strings.HasSuffix(data["NAME"], domain+".") { fqdn = fmt.Sprintf("%s.%s.", data["NAME"], domain) } @@ -294,17 +294,17 @@ func (n *CNRClient) createRecordString(rc *models.RecordConfig, domain string) ( case "A", "AAAA", "ANAME", "CNAME", "MX", "NS", "PTR": answer = rc.GetTargetField() if domain == host { - host = fmt.Sprintf(`%s.`, host) + host = host + "." } case "SSHFP": answer = fmt.Sprintf(`%v %v %s`, rc.SshfpAlgorithm, rc.SshfpFingerprint, rc.GetTargetField()) if domain == host { - host = fmt.Sprintf(`%s.`, host) + host = host + "." } case "NAPTR": answer = fmt.Sprintf(`%v %v "%v" "%v" "%v" %v`, rc.NaptrOrder, rc.NaptrPreference, rc.NaptrFlags, rc.NaptrService, rc.NaptrRegexp, rc.GetTargetField()) if domain == host { - host = fmt.Sprintf(`%s.`, host) + host = host + "." } case "TLSA": answer = fmt.Sprintf(`%v %v %v %s`, rc.TlsaUsage, rc.TlsaSelector, rc.TlsaMatchingType, rc.GetTargetField()) @@ -314,7 +314,7 @@ func (n *CNRClient) createRecordString(rc *models.RecordConfig, domain string) ( answer = txtutil.EncodeQuoted(rc.GetTargetTXTJoined()) case "SRV": if rc.GetTargetField() == "." { - return "", fmt.Errorf("SRV records with empty targets are not supported") + return "", errors.New("SRV records with empty targets are not supported") } // _service._proto.name. TTL Type Priority Weight Port Target. // e.g. _sip._tcp.phone.example.org. 86400 IN SRV 5 6 7 sip.example.org. @@ -325,7 +325,7 @@ func (n *CNRClient) createRecordString(rc *models.RecordConfig, domain string) ( // that have not been updated for a new RR type. } - str := host + " " + fmt.Sprint(rc.TTL) + " " + str := host + " " + strconv.FormatUint(uint64(rc.TTL), 10) + " " if rc.Type != "NS" { // TODO str += "IN " @@ -333,7 +333,7 @@ func (n *CNRClient) createRecordString(rc *models.RecordConfig, domain string) ( str += rc.Type + " " // Handle MX records which have priority if rc.Type == "MX" { - str += fmt.Sprint(uint32(rc.MxPreference)) + " " + str += strconv.FormatUint(uint64(uint32(rc.MxPreference)), 10) + " " } str += answer return str, nil @@ -344,12 +344,12 @@ func (n *CNRClient) deleteRecordString(record *CNRRecord) string { // Initialize values slice values := []string{ record.Host, - fmt.Sprintf("%v", record.TTL), + strconv.FormatUint(uint64(record.TTL), 10), "IN", record.Type, } if record.Type == "SRV" { - values = append(values, fmt.Sprintf("%d", record.Priority)) + values = append(values, strconv.FormatUint(uint64(record.Priority), 10)) } values = append(values, record.Answer) diff --git a/providers/cscglobal/api.go b/providers/cscglobal/api.go index 161acccc4..52ad5a2ec 100644 --- a/providers/cscglobal/api.go +++ b/providers/cscglobal/api.go @@ -3,6 +3,7 @@ package cscglobal import ( "bytes" "encoding/json" + "errors" "fmt" "io" "net/http" @@ -170,7 +171,7 @@ type zoneResourceRecordEdit = struct { // See: https://emretanriverdi.medium.com/json-serialization-in-go-a27aeeb968de CurrentTag *string `json:"currentTag,omitempty"` NewTag *string `json:"newTag,omitempty"` // "" needs to be sent explicitly. - NewFlag *uint8 `json:"newFlag,omitempty"` // 0 needs to be sent explictly. + NewFlag *uint8 `json:"newFlag,omitempty"` // 0 needs to be sent explicitly. } type zoneEditRequest = struct { @@ -200,13 +201,15 @@ type zoneEditStatusResultZoneEditStatusResult struct { } func (client *providerClient) getNameservers(domain string) ([]string, error) { - var bodyString, err = client.get("/domains/" + domain) + bodyString, err := client.get("/domains/" + domain) if err != nil { return nil, err } var dr domainRecord - json.Unmarshal(bodyString, &dr) + if err := json.Unmarshal(bodyString, &dr); err != nil { + return nil, fmt.Errorf("CSC Global: Error can't unmarshal NS: %w", err) + } ns := []string{} ns = append(ns, dr.Nameserver...) sort.Strings(ns) @@ -237,7 +240,9 @@ func (client *providerClient) updateNameservers(ns []string, domain string) erro } var res nsModRequestResult - json.Unmarshal(bodyString, &res) + if err := json.Unmarshal(bodyString, &res); err != nil { + return fmt.Errorf("CSC Global: Error can't unmarshal NS result: %w", err) + } if res.Result.Status.Code != "SUBMITTED" { return fmt.Errorf("CSC Global: Error update NS Code: %s Message: %s AdditionalInfo: %s", res.Result.Status.Code, res.Result.Status.Message, res.Result.Status.AdditionalInformation) } @@ -310,20 +315,22 @@ type domainsResult struct { } func (client *providerClient) getDomains() ([]string, error) { - var bodyString, err = client.get("/domains") + bodyString, err := client.get("/domains") if err != nil { return nil, err } - //printer.Printf("------------------\n") - //printer.Printf("DEBUG: GETDOMAINS bodystring = %s\n", bodyString) - //printer.Printf("------------------\n") + // printer.Printf("------------------\n") + // printer.Printf("DEBUG: GETDOMAINS bodystring = %s\n", bodyString) + // printer.Printf("------------------\n") var dr domainsResult - json.Unmarshal(bodyString, &dr) + if err := json.Unmarshal(bodyString, &dr); err != nil { + return nil, fmt.Errorf("CSC Global: Error can't unmarshal domains: %w", err) + } if dr.Meta.Pages > 1 { - return nil, fmt.Errorf("cscglobal getDomains: unimplemented paganation") + return nil, errors.New("cscglobal getDomains: unimplemented paganation") } var r []string @@ -331,15 +338,15 @@ func (client *providerClient) getDomains() ([]string, error) { r = append(r, d.QualifiedDomainName) } - //printer.Printf("------------------\n") - //printer.Printf("DEBUG: GETDOMAINS dr = %+v\n", dr) - //printer.Printf("------------------\n") + // printer.Printf("------------------\n") + // printer.Printf("DEBUG: GETDOMAINS dr = %+v\n", dr) + // printer.Printf("------------------\n") return r, nil } func (client *providerClient) getZoneRecordsAll(zone string) (*zoneResponse, error) { - var bodyString, err = client.get("/zones/" + zone) + bodyString, err := client.get("/zones/" + zone) if err != nil { return nil, err } @@ -351,7 +358,9 @@ func (client *providerClient) getZoneRecordsAll(zone string) (*zoneResponse, err } var dr zoneResponse - json.Unmarshal(bodyString, &dr) + if err := json.Unmarshal(bodyString, &dr); err != nil { + return nil, fmt.Errorf("CSC Global: Error can't unmarshal zone: %w", err) + } return &dr, nil } @@ -360,7 +369,6 @@ func (client *providerClient) getZoneRecordsAll(zone string) (*zoneResponse, err // It is best to send all the changes for a zone in one big request // because the zone is locked until the change propagates. func (client *providerClient) sendZoneEditRequest(domainname string, edits []zoneResourceRecordEdit) error { - req := zoneEditRequest{ ZoneName: domainname, Edits: &edits, @@ -382,7 +390,7 @@ func (client *providerClient) sendZoneEditRequest(domainname string, edits []zon var errResp zoneEditRequestResultZoneEditRequestResult err = json.Unmarshal(responseBody, &errResp) if err != nil { - return fmt.Errorf("CSC Global API error: %s DATA: %q", err, errResp) + return fmt.Errorf("CSC Global API error: %w DATA: %q", err, errResp) } if errResp.Content.Status != "SUCCESS" { return fmt.Errorf("CSC Global API error: %s DATA: %q", errResp.Content.Status, errResp.Content.Message) @@ -409,15 +417,15 @@ func (client *providerClient) waitRequestURL(statusURL string, returnEarly bool) for { statusBody, err := client.geturl(statusURL) if err != nil { - return fmt.Errorf("CSC Global API error: %s DATA: %q", err, statusBody) + return fmt.Errorf("CSC Global API error: %w DATA: %q", err, statusBody) } var statusResp zoneEditStatusResultZoneEditStatusResult err = json.Unmarshal(statusBody, &statusResp) if err != nil { - return fmt.Errorf("CSC Global API error: %s DATA: %q", err, statusBody) + return fmt.Errorf("CSC Global API error: %w DATA: %q", err, statusBody) } status, msg := statusResp.Content.Status, statusResp.Content.ErrorDescription - //fmt.Printf("DEBUG: stat %s %s\n", statusURL, status) + // fmt.Printf("DEBUG: stat %s %s\n", statusURL, status) if isatty.IsTerminal(os.Stdout.Fd()) { dur := time.Since(t1).Round(time.Second) @@ -429,7 +437,7 @@ func (client *providerClient) waitRequestURL(statusURL string, returnEarly bool) } if status == "FAILED" { parts := strings.Split(statusResp.Links.Cancel, "/") - client.cancelRequest(parts[len(parts)-1]) + _ = client.cancelRequest(parts[len(parts)-1]) return fmt.Errorf("update failed: %s %s", msg, statusURL) } if status == "COMPLETED" { @@ -472,24 +480,26 @@ type pagedZoneEditResponsePagedZoneEditResponse struct { // clearRequests returns after all pending requests for domain are // no longer blocking new mutations. Requests in the FAILED state are -// cancelled (because CSCG wants a human to acknowlege failures but +// cancelled (because CSCG wants a human to acknowledge failures but // thankfully permits an API call to pretend to be the human). func (client *providerClient) clearRequests(domain string) error { if cscDebug { printer.Printf("DEBUG: Clearing requests for %q\n", domain) } - var bodyString, err = client.get(`/zones/edits?size=99999&filter=zoneName==` + domain) + bodyString, err := client.get(`/zones/edits?size=99999&filter=zoneName==` + domain) if err != nil { return err } var dr pagedZoneEditResponsePagedZoneEditResponse - json.Unmarshal(bodyString, &dr) + if err := json.Unmarshal(bodyString, &dr); err != nil { + return fmt.Errorf("CSC Global: Error can't unmarshal zone edits: %w", err) + } // TODO(tlim): Ignore what's beyond the first page. // It is unlikely that there are active jobs beyond the first page. // If there are, the next edit will just wait. - //if dr.Meta.Pages > 1 { + // if dr.Meta.Pages > 1 { // return fmt.Errorf("cancelPendingEdits failed: Pages=%d", dr.Meta.Pages) //} @@ -502,16 +512,19 @@ func (client *providerClient) clearRequests(domain string) error { switch ze.Status { case "NEW", "SUBMITTED", "PROCESSING", "PROPAGATING": printer.Printf("INFO: Waiting for id=%s status=%s\n", ze.ID, ze.Status) - client.waitRequest(ze.ID) + if err := client.waitRequest(ze.ID); err != nil { + return err + } case "FAILED": printer.Printf("INFO: Deleting request status=%s id=%s\n", ze.Status, ze.ID) - client.cancelRequest(ze.ID) + if err := client.cancelRequest(ze.ID); err != nil { + return err + } case "COMPLETED", "CANCELED": continue default: return fmt.Errorf("cscglobal ClearRequests: unimplemented status: %q", ze.Status) } - } return nil @@ -524,7 +537,7 @@ func (client *providerClient) cancelRequest(reqID string) error { func (client *providerClient) put(endpoint string, requestBody []byte) ([]byte, error) { hclient := &http.Client{} - req, _ := http.NewRequest("PUT", apiBase+endpoint, bytes.NewReader(requestBody)) + req, _ := http.NewRequest(http.MethodPut, apiBase+endpoint, bytes.NewReader(requestBody)) // Add headers req.Header.Add("apikey", client.key) @@ -538,7 +551,7 @@ func (client *providerClient) put(endpoint string, requestBody []byte) ([]byte, } bodyString, _ := io.ReadAll(resp.Body) - if resp.StatusCode == 200 { + if resp.StatusCode == http.StatusOK { return bodyString, nil } @@ -558,8 +571,8 @@ func (client *providerClient) put(endpoint string, requestBody []byte) ([]byte, func (client *providerClient) delete(endpoint string) ([]byte, error) { hclient := &http.Client{} - //printer.Printf("DEBUG: delete endpoint: %q\n", apiBase+endpoint) - req, _ := http.NewRequest("DELETE", apiBase+endpoint, nil) + // printer.Printf("DEBUG: delete endpoint: %q\n", apiBase+endpoint) + req, _ := http.NewRequest(http.MethodDelete, apiBase+endpoint, nil) // Add headers req.Header.Add("apikey", client.key) @@ -573,11 +586,11 @@ func (client *providerClient) delete(endpoint string) ([]byte, error) { } bodyString, _ := io.ReadAll(resp.Body) - if resp.StatusCode == 200 { - //printer.Printf("DEBUG: Delete successful (200)\n") + if resp.StatusCode == http.StatusOK { + // printer.Printf("DEBUG: Delete successful (200)\n") return bodyString, nil } - //printer.Printf("DEBUG: Delete failed (%d)\n", resp.StatusCode) + // printer.Printf("DEBUG: Delete failed (%d)\n", resp.StatusCode) // Got a error response from API, see if it's json format var errResp errorResponse @@ -595,7 +608,7 @@ func (client *providerClient) delete(endpoint string) ([]byte, error) { func (client *providerClient) post(endpoint string, requestBody []byte) ([]byte, error) { hclient := &http.Client{} - req, _ := http.NewRequest("POST", apiBase+endpoint, bytes.NewBuffer(requestBody)) + req, _ := http.NewRequest(http.MethodPost, apiBase+endpoint, bytes.NewBuffer(requestBody)) // Add headers req.Header.Add("apikey", client.key) @@ -609,11 +622,11 @@ func (client *providerClient) post(endpoint string, requestBody []byte) ([]byte, } bodyString, _ := io.ReadAll(resp.Body) - //printer.Printf("------------------\n") - //printer.Printf("DEBUG: resp.StatusCode == %d\n", resp.StatusCode) - //printer.Printf("POST RESPONSE = %s\n", bodyString) - //printer.Printf("------------------\n") - if resp.StatusCode == 201 { + // printer.Printf("------------------\n") + // printer.Printf("DEBUG: resp.StatusCode == %d\n", resp.StatusCode) + // printer.Printf("POST RESPONSE = %s\n", bodyString) + // printer.Printf("------------------\n") + if resp.StatusCode == http.StatusCreated { return bodyString, nil } @@ -637,7 +650,7 @@ func (client *providerClient) get(endpoint string) ([]byte, error) { func (client *providerClient) geturl(url string) ([]byte, error) { hclient := &http.Client{} - req, _ := http.NewRequest("GET", url, nil) + req, _ := http.NewRequest(http.MethodGet, url, nil) // Add headers req.Header.Add("apikey", client.key) @@ -645,7 +658,7 @@ func (client *providerClient) geturl(url string) ([]byte, error) { req.Header.Add("Accept", "application/json") // Default CSCGlobal rate limit is twenty requests per second - var backoff = time.Second + backoff := time.Second const maxBackoff = time.Second * 25 @@ -656,11 +669,11 @@ retry: } bodyString, _ := io.ReadAll(resp.Body) - if resp.StatusCode == 200 { + if resp.StatusCode == http.StatusOK { return bodyString, nil } - if resp.StatusCode == 400 { + if resp.StatusCode == http.StatusBadRequest { // 400, error message is in the body as plain text // Apparently CSCGlobal uses status code 400 for rate limit, grump diff --git a/providers/cscglobal/convert.go b/providers/cscglobal/convert.go index 4ffab7c17..d6e33d3fc 100644 --- a/providers/cscglobal/convert.go +++ b/providers/cscglobal/convert.go @@ -19,7 +19,9 @@ func nativeToRecordA(nr nativeRecordA, origin string, defaultTTL uint32) *models TTL: ttl, } rc.SetLabel(nr.Key, origin) - rc.SetTargetIP(net.ParseIP(nr.Value).To4()) + if err := rc.SetTargetIP(net.ParseIP(nr.Value).To4()); err != nil { + panic(err) // Should never happen. + } return rc } @@ -34,7 +36,9 @@ func nativeToRecordCNAME(nr nativeRecordCNAME, origin string, defaultTTL uint32) TTL: ttl, } rc.SetLabel(nr.Key, origin) - rc.SetTarget(nr.Value) + if err := rc.SetTarget(nr.Value); err != nil { + panic(err) // Should never happen. + } return rc } @@ -49,7 +53,9 @@ func nativeToRecordAAAA(nr nativeRecordAAAA, origin string, defaultTTL uint32) * TTL: ttl, } rc.SetLabel(nr.Key, origin) - rc.SetTargetIP(net.ParseIP(nr.Value).To16()) + if err := rc.SetTargetIP(net.ParseIP(nr.Value).To16()); err != nil { + panic(err) // Should never happen. + } return rc } @@ -64,7 +70,9 @@ func nativeToRecordTXT(nr nativeRecordTXT, origin string, defaultTTL uint32) *mo TTL: ttl, } rc.SetLabel(nr.Key, origin) - rc.SetTargetTXT(nr.Value) + if err := rc.SetTargetTXT(nr.Value); err != nil { + panic(err) // Should never happen. + } return rc } @@ -79,7 +87,9 @@ func nativeToRecordMX(nr nativeRecordMX, origin string, defaultTTL uint32) *mode TTL: ttl, } rc.SetLabel(nr.Key, origin) - rc.SetTargetMX(nr.Priority, nr.Value) + if err := rc.SetTargetMX(nr.Priority, nr.Value); err != nil { + panic(err) // Should never happen. + } return rc } @@ -94,7 +104,7 @@ func nativeToRecordNS(nr nativeRecordNS, origin string, defaultTTL uint32) *mode TTL: ttl, } rc.SetLabel(nr.Key, origin) - rc.SetTarget(nr.Value) + rc.MustSetTarget(nr.Value) return rc } @@ -109,7 +119,9 @@ func nativeToRecordSRV(nr nativeRecordSRV, origin string, defaultTTL uint32) *mo TTL: ttl, } rc.SetLabel(nr.Key, origin) - rc.SetTargetSRV(nr.Priority, nr.Weight, nr.Port, nr.Value) + if err := rc.SetTargetSRV(nr.Priority, nr.Weight, nr.Port, nr.Value); err != nil { + panic(err) // Should never happen. + } return rc } @@ -124,6 +136,8 @@ func nativeToRecordCAA(nr nativeRecordCAA, origin string, defaultTTL uint32) *mo TTL: ttl, } rc.SetLabel(nr.Key, origin) - rc.SetTargetCAA(nr.Flag, nr.Tag, nr.Value) + if err := rc.SetTargetCAA(nr.Flag, nr.Tag, nr.Value); err != nil { + panic(err) // Should never happen. + } return rc } diff --git a/providers/cscglobal/cscglobalProvider.go b/providers/cscglobal/cscglobalProvider.go index 8b0d431f9..f74d31e86 100644 --- a/providers/cscglobal/cscglobalProvider.go +++ b/providers/cscglobal/cscglobalProvider.go @@ -2,7 +2,7 @@ package cscglobal import ( "encoding/json" - "fmt" + "errors" "strings" "github.com/StackExchange/dnscontrol/v4/providers" @@ -50,7 +50,7 @@ func newProvider(m map[string]string) (*providerClient, error) { api.key, api.token = m["api-key"], m["user-token"] if api.key == "" || api.token == "" { - return nil, fmt.Errorf("missing CSC Global api-key and/or user-token") + return nil, errors.New("missing CSC Global api-key and/or user-token") } if m["notification_emails"] != "" { diff --git a/providers/cscglobal/dns.go b/providers/cscglobal/dns.go index 840dc81bd..d889f6972 100644 --- a/providers/cscglobal/dns.go +++ b/providers/cscglobal/dns.go @@ -76,7 +76,6 @@ func (client *providerClient) GetNameservers(domain string) ([]*models.Nameserve // GetZoneRecordsCorrections returns a list of corrections that will turn existing records into dc.Records. func (client *providerClient) GetZoneRecordsCorrections(dc *models.DomainConfig, foundRecords models.Records) ([]*models.Correction, int, error) { - toReport, creates, dels, modifications, actualChangeCount, err := diff.NewCompat(dc).IncrementalDiff(foundRecords) if err != nil { return nil, 0, err @@ -144,8 +143,8 @@ func makePurge(cor diff.Correlation) zoneResourceRecordEdit { } if cor.Existing.Type == "CAA" { - var tagValue = cor.Existing.CaaTag - //printer.Printf("DEBUG: CAA TAG = %q\n", tagValue) + tagValue := cor.Existing.CaaTag + // printer.Printf("DEBUG: CAA TAG = %q\n", tagValue) zer.CurrentTag = &tagValue } @@ -173,8 +172,8 @@ func makeAdd(cre diff.Correlation) zoneResourceRecordEdit { switch rec.Type { case "CAA": - var tagValue = rec.CaaTag - var flagValue = rec.CaaFlag + tagValue := rec.CaaTag + flagValue := rec.CaaFlag zer.NewTag = &tagValue zer.NewFlag = &flagValue case "MX": @@ -222,7 +221,7 @@ func makeEdit(m diff.Correlation) zoneResourceRecordEdit { switch old.Type { case "CAA": - var tagValue = old.CaaTag + tagValue := old.CaaTag zer.CurrentTag = &tagValue if old.CaaTag != rec.CaaTag || old.CaaFlag != rec.CaaFlag || old.TTL != rec.TTL { // If anything changed, we need to update both tag and flag. diff --git a/providers/cscglobal/listzones.go b/providers/cscglobal/listzones.go index dfd1a2c3c..c86b14635 100644 --- a/providers/cscglobal/listzones.go +++ b/providers/cscglobal/listzones.go @@ -2,6 +2,5 @@ package cscglobal // ListZones returns all the zones in an account func (client *providerClient) ListZones() ([]string, error) { - return client.getDomains() } diff --git a/providers/cscglobal/registrar.go b/providers/cscglobal/registrar.go index 47ead9721..96db1c6d4 100644 --- a/providers/cscglobal/registrar.go +++ b/providers/cscglobal/registrar.go @@ -1,6 +1,7 @@ package cscglobal import ( + "errors" "fmt" "sort" "strings" @@ -21,7 +22,7 @@ func (client *providerClient) GetRegistrarCorrections(dc *models.DomainConfig) ( if ns.Name[len(ns.Name)-1] == '.' { // When this code was written ns.Name never included a single trailing dot. // If that changes, the code should change too. - return nil, fmt.Errorf("name server includes a trailing dot, has the API changed?") + return nil, errors.New("name server includes a trailing dot, has the API changed?") } expected = append(expected, ns.Name) } diff --git a/providers/desec/convert.go b/providers/desec/convert.go index 4d67c3e57..a9f202e17 100644 --- a/providers/desec/convert.go +++ b/providers/desec/convert.go @@ -11,7 +11,6 @@ import ( // nativeToRecord takes a DNS record from deSEC and returns a native RecordConfig struct. func nativeToRecords(n resourceRecord, origin string) (rcs []*models.RecordConfig) { - // deSEC returns all the values for a given label/rtype pair in each // resourceRecord. In other words, if there are multiple A // records for a label, all the IP addresses are listed in @@ -40,7 +39,7 @@ func recordsToNative(rcs []*models.RecordConfig) []resourceRecord { // deSEC requires one resourceRecord for each label:key tuple, therefore we // might collapse many RecordConfig into one resourceRecord. - var keys = map[models.RecordKey]*resourceRecord{} + keys := map[models.RecordKey]*resourceRecord{} var zrs []resourceRecord for _, r := range rcs { label := r.GetLabel() @@ -67,7 +66,6 @@ func recordsToNative(rcs []*models.RecordConfig) []resourceRecord { zr.TTL = r.TTL } } - } } diff --git a/providers/desec/desecProvider.go b/providers/desec/desecProvider.go index 4c425f7ca..9363e3ae9 100644 --- a/providers/desec/desecProvider.go +++ b/providers/desec/desecProvider.go @@ -3,6 +3,7 @@ package desec import ( "bytes" "encoding/json" + "errors" "fmt" "strings" @@ -24,7 +25,7 @@ func NewDeSec(m map[string]string, metadata json.RawMessage) (providers.DNSServi c := &desecProvider{} c.token = strings.TrimSpace(m["auth-token"]) if c.token == "" { - return nil, fmt.Errorf("missing deSEC auth-token") + return nil, errors.New("missing deSEC auth-token") } return c, nil } @@ -105,7 +106,7 @@ func (c *desecProvider) GetZoneRecords(domain string, meta map[string]string) (m // Convert them to DNScontrol's native format: existingRecords := []*models.RecordConfig{} - //spew.Dump(records) + // spew.Dump(records) for _, rr := range records { existingRecords = append(existingRecords, nativeToRecords(rr, domain)...) } @@ -134,7 +135,7 @@ func PrepDesiredRecords(dc *models.DomainConfig, minTTL uint32) { // provider. We try to do minimal changes otherwise it gets // confusing. - //dc.Punycode() + // dc.Punycode() recordsToKeep := make([]*models.RecordConfig, 0, len(dc.Records)) for _, rec := range dc.Records { if rec.Type == "ALIAS" { @@ -182,8 +183,8 @@ func (c *desecProvider) GetZoneRecordsCorrections(dc *models.DomainConfig, exist // For any key with an update, delete or replace those records. for label := range keysToUpdate { if _, ok := desiredRecords[label]; !ok { - //we could not find this RecordKey in the desiredRecords - //this means it must be deleted + // we could not find this RecordKey in the desiredRecords + // this means it must be deleted for i, msg := range keysToUpdate[label] { if i == 0 { rc := resourceRecord{} @@ -198,12 +199,12 @@ func (c *desecProvider) GetZoneRecordsCorrections(dc *models.DomainConfig, exist fmt.Fprintln(buf, msg) rrs = append(rrs, rc) } else { - //just add the message + // just add the message fmt.Fprintln(buf, msg) } } } else { - //it must be an update or create, both can be done with the same api call. + // it must be an update or create, both can be done with the same api call. ns := recordsToNative(desiredRecords[label]) if len(ns) > 1 { panic("we got more than one resource record to create / modify") @@ -213,7 +214,7 @@ func (c *desecProvider) GetZoneRecordsCorrections(dc *models.DomainConfig, exist rrs = append(rrs, ns[0]) fmt.Fprintln(buf, msg) } else { - //noop just for printing the additional messages + // noop just for printing the additional messages fmt.Fprintln(buf, msg) } } @@ -243,7 +244,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, actualChangeCount, nil } diff --git a/providers/desec/protocol.go b/providers/desec/protocol.go index f36e3bcf5..8cd231168 100644 --- a/providers/desec/protocol.go +++ b/providers/desec/protocol.go @@ -20,7 +20,7 @@ const apiBase = "https://desec.io/api/v1" // Api layer for desec type desecProvider struct { - domainIndex map[string]uint32 //stores the minimum ttl of each domain. (key = domain and value = ttl) + domainIndex map[string]uint32 // stores the minimum ttl of each domain. (key = domain and value = ttl) domainIndexLock sync.Mutex token string } @@ -106,9 +106,9 @@ func (c *desecProvider) searchDomainIndex(domain string) (ttl uint32, found bool func (c *desecProvider) fetchDomainIndex() (map[string]uint32, error) { endpoint := "/domains/" var domainIndex map[string]uint32 - var bodyString, resp, err = c.get(endpoint, "GET") - if resp.StatusCode == 400 && resp.Header.Get("Link") != "" { - //pagination is required + bodyString, resp, err := c.get(endpoint, "GET") + if resp.StatusCode == http.StatusBadRequest && resp.Header.Get("Link") != "" { + // pagination is required links := convertLinks(resp.Header.Get("Link")) endpoint = links["first"] printer.Debugf("initial endpoint %s\n", endpoint) @@ -126,11 +126,11 @@ func (c *desecProvider) fetchDomainIndex() (map[string]uint32, error) { printer.Debugf("next endpoint %s\n", endpoint) } printer.Debugf("Domain Index fetched with pagination (%d domains)\n", len(domainIndex)) - return domainIndex, nil //domainIndex was build using pagination without errors + return domainIndex, nil // domainIndex was build using pagination without errors } - //no pagination required - if err != nil && resp.StatusCode != 400 { + // no pagination required + if err != nil && resp.StatusCode != http.StatusBadRequest { return nil, fmt.Errorf("failed fetching domains: %w", err) } domainIndex, err = appendDomainIndexFromResponse(domainIndex, bodyString) @@ -152,8 +152,8 @@ func appendDomainIndexFromResponse(domainIndex map[string]uint32, bodyString []b domainIndex = make(map[string]uint32, len(dr)) } for _, domain := range dr { - //deSEC allows different minimum ttls per domain - //we store the actual minimum ttl to use it in desecProvider.go GetDomainCorrections() to enforce the minimum ttl and avoid api errors. + // deSEC allows different minimum ttls per domain + // we store the actual minimum ttl to use it in desecProvider.go GetDomainCorrections() to enforce the minimum ttl and avoid api errors. domainIndex[domain.Name] = domain.MinimumTTL } return domainIndex, nil @@ -176,7 +176,7 @@ func convertLinks(links string) map[string]string { continue } // mapping["$label"] = "$URL" - //URL = https://desec.io/api/v1/domains/{domain}/rrsets/?cursor=:next_cursor + // URL = https://desec.io/api/v1/domains/{domain}/rrsets/?cursor=:next_cursor mapping[matches[1]] = strings.TrimSuffix(strings.TrimPrefix(tmpurl[0], "<"), ">") } return mapping @@ -185,16 +185,16 @@ func convertLinks(links string) map[string]string { func (c *desecProvider) getRecords(domain string) ([]resourceRecord, error) { endpoint := "/domains/%s/rrsets/" var rrsNew []resourceRecord - var bodyString, resp, err = c.get(fmt.Sprintf(endpoint, domain), "GET") - if resp.StatusCode == 400 && resp.Header.Get("Link") != "" { - //pagination required + bodyString, resp, err := c.get(fmt.Sprintf(endpoint, domain), "GET") + if resp.StatusCode == http.StatusBadRequest && resp.Header.Get("Link") != "" { + // pagination required links := convertLinks(resp.Header.Get("Link")) endpoint = links["first"] printer.Debugf("getRecords: initial endpoint %s\n", fmt.Sprintf(endpoint, domain)) for endpoint != "" { bodyString, resp, err = c.get(endpoint, "GET") if err != nil { - if resp.StatusCode == 404 { + if resp.StatusCode == http.StatusNotFound { return rrsNew, nil } return rrsNew, fmt.Errorf("getRecords: failed fetching rrsets: %w", err) @@ -209,9 +209,9 @@ func (c *desecProvider) getRecords(domain string) ([]resourceRecord, error) { printer.Debugf("getRecords: next endpoint %s\n", endpoint) } printer.Debugf("Build rrset using pagination (%d rrs)\n", len(rrsNew)) - return rrsNew, nil //domainIndex was build using pagination without errors + return rrsNew, nil // domainIndex was build using pagination without errors } - //no pagination + // no pagination if err != nil { return rrsNew, fmt.Errorf("failed fetching records for domain %s (deSEC): %w", domain, err) } @@ -277,7 +277,7 @@ func (c *desecProvider) upsertRR(rr []resourceRecord, domain string) error { // Uncomment this function in case of using it // It was commented out to satisfy `staticcheck` warnings about unused code -//func (c *desecProvider) deleteRR(domain, shortname, t string) error { +// func (c *desecProvider) deleteRR(domain, shortname, t string) error { // endpoint := fmt.Sprintf("/domains/%s/rrsets/%s/%s/", domain, shortname, t) // if _, _, err := c.get(endpoint, "DELETE"); err != nil { // return fmt.Errorf("failed delete RRset (deSEC): %w", err) @@ -297,7 +297,7 @@ retry: client := &http.Client{} req, _ := http.NewRequest(method, endpoint, nil) q := req.URL.Query() - req.Header.Add("Authorization", fmt.Sprintf("Token %s", c.token)) + req.Header.Add("Authorization", "Token "+c.token) req.URL.RawQuery = q.Encode() @@ -309,9 +309,9 @@ retry: bodyString, _ := io.ReadAll(resp.Body) // Got error from API ? if resp.StatusCode > 299 { - if resp.StatusCode == 429 && retrycnt < 5 { + if resp.StatusCode == http.StatusTooManyRequests && retrycnt < 5 { retrycnt++ - //we've got rate limiting and will try to get the Retry-After Header if this fails we fallback to sleep for 500ms max. 5 retries. + // we've got rate limiting and will try to get the Retry-After Header if this fails we fallback to sleep for 500ms max. 5 retries. waitfor := resp.Header.Get("Retry-After") if waitfor != "" { wait, err := strconv.ParseInt(waitfor, 10, 64) @@ -361,7 +361,7 @@ retry: } q := req.URL.Query() if endpoint != "/auth/login/" { - req.Header.Add("Authorization", fmt.Sprintf("Token %s", c.token)) + req.Header.Add("Authorization", "Token "+c.token) } req.Header.Set("Content-Type", "application/json") @@ -376,9 +376,9 @@ retry: // Got error from API ? if resp.StatusCode > 299 { - if resp.StatusCode == 429 && retrycnt < 5 { + if resp.StatusCode == http.StatusTooManyRequests && retrycnt < 5 { retrycnt++ - //we've got rate limiting and will try to get the Retry-After Header if this fails we fallback to sleep for 500ms max. 5 retries. + // we've got rate limiting and will try to get the Retry-After Header if this fails we fallback to sleep for 500ms max. 5 retries. waitfor := resp.Header.Get("Retry-After") if waitfor != "" { wait, err := strconv.ParseInt(waitfor, 10, 64) @@ -409,6 +409,6 @@ retry: } return bodyString, fmt.Errorf("HTTP status %s Body: %s, the API does not provide more information", resp.Status, bodyString) } - //time.Sleep(334 * time.Millisecond) + // time.Sleep(334 * time.Millisecond) return bodyString, nil } diff --git a/providers/digitalocean/auditrecords.go b/providers/digitalocean/auditrecords.go index 01e7f5001..05f50a302 100644 --- a/providers/digitalocean/auditrecords.go +++ b/providers/digitalocean/auditrecords.go @@ -1,7 +1,7 @@ package digitalocean import ( - "fmt" + "errors" "github.com/StackExchange/dnscontrol/v4/models" "github.com/StackExchange/dnscontrol/v4/pkg/rejectif" @@ -42,10 +42,10 @@ func MaxLengthDO(rc *models.RecordConfig) error { // including the quotes, backlashes used for escapes, spaces between // substrings. // In other words, they're doing the checking on the API protocol - // encoded data instead of on on the resulting TXT record. Sigh. + // encoded data instead of on the resulting TXT record. Sigh. if len(rc.GetTargetRFC1035Quoted()) > 509 { - return fmt.Errorf("encoded txt too long") + return errors.New("encoded txt too long") } return nil diff --git a/providers/digitalocean/digitaloceanProvider.go b/providers/digitalocean/digitaloceanProvider.go index 5f5ad3657..6e334084e 100644 --- a/providers/digitalocean/digitaloceanProvider.go +++ b/providers/digitalocean/digitaloceanProvider.go @@ -3,6 +3,7 @@ package digitalocean import ( "context" "encoding/json" + "errors" "fmt" "log" "net/http" @@ -41,7 +42,7 @@ const perPageSize = 100 // NewDo creates a DO-specific DNS provider. func NewDo(m map[string]string, metadata json.RawMessage) (providers.DNSServiceProvider, error) { if m["token"] == "" { - return nil, fmt.Errorf("no DigitalOcean token provided") + return nil, errors.New("no DigitalOcean token provided") } ctx := context.Background() @@ -63,7 +64,7 @@ retry: return nil, err } if resp.StatusCode != http.StatusOK { - return nil, fmt.Errorf("token for digitalocean is not valid") + return nil, errors.New("token for digitalocean is not valid") } return api, nil @@ -101,7 +102,7 @@ retry: if pauseAndRetry(resp) { goto retry } - //return err + // return err } if resp.StatusCode == http.StatusNotFound { _, _, err := api.client.Domains.Create(ctx, &godo.DomainCreateRequest{ @@ -161,7 +162,10 @@ func (api *digitaloceanProvider) GetZoneRecords(domain string, meta map[string]s var existingRecords []*models.RecordConfig for i := range records { - r := toRc(domain, &records[i]) + r, err := toRc(domain, &records[i]) + if err != nil { + return nil, err + } if r.Type == "SOA" { continue } @@ -272,7 +276,7 @@ retry: return records, nil } -func toRc(domain string, r *godo.DomainRecord) *models.RecordConfig { +func toRc(domain string, r *godo.DomainRecord) (*models.RecordConfig, error) { // This handles "@" etc. name := dnsutil.AddOrigin(r.Name, domain) @@ -303,11 +307,15 @@ func toRc(domain string, r *godo.DomainRecord) *models.RecordConfig { t.SetLabelFromFQDN(name, domain) switch rtype := r.Type; rtype { case "TXT": - t.SetTargetTXT(target) + if err := t.SetTargetTXT(target); err != nil { + return nil, err + } default: - t.SetTarget(target) + if err := t.SetTarget(target); err != nil { + return nil, err + } } - return t + return t, nil } func toReq(rc *models.RecordConfig) *godo.DomainRecordEditRequest { diff --git a/providers/dnsimple/dnsimpleProvider.go b/providers/dnsimple/dnsimpleProvider.go index 860220cc6..5407600c8 100644 --- a/providers/dnsimple/dnsimpleProvider.go +++ b/providers/dnsimple/dnsimpleProvider.go @@ -141,7 +141,7 @@ func (c *dnsimpleProvider) GetZoneRecords(domain string, meta map[string]string) if isQuotedTXT(r.Content) { err = rec.PopulateFromStringFunc(r.Type, r.Content, domain, txtutil.ParseQuoted) } else { - err = rec.SetTargetTXT(fmt.Sprintf("legacy: %s", r.Content)) + err = rec.SetTargetTXT("legacy: " + r.Content) } default: err = rec.PopulateFromString(r.Type, r.Content, domain) @@ -306,7 +306,7 @@ func (c *dnsimpleProvider) getAccountID() (string, error) { return "", err } if whoamiResponse.Data.User != nil && whoamiResponse.Data.Account == nil { - return "", fmt.Errorf("DNSimple token appears to be a user token. Please supply an account token") + return "", errors.New("DNSimple token appears to be a user token. Please supply an account token") } c.accountID = strconv.FormatInt(whoamiResponse.Data.Account.ID, 10) } @@ -461,7 +461,6 @@ func (c *dnsimpleProvider) getNameservers(domainName string) ([]string, error) { } if domainResponse.Data.State == stateRegistered { - delegationResponse, err := client.Registrar.GetDomainDelegation(context.Background(), accountID, domainName) if err != nil { var errorResponse *dnsimpleapi.ErrorResponse @@ -651,7 +650,7 @@ func newProvider(m map[string]string, _ json.RawMessage) (*dnsimpleProvider, err api := &dnsimpleProvider{} api.AccountToken = m["token"] if api.AccountToken == "" { - return nil, fmt.Errorf("missing DNSimple token") + return nil, errors.New("missing DNSimple token") } if m["baseurl"] != "" { diff --git a/providers/dnsmadeeasy/api.go b/providers/dnsmadeeasy/api.go index 879f9b439..4c104665a 100644 --- a/providers/dnsmadeeasy/api.go +++ b/providers/dnsmadeeasy/api.go @@ -1,6 +1,7 @@ package dnsmadeeasy import ( + "errors" "fmt" "net/http" "time" @@ -49,7 +50,7 @@ func (api *dnsMadeEasyProvider) loadDomains() error { for _, domain := range res.Data { if domain.GtdEnabled { - return fmt.Errorf("fetching domains from DNSMADEEASY failed: domains with GTD enabled are not supported") + return errors.New("fetching domains from DNSMADEEASY failed: domains with GTD enabled are not supported") } domains[domain.Name] = domain @@ -97,7 +98,7 @@ func (api *dnsMadeEasyProvider) fetchDomainRecords(domainName string) ([]recordR records := make([]recordResponseDataEntry, 0) for _, record := range res.Data { if record.GtdLocation != "DEFAULT" { - return nil, fmt.Errorf("fetching records from DNSMADEEASY failed: only records with DEFAULT GTD location are supported") + return nil, errors.New("fetching records from DNSMADEEASY failed: only records with DEFAULT GTD location are supported") } records = append(records, record) @@ -127,7 +128,6 @@ func (api *dnsMadeEasyProvider) fetchDomainNameServers(domainName string) ([]str func (api *dnsMadeEasyProvider) createDomain(domain string) error { _, err := api.restAPI.singleDomainCreate(singleDomainRequestData{Name: domain}) - if err != nil { return err } diff --git a/providers/dnsmadeeasy/dnsMadeEasyProvider.go b/providers/dnsmadeeasy/dnsMadeEasyProvider.go index 08f5655aa..2b996aa1a 100644 --- a/providers/dnsmadeeasy/dnsMadeEasyProvider.go +++ b/providers/dnsmadeeasy/dnsMadeEasyProvider.go @@ -2,7 +2,7 @@ package dnsmadeeasy import ( "encoding/json" - "fmt" + "errors" "os" "strings" @@ -45,11 +45,11 @@ func init() { // New creates a new API handle. func New(settings map[string]string, _ json.RawMessage) (providers.DNSServiceProvider, error) { if settings["api_key"] == "" { - return nil, fmt.Errorf("missing DNSMADEEASY api_key") + return nil, errors.New("missing DNSMADEEASY api_key") } if settings["secret_key"] == "" { - return nil, fmt.Errorf("missing DNSMADEEASY secret_key") + return nil, errors.New("missing DNSMADEEASY secret_key") } sandbox := false diff --git a/providers/dnsmadeeasy/restApi.go b/providers/dnsmadeeasy/restApi.go index ac87e29f0..dfc93a139 100644 --- a/providers/dnsmadeeasy/restApi.go +++ b/providers/dnsmadeeasy/restApi.go @@ -7,11 +7,12 @@ import ( "encoding/hex" "encoding/json" "fmt" - "github.com/StackExchange/dnscontrol/v4/pkg/printer" "net/http" "net/http/httputil" "strings" "time" + + "github.com/StackExchange/dnscontrol/v4/pkg/printer" ) const ( @@ -222,7 +223,7 @@ retry: if restApi.dumpHTTPRequest { dump, _ := httputil.DumpRequest(req, true) - printer.Printf(string(dump)) + printer.Printf("%s", string(dump)) } res, err := restApi.httpClient.Do(req) @@ -234,7 +235,7 @@ retry: if restApi.dumpHTTPResponse { dump, _ := httputil.DumpResponse(res, true) - printer.Printf(string(dump)) + printer.Printf("%s", string(dump)) } if res.StatusCode < http.StatusOK || res.StatusCode >= http.StatusBadRequest { diff --git a/providers/doh/api.go b/providers/doh/api.go index 25699f245..07963998f 100644 --- a/providers/doh/api.go +++ b/providers/doh/api.go @@ -20,7 +20,7 @@ func (c *dohProvider) getNameservers(domain string) ([]string, error) { // Perform a NS lookup nss, _, err := resolver.LookupNS(domain) if err != nil { - return nil, fmt.Errorf("failed fetching nameservers list (DNS-over-HTTPS): %s", err) + return nil, fmt.Errorf("failed fetching nameservers list (DNS-over-HTTPS): %w", err) } ns := []string{} diff --git a/providers/domainnameshop/api.go b/providers/domainnameshop/api.go index 8b04d9252..05abf8fb4 100644 --- a/providers/domainnameshop/api.go +++ b/providers/domainnameshop/api.go @@ -3,6 +3,7 @@ package domainnameshop import ( "bytes" "encoding/json" + "errors" "fmt" "net/http" "strconv" @@ -176,7 +177,9 @@ func (api *domainNameShopProvider) UpdateRecord(dnsR *domainNameShopRecord) erro recordID := strconv.Itoa(dnsR.ID) payloadBuf := new(bytes.Buffer) - json.NewEncoder(payloadBuf).Encode(&dnsR) + if err := json.NewEncoder(payloadBuf).Encode(&dnsR); err != nil { + return err + } return api.sendChangeRequest(http.MethodPut, rootAPIURI+"/domains/"+domainID+"/dns/"+recordID, payloadBuf) } @@ -203,20 +206,20 @@ func (api *domainNameShopProvider) sendChangeRequest(method string, uri string, } switch resp.StatusCode { - case 201: + case http.StatusCreated: // Record is deleted return nil - case 204: - //Update successful + case http.StatusNoContent: + // Update successful return nil - case 400: - return fmt.Errorf("DNS record failed validation") - case 403: - return fmt.Errorf("not authorized") - case 404: - return fmt.Errorf("does not exist") - case 409: - return fmt.Errorf("collision") + case http.StatusBadRequest: + return errors.New("DNS record failed validation") + case http.StatusForbidden: + return errors.New("not authorized") + case http.StatusNotFound: + return errors.New("does not exist") + case http.StatusConflict: + return errors.New("collision") default: return fmt.Errorf("unknown statuscode: %v", resp.StatusCode) } diff --git a/providers/domainnameshop/convert.go b/providers/domainnameshop/convert.go index 0a2cedf58..44566fbcf 100644 --- a/providers/domainnameshop/convert.go +++ b/providers/domainnameshop/convert.go @@ -7,7 +7,7 @@ import ( "github.com/miekg/dns/dnsutil" ) -func toRecordConfig(domain string, currentRecord *domainNameShopRecord) *models.RecordConfig { +func toRecordConfig(domain string, currentRecord *domainNameShopRecord) (*models.RecordConfig, error) { name := dnsutil.AddOrigin(currentRecord.Host, domain) target := currentRecord.Data @@ -24,12 +24,16 @@ func toRecordConfig(domain string, currentRecord *domainNameShopRecord) *models. CaaFlag: uint8(currentRecord.CAAFlag), } - t.SetTarget(target) + if err := t.SetTarget(target); err != nil { + return nil, err + } t.SetLabelFromFQDN(name, domain) switch rtype := currentRecord.Type; rtype { case "TXT": - t.SetTargetTXT(target) + if err := t.SetTargetTXT(target); err != nil { + return nil, err + } case "CAA": if currentRecord.CAATag == "0" { t.CaaTag = "issue" @@ -41,7 +45,7 @@ func toRecordConfig(domain string, currentRecord *domainNameShopRecord) *models. default: // nothing additional required } - return t + return t, nil } func (api *domainNameShopProvider) fromRecordConfig(domainName string, rc *models.RecordConfig) (*domainNameShopRecord, error) { diff --git a/providers/domainnameshop/dns.go b/providers/domainnameshop/dns.go index 6915b65f1..69005a427 100644 --- a/providers/domainnameshop/dns.go +++ b/providers/domainnameshop/dns.go @@ -17,7 +17,10 @@ func (api *domainNameShopProvider) GetZoneRecords(domain string, meta map[string var existingRecords []*models.RecordConfig for i := range records { - rC := toRecordConfig(domain, &records[i]) + rC, err := toRecordConfig(domain, &records[i]) + if err != nil { + return nil, err + } existingRecords = append(existingRecords, rC) } @@ -26,11 +29,12 @@ func (api *domainNameShopProvider) GetZoneRecords(domain string, meta map[string // GetZoneRecordsCorrections returns a list of corrections that will turn existing records into dc.Records. func (api *domainNameShopProvider) GetZoneRecordsCorrections(dc *models.DomainConfig, existingRecords models.Records) ([]*models.Correction, int, error) { - // Merge TXT strings to one string for _, rc := range dc.Records { if rc.HasFormatIdenticalToTXT() { - rc.SetTargetTXT(rc.GetTargetTXTJoined()) + if err := rc.SetTargetTXT(rc.GetTargetTXTJoined()); err != nil { + return nil, 0, err + } } } @@ -39,7 +43,7 @@ func (api *domainNameShopProvider) GetZoneRecordsCorrections(dc *models.DomainCo record.TTL = fixTTL(record.TTL) } - toReport, create, delete, modify, actualChangeCount, err := diff.NewCompat(dc).IncrementalDiff(existingRecords) + toReport, toCreate, toDelete, toModify, actualChangeCount, err := diff.NewCompat(dc).IncrementalDiff(existingRecords) if err != nil { return nil, 0, err } @@ -47,7 +51,7 @@ func (api *domainNameShopProvider) GetZoneRecordsCorrections(dc *models.DomainCo corrections := diff.GenerateMessageCorrections(toReport) // Delete record - for _, r := range delete { + for _, r := range toDelete { domainID := r.Existing.Original.(*domainNameShopRecord).DomainID recordID := strconv.Itoa(r.Existing.Original.(*domainNameShopRecord).ID) @@ -59,7 +63,7 @@ func (api *domainNameShopProvider) GetZoneRecordsCorrections(dc *models.DomainCo } // Create records - for _, r := range create { + for _, r := range toCreate { // Retrieve the domain name that is targeted. I.e. example.com instead of sub.example.com domainName := strings.Replace(r.Desired.GetLabelFQDN(), r.Desired.GetLabel()+".", "", -1) @@ -76,7 +80,7 @@ func (api *domainNameShopProvider) GetZoneRecordsCorrections(dc *models.DomainCo corrections = append(corrections, corr) } - for _, r := range modify { + for _, r := range toModify { domainName := strings.Replace(r.Desired.GetLabelFQDN(), r.Desired.GetLabel()+".", "", -1) dnsR, err := api.fromRecordConfig(domainName, r.Desired) @@ -105,9 +109,11 @@ func (api *domainNameShopProvider) GetNameservers(domain string) ([]*models.Name return models.ToNameservers(ns) } -const minAllowedTTL = 60 -const maxAllowedTTL = 604800 -const multiplierTTL = 60 +const ( + minAllowedTTL = 60 + maxAllowedTTL = 604800 + multiplierTTL = 60 +) func fixTTL(ttl uint32) uint32 { // if the TTL is larger than the largest allowed value, return the largest allowed value diff --git a/providers/domainnameshop/domainnameshopProvider.go b/providers/domainnameshop/domainnameshopProvider.go index ed92f3816..152140c3b 100644 --- a/providers/domainnameshop/domainnameshopProvider.go +++ b/providers/domainnameshop/domainnameshopProvider.go @@ -2,7 +2,7 @@ package domainnameshop import ( "encoding/json" - "fmt" + "errors" "github.com/StackExchange/dnscontrol/v4/providers" ) @@ -61,9 +61,9 @@ func init() { // newDomainNameShopProvider creates a Domainnameshop specific DNS provider. func newDomainNameShopProvider(conf map[string]string, metadata json.RawMessage) (providers.DNSServiceProvider, error) { if conf["token"] == "" { - return nil, fmt.Errorf("no Domainnameshop token provided") + return nil, errors.New("no Domainnameshop token provided") } else if conf["secret"] == "" { - return nil, fmt.Errorf("no Domainnameshop secret provided") + return nil, errors.New("no Domainnameshop secret provided") } api := &domainNameShopProvider{ diff --git a/providers/dynadot/api.go b/providers/dynadot/api.go index 232fa2f3e..ae19481fb 100644 --- a/providers/dynadot/api.go +++ b/providers/dynadot/api.go @@ -2,6 +2,7 @@ package dynadot import ( "encoding/xml" + "errors" "fmt" "io" "net/http" @@ -44,12 +45,14 @@ type nsContent struct { } func (c *dynadotProvider) getNameservers(domain string) ([]string, error) { - var bodyString, err = c.get("get_ns", requestParams{"domain": domain}) + bodyString, err := c.get("get_ns", requestParams{"domain": domain}) if err != nil { - return []string{}, fmt.Errorf("failed NS list (Dynadot): %s", err) + return []string{}, fmt.Errorf("failed NS list (Dynadot): %w", err) } var ns getNsResponse - xml.Unmarshal(bodyString, &ns) + if err := xml.Unmarshal(bodyString, &ns); err != nil { + return []string{}, fmt.Errorf("failed to unmarshal NS list (Dynadot): %w", err) + } if ns.GetNsHeader.SuccessCode != 0 { return []string{}, fmt.Errorf("failed NS list (Dynadot): %s", ns.GetNsHeader.Error) @@ -62,19 +65,19 @@ func (c *dynadotProvider) getNameservers(domain string) ([]string, error) { func (c *dynadotProvider) updateNameservers(ns []string, domain string) error { if len(ns) > 13 { - return fmt.Errorf("failed NS update (Dynadot): only up to 13 nameservers are supported") + return errors.New("failed NS update (Dynadot): only up to 13 nameservers are supported") } // Nameservers must first be added to the Dynadot account for _, host := range ns { b, err := c.get("add_ns", requestParams{"host": host}) if err != nil { - return fmt.Errorf("failed NS add (Dynadot): %s", err) + return fmt.Errorf("failed NS add (Dynadot): %w", err) } var resp addNsResponse err = xml.Unmarshal(b, &resp) if err != nil { - return fmt.Errorf("failed NS add (Dynadot): %s", err) + return fmt.Errorf("failed NS add (Dynadot): %w", err) } if resp.AddNsHeader.SuccessCode != 0 { @@ -83,7 +86,6 @@ func (c *dynadotProvider) updateNameservers(ns []string, domain string) error { continue } return fmt.Errorf("failed NS add (Dynadot): %s", resp.AddNsHeader.Error) - } } @@ -96,13 +98,13 @@ func (c *dynadotProvider) updateNameservers(ns []string, domain string) error { b, err := c.get("set_ns", rec) if err != nil { - return fmt.Errorf("failed NS set (Dynadot): %s", err) + return fmt.Errorf("failed NS set (Dynadot): %w", err) } var resp setNsResponse err = xml.Unmarshal(b, &resp) if err != nil { - return fmt.Errorf("failed NS add (Dynadot): %s", err) + return fmt.Errorf("failed NS add (Dynadot): %w", err) } if resp.SetNsHeader.SuccessCode != 0 { @@ -114,7 +116,7 @@ func (c *dynadotProvider) updateNameservers(ns []string, domain string) error { func (c *dynadotProvider) get(command string, params requestParams) ([]byte, error) { client := &http.Client{} - req, _ := http.NewRequest("GET", "https://api.dynadot.com/api3.xml", nil) + req, _ := http.NewRequest(http.MethodGet, "https://api.dynadot.com/api3.xml", nil) q := req.URL.Query() q.Add("key", c.key) diff --git a/providers/dynadot/dynadotProvider.go b/providers/dynadot/dynadotProvider.go index 23da0ec34..342d3ab73 100644 --- a/providers/dynadot/dynadotProvider.go +++ b/providers/dynadot/dynadotProvider.go @@ -1,6 +1,7 @@ package dynadot import ( + "errors" "fmt" "sort" "strings" @@ -36,7 +37,7 @@ func newDynadot(m map[string]string) (providers.Registrar, error) { d.key = m["key"] if d.key == "" { - return nil, fmt.Errorf("missing Dynadot key") + return nil, errors.New("missing Dynadot key") } return d, nil diff --git a/providers/easyname/api.go b/providers/easyname/api.go index 2da122ad8..d9a2ebfdd 100644 --- a/providers/easyname/api.go +++ b/providers/easyname/api.go @@ -72,7 +72,9 @@ func (c *easynameProvider) request(method, uri string, body *bytes.Buffer, resul } bodyString, _ := io.ReadAll(resp.Body) - json.Unmarshal(bodyString, &result) + if err := json.Unmarshal(bodyString, &result); err != nil { + return err + } status := result.GetStatus() if status.Type != "success" && status.Type != "pending" { @@ -115,7 +117,9 @@ func (c *easynameProvider) updateNameservers(nss []string, domain int) error { func (c *easynameProvider) getDomain(domain string) (easynameDomain, error) { if c.domains == nil { - c.fetchDomainList() + if err := c.fetchDomainList(); err != nil { + return easynameDomain{}, err + } } d, ok := c.domains[domain] diff --git a/providers/easyname/easynameProvider.go b/providers/easyname/easynameProvider.go index 3c4ec58f0..39eba7025 100644 --- a/providers/easyname/easynameProvider.go +++ b/providers/easyname/easynameProvider.go @@ -1,6 +1,7 @@ package easyname import ( + "errors" "fmt" "sort" "strings" @@ -33,7 +34,7 @@ func newEasyname(m map[string]string) (providers.Registrar, error) { api := &easynameProvider{} if m["email"] == "" || m["userid"] == "" || m["apikey"] == "" || m["authsalt"] == "" || m["signsalt"] == "" { - return nil, fmt.Errorf("missing easyname email, userid, apikey, authsalt and/or signsalt") + return nil, errors.New("missing easyname email, userid, apikey, authsalt and/or signsalt") } api.apikey, api.signSalt = m["apikey"], m["signsalt"] diff --git a/providers/exoscale/exoscaleProvider.go b/providers/exoscale/exoscaleProvider.go index 999fe2599..9832a4687 100644 --- a/providers/exoscale/exoscaleProvider.go +++ b/providers/exoscale/exoscaleProvider.go @@ -8,12 +8,11 @@ import ( "strconv" "strings" - egoscale "github.com/exoscale/egoscale/v2" - "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/providers" + egoscale "github.com/exoscale/egoscale/v2" ) const ( @@ -94,7 +93,7 @@ func (c *exoscaleProvider) GetNameservers(domain string) ([]*models.Nameserver, // GetZoneRecords gets the records of a zone and returns them in RecordConfig format. func (c *exoscaleProvider) GetZoneRecords(domainName string, meta map[string]string) (models.Records, error) { - //dc.Punycode() + // dc.Punycode() domain, err := c.findDomainByName(domainName) if err != nil { @@ -166,7 +165,7 @@ func (c *exoscaleProvider) GetZoneRecords(domainName string, meta map[string]str switch rtype { case "ALIAS", "URL": rc.Type = rtype - rc.SetTarget(rcontent) + err = rc.SetTarget(rcontent) case "MX": var prio uint16 if record.Priority != nil { @@ -188,7 +187,6 @@ func (c *exoscaleProvider) GetZoneRecords(domainName string, meta map[string]str // GetZoneRecordsCorrections returns a list of corrections that will turn existing records into dc.Records. func (c *exoscaleProvider) GetZoneRecordsCorrections(dc *models.DomainConfig, existingRecords models.Records) ([]*models.Correction, int, error) { - removeOtherNS(dc) domain, err := c.findDomainByName(dc.Name) if err != nil { @@ -220,11 +218,11 @@ func (c *exoscaleProvider) GetZoneRecordsCorrections(dc *models.DomainConfig, ex } for _, mod := range modify { - old := mod.Existing.Original.(*egoscale.DNSDomainRecord) - new := mod.Desired + old_ := mod.Existing.Original.(*egoscale.DNSDomainRecord) + new_ := mod.Desired corrections = append(corrections, &models.Correction{ Msg: mod.String(), - F: c.updateRecordFunc(old, new, domainID), + F: c.updateRecordFunc(old_, new_, domainID), }) } diff --git a/providers/gandiv5/convert.go b/providers/gandiv5/convert.go index 46e325932..b5795450f 100644 --- a/providers/gandiv5/convert.go +++ b/providers/gandiv5/convert.go @@ -13,7 +13,6 @@ import ( // nativeToRecord takes a DNS record from Gandi and returns a native RecordConfig struct. func nativeToRecords(n livedns.DomainRecord, origin string) (rcs []*models.RecordConfig, err error) { - // Gandi returns all the values for a given label/rtype pair in each // livedns.DomainRecord. In other words, if there are multiple A // records for a label, all the IP addresses are listed in @@ -48,7 +47,7 @@ func recordsToNative(rcs []*models.RecordConfig, origin string) []livedns.Domain // Gandi requires one ZoneRecord for each label:key tuple, therefore we // might collapse many RecordConfig into one ZoneRecord. - var keys = map[models.RecordKey]*livedns.DomainRecord{} + keys := map[models.RecordKey]*livedns.DomainRecord{} var zrs []livedns.DomainRecord for _, r := range rcs { @@ -76,7 +75,6 @@ func recordsToNative(rcs []*models.RecordConfig, origin string) []livedns.Domain zr.RrsetTTL = int(r.TTL) } } - } } diff --git a/providers/gandiv5/convert_test.go b/providers/gandiv5/convert_test.go index 1d3a8b131..339106257 100644 --- a/providers/gandiv5/convert_test.go +++ b/providers/gandiv5/convert_test.go @@ -7,10 +7,10 @@ import ( ) func TestRecordsToNative_1(t *testing.T) { - var rcs = []*models.RecordConfig{{}} + rcs := []*models.RecordConfig{{}} rcs[0].SetLabelFromFQDN("foo.example.com", "example.com") rcs[0].Type = "A" - rcs[0].SetTarget("1.2.3.4") + rcs[0].MustSetTarget("1.2.3.4") ns := recordsToNative(rcs, "example.com") @@ -20,17 +20,16 @@ func TestRecordsToNative_1(t *testing.T) { if len(ns[0].RrsetValues) != 1 { t.Errorf("len(ns[0].RrsetValues) != 1; got=%v", ns[0].RrsetValues) } - } func TestRecordsToNative_2(t *testing.T) { - var rcs = []*models.RecordConfig{{}, {}} + rcs := []*models.RecordConfig{{}, {}} rcs[0].SetLabelFromFQDN("foo.example.com", "example.com") rcs[0].Type = "A" - rcs[0].SetTarget("1.2.3.4") + rcs[0].MustSetTarget("1.2.3.4") rcs[1].SetLabelFromFQDN("foo.example.com", "example.com") rcs[1].Type = "A" - rcs[1].SetTarget("5.6.7.8") + rcs[1].MustSetTarget("5.6.7.8") ns := recordsToNative(rcs, "example.com") @@ -40,5 +39,4 @@ func TestRecordsToNative_2(t *testing.T) { if len(ns[0].RrsetValues) != 2 { t.Errorf("len(ns[0].RrsetValues) != 2; got=%v", ns[0].RrsetValues) } - } diff --git a/providers/gandiv5/gandi_v5Provider.go b/providers/gandiv5/gandi_v5Provider.go index 4220e6f5c..6bea18c42 100644 --- a/providers/gandiv5/gandi_v5Provider.go +++ b/providers/gandiv5/gandi_v5Provider.go @@ -15,6 +15,7 @@ Settings from `creds.json`: import ( "encoding/json" + "errors" "fmt" "os" "sort" @@ -95,7 +96,7 @@ func newHelper(m map[string]string, _ json.RawMessage) (*gandiv5Provider, error) api.apikey = m["apikey"] api.token = m["token"] if (api.apikey == "") && (api.token == "") { - return nil, fmt.Errorf("missing Gandi personal access token (or apikey - deprecated)") + return nil, errors.New("missing Gandi personal access token (or apikey - deprecated)") } api.sharingid = m["sharing_id"] api.apiurl = m["apiurl"] @@ -220,7 +221,6 @@ func (client *gandiv5Provider) GetZoneRecordsCorrections(dc *models.DomainConfig } for _, inst := range instructions { switch inst.Type { - case diff2.REPORT: corrections = append(corrections, &models.Correction{Msg: inst.MsgsJoined}) @@ -289,7 +289,6 @@ func (client *gandiv5Provider) GetZoneRecordsCorrections(dc *models.DomainConfig default: panic(fmt.Sprintf("unhandled inst.Type %s", inst.Type)) } - } return corrections, actualChangeCount, nil @@ -297,7 +296,7 @@ func (client *gandiv5Provider) GetZoneRecordsCorrections(dc *models.DomainConfig // debugRecords prints a list of RecordConfig. func debugRecords(note string, recs []*models.RecordConfig) { - printer.Debugf(note) + printer.Debugf("%s", note) for k, v := range recs { printer.Printf(" %v: %v %v %v %v\n", k, v.GetLabel(), v.Type, v.TTL, v.GetTargetDebug()) } @@ -343,7 +342,8 @@ func (client *gandiv5Provider) GetRegistrarCorrections(dc *models.DomainConfig) F: func() (err error) { err = gd.UpdateNameServers(dc.Name, desiredNs) return - }}, + }, + }, }, nil } return nil, nil diff --git a/providers/gcloud/gcloudProvider.go b/providers/gcloud/gcloudProvider.go index ae976139f..27a721265 100644 --- a/providers/gcloud/gcloudProvider.go +++ b/providers/gcloud/gcloudProvider.go @@ -3,6 +3,7 @@ package gcloud import ( "context" "encoding/json" + "errors" "fmt" "log" "regexp" @@ -125,7 +126,7 @@ func New(cfg map[string]string, metadata json.RawMessage) (providers.DNSServiceP } if len(g.Visibility) != 0 { if ok := visibilityCheck.MatchString(g.Visibility); !ok { - return nil, fmt.Errorf("GCLOUD :visibility set but not one of \"public\" or \"private\"") + return nil, errors.New("GCLOUD :visibility set but not one of \"public\" or \"private\"") } printer.Printf("GCLOUD :visibility %s configured\n", g.Visibility) } @@ -242,7 +243,6 @@ func (g *gcloudProvider) getZoneSets(domain string) (models.Records, error) { // 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, int, error) { - changes, actualChangeCount, err := diff2.ByRecordSet(existingRecords, dc, nil) if err != nil { return nil, 0, err @@ -258,7 +258,6 @@ func (g *gcloudProvider) GetZoneRecordsCorrections(dc *models.DomainConfig, exis var newAdds, newDels *gdns.ResourceRecordSet for _, change := range changes { - // Determine the work to be done. n := change.Key.NameFQDN + "." ty := change.Key.Type @@ -303,7 +302,6 @@ func (g *gcloudProvider) GetZoneRecordsCorrections(dc *models.DomainConfig, exis if len(newMsgs) != 0 { accumlatedMsgs = append(accumlatedMsgs, newMsgs...) } - } // Process the remaining work. @@ -380,7 +378,6 @@ func (g *gcloudProvider) mkCorrection(corrections []*models.Correction, accumula // process calls the Google DNS API to process a Change and re-tries if needed. func (g *gcloudProvider) process(origin string, batch *gdns.Change) error { - zoneName, err := g.getZone(origin) if err != nil || zoneName == nil { return fmt.Errorf("zoneNameMap: no zone named %q", origin) @@ -492,13 +489,17 @@ func (g *gcloudProvider) EnsureZoneExists(domain string) error { return err } -const initialBackoff = time.Second * 10 // First delay duration -const maxBackoff = time.Minute * 3 // Maximum backoff delay +const ( + initialBackoff = time.Second * 10 // First delay duration + maxBackoff = time.Minute * 3 // Maximum backoff delay +) // backoff is the amount of time to sleep if a 429 or 504 is received. // It is doubled after each use. -var backoff = initialBackoff -var backoff404 = false // Set if the last call requested a retry of a 404 +var ( + backoff = initialBackoff + backoff404 = false // Set if the last call requested a retry of a 404 +) func retryNeeded(resp *googleapi.ServerResponse, err error) bool { if err != nil { diff --git a/providers/gcore/convert.go b/providers/gcore/convert.go index d4b3731b6..dc092e032 100644 --- a/providers/gcore/convert.go +++ b/providers/gcore/convert.go @@ -75,10 +75,6 @@ func recordsToNative(rcs []*models.RecordConfig, expectedKey models.RecordKey) ( var resultRRSetMetaSourceRecord *models.RecordConfig = nil for _, r := range rcs { - label := r.GetLabel() - if label == "@" { - label = "" - } key := r.Key() if key != expectedKey { diff --git a/providers/gcore/convertMetadata.go b/providers/gcore/convertMetadata.go index 1b940e267..175f8a26a 100644 --- a/providers/gcore/convertMetadata.go +++ b/providers/gcore/convertMetadata.go @@ -374,7 +374,7 @@ func isListStructEqual[T any](a []T, b []T) (bool, error) { return true, nil } - for i := 0; i < len(a); i++ { + for i := range len(a) { result, err := isStructEqual(a[i], b[i]) if err != nil { return false, err diff --git a/providers/gcore/gcoreExtend.go b/providers/gcore/gcoreExtend.go index 18a1fc7cb..d8fbf9ba4 100644 --- a/providers/gcore/gcoreExtend.go +++ b/providers/gcore/gcoreExtend.go @@ -65,7 +65,7 @@ func dnssdkDo(ctx context.Context, c *dnssdk.Client, apiKey string, method, uri } req.Header.Set("Content-Type", "application/json") - req.Header.Set("Authorization", fmt.Sprintf("APIKey %s", apiKey)) + req.Header.Set("Authorization", "APIKey "+apiKey) if c.UserAgent != "" { req.Header.Set("User-Agent", c.UserAgent) } @@ -93,7 +93,7 @@ func dnssdkDo(ctx context.Context, c *dnssdk.Client, apiKey string, method, uri return nil } - // nolint: wrapcheck + //nolint: wrapcheck return json.NewDecoder(resp.Body).Decode(dest) } @@ -115,7 +115,7 @@ func (c *gcoreProvider) dnssdkRRSets(domain string) (gcoreRRSets, error) { func (c *gcoreProvider) dnssdkGetDNSSEC(domain string) (bool, error) { var result gcoreZone - url := fmt.Sprintf("/v2/zones/%s", domain) + url := "/v2/zones/" + domain err := dnssdkDo(c.ctx, c.provider, c.apiKey, http.MethodGet, url, nil, &result) if err != nil { diff --git a/providers/gcore/gcoreProvider.go b/providers/gcore/gcoreProvider.go index 3548635f1..a3a34ee14 100644 --- a/providers/gcore/gcoreProvider.go +++ b/providers/gcore/gcoreProvider.go @@ -3,15 +3,15 @@ package gcore import ( "context" "encoding/json" + "errors" "fmt" "strings" + dnssdk "github.com/G-Core/gcore-dns-sdk-go" "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/providers" - - dnssdk "github.com/G-Core/gcore-dns-sdk-go" ) /* @@ -29,7 +29,7 @@ type gcoreProvider struct { // NewGCore creates the provider. func NewGCore(m map[string]string, metadata json.RawMessage) (providers.DNSServiceProvider, error) { if m["api-key"] == "" { - return nil, fmt.Errorf("missing G-Core API key") + return nil, errors.New("missing G-Core API key") } c := &gcoreProvider{ @@ -139,7 +139,6 @@ func generateChangeMsg(updates []string) string { // correction, and a message to output to the user when the change is // made. func (c *gcoreProvider) GetZoneRecordsCorrections(dc *models.DomainConfig, existing models.Records) ([]*models.Correction, int, error) { - // Make delete happen earlier than creates & updates. var corrections []*models.Correction var deletions []*models.Correction diff --git a/providers/hedns/hednsProvider.go b/providers/hedns/hednsProvider.go index 5db74bc1e..2fcd68f29 100644 --- a/providers/hedns/hednsProvider.go +++ b/providers/hedns/hednsProvider.go @@ -2,6 +2,7 @@ package hedns import ( "crypto/sha1" + "encoding/hex" "encoding/json" "errors" "fmt" @@ -188,7 +189,6 @@ func (c *hednsProvider) GetNameservers(_ string) ([]*models.Nameserver, error) { // GetZoneRecordsCorrections returns a list of corrections that will turn existing records into dc.Records. func (c *hednsProvider) GetZoneRecordsCorrections(dc *models.DomainConfig, records models.Records) ([]*models.Correction, int, error) { - // Get the SOA record to get the ZoneID, then remove it from the list. zoneID := uint64(0) var prunedRecords models.Records @@ -400,7 +400,6 @@ func (c *hednsProvider) authUsernameAndPassword() (authenticated bool, requiresT } func (c *hednsProvider) auth2FA() (authenticated bool, err error) { - if c.TfaValue == "" && c.TfaSecret == "" { return false, errors.New("account requires two-factor authentication but neither totp or totp-key were provided") } @@ -438,7 +437,6 @@ func (c *hednsProvider) auth2FA() (authenticated bool, err error) { } func (c *hednsProvider) authenticate() error { - if c.SessionFilePath != "" { _ = c.loadSessionFile() } @@ -613,7 +611,7 @@ func (c *hednsProvider) generateCredentialHash() string { hash.Write([]byte(c.Username)) hash.Write([]byte(c.Password)) hash.Write([]byte(c.TfaSecret)) - return fmt.Sprintf("%x", hash.Sum(nil)) + return hex.EncodeToString(hash.Sum(nil)) } func (c *hednsProvider) saveSessionFile() error { @@ -632,7 +630,7 @@ func (c *hednsProvider) saveSessionFile() error { } fileName := path.Join(c.SessionFilePath, sessionFileName) - err = os.WriteFile(fileName, []byte(strings.Join(entries, "\n")), 0600) + err = os.WriteFile(fileName, []byte(strings.Join(entries, "\n")), 0o600) return err } @@ -674,7 +672,7 @@ func (c *hednsProvider) loadSessionFile() error { } func (c *hednsProvider) parseResponseForDocumentAndErrors(response *http.Response) (document *goquery.Document, err error) { - var ignoredErrorMessages = [...]string{ + ignoredErrorMessages := [...]string{ errorImproperDelegation, } diff --git a/providers/hetzner/api.go b/providers/hetzner/api.go index 8efcd449e..ce5039ceb 100644 --- a/providers/hetzner/api.go +++ b/providers/hetzner/api.go @@ -66,7 +66,7 @@ func (api *hetznerProvider) createZone(name string) error { } func (api *hetznerProvider) deleteRecord(record *record) error { - url := fmt.Sprintf("/records/%s", record.ID) + url := "/records/" + record.ID return api.request(url, "DELETE", nil, nil, nil) } diff --git a/providers/hetzner/hetznerProvider.go b/providers/hetzner/hetznerProvider.go index 414b2ecfc..b92db3f5b 100644 --- a/providers/hetzner/hetznerProvider.go +++ b/providers/hetzner/hetznerProvider.go @@ -2,7 +2,7 @@ package hetzner import ( "encoding/json" - "fmt" + "errors" "strings" "github.com/StackExchange/dnscontrol/v4/models" @@ -47,7 +47,7 @@ func init() { func New(settings map[string]string, _ json.RawMessage) (providers.DNSServiceProvider, error) { apiKey := settings["api_key"] if apiKey == "" { - return nil, fmt.Errorf("missing HETZNER api_key") + return nil, errors.New("missing HETZNER api_key") } return &hetznerProvider{ diff --git a/providers/hexonet/domains.go b/providers/hexonet/domains.go index e83cc2308..7313f38d4 100644 --- a/providers/hexonet/domains.go +++ b/providers/hexonet/domains.go @@ -40,7 +40,7 @@ func (n *HXClient) ListZones() ([]string, error) { } zoneColumn := r.GetColumn("DNSZONE") if zoneColumn != nil { - //return nil, fmt.Errorf("failed getting DNSZONE BASIC column") + // return nil, fmt.Errorf("failed getting DNSZONE BASIC column") zones = append(zones, zoneColumn.GetData()...) } } diff --git a/providers/hexonet/hexonetProvider.go b/providers/hexonet/hexonetProvider.go index 3b24e1b0b..6dfaf817c 100644 --- a/providers/hexonet/hexonetProvider.go +++ b/providers/hexonet/hexonetProvider.go @@ -3,7 +3,7 @@ package hexonet import ( "encoding/json" - "fmt" + "errors" "github.com/StackExchange/dnscontrol/v4/providers" hxcl "github.com/centralnicgroup-opensource/rtldev-middleware-go-sdk/v4/apiclient" @@ -51,13 +51,13 @@ func newProvider(conf map[string]string) (*HXClient, error) { api.client.SetRemoteIPAddress(conf["ipaddress"]) } if api.APIEntity != "OTE" && api.APIEntity != "LIVE" { - return nil, fmt.Errorf("wrong api system entity used. use \"OTE\" for OT&E system or \"LIVE\" for Live system") + return nil, errors.New("wrong api system entity used. use \"OTE\" for OT&E system or \"LIVE\" for Live system") } if api.APIEntity == "OTE" { api.client.UseOTESystem() } if api.APILogin == "" || api.APIPassword == "" { - return nil, fmt.Errorf("missing login credentials apilogin or apipassword") + return nil, errors.New("missing login credentials apilogin or apipassword") } api.client.SetCredentials(api.APILogin, api.APIPassword) return api, nil diff --git a/providers/hexonet/records.go b/providers/hexonet/records.go index 64c3240b0..37b2c1b38 100644 --- a/providers/hexonet/records.go +++ b/providers/hexonet/records.go @@ -2,6 +2,7 @@ package hexonet import ( "bytes" + "errors" "fmt" "math" "strconv" @@ -48,12 +49,11 @@ func (n *HXClient) GetZoneRecords(domain string, meta map[string]string) (models for _, rec := range actual { if rec.Type == "ALIAS" { - return nil, fmt.Errorf("we support realtime ALIAS RR over our X-DNS service, please get in touch with us") + return nil, errors.New("we support realtime ALIAS RR over our X-DNS service, please get in touch with us") } } return actual, nil - } // GetZoneRecordsCorrections returns a list of corrections that will turn existing records into dc.Records. @@ -92,10 +92,10 @@ func (n *HXClient) GetZoneRecordsCorrections(dc *models.DomainConfig, actual mod for _, chng := range mod { changes = true fmt.Fprintln(buf, chng) - old := chng.Existing.Original.(*HXRecord) - new := chng.Desired - params[fmt.Sprintf("DELRR%d", delrridx)] = n.deleteRecordString(old) - newRecordString, err := n.createRecordString(new, dc.Name) + old_ := chng.Existing.Original.(*HXRecord) + new_ := chng.Desired + params[fmt.Sprintf("DELRR%d", delrridx)] = n.deleteRecordString(old_) + newRecordString, err := n.createRecordString(new_, dc.Name) if err != nil { return corrections, 0, err } @@ -245,7 +245,7 @@ func (n *HXClient) createRecordString(rc *models.RecordConfig, domain string) (s record.Answer = txtutil.EncodeQuoted(rc.GetTargetTXTJoined()) 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')") + return "", errors.New("SRV records with empty targets are not supported (as of 2020-02-27, the API returns 'Invalid attribute value syntax')") } record.Answer = fmt.Sprintf("%d %d %v", rc.SrvWeight, rc.SrvPort, record.Answer) record.Priority = uint32(rc.SrvPriority) @@ -255,9 +255,9 @@ func (n *HXClient) createRecordString(rc *models.RecordConfig, domain string) (s // that have not been updated for a new RR type. } - str := record.Host + " " + fmt.Sprint(record.TTL) + " IN " + record.Type + " " + str := record.Host + " " + strconv.FormatUint(uint64(record.TTL), 10) + " IN " + record.Type + " " if record.Type == "MX" || record.Type == "SRV" { - str += fmt.Sprint(record.Priority) + " " + str += strconv.FormatUint(uint64(record.Priority), 10) + " " } str += record.Answer return str, nil diff --git a/providers/hostingde/hostingdeProvider.go b/providers/hostingde/hostingdeProvider.go index aa109007d..1867be2a2 100644 --- a/providers/hostingde/hostingdeProvider.go +++ b/providers/hostingde/hostingdeProvider.go @@ -2,6 +2,7 @@ package hostingde import ( "encoding/json" + "errors" "fmt" "math" "sort" @@ -56,7 +57,7 @@ func newHostingde(m map[string]string, providermeta json.RawMessage) (*hostingde authToken, ownerAccountID, filterAccountID, baseURL := m["authToken"], m["ownerAccountId"], m["filterAccountId"], m["baseURL"] if authToken == "" { - return nil, fmt.Errorf("hosting.de: authtoken must be provided") + return nil, errors.New("hosting.de: authtoken must be provided") } if baseURL == "" { @@ -103,19 +104,23 @@ func (hp *hostingdeProvider) GetZoneRecords(domain string, meta map[string]strin if err != nil { return nil, err } - return hp.APIRecordsToStandardRecordsModel(domain, zone.Records), nil + return hp.APIRecordsToStandardRecordsModel(domain, zone.Records) } -func (hp *hostingdeProvider) APIRecordsToStandardRecordsModel(domain string, src []record) models.Records { +func (hp *hostingdeProvider) APIRecordsToStandardRecordsModel(domain string, src []record) (models.Records, error) { records := []*models.RecordConfig{} for _, r := range src { if r.Type == "SOA" { continue } - records = append(records, r.nativeToRecord(domain)) + newr, err := r.nativeToRecord(domain) + if err != nil { + return nil, err + } + records = append(records, newr) } - return records + return records, nil } func soaToString(s soaValues) string { @@ -271,9 +276,9 @@ func (hp *hostingdeProvider) GetZoneRecordsCorrections(dc *models.DomainConfig, } corrections = append(corrections, &models.Correction{ - Msg: fmt.Sprintf("\n%s", strings.Join(msg, "\n")), + Msg: "\n" + strings.Join(msg, "\n"), F: func() error { - for i := 0; i < 10; i++ { + for i := range 10 { err := hp.updateZone(&zone.ZoneConfig, DNSSecOptions, create, del, mod) if err == nil { return nil @@ -287,7 +292,7 @@ func (hp *hostingdeProvider) GetZoneRecordsCorrections(dc *models.DomainConfig, // Base of 1.8 seemed like a good trade-off, retrying for approximately 45 seconds. time.Sleep(time.Duration(math.Pow(1.8, float64(i))) * 100 * time.Millisecond) } - return fmt.Errorf("retry exhaustion: zone blocked for 10 attempts") + return errors.New("retry exhaustion: zone blocked for 10 attempts") }, }, ) @@ -353,7 +358,7 @@ func (hp *hostingdeProvider) GetRegistrarCorrections(dc *models.DomainConfig) ([ func (hp *hostingdeProvider) EnsureZoneExists(domain string) error { _, err := hp.getZoneConfig(domain) - if err == errZoneNotFound { + if errors.Is(err, errZoneNotFound) { if err := hp.createZone(domain); err != nil { return err } @@ -371,5 +376,4 @@ func (hp *hostingdeProvider) ListZones() ([]string, error) { zones = append(zones, zoneConfig.Name) } return zones, nil - } diff --git a/providers/hostingde/types.go b/providers/hostingde/types.go index 4f789ba2a..85485a45a 100644 --- a/providers/hostingde/types.go +++ b/providers/hostingde/types.go @@ -11,9 +11,7 @@ import ( "github.com/pkg/errors" ) -var ( - errZoneNotFound = errors.Errorf("zone not found") -) +var errZoneNotFound = errors.Errorf("zone not found") type request struct { AuthToken string `json:"authToken"` @@ -138,7 +136,7 @@ type responseData struct { TotalPages uint `json:"totalPages"` } -func (r record) nativeToRecord(domain string) *models.RecordConfig { +func (r record) nativeToRecord(domain string) (*models.RecordConfig, error) { // normalize cname,mx,ns records with dots to be consistent with our config format. if r.Type == "ALIAS" || r.Type == "CNAME" || r.Type == "MX" || r.Type == "NS" || r.Type == "SRV" { if r.Content != "." { @@ -159,7 +157,7 @@ func (r record) nativeToRecord(domain string) *models.RecordConfig { switch r.Type { case "ALIAS": rc.Type = r.Type - rc.SetTarget(r.Content) + err = rc.SetTarget(r.Content) case "NULLMX": err = rc.PopulateFromString("MX", "0 .", domain) case "MX": @@ -170,15 +168,9 @@ func (r record) nativeToRecord(domain string) *models.RecordConfig { case "SRV": err = rc.SetTargetSRVPriorityString(uint16(r.Priority), r.Content) default: - if err := rc.PopulateFromString(r.Type, r.Content, domain); err != nil { - panic(err) - } + err = rc.PopulateFromString(r.Type, r.Content, domain) } - if err != nil { - panic(err) - } - - return rc + return rc, err } func recordToNative(rc *models.RecordConfig) *record { diff --git a/providers/huaweicloud/convert.go b/providers/huaweicloud/convert.go index e577b0ce5..e30bc49a5 100644 --- a/providers/huaweicloud/convert.go +++ b/providers/huaweicloud/convert.go @@ -1,6 +1,7 @@ package huaweicloud import ( + "errors" "fmt" "slices" "strconv" @@ -49,7 +50,7 @@ func nativeToRecords(n *model.ShowRecordSetByZoneResp, zoneName string) (models. rc.Metadata[metaLine] = *n.Line } if n.Weight != nil { - rc.Metadata[metaWeight] = fmt.Sprintf("%d", *n.Weight) + rc.Metadata[metaWeight] = strconv.Itoa(int(*n.Weight)) } if n.Description != nil { rc.Metadata[metaKey] = *n.Description @@ -63,7 +64,7 @@ func nativeToRecords(n *model.ShowRecordSetByZoneResp, zoneName string) (models. func recordsToNative(rcs models.Records, expectedKey models.RecordKey) (*model.ShowRecordSetByZoneResp, error) { // rcs length is guaranteed to be > 0 if len(rcs) == 0 { - return nil, fmt.Errorf("empty record set") + return nil, errors.New("empty record set") } // line and weight should be the same for all records in the rrset line := rcs[0].Metadata[metaLine] @@ -87,7 +88,7 @@ func recordsToNative(rcs models.Records, expectedKey models.RecordKey) (*model.S weightInt32 := int32(weightInt) // weight should be 0-1000 if weightInt32 < 0 || weightInt32 > 1000 { - return nil, fmt.Errorf("weight must be between 0 and 1000") + return nil, errors.New("weight must be between 0 and 1000") } weight = &weightInt32 } diff --git a/providers/internetbs/api.go b/providers/internetbs/api.go index beaabf135..818005a84 100644 --- a/providers/internetbs/api.go +++ b/providers/internetbs/api.go @@ -29,12 +29,14 @@ type domainRecord struct { } func (c *internetbsProvider) getNameservers(domain string) ([]string, error) { - var bodyString, err = c.get("/Domain/Info", requestParams{"Domain": domain}) + bodyString, err := c.get("/Domain/Info", requestParams{"Domain": domain}) if err != nil { - return []string{}, fmt.Errorf("failed fetching nameservers list (Internet.bs): %s", err) + return []string{}, fmt.Errorf("failed fetching nameservers list (Internet.bs): %w", err) } var dr domainRecord - json.Unmarshal(bodyString, &dr) + if err := json.Unmarshal(bodyString, &dr); err != nil { + return []string{}, fmt.Errorf("failed to unmarshal nameservers list (Internet.bs): %w", err) + } ns := []string{} ns = append(ns, dr.Nameserver...) return ns, nil @@ -45,14 +47,14 @@ func (c *internetbsProvider) updateNameservers(ns []string, domain string) error rec["Domain"] = domain rec["Ns_list"] = strings.Join(ns, ",") if _, err := c.get("/Domain/Update", rec); err != nil { - return fmt.Errorf("failed NS update (Internet.bs): %s", err) + return fmt.Errorf("failed NS update (Internet.bs): %w", err) } return nil } func (c *internetbsProvider) get(endpoint string, params requestParams) ([]byte, error) { client := &http.Client{} - req, _ := http.NewRequest("GET", "https://api.internet.bs/"+endpoint, nil) + req, _ := http.NewRequest(http.MethodGet, "https://api.internet.bs/"+endpoint, nil) q := req.URL.Query() // Add auth params diff --git a/providers/internetbs/internetbsProvider.go b/providers/internetbs/internetbsProvider.go index a1224ff20..f0c9ec467 100644 --- a/providers/internetbs/internetbsProvider.go +++ b/providers/internetbs/internetbsProvider.go @@ -1,6 +1,7 @@ package internetbs import ( + "errors" "fmt" "sort" "strings" @@ -37,7 +38,7 @@ func newInternetBs(m map[string]string) (providers.Registrar, error) { api.key, api.password = m["api-key"], m["password"] if api.key == "" || api.password == "" { - return nil, fmt.Errorf("missing Internet.bs api-key and password") + return nil, errors.New("missing Internet.bs api-key and password") } return api, nil diff --git a/providers/inwx/inwxProvider.go b/providers/inwx/inwxProvider.go index 3c5ca53f0..3c2011533 100644 --- a/providers/inwx/inwxProvider.go +++ b/providers/inwx/inwxProvider.go @@ -2,6 +2,7 @@ package inwx import ( "encoding/json" + "errors" "fmt" "sort" "strings" @@ -89,11 +90,11 @@ func getOTP(TOTPValue string, TOTPKey string) (string, error) { } else if TOTPKey != "" { tan, err := totp.GenerateCode(TOTPKey, time.Now()) if err != nil { - return "", fmt.Errorf("INWX: Unable to generate TOTP from totp-key: %v", err) + return "", fmt.Errorf("INWX: Unable to generate TOTP from totp-key: %w", err) } return tan, nil } else { - return "", fmt.Errorf("INWX: two factor authentication required but no TOTP configured") + return "", errors.New("INWX: two factor authentication required but no TOTP configured") } } @@ -101,7 +102,7 @@ func getOTP(TOTPValue string, TOTPKey string) (string, error) { func (api *inwxAPI) loginHelper(TOTPValue string, TOTPKey string) error { resp, err := api.client.Account.Login() if err != nil { - return fmt.Errorf("INWX: Unable to login") + return errors.New("INWX: Unable to login") } switch TFA := resp.TFA; TFA { @@ -133,13 +134,13 @@ func newInwx(m map[string]string) (*inwxAPI, error) { sandbox := m["sandbox"] == "1" if username == "" { - return nil, fmt.Errorf("INWX: username must be provided") + return nil, errors.New("INWX: username must be provided") } if password == "" { - return nil, fmt.Errorf("INWX: password must be provided") + return nil, errors.New("INWX: password must be provided") } if TOTPValue != "" && TOTPKey != "" { - return nil, fmt.Errorf("INWX: totp and totp-key must not be specified at the same time") + return nil, errors.New("INWX: totp and totp-key must not be specified at the same time") } opts := &goinwx.ClientOptions{Sandbox: sandbox} @@ -228,7 +229,7 @@ func checkRecords(records models.Records) error { for _, r := range records { if r.Type == "TXT" { if strings.ContainsAny(r.GetTargetTXTJoined(), "`") { - return fmt.Errorf("INWX TXT records do not support single-quotes in their target") + return errors.New("INWX TXT records do not support single-quotes in their target") } } } @@ -295,7 +296,7 @@ func (api *inwxAPI) GetZoneRecords(domain string, meta map[string]string) (model return nil, err } - var records = []*models.RecordConfig{} + records := []*models.RecordConfig{} for _, record := range info.Records { if record.Type == "SOA" { @@ -309,7 +310,7 @@ func (api *inwxAPI) GetZoneRecords(domain string, meta map[string]string) (model Records with empty targets (i.e. records with target ".") are not allowed. */ - var rtypeAddDot = map[string]bool{ + rtypeAddDot := map[string]bool{ "CNAME": true, "MX": true, "NS": true, diff --git a/providers/linode/api.go b/providers/linode/api.go index 496a64537..9843457bc 100644 --- a/providers/linode/api.go +++ b/providers/linode/api.go @@ -22,7 +22,7 @@ func (api *linodeProvider) fetchDomainList() error { dr := &domainResponse{} endpoint := fmt.Sprintf("%s?page=%d", domainsPath, page) if err := api.get(endpoint, dr); err != nil { - return fmt.Errorf("failed fetching domain list (Linode): %s", err) + return fmt.Errorf("failed fetching domain list (Linode): %w", err) } for _, domain := range dr.Data { api.domainIndex[domain.Domain] = domain.ID @@ -42,7 +42,7 @@ func (api *linodeProvider) getRecords(id int) ([]domainRecord, error) { dr := &recordResponse{} endpoint := fmt.Sprintf("%s/%d/records?page=%d", domainsPath, id, page) if err := api.get(endpoint, dr); err != nil { - return nil, fmt.Errorf("failed fetching record list (Linode): %s", err) + return nil, fmt.Errorf("failed fetching record list (Linode): %w", err) } records = append(records, dr.Data...) diff --git a/providers/linode/auditrecords.go b/providers/linode/auditrecords.go index 0cce247cf..b961b3927 100644 --- a/providers/linode/auditrecords.go +++ b/providers/linode/auditrecords.go @@ -9,7 +9,6 @@ import ( // 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("CAA", rejectif.CaaFlagIsNonZero) // Last verified 2022-03-25 diff --git a/providers/linode/linodeProvider.go b/providers/linode/linodeProvider.go index 24bbaa1e8..1b53898e4 100644 --- a/providers/linode/linodeProvider.go +++ b/providers/linode/linodeProvider.go @@ -3,6 +3,7 @@ package linode import ( "context" "encoding/json" + "errors" "fmt" "net/http" "net/url" @@ -63,7 +64,7 @@ var defaultNameServerNames = []string{ // NewLinode creates the provider. func NewLinode(m map[string]string, metadata json.RawMessage) (providers.DNSServiceProvider, error) { if m["token"] == "" { - return nil, fmt.Errorf("missing Linode token") + return nil, errors.New("missing Linode token") } ctx := context.Background() @@ -74,7 +75,7 @@ func NewLinode(m map[string]string, metadata json.RawMessage) (providers.DNSServ baseURL, err := url.Parse(defaultBaseURL) if err != nil { - return nil, fmt.Errorf("invalid base URL for Linode") + return nil, errors.New("invalid base URL for Linode") } api := &linodeProvider{client: client, baseURL: baseURL} @@ -226,7 +227,10 @@ func (api *linodeProvider) getRecordsForDomain(domainID int, domain string) (mod existingRecords := make([]*models.RecordConfig, len(records), len(records)+len(defaultNameServerNames)) for i := range records { - existingRecords[i] = toRc(domain, &records[i]) + existingRecords[i], err = toRc(domain, &records[i]) + if err != nil { + return nil, err + } } // Linode always has read-only NS servers, but these are not mentioned in the API response @@ -237,7 +241,9 @@ func (api *linodeProvider) getRecordsForDomain(domainID int, domain string) (mod Original: &domainRecord{}, } rc.SetLabelFromFQDN(domain, domain) - rc.SetTarget(name) + if err := rc.SetTarget(name); err != nil { + return nil, err + } existingRecords = append(existingRecords, rc) } @@ -245,7 +251,7 @@ func (api *linodeProvider) getRecordsForDomain(domainID int, domain string) (mod return existingRecords, nil } -func toRc(domain string, r *domainRecord) *models.RecordConfig { +func toRc(domain string, r *domainRecord) (*models.RecordConfig, error) { rc := &models.RecordConfig{ Type: r.Type, TTL: r.TTLSec, @@ -258,17 +264,17 @@ func toRc(domain string, r *domainRecord) *models.RecordConfig { } rc.SetLabel(r.Name, domain) + var err error switch rtype := r.Type; rtype { // #rtype_variations case "CNAME", "MX", "NS", "SRV": - rc.SetTarget(dnsutil.AddOrigin(r.Target+".", domain)) + err = rc.SetTarget(dnsutil.AddOrigin(r.Target+".", domain)) case "CAA": // Linode doesn't support CAA flags and just returns the tag and value separately - rc.SetTarget(r.Target) + err = rc.SetTarget(r.Target) default: - rc.PopulateFromString(r.Type, r.Target, domain) + err = rc.PopulateFromString(r.Type, r.Target, domain) } - - return rc + return rc, err } func toReq(dc *models.DomainConfig, rc *models.RecordConfig) (*recordEditRequest, error) { @@ -310,7 +316,7 @@ func toReq(dc *models.DomainConfig, rc *models.RecordConfig) (*recordEditRequest return nil, fmt.Errorf("SRV Record must match format \"_service._protocol\" not %s", req.Name) } - var serviceName, protocol = result[1], strings.ToLower(result[2]) + serviceName, protocol := result[1], strings.ToLower(result[2]) req.Protocol = protocol req.Service = serviceName diff --git a/providers/loopia/client.go b/providers/loopia/client.go index cffd5b7e7..f1f9e2c8a 100644 --- a/providers/loopia/client.go +++ b/providers/loopia/client.go @@ -131,8 +131,8 @@ func NewClient(apiUser, apiPassword string, region string, modifyns bool, fetchn } } -//CRUD: Create, Read, Update, Delete -//Create +// CRUD: Create, Read, Update, Delete +// Create // CreateRecordSimulate only prints info about a record addition. Used for debugging. func (c *APIClient) CreateRecordSimulate(domain string, subdomain string, record paramStruct) error { @@ -164,8 +164,8 @@ func (c *APIClient) CreateRecord(domain string, subdomain string, record paramSt return checkResponse(resp.Value) } -//CRUD: Create, Read, Update, Delete -//Read +// CRUD: Create, Read, Update, Delete +// Read // getDomains lists all domains. func (c *APIClient) getDomains() ([]domainObject, error) { @@ -176,7 +176,7 @@ func (c *APIClient) getDomains() ([]domainObject, error) { paramString{Value: c.APIPassword}, }, } - //domainObjectsResponse is basically a zoneRecordsResponse + // domainObjectsResponse is basically a zoneRecordsResponse resp := &domainObjectsResponse{} err := c.rpcCall(call, resp) @@ -231,7 +231,7 @@ func (c *APIClient) GetDomainNS(domain string) ([]string, error) { return []string{defaultNS1, defaultNS2}, nil } - //fetch from the domain - an extra API call. + // fetch from the domain - an extra API call. call := &methodCall{ MethodName: "getZoneRecords", Params: []param{ @@ -264,8 +264,8 @@ func (c *APIClient) GetDomainNS(domain string) ([]string, error) { return apexNSRecords, err } -//CRUD: Create, Read, Update, Delete -//Update +// CRUD: Create, Read, Update, Delete +// Update // UpdateRecordSimulate only prints info about a record update. Used for debugging. func (c *APIClient) UpdateRecordSimulate(domain string, subdomain string, rec paramStruct) error { @@ -305,8 +305,8 @@ func (c *APIClient) UpdateRecord(domain string, subdomain string, rec paramStruc return checkResponse(resp.Value) } -//CRUD: Create, Read, Update, Delete -//Delete +// CRUD: Create, Read, Update, Delete +// Delete // DeleteRecordSimulate only prints info about a record deletion. Used for debugging. func (c *APIClient) DeleteRecordSimulate(domain string, subdomain string, recordID uint32) error { @@ -388,7 +388,7 @@ func (c *APIClient) rpcCall(call *methodCall, resp response) error { return fmt.Errorf("error unmarshalling the API response XML body: %w", err) } - //yes - loopia are stoopid - the 429 error code comes from the DB behind the http proxy + // yes - loopia are stoopid - the 429 error code comes from the DB behind the http proxy c.requestRateLimiter.handleXMLResponse(resp) if resp.faultCode() == 429 { fmt.Printf("XMLresp: %+v\n", resp) @@ -421,7 +421,7 @@ func (c *APIClient) httpPost(url string, bodyType string, body io.Reader) ([]byt c.requestRateLimiter.handleResponse(*resp) // retry the request when rate-limited - if resp.StatusCode == 429 { + if resp.StatusCode == http.StatusTooManyRequests { c.requestRateLimiter.handleRateLimitedRequest() cleanupResponseBody() } else if resp.StatusCode != http.StatusOK { @@ -451,8 +451,8 @@ func checkResponse(value string) error { // Rate limiting taken from Hetzner implementation. v nice. func getHomogenousDelay(headers http.Header, quotaName string) (time.Duration, error) { - //Loopia, to my knowledge, are useless, and do not include such headers. - //In the event that they one day do, use this. + // Loopia, to my knowledge, are useless, and do not include such headers. + // In the event that they one day do, use this. quota, err := parseHeaderAsInt(headers, "X-Ratelimit-Limit-"+cases.Title(language.Und, cases.NoLower).String((quotaName))) if err != nil { return 0, err @@ -545,7 +545,7 @@ func (requestRateLimiter *requestRateLimiter) handleResponse(resp http.Response) } delay := homogenousDelay - if resp.StatusCode == 429 { + if resp.StatusCode == http.StatusTooManyRequests { retryAfterDelay, err := getRetryAfterDelay(resp.Header) if err == nil { delay = retryAfterDelay diff --git a/providers/loopia/client_test.go b/providers/loopia/client_test.go index bab895895..a1bad1baf 100644 --- a/providers/loopia/client_test.go +++ b/providers/loopia/client_test.go @@ -316,7 +316,7 @@ func createFakeServer(t *testing.T, serverResponses map[string]string) string { handler := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { if r.Header.Get("Content-Type") != "text/xml" { - http.Error(w, fmt.Sprintf("invalid content type: %s", r.Header.Get("Content-Type")), http.StatusBadRequest) + http.Error(w, "invalid content type: "+r.Header.Get("Content-Type"), http.StatusBadRequest) return } diff --git a/providers/loopia/convert.go b/providers/loopia/convert.go index 737820df6..6089c635c 100644 --- a/providers/loopia/convert.go +++ b/providers/loopia/convert.go @@ -19,7 +19,9 @@ func nativeToRecord(zr zoneRecord, origin string, subdomain string) (rc *models. Type: record.Type, } rc.SetLabel(subdomain, origin) - rc.SetTarget(record.Rdata) + if err := rc.SetTarget(record.Rdata); err != nil { + return nil, err + } switch rtype := record.Type; rtype { case "CAA": @@ -42,7 +44,7 @@ func nativeToRecord(zr zoneRecord, origin string, subdomain string) (rc *models. } func recordToNative(rc *models.RecordConfig, id ...uint32) paramStruct { - //rc is the record from dnscontrol to loopia + // rc is the record from dnscontrol to loopia zrec := zRec{} zrec.Type = rc.Type zrec.TTL = rc.TTL diff --git a/providers/loopia/convert_test.go b/providers/loopia/convert_test.go index 5c19bcd07..c9c511cd4 100644 --- a/providers/loopia/convert_test.go +++ b/providers/loopia/convert_test.go @@ -8,12 +8,11 @@ import ( ) func TestRecordToNative_1(t *testing.T) { - rc := &models.RecordConfig{ TTL: 3600, } rc.SetLabel("foo", "example.com") - rc.SetTarget("1.2.3.4") + rc.MustSetTarget("1.2.3.4") rc.Type = "A" ns := recordToNative(rc, 0) @@ -25,7 +24,6 @@ func TestRecordToNative_1(t *testing.T) { } func TestNativeToRecord_1(t *testing.T) { - zrec := zRec{} zrec.Type = "A" zrec.TTL = 300 diff --git a/providers/loopia/loopiaProvider.go b/providers/loopia/loopiaProvider.go index 1d4908c33..cfda81d1f 100644 --- a/providers/loopia/loopiaProvider.go +++ b/providers/loopia/loopiaProvider.go @@ -17,6 +17,7 @@ Settings from `creds.json`: import ( "encoding/json" + "errors" "fmt" "sort" "strconv" @@ -86,10 +87,10 @@ func newReg(conf map[string]string) (providers.Registrar, error) { // newHelper generates a handle. func newHelper(m map[string]string, _ json.RawMessage) (*APIClient, error) { if m["username"] == "" { - return nil, fmt.Errorf("missing Loopia API username") + return nil, errors.New("missing Loopia API username") } if m["password"] == "" { - return nil, fmt.Errorf("missing Loopia API password") + return nil, errors.New("missing Loopia API password") } const booleanStringWarn = " setting as a 'string': 't', 'true', 'True' etc" @@ -99,7 +100,7 @@ func newHelper(m map[string]string, _ json.RawMessage) (*APIClient, error) { if m["modify_name_servers"] != "" { // optional modifyNameServers, err = strconv.ParseBool(m["modify_name_servers"]) if err != nil { - return nil, fmt.Errorf("creds.json requires the modify_name_servers" + booleanStringWarn) + return nil, errors.New("creds.json requires the modify_name_servers" + booleanStringWarn) } } @@ -107,15 +108,15 @@ func newHelper(m map[string]string, _ json.RawMessage) (*APIClient, error) { if m["fetch_apex_ns_entries"] != "" { // optional fetchApexNSEntries, err = strconv.ParseBool(m["fetch_apex_ns_entries"]) if err != nil { - return nil, fmt.Errorf("creds.json requires the fetch_apex_ns_entries" + booleanStringWarn) + return nil, errors.New("creds.json requires the fetch_apex_ns_entries" + booleanStringWarn) } } dbg := false - if m["debug"] != "" { //debug is optional + if m["debug"] != "" { // debug is optional dbg, err = strconv.ParseBool(m["debug"]) if err != nil { - return nil, fmt.Errorf("creds.json requires the debug" + booleanStringWarn) + return nil, errors.New("creds.json requires the debug" + booleanStringWarn) } } @@ -133,7 +134,6 @@ func newHelper(m map[string]string, _ json.RawMessage) (*APIClient, error) { // ListZones lists the zones on this account. func (c *APIClient) ListZones() ([]string, error) { - listResp, err := c.getDomains() if err != nil { return nil, err @@ -163,12 +163,11 @@ func (c *APIClient) ListZones() ([]string, error) { // GetZoneRecords gathers the DNS records and converts them to // dnscontrol's format. func (c *APIClient) GetZoneRecords(domain string, meta map[string]string) (models.Records, error) { - // Two approaches. One: get all SubDomains, and get their respective records // simultaneously, or first get subdomains then fill each subdomain with its // respective records on a subsequent pass. - //step 1: subdomains + // step 1: subdomains // Get existing subdomains for a domain: subdomains, err := c.GetSubDomains(domain) if err != nil { @@ -182,12 +181,12 @@ func (c *APIClient) GetZoneRecords(domain string, meta map[string]string) (model // Convert them to DNScontrol's native format: existingRecords := []*models.RecordConfig{} for _, subdomain := range subdomains { - //here seems like a good place to get the records for a subdomain. - //fukn ballz tho: each subdomain requires one API call. 💩 + // here seems like a good place to get the records for a subdomain. + // fukn ballz tho: each subdomain requires one API call. 💩 if c.Debug { fmt.Printf("%s\n", subdomain) } - //step 2: records for subdomains + // step 2: records for subdomains // Get subdomain records: subdomainrecords, err := c.getDomainRecords(domain, subdomain) if err != nil { @@ -195,16 +194,13 @@ func (c *APIClient) GetZoneRecords(domain string, meta map[string]string) (model } for _, subdRr := range subdomainrecords { - - //Note: subdomain cannot be any of [.-_ ] + // Note: subdomain cannot be any of [.-_ ] record, err := nativeToRecord(subdRr, domain, subdomain) if err != nil { return nil, err } existingRecords = append(existingRecords, record) - } - } if c.Debug { @@ -216,7 +212,7 @@ func (c *APIClient) GetZoneRecords(domain string, meta map[string]string) (model // PrepFoundRecords munges any records to make them compatible with // this provider. Usually this is a no-op. -//func PrepFoundRecords(recs models.Records) models.Records { +// func PrepFoundRecords(recs models.Records) models.Records { // If there are records that need to be modified, removed, etc. we // do it here. Usually this is a no-op. //return recs @@ -271,7 +267,6 @@ func gatherAffectedLabels(groups map[models.RecordKey][]string) (labels map[stri // GetZoneRecordsCorrections returns a list of corrections that will turn existing records into dc.Records. func (c *APIClient) GetZoneRecordsCorrections(dc *models.DomainConfig, existingRecords models.Records) ([]*models.Correction, int, error) { - if c.Debug { debugRecords("GenerateZoneRecordsCorrections input:\n", existingRecords) } @@ -330,7 +325,7 @@ func (c *APIClient) GetZoneRecordsCorrections(dc *models.DomainConfig, existingR subdomain := dnsutil.TrimDomainName(fqdn, dc.Name) if d.Existing.NameFQDN == fqdn && d.Existing.Name == subdomain { // fmt.Printf("fqdn extinct wtf: %s\n", fqdn) - //deletion is a member of fqdn. skip its deletion (otherwise extra API call and its error) + // deletion is a member of fqdn. skip its deletion (otherwise extra API call and its error) skip = true } } @@ -357,8 +352,8 @@ func (c *APIClient) GetZoneRecordsCorrections(dc *models.DomainConfig, existingR corrections = append(corrections, &models.Correction{ Msg: d.String(), F: func() error { - //weird BUG: if we provide d.Desired.Name, instead of 'subdomain', - //all change records get assigned a single subdomain, common across all change records. + // weird BUG: if we provide d.Desired.Name, instead of 'subdomain', + // all change records get assigned a single subdomain, common across all change records. // return c.UpdateRecordSimulate(dc.Name, subdomain, zrec) return c.UpdateRecord(dc.Name, subdomain, zrec) }, @@ -370,7 +365,7 @@ func (c *APIClient) GetZoneRecordsCorrections(dc *models.DomainConfig, existingR // debugRecords prints a list of RecordConfig. func debugRecords(note string, recs []*models.RecordConfig) { - printer.Debugf(note) + printer.Debugf("%s", note) for k, v := range recs { printer.Printf(" %v: %v %v %v %v\n", k, v.GetLabel(), v.Type, v.TTL, v.GetTargetCombined()) } @@ -392,7 +387,6 @@ func (c *APIClient) GetNameservers(domain string) ([]*models.Nameserver, error) // GetRegistrarCorrections returns a list of corrections for this registrar. func (c *APIClient) GetRegistrarCorrections(dc *models.DomainConfig) ([]*models.Correction, error) { - existingNs, err := c.GetDomainNS(dc.Name) if err != nil { return nil, err @@ -411,7 +405,8 @@ func (c *APIClient) GetRegistrarCorrections(dc *models.DomainConfig) ([]*models. F: func() (err error) { // err = c.UpdateNameServers(dc.Name, desiredNs) return - }}, + }, + }, }, nil } return nil, nil diff --git a/providers/loopia/types.go b/providers/loopia/types.go index bd934cc90..5caa3f6cd 100644 --- a/providers/loopia/types.go +++ b/providers/loopia/types.go @@ -53,7 +53,7 @@ func (m structMemberInt) structMember() {} // Uncomment this code in case of using it // It was commented out to satisfy `staticcheck` warnings about unused code -//type structMemberBool struct { +// type structMemberBool struct { // Name string `xml:"name"` // Value bool `xml:"value>boolean"` //} @@ -165,7 +165,7 @@ func (zr *zoneRecord) GetZR() zRec { } func (zrec *zRec) SetZR() zoneRecord { - //This method creates a zoneRecord to receive from responses. + // This method creates a zoneRecord to receive from responses. return zoneRecord{ XMLName: xml.Name{Local: "struct"}, Properties: []Property{ @@ -179,7 +179,7 @@ func (zrec *zRec) SetZR() zoneRecord { } func (zrec *zRec) SetPS() paramStruct { - //This method creates a paramStruct for sending in requests. + // This method creates a paramStruct for sending in requests. return paramStruct{ XMLName: xml.Name{Local: "struct"}, StructMembers: []structMember{ diff --git a/providers/luadns/api.go b/providers/luadns/api.go index 0ca8afabc..9591d050d 100644 --- a/providers/luadns/api.go +++ b/providers/luadns/api.go @@ -3,6 +3,7 @@ package luadns import ( "bytes" "encoding/json" + "errors" "fmt" "io" "net/http" @@ -57,29 +58,35 @@ type domainRecord struct { type recordResponse []domainRecord -type requestParams map[string]string -type jsonRequestParams map[string]any +type ( + requestParams map[string]string + jsonRequestParams map[string]any +) func (l *luadnsProvider) fetchAvailableNameservers() error { l.nameserversNames = nil - var bodyString, err = l.get("/users/me", "GET", requestParams{}) + bodyString, err := l.get("/users/me", "GET", requestParams{}) if err != nil { - return fmt.Errorf("failed fetching available nameservers list from LuaDNS: %s", err) + return fmt.Errorf("failed fetching available nameservers list from LuaDNS: %w", err) } var ui userInfoResponse - json.Unmarshal(bodyString, &ui) + if err := json.Unmarshal(bodyString, &ui); err != nil { + return fmt.Errorf("failed to unmarshal available nameservers list from LuaDNS: %w", err) + } l.nameserversNames = ui.NameServers return nil } func (l *luadnsProvider) fetchDomainList() error { l.domainIndex = map[string]uint32{} - var bodyString, err = l.get("/zones", "GET", requestParams{}) + bodyString, err := l.get("/zones", "GET", requestParams{}) if err != nil { - return fmt.Errorf("failed fetching domain list from LuaDNS: %s", err) + return fmt.Errorf("failed fetching domain list from LuaDNS: %w", err) } var dr zoneResponse - json.Unmarshal(bodyString, &dr) + if err := json.Unmarshal(bodyString, &dr); err != nil { + return fmt.Errorf("failed to unmarshal domain list from LuaDNS: %w", err) + } for _, domain := range dr { l.domainIndex[domain.Name] = domain.ID } @@ -104,39 +111,41 @@ func (l *luadnsProvider) createDomain(domain string) error { "name": domain, } if _, err := l.get("/zones", "POST", params); err != nil { - return fmt.Errorf("failed create domain (LuaDNS): %s", err) + return fmt.Errorf("failed create domain (LuaDNS): %w", err) } return nil } func (l *luadnsProvider) createRecord(domainID uint32, rec jsonRequestParams) error { if _, err := l.get(fmt.Sprintf("/zones/%d/records", domainID), "POST", rec); err != nil { - return fmt.Errorf("failed create record (LuaDNS): %s", err) + return fmt.Errorf("failed create record (LuaDNS): %w", err) } return nil } func (l *luadnsProvider) deleteRecord(domainID uint32, recordID uint32) error { if _, err := l.get(fmt.Sprintf("/zones/%d/records/%d", domainID, recordID), "DELETE", requestParams{}); err != nil { - return fmt.Errorf("failed delete record (LuaDNS): %s", err) + return fmt.Errorf("failed delete record (LuaDNS): %w", err) } return nil } func (l *luadnsProvider) modifyRecord(domainID uint32, recordID uint32, rec jsonRequestParams) error { if _, err := l.get(fmt.Sprintf("/zones/%d/records/%d", domainID, recordID), "PUT", rec); err != nil { - return fmt.Errorf("failed update (LuaDNS): %s", err) + return fmt.Errorf("failed update (LuaDNS): %w", err) } return nil } func (l *luadnsProvider) getRecords(domainID uint32) ([]domainRecord, error) { - var bodyString, err = l.get(fmt.Sprintf("/zones/%d/records", domainID), "GET", requestParams{}) + bodyString, err := l.get(fmt.Sprintf("/zones/%d/records", domainID), "GET", requestParams{}) if err != nil { - return nil, fmt.Errorf("failed fetching record list from LuaDNS: %s", err) + return nil, fmt.Errorf("failed fetching record list from LuaDNS: %w", err) } var dr recordResponse - json.Unmarshal(bodyString, &dr) + if err := json.Unmarshal(bodyString, &dr); err != nil { + return nil, fmt.Errorf("failed to unmarshal record response from LuaDNS: %w", err) + } var records []domainRecord for _, rec := range dr { if rec.Type == "SOA" { @@ -149,7 +158,7 @@ func (l *luadnsProvider) getRecords(domainID uint32) ([]domainRecord, error) { func (l *luadnsProvider) get(endpoint string, method string, params any) ([]byte, error) { client := &http.Client{} - var req, err = l.makeRequest(endpoint, method, params) + req, err := l.makeRequest(endpoint, method, params) if err != nil { return []byte{}, err } @@ -163,7 +172,7 @@ func (l *luadnsProvider) get(endpoint string, method string, params any) ([]byte return nil, err } - if resp.StatusCode == 200 { + if resp.StatusCode == http.StatusOK { bodyString, _ := io.ReadAll(resp.Body) return bodyString, nil } @@ -203,29 +212,30 @@ func (l *luadnsProvider) makeRequest(endpoint string, method string, params any) req.Header.Set("Content-Type", "application/json") return req, nil default: - return nil, fmt.Errorf("invalid request type") + return nil, errors.New("invalid request type") } } -func nativeToRecord(domain string, r *domainRecord) *models.RecordConfig { +func nativeToRecord(domain string, r *domainRecord) (*models.RecordConfig, error) { rc := &models.RecordConfig{ Type: r.Type, TTL: r.TTL, Original: r, } rc.SetLabelFromFQDN(r.Name, domain) + var err error switch rtype := rc.Type; rtype { case "TXT": - rc.SetTargetTXT(r.Content) + err = rc.SetTargetTXT(r.Content) default: - rc.PopulateFromString(rtype, r.Content, domain) + err = rc.PopulateFromString(rtype, r.Content, domain) } - return rc + return rc, err } func recordsToNative(rc *models.RecordConfig) jsonRequestParams { r := jsonRequestParams{ - "name": fmt.Sprintf("%s.", rc.GetLabelFQDN()), + "name": rc.GetLabelFQDN() + ".", "type": rc.Type, "ttl": rc.TTL, } diff --git a/providers/luadns/luadnsProvider.go b/providers/luadns/luadnsProvider.go index aa240ab80..106d88d29 100644 --- a/providers/luadns/luadnsProvider.go +++ b/providers/luadns/luadnsProvider.go @@ -2,6 +2,7 @@ package luadns import ( "encoding/json" + "errors" "fmt" "github.com/StackExchange/dnscontrol/v4/models" @@ -51,7 +52,7 @@ func NewLuaDNS(m map[string]string, metadata json.RawMessage) (providers.DNSServ l := &luadnsProvider{} l.creds.email, l.creds.apikey = m["email"], m["apikey"] if l.creds.email == "" || l.creds.apikey == "" { - return nil, fmt.Errorf("missing LuaDNS email or apikey") + return nil, errors.New("missing LuaDNS email or apikey") } // Get a domain to validate authentication @@ -65,7 +66,9 @@ func NewLuaDNS(m map[string]string, metadata json.RawMessage) (providers.DNSServ // GetNameservers returns the nameservers for a domain. func (l *luadnsProvider) GetNameservers(domain string) ([]*models.Nameserver, error) { if len(l.nameserversNames) == 0 { - l.fetchAvailableNameservers() + if err := l.fetchAvailableNameservers(); err != nil { + return nil, err + } } return models.ToNameserversStripTD(l.nameserversNames) } @@ -94,7 +97,11 @@ func (l *luadnsProvider) GetZoneRecords(domain string, meta map[string]string) ( } existingRecords := make([]*models.RecordConfig, len(records)) for i := range records { - existingRecords[i] = nativeToRecord(domain, &records[i]) + newr, err := nativeToRecord(domain, &records[i]) + if err != nil { + return nil, err + } + existingRecords[i] = newr } return existingRecords, nil } diff --git a/providers/msdns/convert.go b/providers/msdns/convert.go index d27372a15..d11187c3d 100644 --- a/providers/msdns/convert.go +++ b/providers/msdns/convert.go @@ -12,7 +12,6 @@ import ( // extractProps and collects Name/Value pairs into maps for easier access. func extractProps(cip []ciProperty) (map[string]string, map[string]uint32, error) { - // Sadly this structure is dynamic JSON i.e. .Value could be an int, string, // or a map. We peek at the first byte to guess at the contents. @@ -76,27 +75,30 @@ func nativeToRecords(nr nativeRecord, origin string) (*models.RecordConfig, erro if ip == nil || ip.To4() == nil { return nil, fmt.Errorf("invalid IP in A record: %q", contents) } - rc.SetTargetIP(ip) + err = rc.SetTargetIP(ip) case "AAAA": contents := sprops["IPv6Address"] ip := net.ParseIP(contents) if ip == nil || ip.To16() == nil { return nil, fmt.Errorf("invalid IPv6 in AAAA record: %q", contents) } - rc.SetTargetIP(ip) + err = rc.SetTargetIP(ip) case "CNAME": - rc.SetTarget(sprops["HostNameAlias"]) + err = rc.SetTarget(sprops["HostNameAlias"]) case "MX": - rc.SetTargetMX(uint16(uprops["Preference"]), sprops["MailExchange"]) + err = rc.SetTargetMX(uint16(uprops["Preference"]), sprops["MailExchange"]) case "NS": - rc.SetTarget(sprops["NameServer"]) + err = rc.SetTarget(sprops["NameServer"]) case "NAPTR": - n := decodeRecordDataNaptr(sprops["Data"]) - rc.SetTargetNAPTR(n.NaptrOrder, n.NaptrPreference, n.NaptrFlags, n.NaptrService, n.NaptrRegexp, n.GetTargetField()) + n, e := decodeRecordDataNaptr(sprops["Data"]) + if e != nil { + return nil, err + } + err = rc.SetTargetNAPTR(n.NaptrOrder, n.NaptrPreference, n.NaptrFlags, n.NaptrService, n.NaptrRegexp, n.GetTargetField()) case "PTR": - rc.SetTarget(sprops["PtrDomainName"]) + err = rc.SetTarget(sprops["PtrDomainName"]) case "SRV": - rc.SetTargetSRV( + err = rc.SetTargetSRV( uint16(uprops["Priority"]), uint16(uprops["Weight"]), uint16(uprops["Port"]), @@ -110,17 +112,20 @@ func nativeToRecords(nr nativeRecord, origin string) (*models.RecordConfig, erro // updates. return nil, nil // If we weren't ignoring them, the code would look like this: - //rc.SetTargetSOA(sprops["PrimaryServer"], sprops["ResponsiblePerson"], + // rc.SetTargetSOA(sprops["PrimaryServer"], sprops["ResponsiblePerson"], // uprops["SerialNumber"], uprops["RefreshInterval"], uprops["RetryDelay"], // uprops["ExpireLimit"], uprops["MinimumTimeToLive"]) case "TXT": - //rc.SetTargetTXTString(sprops["DescriptiveText"]) - rc.SetTargetTXT(sprops["DescriptiveText"]) + // rc.SetTargetTXTString(sprops["DescriptiveText"]) + err = rc.SetTargetTXT(sprops["DescriptiveText"]) default: return nil, fmt.Errorf( "msdns/convert.go:nativeToRecord rtype=%q unknown: props=%+v and %+v", rtype, sprops, uprops) } + if err != nil { + return nil, err + } return rc, nil } diff --git a/providers/msdns/msdnsProvider.go b/providers/msdns/msdnsProvider.go index c543f7eb7..511459f44 100644 --- a/providers/msdns/msdnsProvider.go +++ b/providers/msdns/msdnsProvider.go @@ -51,7 +51,6 @@ func init() { } func newDNS(config map[string]string, metadata json.RawMessage) (providers.DNSServiceProvider, error) { - if runtime.GOOS != "windows" { printer.Println("INFO: MSDNS deactivated. Required OS not detected.") return providers.None{}, nil @@ -78,7 +77,6 @@ func newDNS(config map[string]string, metadata json.RawMessage) (providers.DNSSe // GetZoneRecords gathers the DNS records and converts them to // dnscontrol's format. func (client *msdnsProvider) GetZoneRecords(domain string, meta map[string]string) (models.Records, error) { - // Get the existing DNS records in native format. nativeExistingRecords, err := client.shell.GetDNSZoneRecords(client.dnsserver, domain) if err != nil { diff --git a/providers/msdns/naptr.go b/providers/msdns/naptr.go index e27ed5744..296d543a6 100644 --- a/providers/msdns/naptr.go +++ b/providers/msdns/naptr.go @@ -15,7 +15,6 @@ import ( ) func generatePSCreateNaptr(dnsServerName, domain string, rec *models.RecordConfig) string { - var computername string if dnsServerName != "" { computername = escapePS(dnsServerName) + " " @@ -60,7 +59,7 @@ func generatePSDeleteNaptr(dnsServerName, domain string, rec *models.RecordConfi // decoding -func decodeRecordDataNaptr(s string) models.RecordConfig { +func decodeRecordDataNaptr(s string) (models.RecordConfig, error) { // These strings look like this: // C8AFB0B30153075349502B4432540474657374165F7369702E5F7463702E6578616D706C652E6F72672E // The first 2 groups of 16 bits (4 hex digits) are uinet16. @@ -74,14 +73,16 @@ func decodeRecordDataNaptr(s string) models.RecordConfig { s, rc.NaptrService = eatString(s) s, rc.NaptrRegexp = eatString(s) s, targ := eatString(s) - rc.SetTarget(targ) + if err := rc.SetTarget(targ); err != nil { + return models.RecordConfig{}, err + } // At this point we should have consumed the entire string. if s != "" { printer.Printf("WARNING: REMAINDER:=%q\n", s) } - return rc + return rc, nil } // eatUint16 consumes the first 16 bits of the string, returns it as a diff --git a/providers/msdns/naptr_test.go b/providers/msdns/naptr_test.go index c7ab64429..b58d26d56 100644 --- a/providers/msdns/naptr_test.go +++ b/providers/msdns/naptr_test.go @@ -19,11 +19,13 @@ func Test_decodeRecordDataNaptr(t *testing.T) { {"01", args{"C8AFB0B30153075349502B4432540474657374165F7369702E5F7463702E6578616D706C652E6F72672E"}, models.RecordConfig{NaptrOrder: 45000, NaptrPreference: 46000, NaptrFlags: "S", NaptrService: "SIP+D2T", NaptrRegexp: "test", Name: "_sip._tcp.example.org."}}, } for _, tt := range tests { - tt.want.SetTarget(tt.want.Name) + if err := tt.want.SetTarget(tt.want.Name); err != nil { + t.Fatal(err) + } tt.want.Name = "" t.Run(tt.name, func(t *testing.T) { - if got := decodeRecordDataNaptr(tt.args.s); !reflect.DeepEqual(got, tt.want) { - t.Errorf("decodeRecordDataNaptr() = %+v, want %+v", got, tt.want) + if got, err := decodeRecordDataNaptr(tt.args.s); err != nil || !reflect.DeepEqual(got, tt.want) { + t.Errorf("decodeRecordDataNaptr() = %+v (%v), want %+v", got, err, tt.want) } }) } diff --git a/providers/msdns/powershell.go b/providers/msdns/powershell.go index 3666a3424..56089a6fa 100644 --- a/providers/msdns/powershell.go +++ b/providers/msdns/powershell.go @@ -20,14 +20,13 @@ type psHandle struct { } func eLog(s string) { - f, _ := os.OpenFile("powershell.log", os.O_APPEND|os.O_CREATE|os.O_WRONLY, 0644) - f.WriteString(s) - f.WriteString("\n") + f, _ := os.OpenFile("powershell.log", os.O_APPEND|os.O_CREATE|os.O_WRONLY, 0o644) + _, _ = f.WriteString(s) + _, _ = f.WriteString("\n") f.Close() } func newPowerShell(config map[string]string) (*psHandle, error) { - back := &backend.Local{} sh, err := ps.New(back) if err != nil { @@ -107,7 +106,6 @@ func generatePSZoneAll(dnsserver string) string { } func (psh *psHandle) GetDNSZoneRecords(dnsserver, domain string) ([]nativeRecord, error) { - tmpfile, err := os.CreateTemp("", "zonerecords.*.json") if err != nil { log.Fatal(err) @@ -134,10 +132,10 @@ func (psh *psHandle) GetDNSZoneRecords(dnsserver, domain string) ([]nativeRecord } os.Remove(filename) // TODO(tlim): There should be a debug flag that leaves the tmp file around. - //printer.Printf("CONTENTS = %s\n", contents) - //printer.Printf("CONTENTS STR = %q\n", contents[:10]) - //printer.Printf("CONTENTS HEX = %v\n", []byte(contents)[:10]) - //os.WriteFile("/temp/list.json", contents, 0777) + // printer.Printf("CONTENTS = %s\n", contents) + // printer.Printf("CONTENTS STR = %q\n", contents[:10]) + // printer.Printf("CONTENTS HEX = %v\n", []byte(contents)[:10]) + // os.WriteFile("/temp/list.json", contents, 0777) var records []nativeRecord err = json.Unmarshal(contents, &records) if err != nil { @@ -199,11 +197,10 @@ func generatePSZoneDump(dnsserver, domainname, filename string) string { // Functions for record manipulation func (psh *psHandle) RecordDelete(dnsserver, domain string, rec *models.RecordConfig) error { - var c string if rec.Type == "NAPTR" { c = generatePSDeleteNaptr(dnsserver, domain, rec) - //printer.Printf("DEBUG: deleteNAPTR: %s\n", c) + // printer.Printf("DEBUG: deleteNAPTR: %s\n", c) } else { c = generatePSDelete(dnsserver, domain, rec) } @@ -223,14 +220,13 @@ func (psh *psHandle) RecordDelete(dnsserver, domain string, rec *models.RecordCo } func generatePSDelete(dnsserver, domain string, rec *models.RecordConfig) string { - var b bytes.Buffer fmt.Fprintf(&b, `echo DELETE "%s" "%s" %q`, rec.Type, rec.Name, rec.GetTargetCombined()) fmt.Fprintf(&b, " ; ") if rec.Type == "NAPTR" { x := b.String() + generatePSDeleteNaptr(dnsserver, domain, rec) - //printer.Printf("NAPTR DELETE: %s\n", x) + // printer.Printf("NAPTR DELETE: %s\n", x) return x } @@ -252,19 +248,18 @@ func generatePSDelete(dnsserver, domain string, rec *models.RecordConfig) string } else { fmt.Fprintf(&b, ` -RecordData %q`, rec.GetTargetField()) } - //printer.Printf("DEBUG PSDelete CMD = (\n%s\n)\n", b.String()) + // printer.Printf("DEBUG PSDelete CMD = (\n%s\n)\n", b.String()) return b.String() } func (psh *psHandle) RecordCreate(dnsserver, domain string, rec *models.RecordConfig) error { - var c string if rec.Type == "NAPTR" { c = generatePSCreateNaptr(dnsserver, domain, rec) - //printer.Printf("DEBUG: createNAPTR: %s\n", c) + // printer.Printf("DEBUG: createNAPTR: %s\n", c) } else { c = generatePSCreate(dnsserver, domain, rec) - //printer.Printf("DEBUG: PScreate\n") + // printer.Printf("DEBUG: PScreate\n") } eLog(c) @@ -303,25 +298,25 @@ func generatePSCreate(dnsserver, domain string, rec *models.RecordConfig) string fmt.Fprintf(&b, ` -A -IPv4Address "%s"`, rec.GetTargetIP()) case "AAAA": fmt.Fprintf(&b, ` -AAAA -IPv6Address "%s"`, rec.GetTargetIP()) - //case "ATMA": + // case "ATMA": // fmt.Fprintf(&b, ` -Atma -Address -AddressType {E164 | AESA}`, rec.GetTargetField()) - //case "AFSDB": + // case "AFSDB": // fmt.Fprintf(&b, ` -Afsdb -ServerName -SubType `, rec.GetTargetField()) case "SRV": fmt.Fprintf(&b, ` -Srv -DomainName "%s" -Port %d -Priority %d -Weight %d`, rec.GetTargetField(), rec.SrvPort, rec.SrvPriority, rec.SrvWeight) case "CNAME": fmt.Fprintf(&b, ` -CName -HostNameAlias "%s"`, rec.GetTargetField()) - //case "X25": + // case "X25": // fmt.Fprintf(&b, ` -X25 -PsdnAddress `, rec.GetTargetField()) - //case "WKS": + // case "WKS": // fmt.Fprintf(&b, ` -Wks -InternetAddress -InternetProtocol {UDP | TCP} -Service `, rec.GetTargetField()) case "TXT": - //printer.Printf("DEBUG TXT len = %v\n", rec.GetTargetTXTSegmentCount()) - //printer.Printf("DEBUG TXT target = %q\n", rec.GetTargetField()) + // printer.Printf("DEBUG TXT len = %v\n", rec.GetTargetTXTSegmentCount()) + // printer.Printf("DEBUG TXT target = %q\n", rec.GetTargetField()) fmt.Fprintf(&b, ` -Txt -DescriptiveText %q`, rec.GetTargetTXTJoined()) - //case "RT": + // case "RT": // fmt.Fprintf(&b, ` -RT -IntermediateHost -Preference `, rec.GetTargetField()) - //case "RP": + // case "RP": // fmt.Fprintf(&b, ` -RP -Description -ResponsiblePerson `, rec.GetTargetField()) case "PTR": fmt.Fprintf(&b, ` -Ptr -PtrDomainName "%s"`, rec.GetTargetField()) @@ -329,15 +324,15 @@ func generatePSCreate(dnsserver, domain string, rec *models.RecordConfig) string fmt.Fprintf(&b, ` -NS -NameServer "%s"`, rec.GetTargetField()) case "MX": fmt.Fprintf(&b, ` -MX -MailExchange "%s" -Preference %d`, rec.GetTargetField(), rec.MxPreference) - //case "ISDN": + // case "ISDN": // fmt.Fprintf(&b, ` -Isdn -IsdnNumber -IsdnSubAddress `, rec.GetTargetField()) - //case "HINFO": + // case "HINFO": // fmt.Fprintf(&b, ` -HInfo -Cpu -OperatingSystem `, rec.GetTargetField()) - //case "DNAME": + // case "DNAME": // fmt.Fprintf(&b, ` -DName -DomainNameAlias `, rec.GetTargetField()) - //case "DHCID": + // case "DHCID": // fmt.Fprintf(&b, ` -DhcId -DhcpIdentifier `, rec.GetTargetField()) - //case "TLSA": + // case "TLSA": // fmt.Fprintf(&b, ` -TLSA -CertificateAssociationData -CertificateUsage {CAConstraint | ServiceCertificateConstraint | TrustAnchorAssertion | DomainIssuedCertificate} -MatchingType {ExactMatch | Sha256Hash | Sha512Hash} -Selector {FullCertificate | SubjectPublicKeyInfo}`, rec.GetTargetField()) default: panic(fmt.Errorf("generatePSCreate() has not implemented recType=%s recName=%#v content=%#v)", @@ -345,7 +340,7 @@ func generatePSCreate(dnsserver, domain string, rec *models.RecordConfig) string // We panic so that we quickly find any switch statements // that have not been updated for a new RR type. } - //printer.Printf("DEBUG PSCreate CMD = (DEBUG-START\n%s\nDEBUG-END)\n", b.String()) + // printer.Printf("DEBUG PSCreate CMD = (DEBUG-START\n%s\nDEBUG-END)\n", b.String()) return b.String() } @@ -364,6 +359,7 @@ func (psh *psHandle) RecordModify(dnsserver, domain string, old, rec *models.Rec } return nil } + func generatePSModify(dnsserver, domain string, old, rec *models.RecordConfig) string { // The simple way is to just remove the old record and insert the new record. return "\n\r" + generatePSDelete(dnsserver, domain, old) + " ; " + generatePSCreate(dnsserver, domain, rec) + "\n\r" diff --git a/providers/msdns/powershell_test.go b/providers/msdns/powershell_test.go index 5d36249c7..049dfc3ec 100644 --- a/providers/msdns/powershell_test.go +++ b/providers/msdns/powershell_test.go @@ -66,14 +66,14 @@ func Test_generatePSZoneDump(t *testing.T) { } } -//func Test_generatePSDelete(t *testing.T) { +// func Test_generatePSDelete(t *testing.T) { // type args struct { // domain string // rec *models.RecordConfig // } // tests := []struct { // name string -// args args +// args // want string // }{ // // TODO: Add test cases. @@ -94,7 +94,7 @@ func Test_generatePSZoneDump(t *testing.T) { // } // tests := []struct { // name string -// args args +// args // want string // }{ // // TODO: Add test cases. @@ -109,30 +109,29 @@ func Test_generatePSZoneDump(t *testing.T) { // } func Test_generatePSModify(t *testing.T) { - recA1 := &models.RecordConfig{ Type: "A", Name: "@", } - recA1.SetTarget("1.2.3.4") + recA1.MustSetTarget("1.2.3.4") recA2 := &models.RecordConfig{ Type: "A", Name: "@", } - recA2.SetTarget("10.20.30.40") + recA2.MustSetTarget("10.20.30.40") recMX1 := &models.RecordConfig{ Type: "MX", Name: "@", MxPreference: 5, } - recMX1.SetTarget("foo.com.") + recMX1.MustSetTarget("foo.com.") recMX2 := &models.RecordConfig{ Type: "MX", Name: "@", MxPreference: 50, } - recMX2.SetTarget("foo2.com.") + recMX2.MustSetTarget("foo2.com.") type args struct { domain string @@ -145,16 +144,20 @@ func Test_generatePSModify(t *testing.T) { args args want string }{ - {name: "A", args: args{domain: "example.com", dnsserver: "", old: recA1, rec: recA2}, + { + name: "A", args: args{domain: "example.com", dnsserver: "", old: recA1, rec: recA2}, want: `echo DELETE "A" "@" "1.2.3.4" ; Remove-DnsServerResourceRecord -Force -ZoneName "example.com" -Name "@" -RRType "A" -RecordData "1.2.3.4" ; echo CREATE "A" "@" "10.20.30.40" ; Add-DnsServerResourceRecord -ZoneName "example.com" -Name "@" -TimeToLive $(New-TimeSpan -Seconds 0) -A -IPv4Address "10.20.30.40"`, }, - {name: "MX1", args: args{domain: "example.com", dnsserver: "", old: recMX1, rec: recMX2}, + { + name: "MX1", args: args{domain: "example.com", dnsserver: "", old: recMX1, rec: recMX2}, want: `echo DELETE "MX" "@" "5 foo.com." ; Remove-DnsServerResourceRecord -Force -ZoneName "example.com" -Name "@" -RRType "MX" -RecordData 5,"foo.com." ; echo CREATE "MX" "@" "50 foo2.com." ; Add-DnsServerResourceRecord -ZoneName "example.com" -Name "@" -TimeToLive $(New-TimeSpan -Seconds 0) -MX -MailExchange "foo2.com." -Preference 50`, }, - {name: "A-remote", args: args{domain: "example.com", dnsserver: "myremote", old: recA1, rec: recA2}, + { + name: "A-remote", args: args{domain: "example.com", dnsserver: "myremote", old: recA1, rec: recA2}, want: `echo DELETE "A" "@" "1.2.3.4" ; Remove-DnsServerResourceRecord -ComputerName "myremote" -Force -ZoneName "example.com" -Name "@" -RRType "A" -RecordData "1.2.3.4" ; echo CREATE "A" "@" "10.20.30.40" ; Add-DnsServerResourceRecord -ComputerName "myremote" -ZoneName "example.com" -Name "@" -TimeToLive $(New-TimeSpan -Seconds 0) -A -IPv4Address "10.20.30.40"`, }, - {name: "MX1-remote", args: args{domain: "example.com", dnsserver: "yourremote", old: recMX1, rec: recMX2}, + { + name: "MX1-remote", args: args{domain: "example.com", dnsserver: "yourremote", old: recMX1, rec: recMX2}, want: `echo DELETE "MX" "@" "5 foo.com." ; Remove-DnsServerResourceRecord -ComputerName "yourremote" -Force -ZoneName "example.com" -Name "@" -RRType "MX" -RecordData 5,"foo.com." ; echo CREATE "MX" "@" "50 foo2.com." ; Add-DnsServerResourceRecord -ComputerName "yourremote" -ZoneName "example.com" -Name "@" -TimeToLive $(New-TimeSpan -Seconds 0) -MX -MailExchange "foo2.com." -Preference 50`, }, } diff --git a/providers/msdns/types.go b/providers/msdns/types.go index 315aa267d..679521666 100644 --- a/providers/msdns/types.go +++ b/providers/msdns/types.go @@ -20,11 +20,11 @@ type DNSAccessor interface { // nativeRecord the JSON received from PowerShell when listing all DNS // records in a zone. type nativeRecord struct { - //CimClass interface{} `json:"CimClass"` - //CimInstanceProperties interface{} `json:"CimInstanceProperties"` - //CimSystemProperties interface{} `json:"CimSystemProperties"` - //DistinguishedName string `json:"DistinguishedName"` - //RecordClass string `json:"RecordClass"` + // CimClass interface{} `json:"CimClass"` + // CimInstanceProperties interface{} `json:"CimInstanceProperties"` + // CimSystemProperties interface{} `json:"CimSystemProperties"` + // DistinguishedName string `json:"DistinguishedName"` + // RecordClass string `json:"RecordClass"` RecordType string `json:"RecordType"` HostName string `json:"HostName"` RecordData struct { diff --git a/providers/mythicbeasts/mythicbeastsProvider.go b/providers/mythicbeasts/mythicbeastsProvider.go index a386f2450..45c12ef7a 100644 --- a/providers/mythicbeasts/mythicbeastsProvider.go +++ b/providers/mythicbeasts/mythicbeastsProvider.go @@ -5,6 +5,7 @@ package mythicbeasts import ( "encoding/json" + "errors" "fmt" "io" "net/http" @@ -59,10 +60,10 @@ func init() { func newDsp(conf map[string]string, metadata json.RawMessage) (providers.DNSServiceProvider, error) { if conf["keyID"] == "" { - return nil, fmt.Errorf("missing Mythic Beasts auth keyID") + return nil, errors.New("missing Mythic Beasts auth keyID") } if conf["secret"] == "" { - return nil, fmt.Errorf("missing Mythic Beasts auth secret") + return nil, errors.New("missing Mythic Beasts auth secret") } return &mythicBeastsProvider{ keyID: conf["keyID"], diff --git a/providers/namecheap/namecheapProvider.go b/providers/namecheap/namecheapProvider.go index 057f95b3c..28d618c22 100644 --- a/providers/namecheap/namecheapProvider.go +++ b/providers/namecheap/namecheapProvider.go @@ -2,6 +2,7 @@ package namecheap import ( "encoding/json" + "errors" "fmt" "sort" "strings" @@ -68,7 +69,7 @@ func newProvider(m map[string]string, _ json.RawMessage) (*namecheapProvider, er api := &namecheapProvider{} api.APIUser, api.APIKEY = m["apiuser"], m["apikey"] if api.APIKEY == "" || api.APIUser == "" { - return nil, fmt.Errorf("missing Namecheap apikey and apiuser") + return nil, errors.New("missing Namecheap apikey and apiuser") } api.client = nc.NewClient(api.APIUser, api.APIKEY, api.APIUser) // if BaseURL is specified in creds, use that url @@ -142,7 +143,7 @@ func (n *namecheapProvider) GetZoneRecords(domain string, meta map[string]string } } - // Copying this from GetDomainCorrections. This seems redundent + // Copying this from GetDomainCorrections. This seems redundant // with what toRecords() does. Leaving it out. // for _, r := range records.Hosts { // if r.Type == "SOA" { @@ -237,7 +238,6 @@ func (n *namecheapProvider) GetZoneRecords(domain string, meta map[string]string // GetZoneRecordsCorrections returns a list of corrections that will turn existing records into dc.Records. func (n *namecheapProvider) GetZoneRecordsCorrections(dc *models.DomainConfig, actual models.Records) ([]*models.Correction, int, error) { - // namecheap does not allow setting @ NS with basic DNS dc.Filter(func(r *models.RecordConfig) bool { if r.Type == "NS" && r.GetLabel() == "@" { @@ -249,7 +249,7 @@ func (n *namecheapProvider) GetZoneRecordsCorrections(dc *models.DomainConfig, a return true }) - toReport, create, delete, modify, actualChangeCount, err := diff.NewCompat(dc).IncrementalDiff(actual) + toReport, toCreate, toDelete, toModify, actualChangeCount, err := diff.NewCompat(dc).IncrementalDiff(actual) if err != nil { return nil, 0, err } @@ -261,13 +261,13 @@ func (n *namecheapProvider) GetZoneRecordsCorrections(dc *models.DomainConfig, a // changes though var desc []string - for _, i := range create { + for _, i := range toCreate { desc = append(desc, "\n"+i.String()) } - for _, i := range delete { + for _, i := range toDelete { desc = append(desc, "\n"+i.String()) } - for _, i := range modify { + for _, i := range toModify { desc = append(desc, "\n"+i.String()) } @@ -297,11 +297,15 @@ func toRecords(result *nc.DomainDNSGetHostsResult, origin string) ([]*models.Rec } record.SetLabel(dnsHost.Name, origin) + var err error switch dnsHost.Type { case "MX": - record.SetTargetMX(uint16(dnsHost.MXPref), dnsHost.Address) + err = record.SetTargetMX(uint16(dnsHost.MXPref), dnsHost.Address) default: - record.PopulateFromString(dnsHost.Type, dnsHost.Address, origin) + err = record.PopulateFromString(dnsHost.Type, dnsHost.Address, origin) + } + if err != nil { + return nil, err } records = append(records, &record) @@ -311,7 +315,6 @@ func toRecords(result *nc.DomainDNSGetHostsResult, origin string) ([]*models.Rec } func (n *namecheapProvider) generateRecords(dc *models.DomainConfig) error { - var recs []nc.DomainDNSHost id := 1 @@ -381,7 +384,8 @@ func (n *namecheapProvider) GetRegistrarCorrections(dc *models.DomainConfig) ([] return err }) return - }}, + }, + }, }, nil } return nil, nil diff --git a/providers/namedotcom/auditrecords.go b/providers/namedotcom/auditrecords.go index 94d8442d2..7a6efa718 100644 --- a/providers/namedotcom/auditrecords.go +++ b/providers/namedotcom/auditrecords.go @@ -1,7 +1,7 @@ package namedotcom import ( - "fmt" + "errors" "strings" "github.com/StackExchange/dnscontrol/v4/models" @@ -48,7 +48,7 @@ func MaxLengthNDC(rc *models.RecordConfig) error { sum += 3 * (len(txtStrings) - 1) if sum > 512 { - return fmt.Errorf("encoded txt too long") + return errors.New("encoded txt too long") } return nil } diff --git a/providers/namedotcom/namedotcomProvider.go b/providers/namedotcom/namedotcomProvider.go index a4f8c5fd0..e1fd6d5c0 100644 --- a/providers/namedotcom/namedotcomProvider.go +++ b/providers/namedotcom/namedotcomProvider.go @@ -3,7 +3,7 @@ package namedotcom import ( "encoding/json" - "fmt" + "errors" "time" "github.com/StackExchange/dnscontrol/v4/providers" @@ -49,7 +49,7 @@ func newProvider(conf map[string]string) (*namedotcomProvider, error) { api.client.Server = conf["apiurl"] api.APIUser, api.APIKey, api.APIUrl = conf["apiuser"], conf["apikey"], conf["apiurl"] if api.APIKey == "" || api.APIUser == "" { - return nil, fmt.Errorf("missing Name.com apikey or apiuser") + return nil, errors.New("missing Name.com apikey or apiuser") } if api.APIUrl == "" { api.APIUrl = defaultAPIBase diff --git a/providers/namedotcom/records.go b/providers/namedotcom/records.go index 944f68d27..e730c1dfa 100644 --- a/providers/namedotcom/records.go +++ b/providers/namedotcom/records.go @@ -19,7 +19,10 @@ func (n *namedotcomProvider) GetZoneRecords(domain string, meta map[string]strin actual := make([]*models.RecordConfig, len(records)) for i, r := range records { - actual[i] = toRecord(r, domain) + actual[i], err = toRecord(r, domain) + if err != nil { + return nil, err + } } return actual, nil @@ -53,14 +56,14 @@ func (n *namedotcomProvider) GetZoneRecordsCorrections(dc *models.DomainConfig, corrections = append(corrections, c) } for _, chng := range mod { - old := chng.Existing.Original.(*namecom.Record) - new := chng.Desired + old_ := chng.Existing.Original.(*namecom.Record) + new_ := chng.Desired c := &models.Correction{Msg: chng.String(), F: func() error { - err := n.deleteRecord(old.ID, dc.Name) + err := n.deleteRecord(old_.ID, dc.Name) if err != nil { return err } - return n.createRecord(new, dc.Name) + return n.createRecord(new_, dc.Name) }} corrections = append(corrections, c) } @@ -79,7 +82,7 @@ func checkNSModifications(dc *models.DomainConfig) { dc.Records = newList } -func toRecord(r *namecom.Record, origin string) *models.RecordConfig { +func toRecord(r *namecom.Record, origin string) (*models.RecordConfig, error) { heapr := r // NB(tlim): Unsure if this is actually needed. rc := &models.RecordConfig{ Type: r.Type, @@ -91,23 +94,21 @@ func toRecord(r *namecom.Record, origin string) *models.RecordConfig { } fqdn := r.Fqdn[:len(r.Fqdn)-1] rc.SetLabelFromFQDN(fqdn, origin) + var err error switch rtype := r.Type; rtype { // #rtype_variations case "TXT": - rc.SetTargetTXT(r.Answer) + err = rc.SetTargetTXT(r.Answer) case "MX": - if err := rc.SetTargetMX(uint16(r.Priority), r.Answer); err != nil { - panic(fmt.Errorf("unparsable MX record received from ndc: %w", err)) - } + err = rc.SetTargetMX(uint16(r.Priority), r.Answer) case "SRV": - if err := rc.SetTargetSRVPriorityString(uint16(r.Priority), r.Answer+"."); err != nil { - panic(fmt.Errorf("unparsable SRV record received from ndc: %w", err)) - } + err = rc.SetTargetSRVPriorityString(uint16(r.Priority), r.Answer+".") default: // "A", "AAAA", "ANAME", "CNAME", "NS" - if err := rc.PopulateFromString(rtype, r.Answer, r.Fqdn); err != nil { - panic(fmt.Errorf("unparsable record received from ndc: %w", err)) - } + err = rc.PopulateFromString(rtype, r.Answer, r.Fqdn) } - return rc + if err != nil { + return nil, fmt.Errorf("unparsable record received from ndc: %w", err) + } + return rc, nil } func (n *namedotcomProvider) getRecords(domain string) ([]*namecom.Record, error) { diff --git a/providers/netcup/api.go b/providers/netcup/api.go index 450457db5..0177c064d 100644 --- a/providers/netcup/api.go +++ b/providers/netcup/api.go @@ -13,8 +13,8 @@ const ( ) type netcupProvider struct { - //domainIndex map[string]string - //nameserversNames []string + // domainIndex map[string]string + // nameserversNames []string credentials struct { apikey string customernumber string @@ -35,7 +35,7 @@ func (api *netcupProvider) createRecord(domain string, rec *record) error { } _, err := api.get("updateDnsRecords", data) if err != nil { - return fmt.Errorf("error while trying to create a record: %s", err) + return fmt.Errorf("error while trying to create a record: %w", err) } return nil } @@ -53,7 +53,7 @@ func (api *netcupProvider) deleteRecord(domain string, rec *record) error { } _, err := api.get("updateDnsRecords", data) if err != nil { - return fmt.Errorf("error while trying to delete a record: %s", err) + return fmt.Errorf("error while trying to delete a record: %w", err) } return nil } @@ -71,7 +71,7 @@ func (api *netcupProvider) modifyRecord(domain string, rec *record) error { } _, err := api.get("updateDnsRecords", data) if err != nil { - return fmt.Errorf("error while trying to modify a record: %s", err) + return fmt.Errorf("error while trying to modify a record: %w", err) } return nil } @@ -85,11 +85,13 @@ func (api *netcupProvider) getRecords(domain string) ([]record, error) { } rawJSON, err := api.get("infoDnsRecords", data) if err != nil { - return nil, fmt.Errorf("failed while trying to login (netcup): %s", err) + return nil, fmt.Errorf("failed while trying to login (netcup): %w", err) } resp := &records{} - json.Unmarshal(rawJSON, &resp) + if err := json.Unmarshal(rawJSON, &resp); err != nil { + return nil, fmt.Errorf("failed to unmarshal record response (netcup): %w", err) + } return resp.Records, nil } @@ -101,11 +103,13 @@ func (api *netcupProvider) login(apikey, password, customernumber string) error } rawJSON, err := api.get("login", data) if err != nil { - return fmt.Errorf("failed while trying to login to (netcup): %s", err) + return fmt.Errorf("failed while trying to login to (netcup): %w", err) } resp := &responseLogin{} - json.Unmarshal(rawJSON, &resp) + if err := json.Unmarshal(rawJSON, &resp); err != nil { + return fmt.Errorf("failed to unmarshal login response (netcup): %w", err) + } api.credentials.apikey = apikey api.credentials.customernumber = customernumber api.credentials.sessionID = resp.SessionID @@ -120,7 +124,7 @@ func (api *netcupProvider) get(action string, params interface{}) (json.RawMessa reqJSON, _ := json.Marshal(reqParam) client := &http.Client{} - req, _ := http.NewRequest("POST", endpoint, bytes.NewBuffer(reqJSON)) + req, _ := http.NewRequest(http.MethodPost, endpoint, bytes.NewBuffer(reqJSON)) resp, err := client.Do(req) if err != nil { return nil, err diff --git a/providers/netcup/netcupProvider.go b/providers/netcup/netcupProvider.go index e3d336b7e..3f39e35bb 100644 --- a/providers/netcup/netcupProvider.go +++ b/providers/netcup/netcupProvider.go @@ -2,6 +2,7 @@ package netcup import ( "encoding/json" + "errors" "fmt" "github.com/StackExchange/dnscontrol/v4/models" @@ -37,13 +38,13 @@ func init() { // New creates a new API handle. func New(settings map[string]string, _ json.RawMessage) (providers.DNSServiceProvider, error) { if settings["api-key"] == "" || settings["api-password"] == "" || settings["customer-number"] == "" { - return nil, fmt.Errorf("missing netcup login parameters") + return nil, errors.New("missing netcup login parameters") } api := &netcupProvider{} err := api.login(settings["api-key"], settings["api-password"], settings["customer-number"]) if err != nil { - return nil, fmt.Errorf("login to netcup DNS failed, please check your credentials: %v", err) + return nil, fmt.Errorf("login to netcup DNS failed, please check your credentials: %w", err) } return api, nil } diff --git a/providers/netlify/api.go b/providers/netlify/api.go index 31b700f85..e3b3a234e 100644 --- a/providers/netlify/api.go +++ b/providers/netlify/api.go @@ -57,13 +57,13 @@ type dnsRecordCreate struct { } func (n *netlifyProvider) getDNSZones() ([]*dnsZone, error) { - reqURL := fmt.Sprintf("%s/dns_zones", baseURL) + reqURL := baseURL + "/dns_zones" - req, err := http.NewRequest("GET", reqURL, nil) + req, err := http.NewRequest(http.MethodGet, reqURL, nil) if err != nil { return nil, err } - req.Header.Add("Authorization", fmt.Sprintf("Bearer %s", n.apiToken)) + req.Header.Add("Authorization", "Bearer "+n.apiToken) if n.accountSlug != "" { q := req.URL.Query() @@ -90,11 +90,11 @@ func (n *netlifyProvider) getDNSZones() ([]*dnsZone, error) { func (n *netlifyProvider) getDNSRecords(zoneID string) ([]*dnsRecord, error) { reqURL := fmt.Sprintf("%s/dns_zones/%s/dns_records", baseURL, zoneID) - req, err := http.NewRequest("GET", reqURL, nil) + req, err := http.NewRequest(http.MethodGet, reqURL, nil) if err != nil { return nil, err } - req.Header.Add("Authorization", fmt.Sprintf("Bearer %s", n.apiToken)) + req.Header.Add("Authorization", "Bearer "+n.apiToken) if n.accountSlug != "" { q := req.URL.Query() @@ -121,11 +121,11 @@ func (n *netlifyProvider) getDNSRecords(zoneID string) ([]*dnsRecord, error) { func (n *netlifyProvider) deleteDNSRecord(zoneID string, recordID string) error { reqURL := fmt.Sprintf("%s/dns_zones/%s/dns_records/%s", baseURL, zoneID, recordID) - req, err := http.NewRequest("DELETE", reqURL, nil) + req, err := http.NewRequest(http.MethodDelete, reqURL, nil) if err != nil { return err } - req.Header.Add("Authorization", fmt.Sprintf("Bearer %s", n.apiToken)) + req.Header.Add("Authorization", "Bearer "+n.apiToken) req.Header.Add("Content-Type", "application/json") res, err := http.DefaultClient.Do(req) @@ -145,11 +145,11 @@ func (n *netlifyProvider) createDNSRecord(zoneID string, rec *dnsRecordCreate) ( return nil, err } - req, err := http.NewRequest("POST", reqURL, bytes.NewReader(data)) + req, err := http.NewRequest(http.MethodPost, reqURL, bytes.NewReader(data)) if err != nil { return nil, err } - req.Header.Add("Authorization", fmt.Sprintf("Bearer %s", n.apiToken)) + req.Header.Add("Authorization", "Bearer "+n.apiToken) req.Header.Add("Content-Type", "application/json") res, err := http.DefaultClient.Do(req) diff --git a/providers/netlify/netlifyProvider.go b/providers/netlify/netlifyProvider.go index 65b106e5f..f9d74501f 100644 --- a/providers/netlify/netlifyProvider.go +++ b/providers/netlify/netlifyProvider.go @@ -2,6 +2,7 @@ package netlify import ( "encoding/json" + "errors" "fmt" "strings" @@ -54,7 +55,7 @@ func newNetlify(m map[string]string, message json.RawMessage) (providers.DNSServ api := &netlifyProvider{} api.apiToken = m["token"] if api.apiToken == "" { - return nil, fmt.Errorf("missing Netlify personal access token") + return nil, errors.New("missing Netlify personal access token") } api.accountSlug = m["slug"] @@ -83,7 +84,7 @@ func (n *netlifyProvider) getZone(domain string) (*dnsZone, error) { } } - return nil, fmt.Errorf("no zones found for this domain") + return nil, errors.New("no zones found for this domain") } func (n *netlifyProvider) GetZoneRecords(domain string, meta map[string]string) (models.Records, error) { diff --git a/providers/ns1/ns1Provider.go b/providers/ns1/ns1Provider.go index c6dd83661..8b18764c0 100644 --- a/providers/ns1/ns1Provider.go +++ b/providers/ns1/ns1Provider.go @@ -2,6 +2,7 @@ package ns1 import ( "encoding/json" + "errors" "fmt" "net/http" "strconv" @@ -60,7 +61,7 @@ type nsone struct { func newProvider(creds map[string]string, meta json.RawMessage) (providers.DNSServiceProvider, error) { if creds["api_token"] == "" { - return nil, fmt.Errorf("api_token required for ns1") + return nil, errors.New("api_token required for ns1") } // Enable Sleep API Rate limit strategy - it will sleep until new tokens are available @@ -93,7 +94,7 @@ func (n *nsone) EnsureZoneExists(domain string) error { for rtr := 0; ; rtr++ { httpResp, err := n.Zones.Create(zone) - if err == rest.ErrZoneExists { + if errors.Is(err, rest.ErrZoneExists) { // if domain exists already, just return nil, nothing to do here. return nil } @@ -155,7 +156,7 @@ func (n *nsone) GetZoneDNSSEC(domain string) (bool, error) { for rtr := 0; ; rtr++ { _, httpResp, err := n.DNSSEC.Get(domain) // rest.ErrDNSECNotEnabled is our "disabled" state - if err != nil && err == rest.ErrDNSECNotEnabled { + if err != nil && errors.Is(err, rest.ErrDNSECNotEnabled) { return false, nil } if httpResp.StatusCode == http.StatusTooManyRequests && rtr < clientRetries { @@ -173,7 +174,6 @@ func (n *nsone) GetZoneDNSSEC(domain string) (bool, error) { // getDomainCorrectionsDNSSEC creates DNSSEC zone corrections based on current state and preference func (n *nsone) getDomainCorrectionsDNSSEC(domain, toggleDNSSEC string) *models.Correction { - // get dnssec status from NS1 for domain // if errors are returned, we bail out without any DNSSEC corrections status, err := n.GetZoneDNSSEC(domain) @@ -238,7 +238,6 @@ func (n *nsone) GetZoneRecordsCorrections(dc *models.DomainConfig, existingRecor default: panic(fmt.Sprintf("unhandled inst.Type %s", change.Type)) } - } return corrections, actualChangeCount, nil } @@ -318,10 +317,11 @@ func buildRecord(recs models.Records, domain string, id string) *dns.Record { } else if r.Type == "CAA" { rec.AddAnswer(&dns.Answer{ Rdata: []string{ - fmt.Sprintf("%v", r.CaaFlag), + strconv.FormatUint(uint64(r.CaaFlag), 10), r.CaaTag, r.GetTargetField(), - }}) + }, + }) } else if r.Type == "SRV" { rec.AddAnswer(&dns.Answer{Rdata: strings.Fields(fmt.Sprintf("%d %d %d %v", r.SrvPriority, r.SrvWeight, r.SrvPort, r.GetTargetField()))}) } else if r.Type == "NAPTR" { @@ -331,13 +331,15 @@ func buildRecord(recs models.Records, domain string, id string) *dns.Record { r.NaptrFlags, r.NaptrService, r.NaptrRegexp, - r.GetTargetField()}}) + r.GetTargetField(), + }}) } else if r.Type == "DS" { rec.AddAnswer(&dns.Answer{Rdata: []string{ strconv.Itoa(int(r.DsKeyTag)), strconv.Itoa(int(r.DsAlgorithm)), strconv.Itoa(int(r.DsDigestType)), - r.DsDigest}}) + r.DsDigest, + }}) } else if r.Type == "NS1_URLFWD" { printer.Warnf("NS1_URLFWD is deprecated and may stop working anytime now. Please avoid such records going forward.\n") rec.Type = "URLFWD" @@ -346,13 +348,15 @@ func buildRecord(recs models.Records, domain string, id string) *dns.Record { rec.AddAnswer(&dns.Answer{Rdata: []string{ strconv.Itoa(int(r.SvcPriority)), r.GetTargetField(), - r.SvcParams}}) + r.SvcParams, + }}) } else if r.Type == "TLSA" { rec.AddAnswer(&dns.Answer{Rdata: []string{ strconv.Itoa(int(r.TlsaUsage)), strconv.Itoa(int(r.TlsaSelector)), strconv.Itoa(int(r.TlsaMatchingType)), - r.GetTargetField()}}) + r.GetTargetField(), + }}) } else { rec.AddAnswer(&dns.Answer{Rdata: strings.Fields(r.GetTargetField())}) } @@ -385,7 +389,7 @@ func convert(zr *dns.ZoneRecord, domain string) ([]*models.RecordConfig, error) return nil, fmt.Errorf("unparsable %s record received from ns1: %w", rtype, err) } case "CAA": - //dnscontrol expects quotes around multivalue CAA entries, API doesn't add them + // dnscontrol expects quotes around multivalue CAA entries, API doesn't add them xAns := strings.SplitN(ans, " ", 3) if err := rec.SetTargetCAAStrings(xAns[0], xAns[1], xAns[2]); err != nil { return nil, fmt.Errorf("unparsable %s record received from ns1: %w", rtype, err) diff --git a/providers/opensrs/opensrsProvider.go b/providers/opensrs/opensrsProvider.go index 3f9f41c8f..8538fba0c 100644 --- a/providers/opensrs/opensrsProvider.go +++ b/providers/opensrs/opensrsProvider.go @@ -127,12 +127,12 @@ func newProvider(m map[string]string, metadata json.RawMessage) (*opensrsProvide api.APIKey = m["apikey"] if api.APIKey == "" { - return nil, fmt.Errorf("openSRS apikey must be provided") + return nil, errors.New("openSRS apikey must be provided") } api.UserName = m["username"] if api.UserName == "" { - return nil, fmt.Errorf("openSRS username key must be provided") + return nil, errors.New("openSRS username key must be provided") } if m["baseurl"] != "" { diff --git a/providers/oracle/oracleProvider.go b/providers/oracle/oracleProvider.go index 4f5b37dbb..db9934664 100644 --- a/providers/oracle/oracleProvider.go +++ b/providers/oracle/oracleProvider.go @@ -3,7 +3,8 @@ package oracle import ( "context" "encoding/json" - "fmt" + "errors" + "net/http" "strings" "time" @@ -99,7 +100,6 @@ func (o *oracleProvider) ListZones() ([]string, error) { CompartmentId: &o.compartment, Page: listResp.OpcNextPage, }) - if err != nil { return nil, err } @@ -124,7 +124,7 @@ func (o *oracleProvider) EnsureZoneExists(domain string) error { if err == nil { return nil } - if getResp.RawResponse.StatusCode != 404 { + if getResp.RawResponse.StatusCode != http.StatusNotFound { return err } @@ -173,11 +173,10 @@ func (o *oracleProvider) GetNameservers(domain string) ([]*models.Nameserver, er } nssNoStrip, err := models.ToNameservers(nss) - if err != nil { nssStrip, err := models.ToNameserversStripTD(nss) if err != nil { - return nil, fmt.Errorf("could not determine if trailing dots should be stripped or not") + return nil, errors.New("could not determine if trailing dots should be stripped or not") } return nssStrip, nil diff --git a/providers/ovh/ovhProvider.go b/providers/ovh/ovhProvider.go index 006dae3ca..a616bad4c 100644 --- a/providers/ovh/ovhProvider.go +++ b/providers/ovh/ovhProvider.go @@ -142,7 +142,6 @@ func (c *ovhProvider) GetZoneRecords(domain string, meta map[string]string) (mod // GetZoneRecordsCorrections returns a list of corrections that will turn existing records into dc.Records. func (c *ovhProvider) GetZoneRecordsCorrections(dc *models.DomainConfig, actual models.Records) ([]*models.Correction, int, error) { - corrections, actualChangeCount, err := c.getDiff2DomainCorrections(dc, actual) if err != nil { return nil, 0, err @@ -233,7 +232,6 @@ func nativeToRecord(r *Record, origin string) (*models.RecordConfig, error) { } func (c *ovhProvider) GetRegistrarCorrections(dc *models.DomainConfig) ([]*models.Correction, error) { - // get the actual in-use nameservers actualNs, err := c.fetchRegistrarNS(dc.Name) if err != nil { @@ -263,7 +261,8 @@ func (c *ovhProvider) GetRegistrarCorrections(dc *models.DomainConfig) ([]*model return err } return nil - }}, + }, + }, }, nil } diff --git a/providers/ovh/protocol.go b/providers/ovh/protocol.go index c86fa4ea6..7f86cdfca 100644 --- a/providers/ovh/protocol.go +++ b/providers/ovh/protocol.go @@ -10,8 +10,7 @@ import ( ) // Void an empty structure. -type Void struct { -} +type Void struct{} // fetchDomainList gets list of zones for account func (c *ovhProvider) fetchZones() error { @@ -23,7 +22,6 @@ func (c *ovhProvider) fetchZones() error { var response []string err := c.client.CallAPI("GET", "/domain/zone", nil, &response, true) - if err != nil { return err } @@ -301,7 +299,7 @@ func (c *ovhProvider) updateNS(fqdn string, ns []string) error { // by default zones are in "hosted" mode meaning they default // to OVH default NS. In this mode, the NS can't be updated. domain := Domain{NameServerType: "external"} - err := c.client.CallAPI("PUT", fmt.Sprintf("/domain/%s", fqdn), &domain, &Void{}, true) + err := c.client.CallAPI("PUT", "/domain/"+fqdn, &domain, &Void{}, true) if err != nil { return err } diff --git a/providers/packetframe/api.go b/providers/packetframe/api.go index 626cac519..372c2ef8b 100644 --- a/providers/packetframe/api.go +++ b/providers/packetframe/api.go @@ -195,7 +195,9 @@ func (api *packetframeProvider) handleErrors(resp *http.Response) error { } dr := &domainResponse{} - json.Unmarshal(body, &dr) + if err := json.Unmarshal(body, &dr); err != nil { + return fmt.Errorf("can not unmarshal API error: %w (%s)", err, string(body)) + } return fmt.Errorf("packetframe API error: %s", dr.Message) } diff --git a/providers/packetframe/packetframeProvider.go b/providers/packetframe/packetframeProvider.go index 2d012e978..a8164034c 100644 --- a/providers/packetframe/packetframeProvider.go +++ b/providers/packetframe/packetframeProvider.go @@ -2,6 +2,7 @@ package packetframe import ( "encoding/json" + "errors" "fmt" "net/http" "net/url" @@ -24,12 +25,12 @@ type packetframeProvider struct { // newPacketframe creates the provider. func newPacketframe(m map[string]string, metadata json.RawMessage) (providers.DNSServiceProvider, error) { if m["token"] == "" { - return nil, fmt.Errorf("missing Packetframe token") + return nil, errors.New("missing Packetframe token") } baseURL, err := url.Parse(defaultBaseURL) if err != nil { - return nil, fmt.Errorf("invalid base URL for Packetframe") + return nil, errors.New("invalid base URL for Packetframe") } client := http.Client{} @@ -81,7 +82,6 @@ func (api *packetframeProvider) getZone(domain string) (*zoneInfo, error) { // GetZoneRecords gets the records of a zone and returns them in RecordConfig format. func (api *packetframeProvider) GetZoneRecords(domain string, meta map[string]string) (models.Records, error) { - zone, err := api.getZone(domain) if err != nil { return nil, fmt.Errorf("no such zone %q in Packetframe account", domain) @@ -99,7 +99,10 @@ func (api *packetframeProvider) GetZoneRecords(domain string, meta map[string]st } for i := range records { - existingRecords[i] = toRc(&dc, &records[i]) + existingRecords[i], err = toRc(&dc, &records[i]) + if err != nil { + return nil, err + } } return existingRecords, nil @@ -193,7 +196,7 @@ func toReq(zoneID string, rc *models.RecordConfig) (*domainRecord, error) { return req, nil } -func toRc(dc *models.DomainConfig, r *domainRecord) *models.RecordConfig { +func toRc(dc *models.DomainConfig, r *domainRecord) (*models.RecordConfig, error) { rc := &models.RecordConfig{ Type: r.Type, TTL: uint32(r.TTL), @@ -207,22 +210,22 @@ func toRc(dc *models.DomainConfig, r *domainRecord) *models.RecordConfig { } rc.SetLabel(label, dc.Name) + var err error switch rtype := r.Type; rtype { // #rtype_variations case "TXT": - rc.SetTargetTXT(r.Value) + err = rc.SetTargetTXT(r.Value) case "SRV": spl := strings.Split(r.Value, " ") prio, _ := strconv.ParseUint(spl[0], 10, 16) weight, _ := strconv.ParseUint(spl[1], 10, 16) port, _ := strconv.ParseUint(spl[2], 10, 16) - rc.SetTargetSRV(uint16(prio), uint16(weight), uint16(port), spl[3]) + err = rc.SetTargetSRV(uint16(prio), uint16(weight), uint16(port), spl[3]) case "MX": spl := strings.Split(r.Value, " ") prio, _ := strconv.ParseUint(spl[0], 10, 16) - rc.SetTargetMX(uint16(prio), spl[1]) + err = rc.SetTargetMX(uint16(prio), spl[1]) default: - rc.SetTarget(r.Value) + err = rc.SetTarget(r.Value) } - - return rc + return rc, err } diff --git a/providers/porkbun/api.go b/providers/porkbun/api.go index e16e649db..3c07b72e2 100644 --- a/providers/porkbun/api.go +++ b/providers/porkbun/api.go @@ -3,6 +3,7 @@ package porkbun import ( "bytes" "encoding/json" + "errors" "fmt" "io" "net/http" @@ -70,7 +71,7 @@ func (c *porkbunProvider) post(endpoint string, params requestParams) ([]byte, e } client := &http.Client{} - req, _ := http.NewRequest("POST", baseURL+endpoint, bytes.NewBuffer(personJSON)) + req, _ := http.NewRequest(http.MethodPost, baseURL+endpoint, bytes.NewBuffer(personJSON)) retrycnt := 0 @@ -85,10 +86,10 @@ retry: bodyString, _ := io.ReadAll(resp.Body) - if resp.StatusCode == 202 || resp.StatusCode == 503 { + if resp.StatusCode == http.StatusAccepted || resp.StatusCode == http.StatusServiceUnavailable { retrycnt++ if retrycnt == 5 { - return bodyString, fmt.Errorf("rate limiting exceeded") + return bodyString, errors.New("rate limiting exceeded") } printer.Warnf("Rate limiting.. waiting for %d second(s)\n", retrycnt*10) time.Sleep(time.Second * time.Duration(retrycnt*10)) @@ -131,7 +132,7 @@ func (c *porkbunProvider) modifyRecord(domain string, recordID string, rec reque func (c *porkbunProvider) getRecords(domain string) ([]domainRecord, error) { params := requestParams{} - var bodyString, err = c.post("/dns/retrieve/"+domain, params) + bodyString, err := c.post("/dns/retrieve/"+domain, params) if err != nil { return nil, fmt.Errorf("failed fetching record list from porkbun: %w", err) } @@ -179,7 +180,7 @@ func (c *porkbunProvider) modifyURLForwardingRecord(domain string, recordID stri func (c *porkbunProvider) getURLForwardingRecords(domain string) ([]domainRecord, error) { params := requestParams{} - var bodyString, err = c.post("/domain/getUrlForwarding/"+domain, params) + bodyString, err := c.post("/domain/getUrlForwarding/"+domain, params) if err != nil { return nil, fmt.Errorf("failed fetching url forwarding record list from porkbun: %w", err) } @@ -195,7 +196,7 @@ func (c *porkbunProvider) getURLForwardingRecords(domain string) ([]domainRecord func (c *porkbunProvider) getNameservers(domain string) ([]string, error) { params := requestParams{} - var bodyString, err = c.post(fmt.Sprintf("/domain/getNs/%s", domain), params) + bodyString, err := c.post("/domain/getNs/"+domain, params) if err != nil { return nil, fmt.Errorf("failed fetching nameserver list from porkbun: %w", err) } @@ -221,7 +222,7 @@ func (c *porkbunProvider) getNameservers(domain string) ([]string, error) { func (c *porkbunProvider) updateNameservers(ns []string, domain string) error { params := requestParams{} params["ns"] = ns - if _, err := c.post(fmt.Sprintf("/domain/updateNs/%s", domain), params); err != nil { + if _, err := c.post("/domain/updateNs/"+domain, params); err != nil { return fmt.Errorf("failed NS update (porkbun): %w", err) } return nil @@ -229,7 +230,7 @@ func (c *porkbunProvider) updateNameservers(ns []string, domain string) error { func (c *porkbunProvider) listAllDomains() ([]string, error) { params := requestParams{} - var bodyString, err = c.post("/domain/listAll", params) + bodyString, err := c.post("/domain/listAll", params) if err != nil { return nil, fmt.Errorf("failed listing all domains from porkbun: %w", err) } diff --git a/providers/porkbun/porkbunProvider.go b/providers/porkbun/porkbunProvider.go index b5e1ea140..44c507f82 100644 --- a/providers/porkbun/porkbunProvider.go +++ b/providers/porkbun/porkbunProvider.go @@ -2,6 +2,7 @@ package porkbun import ( "encoding/json" + "errors" "fmt" "sort" "strconv" @@ -11,7 +12,6 @@ import ( "github.com/StackExchange/dnscontrol/v4/pkg/diff2" "github.com/StackExchange/dnscontrol/v4/pkg/printer" "github.com/StackExchange/dnscontrol/v4/providers" - "github.com/miekg/dns/dnsutil" ) @@ -48,7 +48,7 @@ func newPorkbun(m map[string]string, _ json.RawMessage) (*porkbunProvider, error c.apiKey, c.secretKey = m["api_key"], m["secret_key"] if c.apiKey == "" || c.secretKey == "" { - return nil, fmt.Errorf("missing porkbun api_key or secret_key") + return nil, errors.New("missing porkbun api_key or secret_key") } return c, nil @@ -224,7 +224,11 @@ func (c *porkbunProvider) GetZoneRecords(domain string, meta map[string]string) if shouldSkip { continue } - existingRecords = append(existingRecords, toRc(domain, &records[i])) + newr, err := toRc(domain, &records[i]) + if err != nil { + return nil, err + } + existingRecords = append(existingRecords, newr) } for i := range forwards { r := &forwards[i] @@ -238,14 +242,16 @@ func (c *porkbunProvider) GetZoneRecords(domain string, meta map[string]string) }, } rc.SetLabel(r.Subdomain, domain) - rc.SetTarget(r.Location) + if err := rc.SetTarget(r.Location); err != nil { + return nil, err + } existingRecords = append(existingRecords, rc) } return existingRecords, nil } // parses the porkbun format into our standard RecordConfig -func toRc(domain string, r *domainRecord) *models.RecordConfig { +func toRc(domain string, r *domainRecord) (*models.RecordConfig, error) { ttl, _ := strconv.ParseUint(r.TTL, 10, 32) priority, _ := strconv.ParseUint(r.Prio, 10, 16) @@ -258,14 +264,15 @@ func toRc(domain string, r *domainRecord) *models.RecordConfig { } rc.SetLabelFromFQDN(r.Name, domain) + var err error switch rtype := r.Type; rtype { // #rtype_variations case "TXT": - rc.SetTargetTXT(r.Content) + err = rc.SetTargetTXT(r.Content) case "MX", "CNAME", "ALIAS", "NS": if strings.HasSuffix(r.Content, ".") { - rc.SetTarget(r.Content) + err = rc.SetTarget(r.Content) } else { - rc.SetTarget(r.Content + ".") + err = rc.SetTarget(r.Content + ".") } case "CAA": // 0, issue, "letsencrypt.org" @@ -274,7 +281,7 @@ func toRc(domain string, r *domainRecord) *models.RecordConfig { caaFlag, _ := strconv.ParseUint(c[0], 10, 8) rc.CaaFlag = uint8(caaFlag) rc.CaaTag = c[1] - rc.SetTarget(strings.ReplaceAll(c[2], "\"", "")) + err = rc.SetTarget(strings.ReplaceAll(c[2], "\"", "")) case "TLSA": // 0 0 0 00000000000000000000000 c := strings.Split(r.Content, " ") @@ -285,7 +292,7 @@ func toRc(domain string, r *domainRecord) *models.RecordConfig { rc.TlsaSelector = uint8(tlsaSelector) tlsaMatchingType, _ := strconv.ParseUint(c[2], 10, 8) rc.TlsaMatchingType = uint8(tlsaMatchingType) - rc.SetTarget(c[3]) + err = rc.SetTarget(c[3]) case "SRV": // 5 5060 sip.example.com c := strings.Split(r.Content, " ") @@ -294,12 +301,11 @@ func toRc(domain string, r *domainRecord) *models.RecordConfig { rc.SrvWeight = uint16(srvWeight) srvPort, _ := strconv.ParseUint(c[1], 10, 16) rc.SrvPort = uint16(srvPort) - rc.SetTarget(c[2]) + err = rc.SetTarget(c[2]) default: - rc.SetTarget(r.Content) + err = rc.SetTarget(r.Content) } - - return rc + return rc, err } // toReq takes a RecordConfig and turns it into the native format used by the API. diff --git a/providers/powerdns/dns.go b/providers/powerdns/dns.go index a57fd0db2..25e5e091c 100644 --- a/providers/powerdns/dns.go +++ b/providers/powerdns/dns.go @@ -46,7 +46,6 @@ func (dsp *powerdnsProvider) GetZoneRecords(domain string, meta map[string]strin // GetZoneRecordsCorrections returns a list of corrections that will turn existing records into dc.Records. func (dsp *powerdnsProvider) GetZoneRecordsCorrections(dc *models.DomainConfig, existing models.Records) ([]*models.Correction, int, error) { - corrections, actualChangeCount, err := dsp.getDiff2DomainCorrections(dc, existing) if err != nil { return nil, 0, err diff --git a/providers/powerdns/powerdnsProvider.go b/providers/powerdns/powerdnsProvider.go index 4e4c49f71..bea63264d 100644 --- a/providers/powerdns/powerdnsProvider.go +++ b/providers/powerdns/powerdnsProvider.go @@ -2,13 +2,12 @@ package powerdns import ( "encoding/json" - "fmt" - - "github.com/mittwald/go-powerdns/apis/zones" + "errors" "github.com/StackExchange/dnscontrol/v4/models" "github.com/StackExchange/dnscontrol/v4/providers" pdns "github.com/mittwald/go-powerdns" + "github.com/mittwald/go-powerdns/apis/zones" ) var features = providers.DocumentationNotes{ @@ -63,17 +62,17 @@ func newDSP(m map[string]string, metadata json.RawMessage) (providers.DNSService dsp.APIKey = m["apiKey"] if dsp.APIKey == "" { - return nil, fmt.Errorf("PowerDNS API Key is required") + return nil, errors.New("PowerDNS API Key is required") } dsp.APIUrl = m["apiUrl"] if dsp.APIUrl == "" { - return nil, fmt.Errorf("PowerDNS API URL is required") + return nil, errors.New("PowerDNS API URL is required") } dsp.ServerName = m["serverName"] if dsp.ServerName == "" { - return nil, fmt.Errorf("PowerDNS server name is required") + return nil, errors.New("PowerDNS server name is required") } // load js config diff --git a/providers/providers.go b/providers/providers.go index 86ab34a57..b3a4f7ed1 100644 --- a/providers/providers.go +++ b/providers/providers.go @@ -2,6 +2,7 @@ package providers import ( "encoding/json" + "errors" "fmt" "log" @@ -121,7 +122,7 @@ func beCompatible(n string, config map[string]string) (string, error) { if n == "" || n == "-" { // But no TYPE exists in creds.json... if ct == "" { - return "-", fmt.Errorf("creds.json entry missing TYPE field") + return "-", errors.New("creds.json entry missing TYPE field") } // Otherwise, use the value from creds.json. return ct, nil @@ -137,7 +138,7 @@ func beCompatible(n string, config map[string]string) (string, error) { // NB(tlim): My hope is that in 4.0 this entire function will simply be the // following, but I may be wrong: - //return config["TYPE"], nil + // return config["TYPE"], nil } // AuditRecords calls the RecordAudit function for a provider. diff --git a/providers/realtimeregister/api.go b/providers/realtimeregister/api.go index 38a7f9f36..8477ee828 100644 --- a/providers/realtimeregister/api.go +++ b/providers/realtimeregister/api.go @@ -12,7 +12,7 @@ import ( type realtimeregisterAPI struct { apikey string endpoint string - Zones map[string]*Zone //cache + Zones map[string]*Zone // cache ServiceType string } @@ -57,14 +57,13 @@ func (api *realtimeregisterAPI) request(method string, url string, body io.Reade req.Header.Set("Authorization", "ApiKey "+api.apikey) resp, err := client.Do(req) - if err != nil { return nil, err } bodyString, _ := io.ReadAll(resp.Body) - if resp.StatusCode != 200 { + if resp.StatusCode != http.StatusOK { return nil, fmt.Errorf("realtime Register API error on request to %s: %d, %s", url, resp.StatusCode, string(bodyString)) } @@ -88,7 +87,6 @@ func (api *realtimeregisterAPI) getZone(domain string) (*Zone, error) { } func (api *realtimeregisterAPI) getDomainZones(domain string) (*Zones, error) { - url := fmt.Sprintf(api.endpoint+"/dns/zones?name=%s&service=%s", domain, api.ServiceType) return api.getZones(url) @@ -117,7 +115,6 @@ func (api *realtimeregisterAPI) getZones(url string) (*Zones, error) { url, nil, ) - if err != nil { return nil, err } @@ -196,7 +193,6 @@ func (api *realtimeregisterAPI) updateNameservers(domainName string, nameservers fmt.Sprintf(api.endpoint+"/domains/%s/update", domainName), bytes.NewReader(bodyBytes), ) - if err != nil { return err } @@ -205,12 +201,11 @@ func (api *realtimeregisterAPI) updateNameservers(domainName string, nameservers func (api *realtimeregisterAPI) createOrUpdateZone(body *Zone, url string) error { bodyBytes, err := json.Marshal(body) - if err != nil { return err } - //Ugly hack for MX records with null target + // Ugly hack for MX records with null target requestBody := strings.Replace(string(bodyBytes), "\"prio\":-1", "\"prio\":0", -1) _, err = api.request("POST", url, strings.NewReader(requestBody)) diff --git a/providers/realtimeregister/realtimeregisterProvider.go b/providers/realtimeregister/realtimeregisterProvider.go index 47d9a4c4d..6942121f2 100644 --- a/providers/realtimeregister/realtimeregisterProvider.go +++ b/providers/realtimeregister/realtimeregisterProvider.go @@ -2,7 +2,9 @@ package realtimeregister import ( "encoding/json" + "errors" "fmt" + "slices" "sort" "strconv" "strings" @@ -11,7 +13,6 @@ import ( "github.com/StackExchange/dnscontrol/v4/pkg/diff2" "github.com/StackExchange/dnscontrol/v4/providers" "github.com/miekg/dns/dnsutil" - "golang.org/x/exp/slices" ) /* @@ -66,7 +67,7 @@ func newRtr(config map[string]string, _ json.RawMessage) (*realtimeregisterAPI, sandbox := config["sandbox"] == "1" if apikey == "" { - return nil, fmt.Errorf("realtime register: apikey must be provided") + return nil, errors.New("realtime register: apikey must be provided") } api := &realtimeregisterAPI{ @@ -204,7 +205,6 @@ func (api *realtimeregisterAPI) GetRegistrarCorrections(dc *models.DomainConfig) } func toRecordConfig(domain string, record *Record) *models.RecordConfig { - recordConfig := &models.RecordConfig{ Type: record.Type, TTL: uint32(record.TTL), diff --git a/providers/realtimeregister/realtimeregisterProvider_test.go b/providers/realtimeregister/realtimeregisterProvider_test.go index 9fe6dc09d..f42478061 100644 --- a/providers/realtimeregister/realtimeregisterProvider_test.go +++ b/providers/realtimeregister/realtimeregisterProvider_test.go @@ -1,8 +1,9 @@ package realtimeregister import ( - "github.com/stretchr/testify/assert" "testing" + + "github.com/stretchr/testify/assert" ) func TestRemoveEscapeChars(t *testing.T) { diff --git a/providers/route53/auditrecords.go b/providers/route53/auditrecords.go index 76534b99a..4a5d50f43 100644 --- a/providers/route53/auditrecords.go +++ b/providers/route53/auditrecords.go @@ -1,7 +1,7 @@ package route53 import ( - "fmt" + "errors" "github.com/StackExchange/dnscontrol/v4/models" "github.com/StackExchange/dnscontrol/v4/pkg/rejectif" @@ -25,7 +25,7 @@ func AuditRecords(records []*models.RecordConfig) []error { func rejectifTargetEqualsLabel(rc *models.RecordConfig) error { if (rc.GetLabelFQDN() + ".") == rc.GetTargetField() { - return fmt.Errorf("alias target loop") + return errors.New("alias target loop") } return nil } diff --git a/providers/route53/route53Provider.go b/providers/route53/route53Provider.go index daa17623d..f4da1d783 100644 --- a/providers/route53/route53Provider.go +++ b/providers/route53/route53Provider.go @@ -143,7 +143,6 @@ func (r *route53Provider) ListZones() ([]string, error) { } func (r *route53Provider) getZones() error { - if r.zonesByDomain != nil { return nil } @@ -248,7 +247,6 @@ func (r *route53Provider) GetZoneRecords(domain string, meta map[string]string) } func (r *route53Provider) getZone(dc *models.DomainConfig) (r53Types.HostedZone, error) { - if err := r.getZones(); err != nil { return r53Types.HostedZone{}, err } @@ -274,7 +272,7 @@ func (r *route53Provider) getZoneRecords(zone r53Types.HostedZone) (models.Recor return nil, err } - var existingRecords = []*models.RecordConfig{} + existingRecords := []*models.RecordConfig{} for _, set := range records { rts, err := nativeToRecords(set, unescape(zone.Name)) if err != nil { @@ -312,14 +310,13 @@ func (r *route53Provider) GetZoneRecordsCorrections(dc *models.DomainConfig, exi instructions = reorderInstructions(instructions) var reports []*models.Correction - //wasReport := false + // wasReport := false for _, inst := range instructions { instNameFQDN := inst.Key.NameFQDN instType := inst.Key.Type var chg r53Types.Change switch inst.Type { - case diff2.REPORT: // REPORTs are held in a separate list so that they aren't part of the batching process. reports = append(reports, @@ -336,7 +333,7 @@ func (r *route53Provider) GetZoneRecordsCorrections(dc *models.DomainConfig, exi // Make the rrset to be UPSERTed: var rrset *r53Types.ResourceRecordSet if instType == "R53_ALIAS" || strings.HasPrefix(instType, "R53_ALIAS_") { - // A R53_ALIAS_* requires ResourceRecordSet to a a single item, not a list. + // A R53_ALIAS_* requires ResourceRecordSet to a single item, not a list. if len(inst.New) != 1 { log.Fatal("Only one R53_ALIAS_ permitted on a label") } @@ -372,7 +369,6 @@ func (r *route53Provider) GetZoneRecordsCorrections(dc *models.DomainConfig, exi default: panic(fmt.Sprintf("unhandled inst.Type %s", inst.Type)) - } changes = append(changes, chg) @@ -411,7 +407,6 @@ func (r *route53Provider) GetZoneRecordsCorrections(dc *models.DomainConfig, exi } return append(reports, corrections...), actualChangeCount, nil - } // reorderInstructions returns changes reordered to comply with AWS's requirements: @@ -448,7 +443,9 @@ func nativeToRecords(set r53Types.ResourceRecordSet, origin string) ([]*models.R }, } rc.SetLabelFromFQDN(unescape(set.Name), origin) - rc.SetTarget(aws.ToString(set.AliasTarget.DNSName)) + if err := rc.SetTarget(aws.ToString(set.AliasTarget.DNSName)); err != nil { + return nil, err + } // rc.Original stores a pointer to the original set for use by // r53Types.ChangeActionDelete and anything else that needs the // native record verbatim. @@ -671,7 +668,7 @@ func (r *route53Provider) EnsureZoneExists(domain string) error { in := &r53.CreateHostedZoneInput{ Name: &domain, DelegationSetId: r.delegationSet, - CallerReference: aws.String(fmt.Sprint(time.Now().UnixNano())), + CallerReference: aws.String(strconv.FormatInt(time.Now().UnixNano(), 10)), } // reset zone cache diff --git a/providers/route53/route53Provider_test.go b/providers/route53/route53Provider_test.go index e4171896d..a17974347 100644 --- a/providers/route53/route53Provider_test.go +++ b/providers/route53/route53Provider_test.go @@ -10,7 +10,7 @@ import ( ) func TestUnescape(t *testing.T) { - var tests = []struct { + tests := []struct { experiment, expected string }{ {"foo", "foo"}, @@ -42,13 +42,13 @@ func (b batch) String() string { func Test_changeBatcher(t *testing.T) { genChanges := func(action r53Types.ChangeAction, typ r53Types.RRType, namePattern string, n int, targets ...string) []r53Types.Change { changes := make([]r53Types.Change, n) - for i := 0; i < n; i++ { + for i := range n { changes[i].Action = action changes[i].ResourceRecordSet = &r53Types.ResourceRecordSet{ Name: aws.String(fmt.Sprintf(namePattern, i)), Type: typ, } - for j := 0; j < len(targets); j++ { + for j := range len(targets) { changes[i].ResourceRecordSet.ResourceRecords = append(changes[i].ResourceRecordSet.ResourceRecords, r53Types.ResourceRecord{ Value: aws.String(targets[j]), }) diff --git a/providers/rwth/api.go b/providers/rwth/api.go index 643854109..8d6d5d7c2 100644 --- a/providers/rwth/api.go +++ b/providers/rwth/api.go @@ -5,6 +5,7 @@ package rwth import ( "encoding/json" + "errors" "fmt" "io" "net/http" @@ -52,7 +53,7 @@ func checkIsLockedSystemAPIRecord(record RecordReply) error { if record.Type == "soa_record" { // The upload of a BIND zone file can change the SOA record. // Implementing this edge case this is too complex for now. - return fmt.Errorf("SOA records are locked in RWTH zones. They are hence not available for updating") + return errors.New("SOA records are locked in RWTH zones. They are hence not available for updating") } return nil } @@ -61,7 +62,7 @@ func checkIsLockedSystemRecord(record *models.RecordConfig) error { if record.Type == "SOA" { // The upload of a BIND zone file can change the SOA record. // Implementing this edge case this is too complex for now. - return fmt.Errorf("SOA records are locked in RWTH zones. They are hence not available for updating") + return errors.New("SOA records are locked in RWTH zones. They are hence not available for updating") } return nil } @@ -189,7 +190,7 @@ func (api *rwthProvider) request(endpoint string, method string, request url.Val defer cleanupResponseBody() if resp.StatusCode != http.StatusOK { data, _ := io.ReadAll(resp.Body) - printer.Printf(string(data)) + printer.Printf("%s", string(data)) return fmt.Errorf("bad status code from RWTH: %d not 200", resp.StatusCode) } if target == nil { diff --git a/providers/rwth/convert.go b/providers/rwth/convert.go index cac252f3a..74f9e9a19 100644 --- a/providers/rwth/convert.go +++ b/providers/rwth/convert.go @@ -3,6 +3,7 @@ package rwth import ( "fmt" "io" + "strconv" "strings" "github.com/StackExchange/dnscontrol/v4/models" @@ -23,7 +24,7 @@ func (api *rwthProvider) printRecConfig(rr models.RecordConfig) string { // ttl ttl := "" if rr.TTL != 172800 && rr.TTL != 0 { - ttl = fmt.Sprint(rr.TTL) + ttl = strconv.FormatUint(uint64(rr.TTL), 10) } // type diff --git a/providers/rwth/dns.go b/providers/rwth/dns.go index b1433b05d..7046da529 100644 --- a/providers/rwth/dns.go +++ b/providers/rwth/dns.go @@ -1,8 +1,6 @@ package rwth import ( - "fmt" - "github.com/StackExchange/dnscontrol/v4/models" "github.com/StackExchange/dnscontrol/v4/pkg/diff" ) @@ -65,7 +63,7 @@ func (api *rwthProvider) GetZoneRecordsCorrections(dc *models.DomainConfig, exis // And deploy if any corrections were applied if len(corrections) > 0 { corrections = append(corrections, &models.Correction{ - Msg: fmt.Sprintf("Deploy zone %s", domain), + Msg: "Deploy zone " + domain, F: func() error { return api.deployZone(domain) }, }) } diff --git a/providers/rwth/rwthProvider.go b/providers/rwth/rwthProvider.go index 69468587f..754d5359a 100644 --- a/providers/rwth/rwthProvider.go +++ b/providers/rwth/rwthProvider.go @@ -2,7 +2,7 @@ package rwth import ( "encoding/json" - "fmt" + "errors" "github.com/StackExchange/dnscontrol/v4/providers" ) @@ -48,7 +48,7 @@ func init() { // New allocates a DNS service provider. func New(settings map[string]string, _ json.RawMessage) (providers.DNSServiceProvider, error) { if settings["api_token"] == "" { - return nil, fmt.Errorf("missing RWTH api_token") + return nil, errors.New("missing RWTH api_token") } api := &rwthProvider{apiToken: settings["api_token"]} diff --git a/providers/sakuracloud/api.go b/providers/sakuracloud/api.go index 4fe0aa806..57893a641 100644 --- a/providers/sakuracloud/api.go +++ b/providers/sakuracloud/api.go @@ -292,7 +292,7 @@ func (api *sakuracloudAPI) request(method, path string, data []byte) ([]byte, er } req.SetBasicAuth(api.accessToken, api.accessTokenSecret) - req.Header.Add("Content-Type", "applicaiton/json; charset=UTF-8") + req.Header.Add("Content-Type", "application/json; charset=UTF-8") resp, err := api.httpClient.Do(req) if err != nil { return nil, err @@ -349,6 +349,7 @@ func (api *sakuracloudAPI) getCommonServiceItems() ([]*commonServiceItem, error) } for _, item := range respData.CommonServiceItems { + item := item items = append(items, &item) } diff --git a/providers/sakuracloud/convert.go b/providers/sakuracloud/convert.go index 20f7677ff..c407d3014 100644 --- a/providers/sakuracloud/convert.go +++ b/providers/sakuracloud/convert.go @@ -6,7 +6,7 @@ import ( const defaultTTL = uint32(3600) -func toRc(domain string, r domainRecord) *models.RecordConfig { +func toRc(domain string, r domainRecord) (*models.RecordConfig, error) { rc := &models.RecordConfig{ Type: r.Type, TTL: r.TTL, @@ -18,15 +18,15 @@ func toRc(domain string, r domainRecord) *models.RecordConfig { rc.SetLabel(r.Name, domain) + var err error switch r.Type { case "TXT": // TXT records are stored verbatim; no quoting/escaping to parse. - rc.SetTargetTXT(r.RData) + err = rc.SetTargetTXT(r.RData) default: - rc.PopulateFromString(r.Type, r.RData, domain) + err = rc.PopulateFromString(r.Type, r.RData, domain) } - - return rc + return rc, err } func toNative(rc *models.RecordConfig) domainRecord { diff --git a/providers/sakuracloud/records.go b/providers/sakuracloud/records.go index d29c642b7..8f701917b 100644 --- a/providers/sakuracloud/records.go +++ b/providers/sakuracloud/records.go @@ -46,7 +46,10 @@ func (s *sakuracloudProvider) GetZoneRecords(domain string, meta map[string]stri } for _, dr := range item.Settings.DNS.ResourceRecordSets { - rc := toRc(domain, dr) + rc, err := toRc(domain, dr) + if err != nil { + return nil, err + } existingRecords = append(existingRecords, rc) } return existingRecords, nil diff --git a/providers/sakuracloud/sakuracloudProvider.go b/providers/sakuracloud/sakuracloudProvider.go index bdf29a24b..eccd30daa 100644 --- a/providers/sakuracloud/sakuracloudProvider.go +++ b/providers/sakuracloud/sakuracloudProvider.go @@ -2,6 +2,7 @@ package sakuracloud import ( "encoding/json" + "errors" "fmt" "github.com/StackExchange/dnscontrol/v4/models" @@ -61,12 +62,12 @@ func newSakuracloud(config map[string]string, _ json.RawMessage) (*sakuracloudPr // config -- the key/values from creds.json accessToken := config["access_token"] if accessToken == "" { - return nil, fmt.Errorf("access_token is required") + return nil, errors.New("access_token is required") } accessTokenSecret := config["access_token_secret"] if accessTokenSecret == "" { - return nil, fmt.Errorf("access_token_secret is required") + return nil, errors.New("access_token_secret is required") } endpoint := config["endpoint"] diff --git a/providers/softlayer/softlayerProvider.go b/providers/softlayer/softlayerProvider.go index 32f339d38..162ae93c4 100644 --- a/providers/softlayer/softlayerProvider.go +++ b/providers/softlayer/softlayerProvider.go @@ -2,6 +2,7 @@ package softlayer import ( "encoding/json" + "errors" "fmt" "regexp" "strings" @@ -46,7 +47,7 @@ func newReg(conf map[string]string, _ json.RawMessage) (providers.DNSServiceProv s := session.New(conf["username"], conf["api_key"], conf["endpoint_url"], conf["timeout"]) if len(s.UserName) == 0 || len(s.APIKey) == 0 { - return nil, fmt.Errorf("SoftLayer UserName and APIKey must be provided") + return nil, errors.New("SoftLayer UserName and APIKey must be provided") } // s.Debug = true @@ -127,7 +128,6 @@ func (s *softlayerProvider) getDomain(name *string) (*datatypes.Dns_Domain, erro Filter(filter.Path("domains.name").Eq(name).Build()). Mask("resourceRecords"). GetDomains() - if err != nil { return nil, err } @@ -156,11 +156,13 @@ func (s *softlayerProvider) getExistingRecords(domain *datatypes.Dns_Domain) (mo TTL: uint32(*record.Ttl), Original: record, } - recConfig.SetTarget(*record.Data) + if err := recConfig.SetTarget(*record.Data); err != nil { + return nil, err + } switch recType { case "SRV": - var service, protocol = "", "_tcp" + service, protocol := "", "_tcp" if record.Weight != nil { recConfig.SrvWeight = uint16(*record.Weight) @@ -180,7 +182,9 @@ func (s *softlayerProvider) getExistingRecords(domain *datatypes.Dns_Domain) (mo recConfig.SetLabel(fmt.Sprintf("%s.%s", service, strings.ToLower(protocol)), *domain.Name) case "TXT": // OLD: recConfig.TxtStrings = append(recConfig.TxtStrings, *record.Data) - recConfig.SetTargetTXTs(append(recConfig.GetTargetTXTSegmented(), *record.Data)) + if err := recConfig.SetTargetTXTs(append(recConfig.GetTargetTXTSegmented(), *record.Data)); err != nil { + return nil, err + } // NB(tlim) The above code seems too complex. Can it be simplied to this? // recConfig.SetTargetTXT(*record.Data) fallthrough @@ -200,9 +204,9 @@ func (s *softlayerProvider) getExistingRecords(domain *datatypes.Dns_Domain) (mo } func (s *softlayerProvider) createRecordFunc(desired *models.RecordConfig, domain *datatypes.Dns_Domain) func() error { - var ttl, preference, domainID = verifyMinTTL(int(desired.TTL)), int(desired.MxPreference), *domain.Id - var weight, priority, port = int(desired.SrvWeight), int(desired.SrvPriority), int(desired.SrvPort) - var host, data, newType = desired.GetLabel(), desired.GetTargetField(), desired.Type + ttl, preference, domainID := verifyMinTTL(int(desired.TTL)), int(desired.MxPreference), *domain.Id + weight, priority, port := int(desired.SrvWeight), int(desired.SrvPriority), int(desired.SrvPort) + host, data, newType := desired.GetLabel(), desired.GetTargetField(), desired.Type var err error srvRegexp := regexp.MustCompile(`^_(?P\w+)\.\_(?P\w+)$`) @@ -236,7 +240,7 @@ func (s *softlayerProvider) createRecordFunc(desired *models.RecordConfig, domai return fmt.Errorf("SRV Record must match format \"_service._protocol\" not %s", host) } - var serviceName, protocol = result[1], strings.ToLower(result[2]) + serviceName, protocol := result[1], strings.ToLower(result[2]) newSrv := datatypes.Dns_Domain_ResourceRecord_SrvType{ Dns_Domain_ResourceRecord: newRecord, @@ -270,11 +274,11 @@ func (s *softlayerProvider) deleteRecordFunc(resID int) func() error { } func (s *softlayerProvider) updateRecordFunc(existing *datatypes.Dns_Domain_ResourceRecord, desired *models.RecordConfig) func() error { - var ttl, preference = verifyMinTTL(int(desired.TTL)), int(desired.MxPreference) - var priority, weight, port = int(desired.SrvPriority), int(desired.SrvWeight), int(desired.SrvPort) + ttl, preference := verifyMinTTL(int(desired.TTL)), int(desired.MxPreference) + priority, weight, port := int(desired.SrvPriority), int(desired.SrvWeight), int(desired.SrvPort) return func() error { - var changes = false + changes := false var err error switch desired.Type { @@ -305,7 +309,7 @@ func (s *softlayerProvider) updateRecordFunc(existing *datatypes.Dns_Domain_Reso } if !changes { - return fmt.Errorf("didn't find changes when I expect some") + return errors.New("didn't find changes when I expect some") } _, err = service.Id(*existing.Id).EditObject(&updated) @@ -350,7 +354,7 @@ func (s *softlayerProvider) updateRecordFunc(existing *datatypes.Dns_Domain_Reso // delete and recreate? if !changes { - return fmt.Errorf("didn't find changes when I expect some") + return errors.New("didn't find changes when I expect some") } _, err = service.Id(*existing.Id).EditObject(&updated) @@ -377,7 +381,7 @@ func (s *softlayerProvider) updateRecordFunc(existing *datatypes.Dns_Domain_Reso } if !changes { - return fmt.Errorf("didn't find changes when I expect some") + return errors.New("didn't find changes when I expect some") } _, err = service.Id(*existing.Id).EditObject(&updated) diff --git a/providers/transip/transipProvider.go b/providers/transip/transipProvider.go index a83acc397..ea72ee2c9 100644 --- a/providers/transip/transipProvider.go +++ b/providers/transip/transipProvider.go @@ -2,6 +2,7 @@ package transip import ( "encoding/json" + "errors" "fmt" "sort" "strings" @@ -60,13 +61,12 @@ var features = providers.DocumentationNotes{ // NewTransip creates a new TransIP provider. func NewTransip(m map[string]string, metadata json.RawMessage) (providers.DNSServiceProvider, error) { - if m["AccessToken"] == "" && m["PrivateKey"] == "" { - return nil, fmt.Errorf("no TransIP AccessToken or PrivateKey provided") + return nil, errors.New("no TransIP AccessToken or PrivateKey provided") } if m["PrivateKey"] != "" && m["AccountName"] == "" { - return nil, fmt.Errorf("no AccountName given, required for authenticating with PrivateKey") + return nil, errors.New("no AccountName given, required for authenticating with PrivateKey") } client, err := gotransip.NewClient(gotransip.ClientConfiguration{ @@ -74,7 +74,6 @@ func NewTransip(m map[string]string, metadata json.RawMessage) (providers.DNSSer AccountName: m["AccountName"], PrivateKeyReader: strings.NewReader(m["PrivateKey"]), }) - if err != nil { return nil, fmt.Errorf("TransIP client fail %s", err.Error()) } @@ -115,7 +114,6 @@ func (n *transipProvider) ListZones() ([]string, error) { // GetZoneRecordsCorrections returns a list of corrections that will turn existing records into dc.Records. func (n *transipProvider) GetZoneRecordsCorrections(dc *models.DomainConfig, curRecords models.Records) ([]*models.Correction, int, error) { - removeOtherNS(dc) corrections, actualChangeCount, err := n.getCorrectionsUsingDiff2(dc, curRecords) @@ -131,7 +129,6 @@ func (n *transipProvider) getCorrectionsUsingDiff2(dc *models.DomainConfig, reco } for _, change := range instructions { - switch change.Type { case diff2.DELETE: oldEntries, err := recordsToNative(change.Old, true) @@ -181,7 +178,6 @@ func (n *transipProvider) getCorrectionsUsingDiff2(dc *models.DomainConfig, reco case diff2.REPORT: corrections = append(corrections, change.CreateMessage()) } - } return corrections, actualChangeCount, nil @@ -228,7 +224,6 @@ func recordsToNative(records models.Records, useOriginal bool) ([]domain.DNSEntr for iX, record := range records { entry, err := recordToNative(record, useOriginal) - if err != nil { return nil, err } @@ -242,7 +237,6 @@ func recordsToNative(records models.Records, useOriginal bool) ([]domain.DNSEntr func wrapChangeFunction(entries []domain.DNSEntry, executer func(rec domain.DNSEntry) error) func() error { return func() error { for _, entry := range entries { - if err := executer(entry); err != nil { return err } @@ -270,7 +264,7 @@ func canDirectApplyDNSEntries(change diff2.Change) bool { return false } - for i := 0; i < len(desired); i++ { + for i := range len(desired) { if !canUpdateDNSEntry(desired[i], existing[i]) { return false } @@ -284,13 +278,12 @@ func canUpdateDNSEntry(desired *models.RecordConfig, existing *models.RecordConf } func (n *transipProvider) GetZoneRecords(domainName string, meta map[string]string) (models.Records, error) { - entries, err := n.domains.GetDNSEntries(domainName) if err != nil { return nil, err } - var existingRecords = []*models.RecordConfig{} + existingRecords := []*models.RecordConfig{} for _, entry := range entries { rts, err := nativeToRecord(entry, domainName) if err != nil { diff --git a/providers/vultr/vultrProvider.go b/providers/vultr/vultrProvider.go index 25aa9143d..820c8c5aa 100644 --- a/providers/vultr/vultrProvider.go +++ b/providers/vultr/vultrProvider.go @@ -7,13 +7,12 @@ import ( "fmt" "strings" - "golang.org/x/net/idna" - "golang.org/x/oauth2" - "github.com/StackExchange/dnscontrol/v4/models" "github.com/StackExchange/dnscontrol/v4/pkg/diff2" "github.com/StackExchange/dnscontrol/v4/providers" "github.com/vultr/govultr/v2" + "golang.org/x/net/idna" + "golang.org/x/oauth2" ) /* @@ -68,7 +67,7 @@ var defaultNS = []string{ func NewProvider(m map[string]string, metadata json.RawMessage) (providers.DNSServiceProvider, error) { token := m["token"] if token == "" { - return nil, fmt.Errorf("missing Vultr API token") + return nil, errors.New("missing Vultr API token") } config := &oauth2.Config{} @@ -126,7 +125,9 @@ func (api *vultrProvider) GetZoneRecordsCorrections(dc *models.DomainConfig, cur if err != nil { return nil, 0, err } - rec.SetTarget(t) + if err := rec.SetTarget(t); err != nil { + return nil, 0, err + } default: // Nothing to do. }