From b91bcf373ffda8abaa322b1c04b1caaa2825bd19 Mon Sep 17 00:00:00 2001 From: Tom Whitwell Date: Tue, 20 Jun 2023 16:45:16 +0100 Subject: [PATCH 001/438] Add Shell Completion script generation `dnsutils shell-completion ` will generate a shell completion script for the specified shell (bash or zsh). If no shell is specified, the script will be generated for the current shell, using `$SHELL`. --- .editorconfig | 2 +- .../completion-scripts/completion.bash.gotmpl | 34 +++ .../completion-scripts/completion.zsh.gotmpl | 20 ++ commands/completion.go | 91 +++++++ commands/completion_test.go | 249 ++++++++++++++++++ documentation/getting-started.md | 17 ++ go.mod | 1 + 7 files changed, 413 insertions(+), 1 deletion(-) create mode 100644 commands/completion-scripts/completion.bash.gotmpl create mode 100644 commands/completion-scripts/completion.zsh.gotmpl create mode 100644 commands/completion.go create mode 100644 commands/completion_test.go diff --git a/.editorconfig b/.editorconfig index fc14c62c6d..3deaa8a71d 100644 --- a/.editorconfig +++ b/.editorconfig @@ -109,7 +109,7 @@ indent_style = space # Shell # https://google.github.io/styleguide/shell.xml#Indentation -[*.{bash,sh,zsh}] +[*.{bash,sh,zsh,*sh.gotmpl}] indent_size = 2 indent_style = space diff --git a/commands/completion-scripts/completion.bash.gotmpl b/commands/completion-scripts/completion.bash.gotmpl new file mode 100644 index 0000000000..1f04ec5978 --- /dev/null +++ b/commands/completion-scripts/completion.bash.gotmpl @@ -0,0 +1,34 @@ +#!/bin/bash + +: "{{.App.Name}}" + +# Macs have bash3 for which the bash-completion package doesn't include +# _init_completion. This is a minimal version of that function. +_dnscontrol_init_completion() { + COMPREPLY=() + _get_comp_words_by_ref "$@" cur prev words cword +} + +_dnscontrol() { + if [[ "${COMP_WORDS[0]}" != "source" ]]; then + local cur opts base words + COMPREPLY=() + cur="${COMP_WORDS[COMP_CWORD]}" + if declare -F _init_completion >/dev/null 2>&1; then + _init_completion -n "=:" || return + else + _dnscontrol_init_completion -n "=:" || return + fi + words=("${words[@]:0:$cword}") + if [[ "$cur" == "-"* ]]; then + requestComp="${words[*]} ${cur} --generate-bash-completion" + else + requestComp="${words[*]} --generate-bash-completion" + fi + opts=$(eval "${requestComp}" 2>/dev/null) + COMPREPLY=($(compgen -W "${opts}" -- ${cur})) + return 0 + fi +} + +complete -o bashdefault -o default -o nospace -F "_dnscontrol" "{{.App.Name}}" diff --git a/commands/completion-scripts/completion.zsh.gotmpl b/commands/completion-scripts/completion.zsh.gotmpl new file mode 100644 index 0000000000..665a361ecb --- /dev/null +++ b/commands/completion-scripts/completion.zsh.gotmpl @@ -0,0 +1,20 @@ +#compdef "{{.App.Name}}" + +_dnscontrol() { + local -a opts + local cur + cur=${words[-1]} + if [[ "$cur" == "-"* ]]; then + opts=("${(@f)$(${words[@]:0:#words[@]-1} ${cur} --generate-bash-completion)}") + else + opts=("${(@f)$(${words[@]:0:#words[@]-1} --generate-bash-completion)}") + fi + + if [[ "${opts[1]}" != "" ]]; then + _describe 'values' opts + else + _files + fi +} + +compdef "_dnscontrol" "{{.App.Name}}" diff --git a/commands/completion.go b/commands/completion.go new file mode 100644 index 0000000000..47d00cacf7 --- /dev/null +++ b/commands/completion.go @@ -0,0 +1,91 @@ +package commands + +import ( + "embed" + "errors" + "fmt" + "github.com/urfave/cli/v2" + "os" + "path" + "strings" + "text/template" +) + +//go:embed completion-scripts/completion.*.gotmpl +var completionScripts embed.FS + +func shellCompletionCommand() *cli.Command { + supportedShells, templates, err := getCompletionSupportedShells() + if err != nil { + panic(err) + } + return &cli.Command{ + Name: "shell-completion", + Usage: "generate shell completion scripts", + Hidden: true, + ArgsUsage: fmt.Sprintf("[ %s ]", strings.Join(supportedShells, " | ")), + Description: fmt.Sprintf("Generate shell completion script for [ %s ]", strings.Join(supportedShells, " | ")), + BashComplete: func(ctx *cli.Context) { + for _, shell := range supportedShells { + if strings.HasPrefix(shell, ctx.Args().First()) { + ctx.App.Writer.Write([]byte(shell + "\n")) + } + } + }, + Action: func(ctx *cli.Context) error { + var inputShell string + if inputShell = ctx.Args().First(); inputShell == "" { + if inputShell = os.Getenv("SHELL"); inputShell == "" { + return cli.Exit(errors.New("shell not specified"), 1) + } + } + shellName := path.Base(inputShell) // necessary if using $SHELL, noop otherwise + + template := templates[shellName] + if template == nil { + return cli.Exit(fmt.Errorf("unknown shell: %s", inputShell), 1) + } + + err = template.Execute(ctx.App.Writer, struct { + App *cli.App + }{ctx.App}) + if err != nil { + return cli.Exit(fmt.Errorf("failed to print completion script: %w", err), 1) + } + return nil + }, + } +} + +var _ = cmd(catUtils, shellCompletionCommand()) + +// getCompletionSupportedShells returns a list of shells with available completions. +// The list is generated from the embedded completion scripts. +func getCompletionSupportedShells() (shells []string, shellCompletionScripts map[string]*template.Template, err error) { + scripts, err := completionScripts.ReadDir("completion-scripts") + if err != nil { + return nil, nil, fmt.Errorf("failed to read completion scripts: %w", err) + } + + shellCompletionScripts = make(map[string]*template.Template) + + for _, f := range scripts { + fNameWithoutExtension := strings.TrimSuffix(f.Name(), ".gotmpl") + shellName := strings.TrimPrefix(path.Ext(fNameWithoutExtension), ".") + + content, err := completionScripts.ReadFile(path.Join("completion-scripts", f.Name())) + if err != nil { + return nil, nil, fmt.Errorf("failed to read completion script %s", f.Name()) + } + + t := template.New(shellName) + t, err = t.Parse(string(content)) + if err != nil { + return nil, nil, fmt.Errorf("failed to parse template %s", f.Name()) + } + + shells = append(shells, shellName) + shellCompletionScripts[shellName] = t + } + return shells, shellCompletionScripts, nil +} diff --git a/commands/completion_test.go b/commands/completion_test.go new file mode 100644 index 0000000000..d786ed4c97 --- /dev/null +++ b/commands/completion_test.go @@ -0,0 +1,249 @@ +package commands + +import ( + "bytes" + "fmt" + "github.com/google/go-cmp/cmp" + "strings" + "testing" + "text/template" + + "github.com/urfave/cli/v2" + "golang.org/x/exp/slices" +) + +type shellTestDataItem struct { + shellName string + shellPath string + completionScriptTemplate *template.Template +} + +// setupTestShellCompletionCommand resets the buffers used to capture output and errors from the app. +func setupTestShellCompletionCommand(t *testing.T, app *cli.App) func(t *testing.T) { + return func(t *testing.T) { + app.Writer.(*bytes.Buffer).Reset() + cli.ErrWriter.(*bytes.Buffer).Reset() + } +} + +func TestShellCompletionCommand(t *testing.T) { + app := cli.NewApp() + app.Name = "testing" + + var appWriterBuffer bytes.Buffer + app.Writer = &appWriterBuffer // capture output from app + + var appErrWriterBuffer bytes.Buffer + cli.ErrWriter = &appErrWriterBuffer // capture errors from app (apparently, HandleExitCoder doesn't use app.ErrWriter!?) + + cli.OsExiter = func(int) {} // disable os.Exit call + + app.Commands = []*cli.Command{ + shellCompletionCommand(), + } + + shellsAndCompletionScripts, err := testHelperGetShellsAndCompletionScripts() + if err != nil { + t.Fatalf("unexpected error: %v", err) + } + if len(shellsAndCompletionScripts) == 0 { + t.Fatal("no shells found") + } + + invalidShellTestDataItem := shellTestDataItem{ + shellName: "invalid", + shellPath: "/bin/invalid", + } + for _, tt := range shellsAndCompletionScripts { + if tt.shellName == invalidShellTestDataItem.shellName { + t.Fatalf("invalidShellTestDataItem.shellName (%s) is actually a valid shell name", invalidShellTestDataItem.shellName) + } + } + + // Test shell argument + t.Run("shellArg", func(t *testing.T) { + for _, tt := range shellsAndCompletionScripts { + t.Run(tt.shellName, func(t *testing.T) { + tearDownTest := setupTestShellCompletionCommand(t, app) + defer tearDownTest(t) + + err := app.Run([]string{app.Name, "shell-completion", tt.shellName}) + if err != nil { + t.Fatalf("unexpected error: %v", err) + } + + got := appWriterBuffer.String() + want, err := testHelperRenderTemplateFromApp(app, tt.completionScriptTemplate) + if err != nil { + t.Fatalf("unexpected error: %v", err) + } + if diff := cmp.Diff(got, want); diff != "" { + t.Errorf("mismatch (-want +got):\n%s", diff) + } + + stderr := appErrWriterBuffer.String() + if stderr != "" { + t.Errorf("want no stderr, got %q", stderr) + } + }) + } + + t.Run(invalidShellTestDataItem.shellName, func(t *testing.T) { + tearDownTest := setupTestShellCompletionCommand(t, app) + defer tearDownTest(t) + + err := app.Run([]string{app.Name, "shell-completion", "invalid"}) + + if err == nil { + t.Fatal("expected error, but didn't get one") + } + + want := fmt.Sprintf("unknown shell: %s", invalidShellTestDataItem.shellName) + got := strings.TrimSpace(appErrWriterBuffer.String()) + if diff := cmp.Diff(got, want); diff != "" { + t.Errorf("mismatch (-want +got):\n%s", diff) + } + + stdout := appWriterBuffer.String() + if stdout != "" { + t.Errorf("want no stdout, got %q", stdout) + } + }) + }) + + // Test $SHELL envar + t.Run("$SHELL", func(t *testing.T) { + for _, tt := range shellsAndCompletionScripts { + t.Run(tt.shellName, func(t *testing.T) { + tearDownTest := setupTestShellCompletionCommand(t, app) + defer tearDownTest(t) + + t.Setenv("SHELL", tt.shellPath) + + err := app.Run([]string{app.Name, "shell-completion"}) + if err != nil { + t.Fatalf("unexpected error: %v", err) + } + + got := appWriterBuffer.String() + want, err := testHelperRenderTemplateFromApp(app, tt.completionScriptTemplate) + if err != nil { + t.Fatalf("unexpected error: %v", err) + } + if diff := cmp.Diff(got, want); diff != "" { + t.Errorf("mismatch (-want +got):\n%s", diff) + } + + stderr := appErrWriterBuffer.String() + if stderr != "" { + t.Errorf("want no stderr, got %q", stderr) + } + }) + } + + t.Run(invalidShellTestDataItem.shellName, func(t *testing.T) { + tearDownTest := setupTestShellCompletionCommand(t, app) + defer tearDownTest(t) + + t.Setenv("SHELL", invalidShellTestDataItem.shellPath) + + err := app.Run([]string{app.Name, "shell-completion"}) + if err == nil { + t.Fatal("expected error, but didn't get one") + } + + want := fmt.Sprintf("unknown shell: %s", invalidShellTestDataItem.shellPath) + got := strings.TrimSpace(appErrWriterBuffer.String()) + if diff := cmp.Diff(got, want); diff != "" { + t.Errorf("mismatch (-want +got):\n%s", diff) + } + + stdout := appWriterBuffer.String() + if stdout != "" { + t.Errorf("want no stdout, got %q", stdout) + } + }) + }) + + // Test shell argument completion (meta) + t.Run("shell-name-completion", func(t *testing.T) { + type testCase struct { + shellArg string + expected []string + } + testCases := []testCase{ + {shellArg: ""}, // empty 'shell' argument, returns all known shells (expected is filled later) + {shellArg: "invalid", expected: []string{""}}, // invalid shell, returns none + } + + for _, tt := range shellsAndCompletionScripts { + testCases[0].expected = append(testCases[0].expected, tt.shellName) + for i, _ := range tt.shellName { + testCases = append(testCases, testCase{ + shellArg: tt.shellName[:i+1], + expected: []string{tt.shellName}, + }) + } + } + + for _, tC := range testCases { + t.Run(tC.shellArg, func(t *testing.T) { + tearDownTest := setupTestShellCompletionCommand(t, app) + defer tearDownTest(t) + app.EnableBashCompletion = true + defer func() { + app.EnableBashCompletion = false + }() + + err := app.Run([]string{app.Name, "shell-completion", tC.shellArg, "--generate-bash-completion"}) + if err != nil { + t.Fatalf("unexpected error: %v", err) + } + + for _, line := range strings.Split(strings.TrimSpace(appWriterBuffer.String()), "\n") { + if !slices.Contains(tC.expected, line) { + t.Errorf("%q found, but not expected", line) + } + } + }) + } + }) +} + +// testHelperGetShellsAndCompletionScripts collects all supported shells and their completion scripts and returns them +// as a slice of shellTestDataItem. +// The completion scripts are sourced with getCompletionSupportedShells +func testHelperGetShellsAndCompletionScripts() ([]shellTestDataItem, error) { + shells, templates, err := getCompletionSupportedShells() + if err != nil { + return nil, err + } + + var shellsAndValues []shellTestDataItem + for shellName, t := range templates { + if !slices.Contains(shells, shellName) { + return nil, fmt.Errorf( + `"%s" is not present in slice of shells from getCompletionSupportedShells`, shellName) + } + shellsAndValues = append( + shellsAndValues, + shellTestDataItem{ + shellName: shellName, + shellPath: fmt.Sprintf("/bin/%s", shellName), + completionScriptTemplate: t, + }, + ) + } + return shellsAndValues, nil +} + +// testHelperRenderTemplateFromApp renders a given template with a given app. +// This is used to test the output of the CLI command against a 'known good' value. +func testHelperRenderTemplateFromApp(app *cli.App, scriptTemplate *template.Template) (string, error) { + var scriptBytes bytes.Buffer + err := scriptTemplate.Execute(&scriptBytes, struct { + App *cli.App + }{app}) + + return scriptBytes.String(), err +} diff --git a/documentation/getting-started.md b/documentation/getting-started.md index 9235b3c537..357e5826d2 100644 --- a/documentation/getting-started.md +++ b/documentation/getting-started.md @@ -54,6 +54,23 @@ git clone https://github.com/StackExchange/dnscontrol If these don't work, more info is in [#805](https://github.com/StackExchange/dnscontrol/issues/805). +## 1.1. Shell Completion + +Shell completion is available for `zsh` and `bash`. + +### zsh + +Add `eval "$(dnscontrol shell-completion zsh)"` to your `~/.zshrc` file. + +This requires completion to be enabled in zsh. A good tutorial for this is available at +[The Valuable Dev](https://thevaluable.dev/zsh-completion-guide-examples/) [[archived](https://web.archive.org/web/20231015083946/https://thevaluable.dev/zsh-completion-guide-examples/)]. + +### bash + +Add `eval "$(dnscontrol shell-completion bash)"` to your `~/.bashrc` file. + +This requires the `bash-completion` package to be installed. See [scop/bash-completion](https://github.com/scop/bash-completion/) for instructions. + ## 2. Create a place for the config files Create a directory where you'll store your configuration files. diff --git a/go.mod b/go.mod index 8b4b320501..97404706b4 100644 --- a/go.mod +++ b/go.mod @@ -61,6 +61,7 @@ require ( github.com/G-Core/gcore-dns-sdk-go v0.2.6 github.com/fatih/color v1.15.0 github.com/fbiville/markdown-table-formatter v0.3.0 + github.com/google/go-cmp v0.5.9 github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510 github.com/kylelemons/godebug v1.1.0 github.com/mattn/go-isatty v0.0.19 From b147fbf5571759031ed05fa50e0535ac141842f3 Mon Sep 17 00:00:00 2001 From: Tom Whitwell Date: Sun, 15 Oct 2023 11:13:06 +0100 Subject: [PATCH 002/438] wip: complete subcommands after bare flags --- commands/commands.go | 18 ++++++++++ commands/completion.go | 81 +++++++++++++++++++++++++++++++++++++++++- 2 files changed, 98 insertions(+), 1 deletion(-) diff --git a/commands/commands.go b/commands/commands.go index ac858550bf..e5b07faff3 100644 --- a/commands/commands.go +++ b/commands/commands.go @@ -85,6 +85,24 @@ func Run(v string) int { sort.Sort(cli.CommandsByName(commands)) app.Commands = commands app.EnableBashCompletion = true + app.BashComplete = func(cCtx *cli.Context) { + // ripped from cli.DefaultCompleteWithFlags + var lastArg string + + if len(os.Args) > 2 { + lastArg = os.Args[len(os.Args)-2] + } + + if lastArg != "" { + if strings.HasPrefix(lastArg, "-") { + if !islastFlagComplete(lastArg, app.Flags) { + dnscontrolPrintFlagSuggestions(lastArg, app.Flags, cCtx.App.Writer) + return + } + } + } + dnscontrolPrintCommandSuggestions(app.Commands, cCtx.App.Writer) + } if err := app.Run(os.Args); err != nil { return 1 } diff --git a/commands/completion.go b/commands/completion.go index 47d00cacf7..448004555c 100644 --- a/commands/completion.go +++ b/commands/completion.go @@ -4,11 +4,14 @@ import ( "embed" "errors" "fmt" - "github.com/urfave/cli/v2" + "io" "os" "path" "strings" "text/template" + "unicode/utf8" + + "github.com/urfave/cli/v2" ) //go:embed completion-scripts/completion.*.gotmpl @@ -89,3 +92,79 @@ func getCompletionSupportedShells() (shells []string, shellCompletionScripts map } return shells, shellCompletionScripts, nil } + +func dnscontrolPrintCommandSuggestions(commands []*cli.Command, writer io.Writer) { + for _, command := range commands { + if command.Hidden { + continue + } + if strings.HasSuffix(os.Getenv("SHELL"), "zsh") { + for _, name := range command.Names() { + _, _ = fmt.Fprintf(writer, "%s:%s\n", name, command.Usage) + } + } else { + for _, name := range command.Names() { + _, _ = fmt.Fprintf(writer, "%s\n", name) + } + } + } +} + +func dnscontrolCliArgContains(flagName string) bool { + for _, name := range strings.Split(flagName, ",") { + name = strings.TrimSpace(name) + count := utf8.RuneCountInString(name) + if count > 2 { + count = 2 + } + flag := fmt.Sprintf("%s%s", strings.Repeat("-", count), name) + for _, a := range os.Args { + if a == flag { + return true + } + } + } + return false +} + +func dnscontrolPrintFlagSuggestions(lastArg string, flags []cli.Flag, writer io.Writer) { + cur := strings.TrimPrefix(lastArg, "-") + cur = strings.TrimPrefix(cur, "-") + for _, flag := range flags { + if bflag, ok := flag.(*cli.BoolFlag); ok && bflag.Hidden { + continue + } + for _, name := range flag.Names() { + name = strings.TrimSpace(name) + // this will get total count utf8 letters in flag name + count := utf8.RuneCountInString(name) + if count > 2 { + count = 2 // reuse this count to generate single - or -- in flag completion + } + // if flag name has more than one utf8 letter and last argument in cli has -- prefix then + // skip flag completion for short flags example -v or -x + if strings.HasPrefix(lastArg, "--") && count == 1 { + continue + } + // match if last argument matches this flag and it is not repeated + if strings.HasPrefix(name, cur) && cur != name && !dnscontrolCliArgContains(name) { + flagCompletion := fmt.Sprintf("%s%s", strings.Repeat("-", count), name) + _, _ = fmt.Fprintln(writer, flagCompletion) + } + } + } +} + +func islastFlagComplete(lastArg string, flags []cli.Flag) bool { + cur := strings.TrimPrefix(lastArg, "-") + cur = strings.TrimPrefix(cur, "-") + for _, flag := range flags { + for _, name := range flag.Names() { + name = strings.TrimSpace(name) + if strings.HasPrefix(name, cur) && cur != name && !dnscontrolCliArgContains(name) { + return false + } + } + } + return true +} From b1b41c5fbae5ff3440238a96e7d8402b146ceaf8 Mon Sep 17 00:00:00 2001 From: tomf Date: Wed, 25 Oct 2023 05:30:13 +1100 Subject: [PATCH 003/438] Change "push -i" prompt text from "Y/n" to "y/N" to match reality (#2605) --- pkg/printer/printer.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pkg/printer/printer.go b/pkg/printer/printer.go index f23fd91005..da839ab669 100644 --- a/pkg/printer/printer.go +++ b/pkg/printer/printer.go @@ -97,7 +97,7 @@ func (c ConsolePrinter) PrintReport(i int, correction *models.Correction) { // PromptToRun prompts the user to see if they want to execute a correction. func (c ConsolePrinter) PromptToRun() bool { - fmt.Fprint(c.Writer, "Run? (Y/n): ") + fmt.Fprint(c.Writer, "Run? (y/N): ") txt, err := c.Reader.ReadString('\n') run := true if err != nil { From 793c3b11c5701215ba7eb4a2fd9481b8687c7283 Mon Sep 17 00:00:00 2001 From: Filippo Valsorda Date: Tue, 31 Oct 2023 09:22:05 -0400 Subject: [PATCH 004/438] dnscontrol.d.ts: fix DOMAIN_ELSEWHERE_AUTO signature (#2606) --- commands/types/dnscontrol.d.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/commands/types/dnscontrol.d.ts b/commands/types/dnscontrol.d.ts index 0fac62a7f9..376d8c2bd3 100644 --- a/commands/types/dnscontrol.d.ts +++ b/commands/types/dnscontrol.d.ts @@ -822,7 +822,7 @@ declare function DOMAIN_ELSEWHERE(name: string, registrar: string, nameserver_na * * @see https://docs.dnscontrol.org/language-reference/top-level-functions/domain_elsewhere_auto */ -declare function DOMAIN_ELSEWHERE_AUTO(name: string, domain: string, registrar: string, dnsProvider: string): void; +declare function DOMAIN_ELSEWHERE_AUTO(name: string, registrar: string, dnsProvider: string): void; /** * DS adds a DS record to the domain. From cb9491dbe9805a224c99881c5d36f77c52ad5a85 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E9=99=B8?= <37530178+riku22@users.noreply.github.com> Date: Tue, 31 Oct 2023 22:22:44 +0900 Subject: [PATCH 005/438] DNSMADEEASY: DOCS: Fix provider name from DNS Made Simple to DNS Made Easy (#2607) Co-authored-by: Tom Limoncelli --- documentation/SUMMARY.md | 2 +- providers/dnsmadeeasy/restApi.go | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/documentation/SUMMARY.md b/documentation/SUMMARY.md index fd4ee01242..b8e9f87910 100644 --- a/documentation/SUMMARY.md +++ b/documentation/SUMMARY.md @@ -106,7 +106,7 @@ * [CSC Global](providers/cscglobal.md) * [deSEC](providers/desec.md) * [DigitalOcean](providers/digitalocean.md) - * [DNS Made Simple](providers/dnsmadeeasy.md) + * [DNS Made Easy](providers/dnsmadeeasy.md) * [DNSimple](providers/dnsimple.md) * [DNS-over-HTTPS](providers/dnsoverhttps.md) * [DOMAINNAMESHOP](providers/domainnameshop.md) diff --git a/providers/dnsmadeeasy/restApi.go b/providers/dnsmadeeasy/restApi.go index 02b570c57d..ac87e29f0b 100644 --- a/providers/dnsmadeeasy/restApi.go +++ b/providers/dnsmadeeasy/restApi.go @@ -207,7 +207,7 @@ func (restApi *dnsMadeEasyRestAPI) createRequest(request *apiRequest) (*http.Req return req, nil } -// DNS Made Simple only allows 150 request / 5 minutes +// DNS Made Easy only allows 150 request / 5 minutes // backoff is the amount of time to sleep if a "Rate limit exceeded" error is received // It is increased up to maxBackoff after each use // It is reset after successful request From 486f461d19ae305e720960ab6df0c8b3e780c8a9 Mon Sep 17 00:00:00 2001 From: Tom Limoncelli Date: Tue, 31 Oct 2023 09:26:37 -0400 Subject: [PATCH 006/438] update go.mod --- go.mod | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/go.mod b/go.mod index f6378d0e36..1da27cb144 100644 --- a/go.mod +++ b/go.mod @@ -62,7 +62,7 @@ require ( github.com/G-Core/gcore-dns-sdk-go v0.2.6 github.com/fatih/color v1.15.0 github.com/fbiville/markdown-table-formatter v0.3.0 - github.com/google/go-cmp v0.5.9 + github.com/google/go-cmp v0.6.0 github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510 github.com/kylelemons/godebug v1.1.0 github.com/mattn/go-isatty v0.0.20 From 60dfbad2036081715737b309823b3184e1a15b97 Mon Sep 17 00:00:00 2001 From: Tom Limoncelli Date: Tue, 31 Oct 2023 09:55:13 -0400 Subject: [PATCH 007/438] CHORE: Verify CI/CD process (#2608) From a864d0da47375b02c223a6435e75d73c83a9915e Mon Sep 17 00:00:00 2001 From: Tom Limoncelli Date: Wed, 1 Nov 2023 13:20:22 -0400 Subject: [PATCH 008/438] CHORE: Update dependencies (#2617) --- go.mod | 46 +++++++++++++------------- go.sum | 101 ++++++++++++++++++++++++++++----------------------------- 2 files changed, 73 insertions(+), 74 deletions(-) diff --git a/go.mod b/go.mod index 1da27cb144..42ab484b53 100644 --- a/go.mod +++ b/go.mod @@ -13,16 +13,16 @@ require ( github.com/TomOnTime/utfutil v0.0.0-20230223141146-125e65197b36 github.com/akamai/AkamaiOPEN-edgegrid-golang v1.2.2 github.com/andreyvit/diff v0.0.0-20170406064948-c7f18ee00883 - github.com/aws/aws-sdk-go-v2 v1.21.2 - github.com/aws/aws-sdk-go-v2/config v1.19.0 - github.com/aws/aws-sdk-go-v2/credentials v1.13.43 - github.com/aws/aws-sdk-go-v2/service/route53 v1.30.2 - github.com/aws/aws-sdk-go-v2/service/route53domains v1.17.5 + github.com/aws/aws-sdk-go-v2 v1.22.0 + github.com/aws/aws-sdk-go-v2/config v1.20.0 + github.com/aws/aws-sdk-go-v2/credentials v1.14.0 + github.com/aws/aws-sdk-go-v2/service/route53 v1.32.0 + github.com/aws/aws-sdk-go-v2/service/route53domains v1.18.0 github.com/babolivier/go-doh-client v0.0.0-20201028162107-a76cff4cb8b6 github.com/bhendo/go-powershell v0.0.0-20190719160123-219e7fb4e41e github.com/billputer/go-namecheap v0.0.0-20210108011502-994a912fb7f9 github.com/centralnicgroup-opensource/rtldev-middleware-go-sdk/v3 v3.5.5 - github.com/cloudflare/cloudflare-go v0.79.0 + github.com/cloudflare/cloudflare-go v0.80.0 github.com/digitalocean/godo v1.105.0 github.com/ditashi/jsbeautifier-go v0.0.0-20141206144643-2520a8026a9c github.com/dnsimple/dnsimple-go v1.2.0 @@ -38,7 +38,7 @@ require ( github.com/miekg/dns v1.1.56 github.com/mittwald/go-powerdns v0.6.2 github.com/namedotcom/go v0.0.0-20180403034216-08470befbe04 - github.com/nrdcg/goinwx v0.9.0 + github.com/nrdcg/goinwx v0.10.0 github.com/oracle/oci-go-sdk/v32 v32.0.0 github.com/ovh/go-ovh v1.1.0 github.com/philhug/opensrs-go v0.0.0-20171126225031-9dfa7433020d @@ -48,12 +48,12 @@ require ( github.com/robertkrimen/otto v0.2.1 github.com/softlayer/softlayer-go v1.1.2 github.com/stretchr/testify v1.8.4 - github.com/transip/gotransip/v6 v6.22.0 + github.com/transip/gotransip/v6 v6.22.1 github.com/urfave/cli/v2 v2.25.7 github.com/xddxdd/ottoext v0.0.0-20221109171055-210517fa4419 golang.org/x/net v0.17.0 golang.org/x/oauth2 v0.13.0 - google.golang.org/api v0.148.0 + google.golang.org/api v0.149.0 gopkg.in/ns1/ns1-go.v2 v2.7.13 ) @@ -73,21 +73,21 @@ require ( ) require ( - cloud.google.com/go/compute v1.23.0 // indirect + cloud.google.com/go/compute v1.23.1 // indirect cloud.google.com/go/compute/metadata v0.2.3 // indirect github.com/Azure/azure-sdk-for-go/sdk/internal v1.3.0 // indirect github.com/Azure/go-autorest v14.2.0+incompatible // indirect github.com/AzureAD/microsoft-authentication-library-for-go v1.1.1 // indirect github.com/andybalholm/cascadia v1.3.1 // indirect - github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.13.13 // indirect - github.com/aws/aws-sdk-go-v2/internal/configsources v1.1.43 // indirect - github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.4.37 // indirect - github.com/aws/aws-sdk-go-v2/internal/ini v1.3.45 // indirect - github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.9.37 // indirect - github.com/aws/aws-sdk-go-v2/service/sso v1.15.2 // indirect - github.com/aws/aws-sdk-go-v2/service/ssooidc v1.17.3 // indirect - github.com/aws/aws-sdk-go-v2/service/sts v1.23.2 // indirect - github.com/aws/smithy-go v1.15.0 // indirect + github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.14.0 // indirect + github.com/aws/aws-sdk-go-v2/internal/configsources v1.2.0 // indirect + github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.5.0 // indirect + github.com/aws/aws-sdk-go-v2/internal/ini v1.4.0 // indirect + github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.10.0 // indirect + github.com/aws/aws-sdk-go-v2/service/sso v1.16.0 // indirect + github.com/aws/aws-sdk-go-v2/service/ssooidc v1.18.0 // indirect + github.com/aws/aws-sdk-go-v2/service/sts v1.24.0 // indirect + github.com/aws/smithy-go v1.16.0 // indirect github.com/boombuler/barcode v1.0.1 // indirect github.com/cenkalti/backoff v2.2.1+incompatible // indirect github.com/cenkalti/backoff/v3 v3.0.0 // indirect @@ -104,8 +104,8 @@ require ( github.com/golang/protobuf v1.5.3 // indirect github.com/google/go-querystring v1.1.0 // indirect github.com/google/s2a-go v0.1.7 // indirect - github.com/google/uuid v1.3.1 // indirect - github.com/googleapis/enterprise-certificate-proxy v0.3.1 // indirect + github.com/google/uuid v1.4.0 // indirect + github.com/googleapis/enterprise-certificate-proxy v0.3.2 // indirect github.com/googleapis/gax-go/v2 v2.12.0 // indirect github.com/gopherjs/gopherjs v1.17.2 // indirect github.com/hashicorp/errwrap v1.1.0 // indirect @@ -143,8 +143,8 @@ require ( golang.org/x/time v0.3.0 // indirect golang.org/x/tools v0.14.0 // indirect google.golang.org/appengine v1.6.7 // indirect - google.golang.org/genproto/googleapis/rpc v0.0.0-20231012201019-e917dd12ba7a // indirect - google.golang.org/grpc v1.58.3 // indirect + google.golang.org/genproto/googleapis/rpc v0.0.0-20231016165738-49dd2c1f3d0b // indirect + google.golang.org/grpc v1.59.0 // indirect google.golang.org/protobuf v1.31.0 // indirect gopkg.in/ini.v1 v1.66.6 // indirect gopkg.in/sourcemap.v1 v1.0.5 // indirect diff --git a/go.sum b/go.sum index a90b47734f..0a5407ca43 100644 --- a/go.sum +++ b/go.sum @@ -1,6 +1,6 @@ cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= -cloud.google.com/go/compute v1.23.0 h1:tP41Zoavr8ptEqaW6j+LQOnyBBhO7OkOMAGrgLopTwY= -cloud.google.com/go/compute v1.23.0/go.mod h1:4tCnrn48xsqlwSAiLf1HXMQk8CONslYbdiEZc9FEIbM= +cloud.google.com/go/compute v1.23.1 h1:V97tBoDaZHb6leicZ1G6DLK2BAaZLJ/7+9BB/En3hR0= +cloud.google.com/go/compute v1.23.1/go.mod h1:CqB3xpmPKKt3OJpW2ndFIXnA9A4xAy/F3Xp1ixncW78= cloud.google.com/go/compute/metadata v0.2.3 h1:mg4jlk7mCAj6xXp9UJ4fjI9VUI5rubuGBW5aJ7UnBMY= cloud.google.com/go/compute/metadata v0.2.3/go.mod h1:VAV5nSsACxMJvgaAuX6Pk2AawlZn8kiOGuCv6gTkwuA= github.com/Azure/azure-sdk-for-go/sdk/azcore v1.8.0 h1:9kDVnTz3vbfweTqAUmk/a/pH5pWFCHtvRpHYC0G/dcA= @@ -33,34 +33,34 @@ github.com/andreyvit/diff v0.0.0-20170406064948-c7f18ee00883/go.mod h1:rCTlJbsFo github.com/andybalholm/cascadia v1.3.1 h1:nhxRkql1kdYCc8Snf7D5/D3spOX+dBgjA6u8x004T2c= github.com/andybalholm/cascadia v1.3.1/go.mod h1:R4bJ1UQfqADjvDa4P6HZHLh/3OxWWEqc0Sk8XGwHqvA= github.com/armon/go-radix v0.0.0-20180808171621-7fddfc383310/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8= -github.com/aws/aws-sdk-go-v2 v1.21.2 h1:+LXZ0sgo8quN9UOKXXzAWRT3FWd4NxeXWOZom9pE7GA= -github.com/aws/aws-sdk-go-v2 v1.21.2/go.mod h1:ErQhvNuEMhJjweavOYhxVkn2RUx7kQXVATHrjKtxIpM= -github.com/aws/aws-sdk-go-v2/config v1.19.0 h1:AdzDvwH6dWuVARCl3RTLGRc4Ogy+N7yLFxVxXe1ClQ0= -github.com/aws/aws-sdk-go-v2/config v1.19.0/go.mod h1:ZwDUgFnQgsazQTnWfeLWk5GjeqTQTL8lMkoE1UXzxdE= -github.com/aws/aws-sdk-go-v2/credentials v1.13.43 h1:LU8vo40zBlo3R7bAvBVy/ku4nxGEyZe9N8MqAeFTzF8= -github.com/aws/aws-sdk-go-v2/credentials v1.13.43/go.mod h1:zWJBz1Yf1ZtX5NGax9ZdNjhhI4rgjfgsyk6vTY1yfVg= -github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.13.13 h1:PIktER+hwIG286DqXyvVENjgLTAwGgoeriLDD5C+YlQ= -github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.13.13/go.mod h1:f/Ib/qYjhV2/qdsf79H3QP/eRE4AkVyEf6sk7XfZ1tg= -github.com/aws/aws-sdk-go-v2/internal/configsources v1.1.43 h1:nFBQlGtkbPzp/NjZLuFxRqmT91rLJkgvsEQs68h962Y= -github.com/aws/aws-sdk-go-v2/internal/configsources v1.1.43/go.mod h1:auo+PiyLl0n1l8A0e8RIeR8tOzYPfZZH/JNlrJ8igTQ= -github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.4.37 h1:JRVhO25+r3ar2mKGP7E0LDl8K9/G36gjlqca5iQbaqc= -github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.4.37/go.mod h1:Qe+2KtKml+FEsQF/DHmDV+xjtche/hwoF75EG4UlHW8= -github.com/aws/aws-sdk-go-v2/internal/ini v1.3.45 h1:hze8YsjSh8Wl1rYa1CJpRmXP21BvOBuc76YhW0HsuQ4= -github.com/aws/aws-sdk-go-v2/internal/ini v1.3.45/go.mod h1:lD5M20o09/LCuQ2mE62Mb/iSdSlCNuj6H5ci7tW7OsE= -github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.9.37 h1:WWZA/I2K4ptBS1kg0kV1JbBtG/umed0vwHRrmcr9z7k= -github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.9.37/go.mod h1:vBmDnwWXWxNPFRMmG2m/3MKOe+xEcMDo1tanpaWCcck= -github.com/aws/aws-sdk-go-v2/service/route53 v1.30.2 h1:/RPQNjh1sDIezpXaFIkZb7MlXnSyAqjVdAwcJuGYTqg= -github.com/aws/aws-sdk-go-v2/service/route53 v1.30.2/go.mod h1:TQZBt/WaQy+zTHoW++rnl8JBrmZ0VO6EUbVua1+foCA= -github.com/aws/aws-sdk-go-v2/service/route53domains v1.17.5 h1:18p6+HD6xj5oOtDNi1XvW0PkZw/xticjOvSbIWFyw6I= -github.com/aws/aws-sdk-go-v2/service/route53domains v1.17.5/go.mod h1:BhMj1pZPuQfzuS96s4ScniYr9qhPwDMA19N4eWPM1Lg= -github.com/aws/aws-sdk-go-v2/service/sso v1.15.2 h1:JuPGc7IkOP4AaqcZSIcyqLpFSqBWK32rM9+a1g6u73k= -github.com/aws/aws-sdk-go-v2/service/sso v1.15.2/go.mod h1:gsL4keucRCgW+xA85ALBpRFfdSLH4kHOVSnLMSuBECo= -github.com/aws/aws-sdk-go-v2/service/ssooidc v1.17.3 h1:HFiiRkf1SdaAmV3/BHOFZ9DjFynPHj8G/UIO1lQS+fk= -github.com/aws/aws-sdk-go-v2/service/ssooidc v1.17.3/go.mod h1:a7bHA82fyUXOm+ZSWKU6PIoBxrjSprdLoM8xPYvzYVg= -github.com/aws/aws-sdk-go-v2/service/sts v1.23.2 h1:0BkLfgeDjfZnZ+MhB3ONb01u9pwFYTCZVhlsSSBvlbU= -github.com/aws/aws-sdk-go-v2/service/sts v1.23.2/go.mod h1:Eows6e1uQEsc4ZaHANmsPRzAKcVDrcmjjWiih2+HUUQ= -github.com/aws/smithy-go v1.15.0 h1:PS/durmlzvAFpQHDs4wi4sNNP9ExsqZh6IlfdHXgKK8= -github.com/aws/smithy-go v1.15.0/go.mod h1:Tg+OJXh4MB2R/uN61Ko2f6hTZwB/ZYGOtib8J3gBHzA= +github.com/aws/aws-sdk-go-v2 v1.22.0 h1:CpTS3XO3MWNel8ohoazkLZC6scvkYL2k+m0yzFJ17Hg= +github.com/aws/aws-sdk-go-v2 v1.22.0/go.mod h1:Kd0OJtkW3Q0M0lUWGszapWjEvrXDzRW+D21JNsroB+c= +github.com/aws/aws-sdk-go-v2/config v1.20.0 h1:q2+/mqFhY0J9m3Tb5RGFE3R4sdaUkIe4k2EuDfE3c08= +github.com/aws/aws-sdk-go-v2/config v1.20.0/go.mod h1:7+1riCZXyT+sAGvneR5j+Zl1GyfbBUNQurpQTE6FP6k= +github.com/aws/aws-sdk-go-v2/credentials v1.14.0 h1:LQquqPE7cL55RQmA/UBoBKehDlEtMnQKm3B0Q672ePE= +github.com/aws/aws-sdk-go-v2/credentials v1.14.0/go.mod h1:q/3oaTPlamrQWHPwJe56Mjq9g1TYDgddvgTgWJtHTmE= +github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.14.0 h1:lF/cVllNAPKgjDwN2RsQUX9g/f6hXer9f10ubLFSoug= +github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.14.0/go.mod h1:c28nJNzMVVb9TQpZ5q4tzZvwEJwf/7So7Ie2s90l1Fw= +github.com/aws/aws-sdk-go-v2/internal/configsources v1.2.0 h1:tN6dNNE4SzMuyMnVtQJXGVKX177/d5Zy4MuA1HA4KUc= +github.com/aws/aws-sdk-go-v2/internal/configsources v1.2.0/go.mod h1:F6MXWETIeetAHwFHyoHEqrcB3NpijFv9nLP5h9CXtT0= +github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.5.0 h1:bfdsbTARDjaC/dSYGMO+E0psxFU4hTvCLnqYAfZ3D38= +github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.5.0/go.mod h1:Jg8XVv5M2V2wiAMvBFx+O59jg6Yr8vhP0bgNF/IuquM= +github.com/aws/aws-sdk-go-v2/internal/ini v1.4.0 h1:21tlTXq3ev10yLMAjXZzpkZbrl49h3ElSjmxD57tD/E= +github.com/aws/aws-sdk-go-v2/internal/ini v1.4.0/go.mod h1:d9YrBHJhyzDCv5UsEVRizHlFV6Q0sLemFq6uxuqWfUw= +github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.10.0 h1:dJnwy5Awv+uvfk73aRENVbv1cSQQ60ydCkPaun097KM= +github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.10.0/go.mod h1:RsPWWy7u/hwmFX57sQ7MLvrvJeYyNkiMm5BaavpoU18= +github.com/aws/aws-sdk-go-v2/service/route53 v1.32.0 h1:TC7uLTp9vemCykin+hJnURU3BPitLh3JMOIZsF/4Mus= +github.com/aws/aws-sdk-go-v2/service/route53 v1.32.0/go.mod h1:NIbTGg7AEJXUJz9ghYwsPWystZomU+GjQ7bx4Zx4UyM= +github.com/aws/aws-sdk-go-v2/service/route53domains v1.18.0 h1:1C2plijzIYGfNNaosOsCkizOdN2lkG3z9XSkgHSP8GI= +github.com/aws/aws-sdk-go-v2/service/route53domains v1.18.0/go.mod h1:phiukOXz4eEcmoQlPHxV2iE7lz8daPaNILhJuOtcEQo= +github.com/aws/aws-sdk-go-v2/service/sso v1.16.0 h1:ZIlR6Wr/EgYwBdEz1NWBqdUsTh0mV7A68pId3YZl6H0= +github.com/aws/aws-sdk-go-v2/service/sso v1.16.0/go.mod h1:O7B5cpuhhJKefAKkM7onb0McmpHyKnsH4RrHJhOyq7M= +github.com/aws/aws-sdk-go-v2/service/ssooidc v1.18.0 h1:3BZyJei4k1SHdSAFhg9Qg15NnG3v5zosZyFWPm7df/A= +github.com/aws/aws-sdk-go-v2/service/ssooidc v1.18.0/go.mod h1:Td8EvzggonY02wLaqSpwybI3GbmA0PWoprKGil2uwJg= +github.com/aws/aws-sdk-go-v2/service/sts v1.24.0 h1:f/V5Y9OaHuNRrA9MntNQNAtMFXqhKj8HTEPnH81eXMI= +github.com/aws/aws-sdk-go-v2/service/sts v1.24.0/go.mod h1:HnCUMNz2XqwnEEk5X6oeDYB2HgOLFpJ/LyfilN8WErs= +github.com/aws/smithy-go v1.16.0 h1:gJZEH/Fqh+RsvlJ1Zt4tVAtV6bKkp3cC+R6FCZMNzik= +github.com/aws/smithy-go v1.16.0/go.mod h1:NukqUGpCZIILqqiV0NIjeFh24kd/FAa4beRb6nbIUPE= github.com/babolivier/go-doh-client v0.0.0-20201028162107-a76cff4cb8b6 h1:4NNbNM2Iq/k57qEu7WfL67UrbPq1uFWxW4qODCohi+0= github.com/babolivier/go-doh-client v0.0.0-20201028162107-a76cff4cb8b6/go.mod h1:J29hk+f9lJrblVIfiJOtTFk+OblBawmib4uz/VdKzlg= github.com/bgentry/speakeasy v0.1.0/go.mod h1:+zsyZBPWlz7T6j88CTgSN5bM796AkVf0kBD4zp0CCIs= @@ -81,8 +81,8 @@ github.com/centralnicgroup-opensource/rtldev-middleware-go-sdk/v3 v3.5.5/go.mod github.com/chzyer/logex v1.2.1/go.mod h1:JLbx6lG2kDbNRFnfkgvh4eRJRPX1QCoOIWomwysCBrQ= github.com/chzyer/test v1.0.0/go.mod h1:2JlltgoNkt4TW/z9V/IzDdFaMTM2JPIi26O1pF38GC8= github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= -github.com/cloudflare/cloudflare-go v0.79.0 h1:ErwCYDjFCYppDJlDJ/5WhsSmzegAUe2+K9qgFyQDg3M= -github.com/cloudflare/cloudflare-go v0.79.0/go.mod h1:gkHQf9xEubaQPEuerBuoinR9P8bf8a05Lq0X6WKy1Oc= +github.com/cloudflare/cloudflare-go v0.80.0 h1:BfCFK9gy+2H/R3yjZWzFvWsVXwr2zICCfmAW3brbHpE= +github.com/cloudflare/cloudflare-go v0.80.0/go.mod h1:gkHQf9xEubaQPEuerBuoinR9P8bf8a05Lq0X6WKy1Oc= github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc= github.com/cpuguy83/go-md2man/v2 v2.0.2 h1:p1EgwI/C7NhT0JmVkwCD2ZBK8j4aeHQX2pMHHBfMQ6w= github.com/cpuguy83/go-md2man/v2 v2.0.2/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o= @@ -178,7 +178,6 @@ github.com/google/go-cmp v0.5.2/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/ github.com/google/go-cmp v0.5.3/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.6/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= -github.com/google/go-cmp v0.5.8/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI= github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= github.com/google/go-github/v35 v35.3.0 h1:fU+WBzuukn0VssbayTT+Zo3/ESKX9JYWjbZTLOTEyho= @@ -193,10 +192,10 @@ github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510 h1:El6M4kTTCOh6aBiKaU github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510/go.mod h1:pupxD2MaaD3pAXIBCelhxNneeOaAeabZDe5s4K6zSpQ= github.com/google/uuid v1.1.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= -github.com/google/uuid v1.3.1 h1:KjJaJ9iWZ3jOFZIf1Lqf4laDRCasjl0BCmnEGxkdLb4= -github.com/google/uuid v1.3.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= -github.com/googleapis/enterprise-certificate-proxy v0.3.1 h1:SBWmZhjUDRorQxrN0nwzf+AHBxnbFjViHQS4P0yVpmQ= -github.com/googleapis/enterprise-certificate-proxy v0.3.1/go.mod h1:VLSiSSBs/ksPL8kq3OBOQ6WRI2QnaFynd1DCjZ62+V0= +github.com/google/uuid v1.4.0 h1:MtMxsa51/r9yyhkyLsVeVt0B+BGQZzpQiTQ4eHZ8bc4= +github.com/google/uuid v1.4.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +github.com/googleapis/enterprise-certificate-proxy v0.3.2 h1:Vie5ybvEvT75RniqhfFxPRy3Bf7vr3h0cechB90XaQs= +github.com/googleapis/enterprise-certificate-proxy v0.3.2/go.mod h1:VLSiSSBs/ksPL8kq3OBOQ6WRI2QnaFynd1DCjZ62+V0= github.com/googleapis/gax-go/v2 v2.12.0 h1:A+gCJKdRfqXkr+BIRGtZLibNXf0m1f9E4HG56etFpas= github.com/googleapis/gax-go/v2 v2.12.0/go.mod h1:y+aIqrI5eb1YGMVJfuV3185Ts/D7qKpsEkdD5+I6QGU= github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY= @@ -336,8 +335,8 @@ github.com/namedotcom/go v0.0.0-20180403034216-08470befbe04 h1:o6uBwrhM5C8Ll3MAA github.com/namedotcom/go v0.0.0-20180403034216-08470befbe04/go.mod h1:5sN+Lt1CaY4wsPvgQH/jsuJi4XO2ssZbdsIizr4CVC8= github.com/nbio/st v0.0.0-20140626010706-e9e8d9816f32/go.mod h1:9wM+0iRr9ahx58uYLpLIr5fm8diHn0JbqRycJi6w0Ms= github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno= -github.com/nrdcg/goinwx v0.9.0 h1:oh+yPdRDwc1IWsAU2nfsNorI/fkR+Gxm4O7yS+0NnjM= -github.com/nrdcg/goinwx v0.9.0/go.mod h1:mnMSTi7CXBu2io4DzdOBoGFA1XclD0sEPWJaDhNgkA4= +github.com/nrdcg/goinwx v0.10.0 h1:6W630bjDxQD6OuXKqrFRYVpTt0G/9GXXm3CeOrN0zJM= +github.com/nrdcg/goinwx v0.10.0/go.mod h1:mnMSTi7CXBu2io4DzdOBoGFA1XclD0sEPWJaDhNgkA4= github.com/nu7hatch/gouuid v0.0.0-20131221200532-179d4d0c4d8d/go.mod h1:YUTz3bUH2ZwIWBy3CJBeOBEugqcmXREj14T+iG/4k4U= github.com/oracle/oci-go-sdk/v32 v32.0.0 h1:SSbzrQO3WRcPJEZ8+b3SFPYsPtkFM96clqrp03lrwbU= github.com/oracle/oci-go-sdk/v32 v32.0.0/go.mod h1:aZc4jC59IuNP3cr5y1nj555QvwojMX2nMJaBiozuuEs= @@ -404,8 +403,8 @@ github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk= github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= -github.com/transip/gotransip/v6 v6.22.0 h1:22nRVa0wQwCakRB4zlCVBgexEACBnvLjYuvDRm31q3w= -github.com/transip/gotransip/v6 v6.22.0/go.mod h1:nzv9eN2tdsUrm5nG5ZX6AugYIU4qgsMwIn2c0EZLk8c= +github.com/transip/gotransip/v6 v6.22.1 h1:xM/UV++Em9CBRXsi+WQo7bBCIEylyE72XVB5ktmCvlM= +github.com/transip/gotransip/v6 v6.22.1/go.mod h1:nzv9eN2tdsUrm5nG5ZX6AugYIU4qgsMwIn2c0EZLk8c= github.com/ugorji/go v1.1.7/go.mod h1:kZn38zHttfInRq0xu/PH0az30d+z6vm202qpg1oXVMw= github.com/ugorji/go v1.2.6/go.mod h1:anCg0y61KIhDlPZmnH+so+RQbysYVyDko0IMgJv0Nn0= github.com/ugorji/go/codec v1.1.7/go.mod h1:Ax+UKWsSmolVDwsd+7N3ZtXu+yMGCf907BLYF3GoBXY= @@ -538,8 +537,8 @@ golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8T golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= -google.golang.org/api v0.148.0 h1:HBq4TZlN4/1pNcu0geJZ/Q50vIwIXT532UIMYoo0vOs= -google.golang.org/api v0.148.0/go.mod h1:8/TBgwaKjfqTdacOJrOv2+2Q6fBDU1uHKK06oGSkxzU= +google.golang.org/api v0.149.0 h1:b2CqT6kG+zqJIVKRQ3ELJVLN1PwHZ6DJ3dW8yl82rgY= +google.golang.org/api v0.149.0/go.mod h1:Mwn1B7JTXrzXtnvmzQE2BD6bYZQ8DShKZDZbeN9I7qI= google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= google.golang.org/appengine v1.6.7 h1:FZR1q0exgwxzPzp/aF+VccGrSfxfPpkBqjIIEq3ru6c= @@ -547,19 +546,19 @@ google.golang.org/appengine v1.6.7/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCID google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc= google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo= -google.golang.org/genproto v0.0.0-20231002182017-d307bd883b97 h1:SeZZZx0cP0fqUyA+oRzP9k7cSwJlvDFiROO72uwD6i0= -google.golang.org/genproto v0.0.0-20231002182017-d307bd883b97/go.mod h1:t1VqOqqvce95G3hIDCT5FeO3YUc6Q4Oe24L/+rNMxRk= -google.golang.org/genproto/googleapis/api v0.0.0-20231002182017-d307bd883b97 h1:W18sezcAYs+3tDZX4F80yctqa12jcP1PUS2gQu1zTPU= -google.golang.org/genproto/googleapis/api v0.0.0-20231002182017-d307bd883b97/go.mod h1:iargEX0SFPm3xcfMI0d1domjg0ZF4Aa0p2awqyxhvF0= -google.golang.org/genproto/googleapis/rpc v0.0.0-20231012201019-e917dd12ba7a h1:a2MQQVoTo96JC9PMGtGBymLp7+/RzpFc2yX/9WfFg1c= -google.golang.org/genproto/googleapis/rpc v0.0.0-20231012201019-e917dd12ba7a/go.mod h1:4cYg8o5yUbm77w8ZX00LhMVNl/YVBFJRYWDc0uYWMs0= +google.golang.org/genproto v0.0.0-20231016165738-49dd2c1f3d0b h1:+YaDE2r2OG8t/z5qmsh7Y+XXwCbvadxxZ0YY6mTdrVA= +google.golang.org/genproto v0.0.0-20231016165738-49dd2c1f3d0b/go.mod h1:CgAqfJo+Xmu0GwA0411Ht3OU3OntXwsGmrmjI8ioGXI= +google.golang.org/genproto/googleapis/api v0.0.0-20231016165738-49dd2c1f3d0b h1:CIC2YMXmIhYw6evmhPxBKJ4fmLbOFtXQN/GV3XOZR8k= +google.golang.org/genproto/googleapis/api v0.0.0-20231016165738-49dd2c1f3d0b/go.mod h1:IBQ646DjkDkvUIsVq/cc03FUFQ9wbZu7yE396YcL870= +google.golang.org/genproto/googleapis/rpc v0.0.0-20231016165738-49dd2c1f3d0b h1:ZlWIi1wSK56/8hn4QcBp/j9M7Gt3U/3hZw3mC7vDICo= +google.golang.org/genproto/googleapis/rpc v0.0.0-20231016165738-49dd2c1f3d0b/go.mod h1:swOH3j0KzcDDgGUWr+SNpyTen5YrXjS3eyPzFYKc6lc= google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg= google.golang.org/grpc v1.25.1/go.mod h1:c3i+UQWmh7LiEpx4sFZnkU36qjEYZ0imhYfXVyQciAY= google.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= google.golang.org/grpc v1.33.2/go.mod h1:JMHMWHQWaTccqQQlmk3MJZS+GWXOdAesneDmEnv2fbc= -google.golang.org/grpc v1.58.3 h1:BjnpXut1btbtgN/6sp+brB2Kbm2LjNXnidYujAVbSoQ= -google.golang.org/grpc v1.58.3/go.mod h1:tgX3ZQDlNJGU96V6yHh1T/JeoBQ2TXdr43YbYSsCJk0= +google.golang.org/grpc v1.59.0 h1:Z5Iec2pjwb+LEOqzpB2MR12/eKFhDPhuqW91O+4bwUk= +google.golang.org/grpc v1.59.0/go.mod h1:aUPDwccQo6OTjy7Hct4AfBPD1GptF4fyUjIkQ9YtF98= google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8= google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0= google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM= From 65c47cbfe848f24f75557d679ec6b8e4873fd70d Mon Sep 17 00:00:00 2001 From: Tom Limoncelli Date: Wed, 1 Nov 2023 13:20:42 -0400 Subject: [PATCH 009/438] GCLOUD: Remove extra newline (#2611) --- providers/gcloud/gcloudProvider.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/providers/gcloud/gcloudProvider.go b/providers/gcloud/gcloudProvider.go index 8fd387ee20..d0c9e47dfa 100644 --- a/providers/gcloud/gcloudProvider.go +++ b/providers/gcloud/gcloudProvider.go @@ -352,14 +352,14 @@ func (g *gcloudProvider) GetZoneRecordsCorrections(dc *models.DomainConfig, exis chgSet := []correctionValues{} for len(chg.Change.Deletions) > 0 { b := setBatchLen(len(chg.Change.Deletions)) - chgSet = append(chgSet, correctionValues{Change: &gdns.Change{Deletions: chg.Change.Deletions[:b:b], Kind: "dns#change"}, Msgs: "\n" + strings.Join(chg.Msgs.Deletions[:b:b], "")}) + chgSet = append(chgSet, correctionValues{Change: &gdns.Change{Deletions: chg.Change.Deletions[:b:b], Kind: "dns#change"}, Msgs: strings.Join(chg.Msgs.Deletions[:b:b], "")}) chg.Change.Deletions = chg.Change.Deletions[b:] chg.Msgs.Deletions = chg.Msgs.Deletions[b:] } for i := 0; len(chg.Change.Additions) > 0; i++ { b := setBatchLen(len(chg.Change.Additions)) if len(chgSet) == i { - chgSet = append(chgSet, correctionValues{Change: &gdns.Change{Additions: chg.Change.Additions[:b:b], Kind: "dns#change"}, Msgs: "\n" + strings.Join(chg.Msgs.Additions[:b:b], "")}) + chgSet = append(chgSet, correctionValues{Change: &gdns.Change{Additions: chg.Change.Additions[:b:b], Kind: "dns#change"}, Msgs: strings.Join(chg.Msgs.Additions[:b:b], "")}) } else { chgSet[i].Change.Additions = chg.Change.Additions[:b:b] chgSet[i].Msgs += strings.Join(chg.Msgs.Additions[:b:b], "") From bf4118a0414ba8856d654335842ba57b1a432b38 Mon Sep 17 00:00:00 2001 From: Joachim Schwarm Date: Wed, 1 Nov 2023 18:34:34 +0100 Subject: [PATCH 010/438] INWX: Paginate through Nameserver Records (#2609) Co-authored-by: Tom Limoncelli --- documentation/providers/inwx.md | 6 ------ providers/inwx/inwxProvider.go | 26 ++++++++++++++++---------- 2 files changed, 16 insertions(+), 16 deletions(-) diff --git a/documentation/providers/inwx.md b/documentation/providers/inwx.md index 036a77edea..ceb29671a7 100644 --- a/documentation/providers/inwx.md +++ b/documentation/providers/inwx.md @@ -109,9 +109,3 @@ D("example.com", REG_INWX, DnsProvider(DSP_CF), ); ``` {% endcode %} - -{% hint style="info" %} -**NOTE**: The INWX provider implementation currently only supports up to 2,147,483,647 domains. If you exceed -this limit, it is expected that DNSControl will fail to recognize some domains. Should you exceed this -limit, please [open an issue on GitHub](https://github.com/StackExchange/dnscontrol/issues/new/choose). -{% endhint %} diff --git a/providers/inwx/inwxProvider.go b/providers/inwx/inwxProvider.go index a00a60b03f..0c4cfdaf83 100644 --- a/providers/inwx/inwxProvider.go +++ b/providers/inwx/inwxProvider.go @@ -395,18 +395,24 @@ func (api *inwxAPI) GetRegistrarCorrections(dc *models.DomainConfig) ([]*models. // fetchNameserverDomains returns the domains configured in INWX nameservers func (api *inwxAPI) fetchNameserverDomains() error { + zones := map[string]int{} request := &goinwx.NameserverListRequest{} - request.PageLimit = 2147483647 // int32 max value, highest number API accepts - info, err := api.client.Nameservers.ListWithParams(request) - if err != nil { - return err - } - - api.domainIndex = map[string]int{} - for _, domain := range info.Domains { - api.domainIndex[domain.Domain] = domain.RoID + page := 1 + for { + request.Page = page + info, err := api.client.Nameservers.ListWithParams(request) + if err != nil { + return err + } + for _, domain := range info.Domains { + zones[domain.Domain] = domain.RoID + } + if len(zones) >= info.Count { + break + } + page++ } - + api.domainIndex = zones return nil } From f2420e5fd408a3802dae49fb24cccda0bc20eef7 Mon Sep 17 00:00:00 2001 From: Amelia Aronsohn Date: Thu, 2 Nov 2023 07:22:27 -0700 Subject: [PATCH 011/438] [DNSimple] Update DNSimple's Default name servers (#2618) Signed-off-by: Amelia Aronsohn Co-authored-by: Tom Limoncelli --- providers/dnsimple/dnsimpleProvider.go | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/providers/dnsimple/dnsimpleProvider.go b/providers/dnsimple/dnsimpleProvider.go index e1fc4277eb..b3d2b195fa 100644 --- a/providers/dnsimple/dnsimpleProvider.go +++ b/providers/dnsimple/dnsimpleProvider.go @@ -48,7 +48,7 @@ const stateRegistered = "registered" var defaultNameServerNames = []string{ "ns1.dnsimple.com", - "ns2.dnsimple.com", + "ns2.dnsimple-edge.net", "ns3.dnsimple.com", "ns4.dnsimple-edge.org", } @@ -533,7 +533,6 @@ func (c *dnsimpleProvider) deleteRecordFunc(recordID int64, domainName string) f } return nil - } } From 7a1effb1d2eae1764004eb62b9e4baccb9ac0fb2 Mon Sep 17 00:00:00 2001 From: Tom Limoncelli Date: Sun, 12 Nov 2023 16:36:46 -0500 Subject: [PATCH 012/438] CHORE: lint (#2619) --- commands/completion_test.go | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/commands/completion_test.go b/commands/completion_test.go index d786ed4c97..9cbe77467f 100644 --- a/commands/completion_test.go +++ b/commands/completion_test.go @@ -3,11 +3,12 @@ package commands import ( "bytes" "fmt" - "github.com/google/go-cmp/cmp" "strings" "testing" "text/template" + "github.com/google/go-cmp/cmp" + "github.com/urfave/cli/v2" "golang.org/x/exp/slices" ) @@ -178,7 +179,7 @@ func TestShellCompletionCommand(t *testing.T) { for _, tt := range shellsAndCompletionScripts { testCases[0].expected = append(testCases[0].expected, tt.shellName) - for i, _ := range tt.shellName { + for i := range tt.shellName { testCases = append(testCases, testCase{ shellArg: tt.shellName[:i+1], expected: []string{tt.shellName}, From b5ce16590329cdb0aa2d9a83134da87cc079f925 Mon Sep 17 00:00:00 2001 From: Tom Limoncelli Date: Sun, 12 Nov 2023 17:01:50 -0500 Subject: [PATCH 013/438] CHORE: update deps (#2620) --- commands/types/dnscontrol.d.ts | 2 +- documentation/providers/azure_dns.md | 2 + go.mod | 67 +++++++------ go.sum | 139 ++++++++++++++------------- 4 files changed, 106 insertions(+), 104 deletions(-) diff --git a/commands/types/dnscontrol.d.ts b/commands/types/dnscontrol.d.ts index 376d8c2bd3..0fac62a7f9 100644 --- a/commands/types/dnscontrol.d.ts +++ b/commands/types/dnscontrol.d.ts @@ -822,7 +822,7 @@ declare function DOMAIN_ELSEWHERE(name: string, registrar: string, nameserver_na * * @see https://docs.dnscontrol.org/language-reference/top-level-functions/domain_elsewhere_auto */ -declare function DOMAIN_ELSEWHERE_AUTO(name: string, registrar: string, dnsProvider: string): void; +declare function DOMAIN_ELSEWHERE_AUTO(name: string, domain: string, registrar: string, dnsProvider: string): void; /** * DS adds a DS record to the domain. diff --git a/documentation/providers/azure_dns.md b/documentation/providers/azure_dns.md index 241bc4f6d6..a9eac9cfb3 100644 --- a/documentation/providers/azure_dns.md +++ b/documentation/providers/azure_dns.md @@ -68,4 +68,6 @@ DNSControl depends on a standard [Client credentials Authentication](https://doc ## New domains If a domain does not exist in your Azure account, DNSControl will *not* automatically add it with the `push` command. You can do that either manually via the control panel, or via the command `dnscontrol create-domains` command. +## Caveats +The ResourceGroup is case sensitive. diff --git a/go.mod b/go.mod index 42ab484b53..bfa26ffb6c 100644 --- a/go.mod +++ b/go.mod @@ -13,17 +13,17 @@ require ( github.com/TomOnTime/utfutil v0.0.0-20230223141146-125e65197b36 github.com/akamai/AkamaiOPEN-edgegrid-golang v1.2.2 github.com/andreyvit/diff v0.0.0-20170406064948-c7f18ee00883 - github.com/aws/aws-sdk-go-v2 v1.22.0 - github.com/aws/aws-sdk-go-v2/config v1.20.0 - github.com/aws/aws-sdk-go-v2/credentials v1.14.0 - github.com/aws/aws-sdk-go-v2/service/route53 v1.32.0 - github.com/aws/aws-sdk-go-v2/service/route53domains v1.18.0 + github.com/aws/aws-sdk-go-v2 v1.22.2 + github.com/aws/aws-sdk-go-v2/config v1.23.0 + github.com/aws/aws-sdk-go-v2/credentials v1.15.2 + github.com/aws/aws-sdk-go-v2/service/route53 v1.34.1 + github.com/aws/aws-sdk-go-v2/service/route53domains v1.19.1 github.com/babolivier/go-doh-client v0.0.0-20201028162107-a76cff4cb8b6 github.com/bhendo/go-powershell v0.0.0-20190719160123-219e7fb4e41e github.com/billputer/go-namecheap v0.0.0-20210108011502-994a912fb7f9 github.com/centralnicgroup-opensource/rtldev-middleware-go-sdk/v3 v3.5.5 - github.com/cloudflare/cloudflare-go v0.80.0 - github.com/digitalocean/godo v1.105.0 + github.com/cloudflare/cloudflare-go v0.81.0 + github.com/digitalocean/godo v1.105.1 github.com/ditashi/jsbeautifier-go v0.0.0-20141206144643-2520a8026a9c github.com/dnsimple/dnsimple-go v1.2.0 github.com/exoscale/egoscale v0.90.2 @@ -33,14 +33,13 @@ require ( github.com/google/go-github/v35 v35.3.0 github.com/gopherjs/jquery v0.0.0-20191017083323-73f4c7416038 github.com/hashicorp/vault/api v1.10.0 - github.com/jarcoal/httpmock v1.0.8 // indirect github.com/jinzhu/copier v0.4.0 github.com/miekg/dns v1.1.56 github.com/mittwald/go-powerdns v0.6.2 github.com/namedotcom/go v0.0.0-20180403034216-08470befbe04 github.com/nrdcg/goinwx v0.10.0 github.com/oracle/oci-go-sdk/v32 v32.0.0 - github.com/ovh/go-ovh v1.1.0 + github.com/ovh/go-ovh v1.4.3 github.com/philhug/opensrs-go v0.0.0-20171126225031-9dfa7433020d github.com/pkg/errors v0.9.1 github.com/pquerna/otp v1.4.0 @@ -48,45 +47,45 @@ require ( github.com/robertkrimen/otto v0.2.1 github.com/softlayer/softlayer-go v1.1.2 github.com/stretchr/testify v1.8.4 - github.com/transip/gotransip/v6 v6.22.1 + github.com/transip/gotransip/v6 v6.23.0 github.com/urfave/cli/v2 v2.25.7 github.com/xddxdd/ottoext v0.0.0-20221109171055-210517fa4419 - golang.org/x/net v0.17.0 - golang.org/x/oauth2 v0.13.0 - google.golang.org/api v0.149.0 + golang.org/x/net v0.18.0 + golang.org/x/oauth2 v0.14.0 + google.golang.org/api v0.150.0 gopkg.in/ns1/ns1-go.v2 v2.7.13 ) require ( - github.com/Azure/azure-sdk-for-go/sdk/azcore v1.8.0 + github.com/Azure/azure-sdk-for-go/sdk/azcore v1.9.0 github.com/G-Core/gcore-dns-sdk-go v0.2.6 - github.com/fatih/color v1.15.0 + github.com/fatih/color v1.16.0 github.com/fbiville/markdown-table-formatter v0.3.0 github.com/google/go-cmp v0.6.0 github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510 github.com/kylelemons/godebug v1.1.0 github.com/mattn/go-isatty v0.0.20 github.com/vultr/govultr/v2 v2.17.2 - golang.org/x/exp v0.0.0-20231006140011-7918f672742d - golang.org/x/text v0.13.0 + golang.org/x/exp v0.0.0-20231110203233-9a3e6036ecaa + golang.org/x/text v0.14.0 gopkg.in/yaml.v3 v3.0.1 ) require ( cloud.google.com/go/compute v1.23.1 // indirect cloud.google.com/go/compute/metadata v0.2.3 // indirect - github.com/Azure/azure-sdk-for-go/sdk/internal v1.3.0 // indirect + github.com/Azure/azure-sdk-for-go/sdk/internal v1.5.0 // indirect github.com/Azure/go-autorest v14.2.0+incompatible // indirect github.com/AzureAD/microsoft-authentication-library-for-go v1.1.1 // indirect github.com/andybalholm/cascadia v1.3.1 // indirect - github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.14.0 // indirect - github.com/aws/aws-sdk-go-v2/internal/configsources v1.2.0 // indirect - github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.5.0 // indirect - github.com/aws/aws-sdk-go-v2/internal/ini v1.4.0 // indirect - github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.10.0 // indirect - github.com/aws/aws-sdk-go-v2/service/sso v1.16.0 // indirect - github.com/aws/aws-sdk-go-v2/service/ssooidc v1.18.0 // indirect - github.com/aws/aws-sdk-go-v2/service/sts v1.24.0 // indirect + github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.14.3 // indirect + github.com/aws/aws-sdk-go-v2/internal/configsources v1.2.2 // indirect + github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.5.2 // indirect + github.com/aws/aws-sdk-go-v2/internal/ini v1.6.0 // indirect + github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.10.2 // indirect + github.com/aws/aws-sdk-go-v2/service/sso v1.17.1 // indirect + github.com/aws/aws-sdk-go-v2/service/ssooidc v1.19.1 // indirect + github.com/aws/aws-sdk-go-v2/service/sts v1.25.1 // indirect github.com/aws/smithy-go v1.16.0 // indirect github.com/boombuler/barcode v1.0.1 // indirect github.com/cenkalti/backoff v2.2.1+incompatible // indirect @@ -136,17 +135,17 @@ require ( github.com/stretchr/objx v0.5.0 // indirect github.com/xrash/smetrics v0.0.0-20201216005158-039620a65673 // indirect go.opencensus.io v0.24.0 // indirect - golang.org/x/crypto v0.14.0 // indirect - golang.org/x/mod v0.13.0 // indirect - golang.org/x/sync v0.4.0 // indirect - golang.org/x/sys v0.13.0 // indirect - golang.org/x/time v0.3.0 // indirect - golang.org/x/tools v0.14.0 // indirect + golang.org/x/crypto v0.15.0 // indirect + golang.org/x/mod v0.14.0 // indirect + golang.org/x/sync v0.5.0 // indirect + golang.org/x/sys v0.14.0 // indirect + golang.org/x/time v0.4.0 // indirect + golang.org/x/tools v0.15.0 // indirect google.golang.org/appengine v1.6.7 // indirect - google.golang.org/genproto/googleapis/rpc v0.0.0-20231016165738-49dd2c1f3d0b // indirect + google.golang.org/genproto/googleapis/rpc v0.0.0-20231030173426-d783a09b4405 // indirect google.golang.org/grpc v1.59.0 // indirect google.golang.org/protobuf v1.31.0 // indirect - gopkg.in/ini.v1 v1.66.6 // indirect + gopkg.in/ini.v1 v1.67.0 // indirect gopkg.in/sourcemap.v1 v1.0.5 // indirect gopkg.in/square/go-jose.v2 v2.5.1 // indirect moul.io/http2curl v1.0.0 // indirect diff --git a/go.sum b/go.sum index 0a5407ca43..8da2cf52f3 100644 --- a/go.sum +++ b/go.sum @@ -3,12 +3,12 @@ cloud.google.com/go/compute v1.23.1 h1:V97tBoDaZHb6leicZ1G6DLK2BAaZLJ/7+9BB/En3h cloud.google.com/go/compute v1.23.1/go.mod h1:CqB3xpmPKKt3OJpW2ndFIXnA9A4xAy/F3Xp1ixncW78= cloud.google.com/go/compute/metadata v0.2.3 h1:mg4jlk7mCAj6xXp9UJ4fjI9VUI5rubuGBW5aJ7UnBMY= cloud.google.com/go/compute/metadata v0.2.3/go.mod h1:VAV5nSsACxMJvgaAuX6Pk2AawlZn8kiOGuCv6gTkwuA= -github.com/Azure/azure-sdk-for-go/sdk/azcore v1.8.0 h1:9kDVnTz3vbfweTqAUmk/a/pH5pWFCHtvRpHYC0G/dcA= -github.com/Azure/azure-sdk-for-go/sdk/azcore v1.8.0/go.mod h1:3Ug6Qzto9anB6mGlEdgYMDF5zHQ+wwhEaYR4s17PHMw= +github.com/Azure/azure-sdk-for-go/sdk/azcore v1.9.0 h1:fb8kj/Dh4CSwgsOzHeZY4Xh68cFVbzXx+ONXGMY//4w= +github.com/Azure/azure-sdk-for-go/sdk/azcore v1.9.0/go.mod h1:uReU2sSxZExRPBAg3qKzmAucSi51+SP1OhohieR821Q= github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.4.0 h1:BMAjVKJM0U/CYF27gA0ZMmXGkOcvfFtD0oHVZ1TIPRI= github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.4.0/go.mod h1:1fXstnBMas5kzG+S3q8UoJcmyU6nUeunJcMDHcRYHhs= -github.com/Azure/azure-sdk-for-go/sdk/internal v1.3.0 h1:sXr+ck84g/ZlZUOZiNELInmMgOsuGwdjjVkEIde0OtY= -github.com/Azure/azure-sdk-for-go/sdk/internal v1.3.0/go.mod h1:okt5dMMTOFjX/aovMlrjvvXoPMBVSPzk9185BT0+eZM= +github.com/Azure/azure-sdk-for-go/sdk/internal v1.5.0 h1:d81/ng9rET2YqdVkVwkb6EXeRrLJIwyGnJcAlAWKwhs= +github.com/Azure/azure-sdk-for-go/sdk/internal v1.5.0/go.mod h1:s4kgfzA0covAXNicZHDMN58jExvcng2mC/DepXiF1EI= github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/dns/armdns v1.1.0 h1:8iR6OLffWWorFdzL2JFCab5xpD8VKEE2DUBBl+HNTDY= github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/dns/armdns v1.1.0/go.mod h1:copqlcjMWc/wgQ1N2fzsJFQxDdqKGg1EQt8T5wJMOGE= github.com/Azure/go-autorest v14.2.0+incompatible h1:V5VMDjClD3GiElqLWO7mz2MxNAK/vTfRHdAubSIPRgs= @@ -33,32 +33,32 @@ github.com/andreyvit/diff v0.0.0-20170406064948-c7f18ee00883/go.mod h1:rCTlJbsFo github.com/andybalholm/cascadia v1.3.1 h1:nhxRkql1kdYCc8Snf7D5/D3spOX+dBgjA6u8x004T2c= github.com/andybalholm/cascadia v1.3.1/go.mod h1:R4bJ1UQfqADjvDa4P6HZHLh/3OxWWEqc0Sk8XGwHqvA= github.com/armon/go-radix v0.0.0-20180808171621-7fddfc383310/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8= -github.com/aws/aws-sdk-go-v2 v1.22.0 h1:CpTS3XO3MWNel8ohoazkLZC6scvkYL2k+m0yzFJ17Hg= -github.com/aws/aws-sdk-go-v2 v1.22.0/go.mod h1:Kd0OJtkW3Q0M0lUWGszapWjEvrXDzRW+D21JNsroB+c= -github.com/aws/aws-sdk-go-v2/config v1.20.0 h1:q2+/mqFhY0J9m3Tb5RGFE3R4sdaUkIe4k2EuDfE3c08= -github.com/aws/aws-sdk-go-v2/config v1.20.0/go.mod h1:7+1riCZXyT+sAGvneR5j+Zl1GyfbBUNQurpQTE6FP6k= -github.com/aws/aws-sdk-go-v2/credentials v1.14.0 h1:LQquqPE7cL55RQmA/UBoBKehDlEtMnQKm3B0Q672ePE= -github.com/aws/aws-sdk-go-v2/credentials v1.14.0/go.mod h1:q/3oaTPlamrQWHPwJe56Mjq9g1TYDgddvgTgWJtHTmE= -github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.14.0 h1:lF/cVllNAPKgjDwN2RsQUX9g/f6hXer9f10ubLFSoug= -github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.14.0/go.mod h1:c28nJNzMVVb9TQpZ5q4tzZvwEJwf/7So7Ie2s90l1Fw= -github.com/aws/aws-sdk-go-v2/internal/configsources v1.2.0 h1:tN6dNNE4SzMuyMnVtQJXGVKX177/d5Zy4MuA1HA4KUc= -github.com/aws/aws-sdk-go-v2/internal/configsources v1.2.0/go.mod h1:F6MXWETIeetAHwFHyoHEqrcB3NpijFv9nLP5h9CXtT0= -github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.5.0 h1:bfdsbTARDjaC/dSYGMO+E0psxFU4hTvCLnqYAfZ3D38= -github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.5.0/go.mod h1:Jg8XVv5M2V2wiAMvBFx+O59jg6Yr8vhP0bgNF/IuquM= -github.com/aws/aws-sdk-go-v2/internal/ini v1.4.0 h1:21tlTXq3ev10yLMAjXZzpkZbrl49h3ElSjmxD57tD/E= -github.com/aws/aws-sdk-go-v2/internal/ini v1.4.0/go.mod h1:d9YrBHJhyzDCv5UsEVRizHlFV6Q0sLemFq6uxuqWfUw= -github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.10.0 h1:dJnwy5Awv+uvfk73aRENVbv1cSQQ60ydCkPaun097KM= -github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.10.0/go.mod h1:RsPWWy7u/hwmFX57sQ7MLvrvJeYyNkiMm5BaavpoU18= -github.com/aws/aws-sdk-go-v2/service/route53 v1.32.0 h1:TC7uLTp9vemCykin+hJnURU3BPitLh3JMOIZsF/4Mus= -github.com/aws/aws-sdk-go-v2/service/route53 v1.32.0/go.mod h1:NIbTGg7AEJXUJz9ghYwsPWystZomU+GjQ7bx4Zx4UyM= -github.com/aws/aws-sdk-go-v2/service/route53domains v1.18.0 h1:1C2plijzIYGfNNaosOsCkizOdN2lkG3z9XSkgHSP8GI= -github.com/aws/aws-sdk-go-v2/service/route53domains v1.18.0/go.mod h1:phiukOXz4eEcmoQlPHxV2iE7lz8daPaNILhJuOtcEQo= -github.com/aws/aws-sdk-go-v2/service/sso v1.16.0 h1:ZIlR6Wr/EgYwBdEz1NWBqdUsTh0mV7A68pId3YZl6H0= -github.com/aws/aws-sdk-go-v2/service/sso v1.16.0/go.mod h1:O7B5cpuhhJKefAKkM7onb0McmpHyKnsH4RrHJhOyq7M= -github.com/aws/aws-sdk-go-v2/service/ssooidc v1.18.0 h1:3BZyJei4k1SHdSAFhg9Qg15NnG3v5zosZyFWPm7df/A= -github.com/aws/aws-sdk-go-v2/service/ssooidc v1.18.0/go.mod h1:Td8EvzggonY02wLaqSpwybI3GbmA0PWoprKGil2uwJg= -github.com/aws/aws-sdk-go-v2/service/sts v1.24.0 h1:f/V5Y9OaHuNRrA9MntNQNAtMFXqhKj8HTEPnH81eXMI= -github.com/aws/aws-sdk-go-v2/service/sts v1.24.0/go.mod h1:HnCUMNz2XqwnEEk5X6oeDYB2HgOLFpJ/LyfilN8WErs= +github.com/aws/aws-sdk-go-v2 v1.22.2 h1:lV0U8fnhAnPz8YcdmZVV60+tr6CakHzqA6P8T46ExJI= +github.com/aws/aws-sdk-go-v2 v1.22.2/go.mod h1:Kd0OJtkW3Q0M0lUWGszapWjEvrXDzRW+D21JNsroB+c= +github.com/aws/aws-sdk-go-v2/config v1.23.0 h1:kqzEfGGDIrRJpfJckgwuZfFTbU9NB1jZnRcaO9MpOqE= +github.com/aws/aws-sdk-go-v2/config v1.23.0/go.mod h1:p7wbxKXXjS1GGQOss7VXOazVMFF9bjUGq85/4wR/fSw= +github.com/aws/aws-sdk-go-v2/credentials v1.15.2 h1:rKH7khRMxPdD0u3dHecd0Q7NOVw3EUe7AqdkUOkiOGI= +github.com/aws/aws-sdk-go-v2/credentials v1.15.2/go.mod h1:tXM8wmaeAhfC7nZoCxb0FzM/aRaB1m1WQ7x0qlBLq80= +github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.14.3 h1:G5KawTAkyHH6WyKQCdHiW4h3PmAXNJpOgwKg3H7sDRE= +github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.14.3/go.mod h1:hugKmSFnZB+HgNI1sYGT14BUPZkO6alC/e0AWu+0IAQ= +github.com/aws/aws-sdk-go-v2/internal/configsources v1.2.2 h1:AaQsr5vvGR7rmeSWBtTCcw16tT9r51mWijuCQhzLnq8= +github.com/aws/aws-sdk-go-v2/internal/configsources v1.2.2/go.mod h1:o1IiRn7CWocIFTXJjGKJDOwxv1ibL53NpcvcqGWyRBA= +github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.5.2 h1:UZx8SXZ0YtzRiALzYAWcjb9Y9hZUR7MBKaBQ5ouOjPs= +github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.5.2/go.mod h1:ipuRpcSaklmxR6C39G187TpBAO132gUfleTGccUPs8c= +github.com/aws/aws-sdk-go-v2/internal/ini v1.6.0 h1:hwZB07/beLiCopuRKF0t+dEHmP39iN4YtDh3X5d3hrg= +github.com/aws/aws-sdk-go-v2/internal/ini v1.6.0/go.mod h1:rdAuXeHWhI/zkpYcO5n8WCpaIgY9MUxFyBsuqq3kjyA= +github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.10.2 h1:h7j73yuAVVjic8pqswh+L/7r2IHP43QwRyOu6zcCDDE= +github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.10.2/go.mod h1:H07AHdK5LSy8F7EJUQhoxyiCNkePoHj2D8P2yGTWafo= +github.com/aws/aws-sdk-go-v2/service/route53 v1.34.1 h1:HzAQvhCCrfAtl1uc2w27CJicm0HxdLs6HI2ZTMAZObQ= +github.com/aws/aws-sdk-go-v2/service/route53 v1.34.1/go.mod h1:kEKnDzZL0k1f2sE1utJ/ljZDF17aChgH9j+jUv+jr38= +github.com/aws/aws-sdk-go-v2/service/route53domains v1.19.1 h1:jZSQwl1JAX9GRew86efQecc+pDiAu/WwnefnrUhpNxk= +github.com/aws/aws-sdk-go-v2/service/route53domains v1.19.1/go.mod h1:5uJ+xB76ttmfE0FD6f07TiF3BmwKevmfK7ixkV7mjVA= +github.com/aws/aws-sdk-go-v2/service/sso v1.17.1 h1:km+ZNjtLtpXYf42RdaDZnNHm9s7SYAuDGTafy6nd89A= +github.com/aws/aws-sdk-go-v2/service/sso v1.17.1/go.mod h1:aHBr3pvBSD5MbzOvQtYutyPLLRPbl/y9x86XyJJnUXQ= +github.com/aws/aws-sdk-go-v2/service/ssooidc v1.19.1 h1:iRFNqZH4a67IqPvK8xxtyQYnyrlsvwmpHOe9r55ggBA= +github.com/aws/aws-sdk-go-v2/service/ssooidc v1.19.1/go.mod h1:pTy5WM+6sNv2tB24JNKFtn6EvciQ5k40ZJ0pq/Iaxj0= +github.com/aws/aws-sdk-go-v2/service/sts v1.25.1 h1:txgVXIXWPXyqdiVn92BV6a/rgtpX31HYdsOYj0sVQQQ= +github.com/aws/aws-sdk-go-v2/service/sts v1.25.1/go.mod h1:VAiJiNaoP1L89STFlEMgmHX1bKixY+FaP+TpRFrmyZ4= github.com/aws/smithy-go v1.16.0 h1:gJZEH/Fqh+RsvlJ1Zt4tVAtV6bKkp3cC+R6FCZMNzik= github.com/aws/smithy-go v1.16.0/go.mod h1:NukqUGpCZIILqqiV0NIjeFh24kd/FAa4beRb6nbIUPE= github.com/babolivier/go-doh-client v0.0.0-20201028162107-a76cff4cb8b6 h1:4NNbNM2Iq/k57qEu7WfL67UrbPq1uFWxW4qODCohi+0= @@ -81,8 +81,8 @@ github.com/centralnicgroup-opensource/rtldev-middleware-go-sdk/v3 v3.5.5/go.mod github.com/chzyer/logex v1.2.1/go.mod h1:JLbx6lG2kDbNRFnfkgvh4eRJRPX1QCoOIWomwysCBrQ= github.com/chzyer/test v1.0.0/go.mod h1:2JlltgoNkt4TW/z9V/IzDdFaMTM2JPIi26O1pF38GC8= github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= -github.com/cloudflare/cloudflare-go v0.80.0 h1:BfCFK9gy+2H/R3yjZWzFvWsVXwr2zICCfmAW3brbHpE= -github.com/cloudflare/cloudflare-go v0.80.0/go.mod h1:gkHQf9xEubaQPEuerBuoinR9P8bf8a05Lq0X6WKy1Oc= +github.com/cloudflare/cloudflare-go v0.81.0 h1:NSLpR2cBn5K1cFXkYsZ7skVNFN+AAJBKdUWAj8v1PGA= +github.com/cloudflare/cloudflare-go v0.81.0/go.mod h1:TIT8ltdOkZthsC+6owWe0ODSgl84sq3f8iAsja8E1KQ= github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc= github.com/cpuguy83/go-md2man/v2 v2.0.2 h1:p1EgwI/C7NhT0JmVkwCD2ZBK8j4aeHQX2pMHHBfMQ6w= github.com/cpuguy83/go-md2man/v2 v2.0.2/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o= @@ -95,8 +95,8 @@ github.com/decred/dcrd/crypto/blake256 v1.0.0/go.mod h1:sQl2p6Y26YV+ZOcSTP6thNdn github.com/decred/dcrd/dcrec/secp256k1/v4 v4.0.0-20210816181553-5444fa50b93d/go.mod h1:tmAIfUFEirG/Y8jhZ9M+h36obRZAk/1fcSpXwAVlfqE= github.com/deepmap/oapi-codegen v1.9.1 h1:yHmEnA7jSTUMQgV+uN02WpZtwHnz2CBW3mZRIxr1vtI= github.com/deepmap/oapi-codegen v1.9.1/go.mod h1:PLqNAhdedP8ttRpBBkzLKU3bp+Fpy+tTgeAMlztR2cw= -github.com/digitalocean/godo v1.105.0 h1:bUfWVsyQCYZ7OQLK+p2EBFYWD5BoOgpyq/PMSQHEeMg= -github.com/digitalocean/godo v1.105.0/go.mod h1:R6EmmWI8CT1+fCtjWY9UCB+L5uufuZH13wk3YhxycCs= +github.com/digitalocean/godo v1.105.1 h1:3FjFDurw7po27Y0uHhdR+EvwNil06KCeu1Nx/0jZbmI= +github.com/digitalocean/godo v1.105.1/go.mod h1:R6EmmWI8CT1+fCtjWY9UCB+L5uufuZH13wk3YhxycCs= github.com/ditashi/jsbeautifier-go v0.0.0-20141206144643-2520a8026a9c h1:+Zo5Ca9GH0RoeVZQKzFJcTLoAixx5s5Gq3pTIS+n354= github.com/ditashi/jsbeautifier-go v0.0.0-20141206144643-2520a8026a9c/go.mod h1:HJGU9ULdREjOcVGZVPB5s6zYmHi1RxzT71l2wQyLmnE= github.com/dnaeon/go-vcr v1.2.0 h1:zHCHvJYTMh1N7xnV7zf1m1GPBF9Ad0Jk/whtQ1663qI= @@ -110,8 +110,8 @@ github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7 github.com/exoscale/egoscale v0.90.2 h1:oGSJy5Dxbcn5m5F0/DcnU4WXJg+2j3g+UgEu4yyKG9M= github.com/exoscale/egoscale v0.90.2/go.mod h1:NDhQbdGNKwnLVC2YGTB6ds9WIPw+V5ckvEEV8ho7pFE= github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4= -github.com/fatih/color v1.15.0 h1:kOqh6YHBtK8aywxGerMG2Eq3H6Qgoqeo13Bk2Mv/nBs= -github.com/fatih/color v1.15.0/go.mod h1:0h5ZqXfHYED7Bhv2ZJamyIOUej9KtShiJESRwBDUSsw= +github.com/fatih/color v1.16.0 h1:zmkK9Ngbjj+K0yRhTVONQh1p/HknKYSlNT+vZCzyokM= +github.com/fatih/color v1.16.0/go.mod h1:fL2Sau1YI5c0pdGEVCbKQbLXB6edEj1ZgiY4NijnWvE= github.com/fatih/structs v1.1.0 h1:Q7juDM0QtcnhCpeyLGQKyg4TOIghuNXrkL32pHAUMxo= github.com/fatih/structs v1.1.0/go.mod h1:9NiDSp5zOcgEDl+j00MP/WkGVPOlPRLejGD8Ga6PJ7M= github.com/fbiville/markdown-table-formatter v0.3.0 h1:PIm1UNgJrFs8q1htGTw+wnnNYvwXQMMMIKNZop2SSho= @@ -232,8 +232,8 @@ github.com/hashicorp/hcl v1.0.0 h1:0Anlzjpi4vEasTeNFn2mLJgTSwt0+6sfsiTG8qcWGx4= github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ= github.com/hashicorp/vault/api v1.10.0 h1:/US7sIjWN6Imp4o/Rj1Ce2Nr5bki/AXi9vAW3p2tOJQ= github.com/hashicorp/vault/api v1.10.0/go.mod h1:jo5Y/ET+hNyz+JnKDt8XLAdKs+AM0G5W0Vp1IrFI8N8= -github.com/jarcoal/httpmock v1.0.8 h1:8kI16SoO6LQKgPE7PvQuV+YuD/inwHd7fOOe2zMbo4k= -github.com/jarcoal/httpmock v1.0.8/go.mod h1:ATjnClrvW/3tijVmpL/va5Z3aAyGvqU3gCT8nX0Txik= +github.com/jarcoal/httpmock v1.3.0 h1:2RJ8GP0IIaWwcC9Fp2BmVi8Kog3v2Hn7VXM3fTd+nuc= +github.com/jarcoal/httpmock v1.3.0/go.mod h1:3yb8rc4BI7TCBhFY8ng0gjuLKJNquuDNiPaZjnENuYg= github.com/jinzhu/copier v0.4.0 h1:w3ciUoD19shMCRargcpm0cm91ytaBhDvuRpz1ODO/U8= github.com/jinzhu/copier v0.4.0/go.mod h1:DfbEm0FYsaqBcKcFuvmOZb218JkPGtvSHsKg8S8hyyg= github.com/jmespath/go-jmespath v0.4.0 h1:BEgLn5cpjn8UN1mAw4NjwDrS35OdebyEtFe+9YPoQUg= @@ -316,6 +316,8 @@ github.com/mattn/go-isatty v0.0.14/go.mod h1:7GGIvUiUoEMVVmxf/4nioHXj79iQHKdU27k github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM= github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY= github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y= +github.com/maxatome/go-testdeep v1.12.0 h1:Ql7Go8Tg0C1D/uMMX59LAoYK7LffeJQ6X2T04nTH68g= +github.com/maxatome/go-testdeep v1.12.0/go.mod h1:lPZc/HAcJMP92l7yI6TRz1aZN5URwUBUAfUNvrclaNM= github.com/miekg/dns v1.1.56 h1:5imZaSeoRNvpM9SzWNhEcP9QliKiz20/dA2QabIGVnE= github.com/miekg/dns v1.1.56/go.mod h1:cRm6Oo2C8TY9ZS/TqsSrseAcncm74lfK5G+ikN2SWWY= github.com/mitchellh/cli v1.0.0/go.mod h1:hNIlj7HEI86fIcpObd7a0FcrxTWetlwJDGcceTlRvqc= @@ -340,8 +342,8 @@ github.com/nrdcg/goinwx v0.10.0/go.mod h1:mnMSTi7CXBu2io4DzdOBoGFA1XclD0sEPWJaDh github.com/nu7hatch/gouuid v0.0.0-20131221200532-179d4d0c4d8d/go.mod h1:YUTz3bUH2ZwIWBy3CJBeOBEugqcmXREj14T+iG/4k4U= github.com/oracle/oci-go-sdk/v32 v32.0.0 h1:SSbzrQO3WRcPJEZ8+b3SFPYsPtkFM96clqrp03lrwbU= github.com/oracle/oci-go-sdk/v32 v32.0.0/go.mod h1:aZc4jC59IuNP3cr5y1nj555QvwojMX2nMJaBiozuuEs= -github.com/ovh/go-ovh v1.1.0 h1:bHXZmw8nTgZin4Nv7JuaLs0KG5x54EQR7migYTd1zrk= -github.com/ovh/go-ovh v1.1.0/go.mod h1:AxitLZ5HBRPyUd+Zl60Ajaag+rNTdVXWIkzfrVuTXWA= +github.com/ovh/go-ovh v1.4.3 h1:Gs3V823zwTFpzgGLZNI6ILS4rmxZgJwJCz54Er9LwD0= +github.com/ovh/go-ovh v1.4.3/go.mod h1:AkPXVtgwB6xlKblMjRKJJmjRp+ogrE7fz2lVgcQY8SY= github.com/patrickmn/go-cache v2.1.0+incompatible h1:HRMgzkcYKYpi3C8ajMPV8OFXaaRUnok+kx1WdO15EQc= github.com/patrickmn/go-cache v2.1.0+incompatible/go.mod h1:3Qf8kWWT7OJRJbdiICTKqZju1ZixQ/KpMGzzAfe6+WQ= github.com/peterhellberg/link v1.1.0 h1:s2+RH8EGuI/mI4QwrWGSYQCRz7uNgip9BaM04HKu5kc= @@ -403,8 +405,8 @@ github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk= github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= -github.com/transip/gotransip/v6 v6.22.1 h1:xM/UV++Em9CBRXsi+WQo7bBCIEylyE72XVB5ktmCvlM= -github.com/transip/gotransip/v6 v6.22.1/go.mod h1:nzv9eN2tdsUrm5nG5ZX6AugYIU4qgsMwIn2c0EZLk8c= +github.com/transip/gotransip/v6 v6.23.0 h1:PsTdjortrEZ8IFFifEryzjVjOy9SgK4ahlnhKBBIQgA= +github.com/transip/gotransip/v6 v6.23.0/go.mod h1:nzv9eN2tdsUrm5nG5ZX6AugYIU4qgsMwIn2c0EZLk8c= github.com/ugorji/go v1.1.7/go.mod h1:kZn38zHttfInRq0xu/PH0az30d+z6vm202qpg1oXVMw= github.com/ugorji/go v1.2.6/go.mod h1:anCg0y61KIhDlPZmnH+so+RQbysYVyDko0IMgJv0Nn0= github.com/ugorji/go/codec v1.1.7/go.mod h1:Ax+UKWsSmolVDwsd+7N3ZtXu+yMGCf907BLYF3GoBXY= @@ -436,19 +438,19 @@ golang.org/x/crypto v0.0.0-20201217014255-9d1352758620/go.mod h1:jdWPYTVW3xRLrWP golang.org/x/crypto v0.0.0-20210711020723-a769d52b0f97/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= golang.org/x/crypto v0.0.0-20210817164053-32db794688a5/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= -golang.org/x/crypto v0.14.0 h1:wBqGXzWJW6m1XrIKlAH0Hs1JJ7+9KBwnIO8v66Q9cHc= -golang.org/x/crypto v0.14.0/go.mod h1:MVFd36DqK4CsrnJYDkBA3VC4m2GkXAM0PvzMCn4JQf4= +golang.org/x/crypto v0.15.0 h1:frVn1TEaCEaZcn3Tmd7Y2b5KKPaZ+I32Q2OA3kYp5TA= +golang.org/x/crypto v0.15.0/go.mod h1:4ChreQoLWfG3xLDer1WdlH5NdlQ3+mwnQq1YTKY+72g= golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= -golang.org/x/exp v0.0.0-20231006140011-7918f672742d h1:jtJma62tbqLibJ5sFQz8bKtEM8rJBtfilJ2qTU199MI= -golang.org/x/exp v0.0.0-20231006140011-7918f672742d/go.mod h1:ldy0pHrwJyGW56pPQzzkH36rKxoZW1tw7ZJpeKx+hdo= +golang.org/x/exp v0.0.0-20231110203233-9a3e6036ecaa h1:FRnLl4eNAQl8hwxVVC17teOw8kdjVDVAiFMtgUdTSRQ= +golang.org/x/exp v0.0.0-20231110203233-9a3e6036ecaa/go.mod h1:zk2irFbV9DP96SEBUUAy67IdHUaZuSnrz1n472HUCLE= golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU= golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.4.1/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4= -golang.org/x/mod v0.13.0 h1:I/DsJXRlw/8l/0c24sM9yb0T4z9liZTduXvdAWYiysY= -golang.org/x/mod v0.13.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c= +golang.org/x/mod v0.14.0 h1:dGoOF9QVLYng8IHTm7BAyWqCqSheQ5pYWGhzW00YJr0= +golang.org/x/mod v0.14.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c= golang.org/x/net v0.0.0-20180406214816-61147c48b25b/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= @@ -466,19 +468,19 @@ golang.org/x/net v0.0.0-20210913180222-943fd674d43e/go.mod h1:9nx3DQGgdP8bBQD5qx golang.org/x/net v0.0.0-20210916014120-12bc252f5db8/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= golang.org/x/net v0.7.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs= -golang.org/x/net v0.17.0 h1:pVaXccu2ozPjCXewfr1S7xza/zcXTity9cCdXQYSjIM= -golang.org/x/net v0.17.0/go.mod h1:NxSsAGuq816PNPmqtQdLE42eU2Fs7NoRIZrHJAlaCOE= +golang.org/x/net v0.18.0 h1:mIYleuAkSbHh0tCv7RvjL3F6ZVbLjq4+R7zbOn3Kokg= +golang.org/x/net v0.18.0/go.mod h1:/czyP5RqHAH4odGYxBJ1qz0+CE5WZ+2j1YgoEo8F2jQ= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= -golang.org/x/oauth2 v0.13.0 h1:jDDenyj+WgFtmV3zYVoi8aE2BwtXFLWOA67ZfNWftiY= -golang.org/x/oauth2 v0.13.0/go.mod h1:/JMhi4ZRXAf4HG9LiNmxvk+45+96RUlVThiH8FzNBn0= +golang.org/x/oauth2 v0.14.0 h1:P0Vrf/2538nmC0H+pEQ3MNFRRnVR7RlqyVw+bvm26z0= +golang.org/x/oauth2 v0.14.0/go.mod h1:lAtNWgaWfL4cm7j2OV8TxGi9Qb7ECORx8DktCY74OwM= golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20200625203802-6e8e738ad208/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.4.0 h1:zxkM55ReGkDlKSM+Fu41A+zmbZuaPVbGMzvvdUPznYQ= -golang.org/x/sync v0.4.0/go.mod h1:FU7BRWz2tNW+3quACPkgCx/L+uEAv1htQ0V83Z9Rj+Y= +golang.org/x/sync v0.5.0 h1:60k92dhOjHxJkrqnwsfl8KuaHbn/5dl0lUPUklKo3qE= +golang.org/x/sync v0.5.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= golang.org/x/sys v0.0.0-20180823144017-11551d06cbcc/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= @@ -502,8 +504,8 @@ golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBc golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.13.0 h1:Af8nKPmuFypiUBjVoU9V20FiaFXOcuZI21p0ycVYYGE= -golang.org/x/sys v0.13.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.14.0 h1:Vz7Qs629MkJkGyHxUlRHizWJRG2j8fbQKjELVSNhy7Q= +golang.org/x/sys v0.14.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= @@ -515,12 +517,12 @@ golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= golang.org/x/text v0.3.8/go.mod h1:E6s5w1FMmriuDzIBO73fBruAKo1PCIq6d2Q6DHfQ8WQ= golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= -golang.org/x/text v0.13.0 h1:ablQoSUd0tRdKxZewP80B+BaqeKJuVhuRxj/dkrun3k= -golang.org/x/text v0.13.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE= +golang.org/x/text v0.14.0 h1:ScX5w1eTa3QqT8oi6+ziP7dTV1S2+ALU0bI+0zXKWiQ= +golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU= golang.org/x/time v0.0.0-20201208040808-7e3f01d25324/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20210220033141-f8bda1e9f3ba/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= -golang.org/x/time v0.3.0 h1:rg5rLMjNzMS1RkNLzCG38eapWhnYLFYXDXj2gOlr8j4= -golang.org/x/time v0.3.0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= +golang.org/x/time v0.4.0 h1:Z81tqI5ddIoXDPvVQ7/7CC9TnLM7ubaFG2qXYd5BbYY= +golang.org/x/time v0.4.0/go.mod h1:3BpzKBy/shNhVucY/MWOyx10tF3SFh9QdLuxbVysPQM= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY= @@ -531,14 +533,14 @@ golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtn golang.org/x/tools v0.0.0-20200918232735-d647fc253266/go.mod h1:z6u4i615ZeAfBE4XtMziQW1fSVJXACjjbWkB/mvPzlU= golang.org/x/tools v0.0.0-20210114065538-d78b04bdf963/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc= -golang.org/x/tools v0.14.0 h1:jvNa2pY0M4r62jkRQ6RwEZZyPcymeL9XZMLBbV7U2nc= -golang.org/x/tools v0.14.0/go.mod h1:uYBEerGOWcJyEORxN+Ek8+TT266gXkNlHdJBwexUsBg= +golang.org/x/tools v0.15.0 h1:zdAyfUGbYmuVokhzVmghFl2ZJh5QhcfebBgmVPFYA+8= +golang.org/x/tools v0.15.0/go.mod h1:hpksKq4dtpQWS1uQ61JkdqWM3LscIS6Slf+VVkm+wQk= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= -google.golang.org/api v0.149.0 h1:b2CqT6kG+zqJIVKRQ3ELJVLN1PwHZ6DJ3dW8yl82rgY= -google.golang.org/api v0.149.0/go.mod h1:Mwn1B7JTXrzXtnvmzQE2BD6bYZQ8DShKZDZbeN9I7qI= +google.golang.org/api v0.150.0 h1:Z9k22qD289SZ8gCJrk4DrWXkNjtfvKAUo/l1ma8eBYE= +google.golang.org/api v0.150.0/go.mod h1:ccy+MJ6nrYFgE3WgRx/AMXOxOmU8Q4hSa+jjibzhxcg= google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= google.golang.org/appengine v1.6.7 h1:FZR1q0exgwxzPzp/aF+VccGrSfxfPpkBqjIIEq3ru6c= @@ -550,8 +552,8 @@ google.golang.org/genproto v0.0.0-20231016165738-49dd2c1f3d0b h1:+YaDE2r2OG8t/z5 google.golang.org/genproto v0.0.0-20231016165738-49dd2c1f3d0b/go.mod h1:CgAqfJo+Xmu0GwA0411Ht3OU3OntXwsGmrmjI8ioGXI= google.golang.org/genproto/googleapis/api v0.0.0-20231016165738-49dd2c1f3d0b h1:CIC2YMXmIhYw6evmhPxBKJ4fmLbOFtXQN/GV3XOZR8k= google.golang.org/genproto/googleapis/api v0.0.0-20231016165738-49dd2c1f3d0b/go.mod h1:IBQ646DjkDkvUIsVq/cc03FUFQ9wbZu7yE396YcL870= -google.golang.org/genproto/googleapis/rpc v0.0.0-20231016165738-49dd2c1f3d0b h1:ZlWIi1wSK56/8hn4QcBp/j9M7Gt3U/3hZw3mC7vDICo= -google.golang.org/genproto/googleapis/rpc v0.0.0-20231016165738-49dd2c1f3d0b/go.mod h1:swOH3j0KzcDDgGUWr+SNpyTen5YrXjS3eyPzFYKc6lc= +google.golang.org/genproto/googleapis/rpc v0.0.0-20231030173426-d783a09b4405 h1:AB/lmRny7e2pLhFEYIbl5qkDAUt2h0ZRO4wGPhZf+ik= +google.golang.org/genproto/googleapis/rpc v0.0.0-20231030173426-d783a09b4405/go.mod h1:67X1fPuzjcrkymZzZV1vvkFeTn2Rvc6lYF9MYFGCcwE= google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg= google.golang.org/grpc v1.25.1/go.mod h1:c3i+UQWmh7LiEpx4sFZnkU36qjEYZ0imhYfXVyQciAY= @@ -587,9 +589,8 @@ gopkg.in/h2non/gock.v1 v1.1.2 h1:jBbHXgGBK/AoPVfJh5x4r/WxIrElvbLel8TCZkkZJoY= gopkg.in/h2non/gock.v1 v1.1.2/go.mod h1:n7UGz/ckNChHiK05rDoiC4MYSunEC/lyaUm2WWaDva0= gopkg.in/httprequest.v1 v1.1.1/go.mod h1:/CkavNL+g3qLOrpFHVrEx4NKepeqR4XTZWNj4sGGjz0= gopkg.in/ini.v1 v1.51.1/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k= -gopkg.in/ini.v1 v1.57.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k= -gopkg.in/ini.v1 v1.66.6 h1:LATuAqN/shcYAOkv3wl2L4rkaKqkcgTBQjOyYDvcPKI= -gopkg.in/ini.v1 v1.66.6/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k= +gopkg.in/ini.v1 v1.67.0 h1:Dgnx+6+nfE+IfzjUEISNeydPJh9AXNNsWbGP9KzCsOA= +gopkg.in/ini.v1 v1.67.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k= gopkg.in/mgo.v2 v2.0.0-20160818015218-f2b6f6c918c4/go.mod h1:yeKp02qBN3iKW1OzL3MGk2IdtZzaj7SFntXj72NppTA= gopkg.in/mgo.v2 v2.0.0-20190816093944-a6b53ec6cb22/go.mod h1:yeKp02qBN3iKW1OzL3MGk2IdtZzaj7SFntXj72NppTA= gopkg.in/ns1/ns1-go.v2 v2.7.13 h1:r07CLALg18f/L1KIK1ZJdbirBV349UtYT1rDWGjnaTk= From b8096b7b8a90e45b876f3373723fe9cac04dc46c Mon Sep 17 00:00:00 2001 From: Stefan Date: Wed, 15 Nov 2023 16:28:41 +0100 Subject: [PATCH 014/438] PORKBUN: implement ListZones() (#2622) --- providers/porkbun/api.go | 35 ++++++++++++++++++++++++++++++++++ providers/porkbun/listzones.go | 9 +++++++++ 2 files changed, 44 insertions(+) create mode 100644 providers/porkbun/listzones.go diff --git a/providers/porkbun/api.go b/providers/porkbun/api.go index 3145319af8..698f14c8d7 100644 --- a/providers/porkbun/api.go +++ b/providers/porkbun/api.go @@ -41,6 +41,23 @@ type recordResponse struct { Records []domainRecord `json:"records"` } +type domainListRecord struct { + Domain string `json:"domain"` + Status string `json:"status"` + TLD string `json:"tld"` + CreateDate string `json:"createDate"` + ExpireDate string `json:"expireDate"` + SecurityLock string `json:"securityLock"` + WhoisPrivacy string `json:"whoisPrivacy"` + AutoRenew string `json:"autoRenew"` + NotLocal string `json:"notLocal"` +} + +type domainListResponse struct { + Status string `json:"status"` + Domains []domainListRecord `json:"domains"` +} + type nsResponse struct { Status string `json:"status"` Nameservers []string `json:"ns"` @@ -150,3 +167,21 @@ func (c *porkbunProvider) updateNameservers(ns []string, domain string) error { } return nil } + +func (c *porkbunProvider) listAllDomains() ([]string, error) { + params := requestParams{} + var bodyString, err = c.post("/domain/listAll", params) + if err != nil { + return nil, fmt.Errorf("failed listing all domains from porkbun: %w", err) + } + + var dlr domainListResponse + json.Unmarshal(bodyString, &dlr) + + var domains []string + for _, domain := range dlr.Domains { + domains = append(domains, domain.Domain) + } + sort.Strings(domains) + return domains, nil +} diff --git a/providers/porkbun/listzones.go b/providers/porkbun/listzones.go new file mode 100644 index 0000000000..a5f9f89c15 --- /dev/null +++ b/providers/porkbun/listzones.go @@ -0,0 +1,9 @@ +package porkbun + +func (client *porkbunProvider) ListZones() ([]string, error) { + zones, err := client.listAllDomains() + if err != nil { + return nil, err + } + return zones, err +} From 32fe2753d81a681156dae5453f3b3724f30d70aa Mon Sep 17 00:00:00 2001 From: imlonghao Date: Thu, 16 Nov 2023 23:56:31 +0800 Subject: [PATCH 015/438] PORKBUN: Improve non .DE domain delegation processing (remove the trailing dot in NS) (#2624) Co-authored-by: Tom Limoncelli --- providers/porkbun/api.go | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/providers/porkbun/api.go b/providers/porkbun/api.go index 698f14c8d7..066cf50855 100644 --- a/providers/porkbun/api.go +++ b/providers/porkbun/api.go @@ -7,6 +7,7 @@ import ( "io" "net/http" "sort" + "strings" "time" ) @@ -156,7 +157,15 @@ func (c *porkbunProvider) getNameservers(domain string) ([]string, error) { json.Unmarshal(bodyString, &ns) sort.Strings(ns.Nameservers) - return ns.Nameservers, nil + + var nameservers []string + for _, nameserver := range ns.Nameservers { + // Remove the trailing dot only if it exists. + // This provider seems to add the trailing dot to some domains but not others. + // The .DE domains seem to always include the dot, others don't. + nameservers = append(nameservers, strings.TrimSuffix(nameserver, ".")) + } + return nameservers, nil } func (c *porkbunProvider) updateNameservers(ns []string, domain string) error { From 8040e7bba269b605dd0f796e004acb835a0b2c12 Mon Sep 17 00:00:00 2001 From: Tom Limoncelli Date: Sat, 18 Nov 2023 10:37:46 -0500 Subject: [PATCH 016/438] REFACTOR: Add Joined and Segmented accessors to TXT, and other cleanups (#2628) --- models/dns.go | 16 ---------------- models/dnsrr.go | 24 ------------------------ models/quotes_test.go | 4 ++-- models/record.go | 31 ------------------------------- models/t_txt.go | 20 +++++++++++++++++++- models/target.go | 3 ++- pkg/diff/diff.go | 31 ------------------------------- pkg/diff/diff2compat.go | 9 ++------- pkg/txtutil/txtutil.go | 5 +++++ providers/powerdns/convert.go | 2 +- 10 files changed, 31 insertions(+), 114 deletions(-) diff --git a/models/dns.go b/models/dns.go index 7b73eb895c..a2ed16f626 100644 --- a/models/dns.go +++ b/models/dns.go @@ -118,19 +118,3 @@ func (config *DNSConfig) DomainContainingFQDN(fqdn string) *DomainConfig { } return d } - -//// IgnoreName describes an IGNORE_NAME rule. -//type IgnoreName struct { -// Pattern string `json:"pattern"` // Glob pattern. -// Types string `json:"types"` // All caps rtype names, comma separated. -//} -// -//// IgnoreTarget describes an IGNORE_TARGET rule. -//type IgnoreTarget struct { -// Pattern string `json:"pattern"` // Glob pattern. -// Type string `json:"type"` // All caps rtype name. -//} -// -//func (i *IgnoreTarget) String() string { -// return i.Pattern -//} diff --git a/models/dnsrr.go b/models/dnsrr.go index 1ef0f82120..c4d357649e 100644 --- a/models/dnsrr.go +++ b/models/dnsrr.go @@ -9,35 +9,11 @@ import ( "github.com/miekg/dns" ) -//// Header Header returns the header of an resource record. -//func (rc *RecordConfig) Header() *dns.RR_Header { -// log.Fatal("Header not implemented") -// return nil -//} - // String returns the text representation of the resource record. func (rc *RecordConfig) String() string { return rc.GetTargetCombined() } -//// copy returns a copy of the RR -//func (rc *RecordConfig) copy() dns.RR { -// log.Fatal("Copy not implemented") -// return dns.TypeToRR[dns.TypeA]() -//} -// -//// len returns the length (in octets) of the uncompressed RR in wire format. -//func (rc *RecordConfig) len() int { -// log.Fatal("len not implemented") -// return 0 -//} -// -//// pack packs an RR into wire format. -//func (rc *RecordConfig) pack([]byte, int, map[string]int, bool) (int, error) { -// log.Fatal("pack not implemented") -// return 0, nil -//} - // Conversions // RRstoRCs converts []dns.RR to []RecordConfigs. diff --git a/models/quotes_test.go b/models/quotes_test.go index 86cc80f730..9ca3214015 100644 --- a/models/quotes_test.go +++ b/models/quotes_test.go @@ -63,11 +63,11 @@ func TestParseQuotedTxt(t *testing.T) { for i, test := range tests { ls := ParseQuotedTxt(test.d1) if len(ls) != len(test.e2) { - t.Errorf("%v: expected TxtStrings=(%v) got (%v)", i, test.e2, ls) + t.Errorf("%v: expected LEN TxtStrings=q(%q) got q(%q)", i, test.e2, ls) } for i := range ls { if ls[i] != test.e2[i] { - t.Errorf("%v: expected TxtStrings=(%v) got (%v)", i, test.e2, ls) + t.Errorf("%v: expected TxtStrings=q(%q) got q(%q)", i, test.e2, ls) } } } diff --git a/models/record.go b/models/record.go index 894c49dace..8c95c3894c 100644 --- a/models/record.go +++ b/models/record.go @@ -269,14 +269,6 @@ func (rc *RecordConfig) SetLabel(short, origin string) { } } -// UnsafeSetLabelNull sets the label to "". Normally the FQDN is denoted by .Name being -// "@" however this can be used to violate that assertion. It should only be used -// on copies of a RecordConfig that is being used for non-standard things like -// Marshalling yaml. -func (rc *RecordConfig) UnsafeSetLabelNull() { - rc.Name = "" -} - // SetLabelFromFQDN sets the .Name/.NameFQDN fields given a FQDN and origin. // fqdn may have a trailing "." but it is not required. // origin may not have a trailing dot. @@ -512,16 +504,6 @@ func (recs Records) HasRecordTypeName(rtype, name string) bool { return false } -// FQDNMap returns a map of all LabelFQDNs. Useful for making a -// truthtable of labels that exist in Records. -func (recs Records) FQDNMap() (m map[string]bool) { - m = map[string]bool{} - for _, rec := range recs { - m[rec.GetLabelFQDN()] = true - } - return m -} - // GetByType returns the records that match rtype typeName. func (recs Records) GetByType(typeName string) Records { results := Records{} @@ -542,19 +524,6 @@ func (recs Records) GroupedByKey() map[RecordKey]Records { return groups } -// GroupedByLabel returns a map of keys to records, and their original key order. -func (recs Records) GroupedByLabel() ([]string, map[string]Records) { - order := []string{} - groups := map[string]Records{} - for _, rec := range recs { - if _, found := groups[rec.Name]; !found { - order = append(order, rec.Name) - } - groups[rec.Name] = append(groups[rec.Name], rec) - } - return order, groups -} - // GroupedByFQDN returns a map of keys to records, grouped by FQDN. func (recs Records) GroupedByFQDN() ([]string, map[string]Records) { order := []string{} diff --git a/models/t_txt.go b/models/t_txt.go index 4a39c06c44..87b7470dec 100644 --- a/models/t_txt.go +++ b/models/t_txt.go @@ -147,11 +147,29 @@ func (rc *RecordConfig) SetTargetTXTs(s []string) error { return nil } -// GetTargetTXTJoined returns the TXT target as one string. If it was stored as multiple strings, concatenate them. +// GetTargetTXTJoined returns the TXT target as one string. func (rc *RecordConfig) GetTargetTXTJoined() string { return strings.Join(rc.TxtStrings, "") } +// GetTargetTXTSegmented returns the TXT target as 255-octet segments, with the remainder in the last segment. +func (rc *RecordConfig) GetTargetTXTSegmented() []string { + return splitChunks(strings.Join(rc.TxtStrings, ""), 255) +} + +func splitChunks(buf string, lim int) []string { + var chunk string + chunks := make([]string, 0, len(buf)/lim+1) + for len(buf) >= lim { + chunk, buf = buf[:lim], buf[lim:] + chunks = append(chunks, chunk) + } + if len(buf) > 0 { + chunks = append(chunks, buf[:]) + } + return chunks +} + // SetTargetTXTfromRFC1035Quoted parses a series of quoted strings // and sets .TxtStrings based on the result. // Note: Most APIs do notThis is rarely used. Try using SetTargetTXT() first. diff --git a/models/target.go b/models/target.go index 9a189d8ffa..5602c3a71e 100644 --- a/models/target.go +++ b/models/target.go @@ -3,6 +3,7 @@ package models import ( "fmt" "net" + "runtime/debug" "strings" "github.com/miekg/dns" @@ -26,7 +27,7 @@ func (rc *RecordConfig) GetTargetField() string { if debugWarnTxtField { if rc.Type == "TXT" { fmt.Printf("DEBUG: WARNING: GetTargetField called on TXT record is frequently wrong: %q\n", rc.target) - //debug.PrintStack() + debug.PrintStack() } } return rc.target diff --git a/pkg/diff/diff.go b/pkg/diff/diff.go index 16412ae2f7..031b9a720f 100644 --- a/pkg/diff/diff.go +++ b/pkg/diff/diff.go @@ -32,37 +32,6 @@ func (d *differ) content(r *models.RecordConfig) string { return r.ToDiffable() } -// ChangesetLess returns true if c[i] < c[j]. -func ChangesetLess(c Changeset, i, j int) bool { - var a, b string - // Which fields are we comparing? - // Usually only Desired OR Existing content exists (we're either - // adding or deleting records). In those cases, just use whichever - // isn't nil. - // In the case where both Desired AND Existing exist, it doesn't - // matter which we use as long as we are consistent. I flipped a - // coin and picked to use Desired in that case. - - if c[i].Desired != nil { - a = c[i].Desired.NameFQDN - } else { - a = c[i].Existing.NameFQDN - } - - if c[j].Desired != nil { - b = c[j].Desired.NameFQDN - } else { - b = c[j].Existing.NameFQDN - } - - return a < b - - // TODO(tlim): This won't correctly sort: - // []string{"example.com", "foo.example.com", "bar.example.com"} - // A simple way to do that correctly is to split on ".", reverse the - // elements, and sort on the result. -} - // CorrectionLess returns true when comparing corrections. func CorrectionLess(c []*models.Correction, i, j int) bool { return c[i].Msg < c[j].Msg diff --git a/pkg/diff/diff2compat.go b/pkg/diff/diff2compat.go index b9f617da30..fb726d617d 100644 --- a/pkg/diff/diff2compat.go +++ b/pkg/diff/diff2compat.go @@ -10,15 +10,10 @@ import ( // NewCompat is a constructor that uses the new pkg/diff2 system // instead of pkg/diff. // -// It is for backwards compatibility only. New providers should use -// pkg/diff2. Older providers should use this to reduce their -// dependency on pkg/diff2 until they can move to the pkg/diff2/By*() -// functions. +// It is for backwards compatibility only. New providers should use pkg/diff2. // // To use this simply change New() to NewCompat(). If that doesn't -// work please report a bug. The only exception is if you depend on -// the extraValues feature, which will not be supported. That -// parameter must be set to nil. +// work please report a bug. The extraValues feature is not supported. func NewCompat(dc *models.DomainConfig, extraValues ...func(*models.RecordConfig) map[string]string) Differ { if len(extraValues) != 0 { panic("extraValues not supported") diff --git a/pkg/txtutil/txtutil.go b/pkg/txtutil/txtutil.go index 5aa6b1d4ba..a37948c741 100644 --- a/pkg/txtutil/txtutil.go +++ b/pkg/txtutil/txtutil.go @@ -17,6 +17,11 @@ func SplitSingleLongTxt(records []*models.RecordConfig) { } } +// Segment returns the string as 255-octet segments, the last being the remainder. +func Segment(s string) []string { + return splitChunks(s, 255) +} + func splitChunks(buf string, lim int) []string { var chunk string chunks := make([]string, 0, len(buf)/lim+1) diff --git a/providers/powerdns/convert.go b/providers/powerdns/convert.go index 307955552f..591cb1882c 100644 --- a/providers/powerdns/convert.go +++ b/providers/powerdns/convert.go @@ -22,7 +22,7 @@ func toRecordConfig(domain string, r zones.Record, ttl int, name string, rtype s switch rtype { case "TXT": - // PowerDNS API accepts long TXTs without requiring to split them + // PowerDNS API accepts long TXTs without requiring to split them. // The API then returns them as they initially came in, e.g. "averylooooooo[...]oooooongstring" or "string" "string" // So we need to strip away " and split into multiple string // We can't use SetTargetRFC1035Quoted, it would split the long strings into multiple parts From 159fdf07adc0335fa4aea2c3ea5d4c05664de17b Mon Sep 17 00:00:00 2001 From: Tom Limoncelli Date: Sat, 18 Nov 2023 15:06:20 -0500 Subject: [PATCH 017/438] REFACTOR: providers should not directly access .TxtStrings (#2629) --- models/t_txt.go | 13 +++++++++++++ providers/axfrddns/axfrddnsProvider.go | 4 ++-- providers/azuredns/azureDnsProvider.go | 4 ++-- providers/cscglobal/dns.go | 10 +++++----- providers/digitalocean/auditrecords.go | 3 +-- providers/domainnameshop/dns.go | 2 +- providers/gcore/convert.go | 2 +- providers/hetzner/types.go | 4 ++-- providers/hexonet/records.go | 4 ++-- providers/hostingde/types.go | 5 +++-- providers/inwx/inwxProvider.go | 3 ++- providers/loopia/auditrecords.go | 3 ++- providers/msdns/powershell.go | 2 +- providers/namedotcom/auditrecords.go | 7 ++++--- providers/namedotcom/records.go | 2 +- providers/ns1/ns1Provider.go | 2 +- providers/softlayer/softlayerProvider.go | 5 ++++- providers/vultr/vultrProvider.go | 2 +- 18 files changed, 48 insertions(+), 29 deletions(-) diff --git a/models/t_txt.go b/models/t_txt.go index 87b7470dec..7b7b78a4d3 100644 --- a/models/t_txt.go +++ b/models/t_txt.go @@ -157,6 +157,19 @@ func (rc *RecordConfig) GetTargetTXTSegmented() []string { return splitChunks(strings.Join(rc.TxtStrings, ""), 255) } +// GetTargetTXTSegmentCount returns the number of 255-octet segments required to store TXT target. +func (rc *RecordConfig) GetTargetTXTSegmentCount() int { + var total int + for i := range rc.TxtStrings { + total = len(rc.TxtStrings[i]) + } + segs := total / 255 // integer division, decimals are truncated + if (total % 255) > 0 { + return segs + 1 + } + return segs +} + func splitChunks(buf string, lim int) []string { var chunk string chunks := make([]string, 0, len(buf)/lim+1) diff --git a/providers/axfrddns/axfrddnsProvider.go b/providers/axfrddns/axfrddnsProvider.go index b7a1f17cef..f283ee9418 100644 --- a/providers/axfrddns/axfrddnsProvider.go +++ b/providers/axfrddns/axfrddnsProvider.go @@ -327,8 +327,8 @@ func (c *axfrddnsProvider) GetZoneRecords(domain string, meta map[string]string) last := foundRecords[len(foundRecords)-1] if last.Type == "TXT" && last.Name == dnssecDummyLabel && - len(last.TxtStrings) == 1 && - last.TxtStrings[0] == dnssecDummyTxt { + last.GetTargetTXTSegmentCount() == 1 && + last.GetTargetTXTSegmented()[0] == dnssecDummyTxt { c.hasDnssecRecords = true foundRecords = foundRecords[0:(len(foundRecords) - 1)] } diff --git a/providers/azuredns/azureDnsProvider.go b/providers/azuredns/azureDnsProvider.go index cb2230132b..105e46e6e5 100644 --- a/providers/azuredns/azureDnsProvider.go +++ b/providers/azuredns/azureDnsProvider.go @@ -525,9 +525,9 @@ func (a *azurednsProvider) recordToNativeDiff2(recordKey models.RecordKey, recor recordSet.Properties.TxtRecords = []*adns.TxtRecord{} } // Empty TXT record needs to have no value set in it's properties - if !(len(rec.TxtStrings) == 1 && rec.TxtStrings[0] == "") { + if !(rec.GetTargetTXTSegmentCount() == 1 && rec.GetTargetTXTSegmented()[0] == "") { var txts []*string - for _, txt := range rec.TxtStrings { + for _, txt := range rec.GetTargetTXTSegmented() { txts = append(txts, to.StringPtr(txt)) } recordSet.Properties.TxtRecords = append(recordSet.Properties.TxtRecords, &adns.TxtRecord{Value: txts}) diff --git a/providers/cscglobal/dns.go b/providers/cscglobal/dns.go index 4cf3cb5175..e78432a3bb 100644 --- a/providers/cscglobal/dns.go +++ b/providers/cscglobal/dns.go @@ -132,7 +132,7 @@ func makePurge(domainname string, cor diff.Correlation) zoneResourceRecordEdit { switch cor.Existing.Type { case "TXT": - existingTarget = strings.Join(cor.Existing.TxtStrings, "") + existingTarget = cor.Existing.GetTargetTXTJoined() default: existingTarget = cor.Existing.GetTargetField() } @@ -159,7 +159,7 @@ func makeAdd(domainname string, cre diff.Correlation) zoneResourceRecordEdit { var recTarget string switch rec.Type { case "TXT": - recTarget = strings.Join(rec.TxtStrings, "") + recTarget = rec.GetTargetTXTJoined() default: recTarget = rec.GetTargetField() } @@ -185,7 +185,7 @@ func makeAdd(domainname string, cre diff.Correlation) zoneResourceRecordEdit { zer.NewWeight = rec.SrvWeight zer.NewPort = rec.SrvPort case "TXT": - zer.NewValue = strings.Join(rec.TxtStrings, "") + zer.NewValue = rec.GetTargetTXTJoined() default: // "A", "CNAME", "NS" // Nothing to do. } @@ -201,8 +201,8 @@ func makeEdit(domainname string, m diff.Correlation) zoneResourceRecordEdit { var oldTarget, recTarget string switch old.Type { case "TXT": - oldTarget = strings.Join(old.TxtStrings, "") - recTarget = strings.Join(rec.TxtStrings, "") + oldTarget = old.GetTargetTXTJoined() + recTarget = rec.GetTargetTXTJoined() default: oldTarget = old.GetTargetField() recTarget = rec.GetTargetField() diff --git a/providers/digitalocean/auditrecords.go b/providers/digitalocean/auditrecords.go index 49263f45cd..95382cc924 100644 --- a/providers/digitalocean/auditrecords.go +++ b/providers/digitalocean/auditrecords.go @@ -44,10 +44,9 @@ func MaxLengthDO(rc *models.RecordConfig) error { // In other words, they're doing the checking on the API protocol // encoded data instead of on on the resulting TXT record. Sigh. - if len(rc.GetTargetField()) > 509 { + if len(rc.GetTargetRFC1035Quoted()) > 509 { return fmt.Errorf("encoded txt too long") } - // FIXME(tlim): Try replacing GetTargetField() with (2 + (3*len(rc.TxtStrings) - 1)) return nil } diff --git a/providers/domainnameshop/dns.go b/providers/domainnameshop/dns.go index e7619c11d8..320506b6f6 100644 --- a/providers/domainnameshop/dns.go +++ b/providers/domainnameshop/dns.go @@ -30,7 +30,7 @@ func (api *domainNameShopProvider) GetZoneRecordsCorrections(dc *models.DomainCo // Merge TXT strings to one string for _, rc := range dc.Records { if rc.HasFormatIdenticalToTXT() { - rc.SetTargetTXT(strings.Join(rc.TxtStrings, "")) + rc.SetTargetTXT(rc.GetTargetTXTJoined()) } } diff --git a/providers/gcore/convert.go b/providers/gcore/convert.go index f3e4ebb5a3..b5c1cc6bff 100644 --- a/providers/gcore/convert.go +++ b/providers/gcore/convert.go @@ -86,7 +86,7 @@ func recordsToNative(rcs []*models.RecordConfig, expectedKey models.RecordKey) * } case "TXT": // Avoid double quoting for TXT records rr = dnssdk.ResourceRecord{ - Content: convertTxtSliceToSdkAnySlice(r.TxtStrings), + Content: convertTxtSliceToSdkAnySlice(r.GetTargetTXTSegmented()), Meta: nil, Enabled: true, } diff --git a/providers/hetzner/types.go b/providers/hetzner/types.go index 80ad3c8e7f..20dacdfb1e 100644 --- a/providers/hetzner/types.go +++ b/providers/hetzner/types.go @@ -63,7 +63,7 @@ func fromRecordConfig(in *models.RecordConfig, zone *zone) record { ZoneID: zone.ID, } - if r.Type == "TXT" && len(in.TxtStrings) == 1 { + if r.Type == "TXT" && (in.GetTargetTXTSegmentCount() == 1) { // HACK: HETZNER rejects values that fit into 255 bytes w/o quotes, // but do not fit w/ added quotes (via GetTargetCombined()). // Sending the raw, non-quoted value works for the comprehensive @@ -71,7 +71,7 @@ func fromRecordConfig(in *models.RecordConfig, zone *zone) record { // The HETZNER validation does not provide helpful error messages. // {"error":{"message":"422 Unprocessable Entity: missing: ; ","code":422}} // Last checked: 2023-04-01 - valueNotQuoted := in.TxtStrings[0] + valueNotQuoted := in.GetTargetTXTSegmented()[0] if len(valueNotQuoted) == 254 || len(valueNotQuoted) == 255 { r.Value = valueNotQuoted } diff --git a/providers/hexonet/records.go b/providers/hexonet/records.go index 3cb1846db7..ac313f714f 100644 --- a/providers/hexonet/records.go +++ b/providers/hexonet/records.go @@ -242,7 +242,7 @@ func (n *HXClient) createRecordString(rc *models.RecordConfig, domain string) (s case "CAA": record.Answer = fmt.Sprintf(`%v %s "%s"`, rc.CaaFlag, rc.CaaTag, record.Answer) case "TXT": - record.Answer = encodeTxt(rc.TxtStrings) + record.Answer = encodeTxt(rc.GetTargetTXTSegmented()) case "SRV": if rc.GetTargetField() == "." { return "", fmt.Errorf("SRV records with empty targets are not supported (as of 2020-02-27, the API returns 'Invalid attribute value syntax')") @@ -267,7 +267,7 @@ func (n *HXClient) deleteRecordString(record *HXRecord, domain string) string { return record.Raw } -// encodeTxt encodes TxtStrings for sending in the CREATE/MODIFY API: +// encodeTxt encodes []string for sending in the CREATE/MODIFY API: func encodeTxt(txts []string) string { var r []string for _, txt := range txts { diff --git a/providers/hostingde/types.go b/providers/hostingde/types.go index 0a1f924a5b..4f789ba2a9 100644 --- a/providers/hostingde/types.go +++ b/providers/hostingde/types.go @@ -193,8 +193,9 @@ func recordToNative(rc *models.RecordConfig) *record { case "A", "AAAA", "ALIAS", "CAA", "CNAME", "DNSKEY", "DS", "NS", "NSEC", "NSEC3", "NSEC3PARAM", "PTR", "RRSIG", "SSHFP", "TSLA": // Nothing special. case "TXT": - txtStrings := make([]string, len(rc.TxtStrings)) - copy(txtStrings, rc.TxtStrings) + // TODO(tlim): Move this to a function with unit tests. + txtStrings := make([]string, rc.GetTargetTXTSegmentCount()) + copy(txtStrings, rc.GetTargetTXTSegmented()) // Escape quotes for i := range txtStrings { diff --git a/providers/inwx/inwxProvider.go b/providers/inwx/inwxProvider.go index 0c4cfdaf83..a2de4cb037 100644 --- a/providers/inwx/inwxProvider.go +++ b/providers/inwx/inwxProvider.go @@ -213,9 +213,10 @@ func (api *inwxAPI) deleteRecord(RecordID int) error { // checkRecords ensures that there is no single-quote inside TXT records which would be ignored by INWX. func checkRecords(records models.Records) error { + // TODO(tlim) Remove this function. auditrecords.go takes care of this now. for _, r := range records { if r.Type == "TXT" { - for _, target := range r.TxtStrings { + for _, target := range r.GetTargetTXTSegmented() { if strings.ContainsAny(target, "`") { return fmt.Errorf("INWX TXT records do not support single-quotes in their target") } diff --git a/providers/loopia/auditrecords.go b/providers/loopia/auditrecords.go index 0accc622c4..d9d8cb2d5f 100644 --- a/providers/loopia/auditrecords.go +++ b/providers/loopia/auditrecords.go @@ -2,6 +2,7 @@ package loopia import ( "fmt" + "github.com/StackExchange/dnscontrol/v4/models" "github.com/StackExchange/dnscontrol/v4/pkg/rejectif" ) @@ -24,7 +25,7 @@ func AuditRecords(records []*models.RecordConfig) []error { // TxtHasSegmentLen450orLonger audits TXT records for strings that are >450 octets. func TxtHasSegmentLen450orLonger(rc *models.RecordConfig) error { - for _, txt := range rc.TxtStrings { + for _, txt := range rc.GetTargetTXTSegmented() { if len(txt) > 450 { return fmt.Errorf("%q txtstring length > 450", rc.GetLabel()) } diff --git a/providers/msdns/powershell.go b/providers/msdns/powershell.go index 367deb5a51..75fef9d45d 100644 --- a/providers/msdns/powershell.go +++ b/providers/msdns/powershell.go @@ -316,7 +316,7 @@ func generatePSCreate(dnsserver, domain string, rec *models.RecordConfig) string //case "WKS": // fmt.Fprintf(&b, ` -Wks -InternetAddress -InternetProtocol {UDP | TCP} -Service `, rec.GetTargetField()) case "TXT": - //printer.Printf("DEBUG TXT len = %v\n", rec.TxtStrings) + //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": diff --git a/providers/namedotcom/auditrecords.go b/providers/namedotcom/auditrecords.go index 7db65ad504..2d9a64c847 100644 --- a/providers/namedotcom/auditrecords.go +++ b/providers/namedotcom/auditrecords.go @@ -29,18 +29,19 @@ func AuditRecords(records []*models.RecordConfig) []error { // are longer than permitted by NDC. Sadly their // length limit is undocumented. This seems to work. func MaxLengthNDC(rc *models.RecordConfig) error { - if len(rc.TxtStrings) == 0 { + txtStrings := rc.GetTargetTXTSegmented() + if len(txtStrings) == 0 { return nil } sum := 2 // Count the start and end quote. // Add the length of each segment. - for _, segment := range rc.TxtStrings { + for _, segment := range txtStrings { sum += len(segment) // The length of each segment sum += strings.Count(segment, `"`) // Add 1 for any char to be escaped } // Add 3 (quote space quote) for each interior join. - sum += 3 * (len(rc.TxtStrings) - 1) + sum += 3 * (len(txtStrings) - 1) if sum > 512 { return fmt.Errorf("encoded txt too long") diff --git a/providers/namedotcom/records.go b/providers/namedotcom/records.go index b9edb4ef8e..af58fde7b1 100644 --- a/providers/namedotcom/records.go +++ b/providers/namedotcom/records.go @@ -154,7 +154,7 @@ func (n *namedotcomProvider) createRecord(rc *models.RecordConfig, domain string case "A", "AAAA", "ANAME", "CNAME", "MX", "NS": // nothing case "TXT": - // record.Answer = encodeTxt(rc.TxtStrings) + // nothing case "SRV": if rc.GetTargetField() == "." { return errors.New("SRV records with empty targets are not supported (as of 2019-11-05, the API returns 'Parameter Value Error - Invalid Srv Format')") diff --git a/providers/ns1/ns1Provider.go b/providers/ns1/ns1Provider.go index 59a048cc35..a92db2860d 100644 --- a/providers/ns1/ns1Provider.go +++ b/providers/ns1/ns1Provider.go @@ -302,7 +302,7 @@ func buildRecord(recs models.Records, domain string, id string) *dns.Record { if r.Type == "MX" { rec.AddAnswer(&dns.Answer{Rdata: strings.Fields(fmt.Sprintf("%d %v", r.MxPreference, r.GetTargetField()))}) } else if r.Type == "TXT" { - rec.AddAnswer(&dns.Answer{Rdata: r.TxtStrings}) + rec.AddAnswer(&dns.Answer{Rdata: r.GetTargetTXTSegmented()}) } else if r.Type == "CAA" { rec.AddAnswer(&dns.Answer{ Rdata: []string{ diff --git a/providers/softlayer/softlayerProvider.go b/providers/softlayer/softlayerProvider.go index 4238302b89..a47d432a6f 100644 --- a/providers/softlayer/softlayerProvider.go +++ b/providers/softlayer/softlayerProvider.go @@ -173,7 +173,10 @@ func (s *softlayerProvider) getExistingRecords(domain *datatypes.Dns_Domain) (mo } recConfig.SetLabel(fmt.Sprintf("%s.%s", service, strings.ToLower(protocol)), *domain.Name) case "TXT": - recConfig.TxtStrings = append(recConfig.TxtStrings, *record.Data) + // OLD: recConfig.TxtStrings = append(recConfig.TxtStrings, *record.Data) + recConfig.SetTargetTXTs(append(recConfig.GetTargetTXTSegmented(), *record.Data)) + // NB(tlim) The above code seems too complex. Can it be simplied to this? + // recConfig.SetTargetTXT(*record.Data) fallthrough case "MX": if record.MxPriority != nil { diff --git a/providers/vultr/vultrProvider.go b/providers/vultr/vultrProvider.go index 1a5b5b5772..c09ec349d5 100644 --- a/providers/vultr/vultrProvider.go +++ b/providers/vultr/vultrProvider.go @@ -314,7 +314,7 @@ func toVultrRecord(dc *models.DomainConfig, rc *models.RecordConfig, vultrID str // Vultr doesn't permit TXT strings to include double-quotes // therefore, we don't have to escape interior double-quotes. // Vultr's API requires the string to begin and end with double-quotes. - r.Data = `"` + strings.Join(rc.TxtStrings, "") + `"` + r.Data = `"` + strings.Join(rc.GetTargetTXTSegmented(), "") + `"` default: } From 3dab594757ef2fde461b71e3c4882c2e90cb5333 Mon Sep 17 00:00:00 2001 From: Tom Limoncelli Date: Sun, 19 Nov 2023 13:44:49 -0500 Subject: [PATCH 018/438] CHORE: More cleanups (#2632) --- commands/gz_test.go | 11 +++++------ documentation/providers/azure_dns.md | 2 ++ pkg/diff/diff2compat.go | 2 +- pkg/diff2/compareconfig.go | 1 + pkg/normalize/validate_test.go | 2 +- pkg/rejectif/txt.go | 10 ++++++++++ providers/desec/desecProvider.go | 3 +-- providers/powerdns/auditrecords.go | 12 ++++++++++-- providers/transip/auditrecords.go | 10 +++++++--- 9 files changed, 38 insertions(+), 15 deletions(-) diff --git a/commands/gz_test.go b/commands/gz_test.go index c7c56bece7..594debb839 100644 --- a/commands/gz_test.go +++ b/commands/gz_test.go @@ -66,13 +66,12 @@ func testFormat(t *testing.T, domain, format string) { log.Fatal(fmt.Errorf("can't read expected %q: %w", outfile.Name(), err)) } - // // Update got -> want - // err = os.WriteFile(expectedFilename, got, 0644) - // if err != nil { - // log.Fatal(err) - // } - 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) + if err != nil { + log.Fatal(err) + } t.Errorf("testFormat mismatch (-got +want):\n%s", diff.LineDiff(g, w)) } } diff --git a/documentation/providers/azure_dns.md b/documentation/providers/azure_dns.md index a9eac9cfb3..2d1070917a 100644 --- a/documentation/providers/azure_dns.md +++ b/documentation/providers/azure_dns.md @@ -45,6 +45,8 @@ export AZURE_CLIENT_SECRET=BBBBBBBBB ``` {% endcode %} +NOTE: The ResourceGroup is case sensitive. + ## Metadata This provider does not recognize any special metadata fields unique to Azure DNS. diff --git a/pkg/diff/diff2compat.go b/pkg/diff/diff2compat.go index fb726d617d..78cb75a684 100644 --- a/pkg/diff/diff2compat.go +++ b/pkg/diff/diff2compat.go @@ -13,7 +13,7 @@ import ( // It is for backwards compatibility only. New providers should use pkg/diff2. // // To use this simply change New() to NewCompat(). If that doesn't -// work please report a bug. The extraValues feature is not supported. +// work please report a bug. The extraValues parameter is not supported. func NewCompat(dc *models.DomainConfig, extraValues ...func(*models.RecordConfig) map[string]string) Differ { if len(extraValues) != 0 { panic("extraValues not supported") diff --git a/pkg/diff2/compareconfig.go b/pkg/diff2/compareconfig.go index 0b75d32a22..0ec0320dac 100644 --- a/pkg/diff2/compareconfig.go +++ b/pkg/diff2/compareconfig.go @@ -215,6 +215,7 @@ func mkCompareBlobs(rc *models.RecordConfig, f func(*models.RecordConfig) string } } + // We do this to save memory. This assures the first return value uses the same memory as the second. lenWithoutTTL := len(comp) compFull := comp + fmt.Sprintf(" ttl=%d", rc.TTL) diff --git a/pkg/normalize/validate_test.go b/pkg/normalize/validate_test.go index 0bd8420140..5a6d3dc7f3 100644 --- a/pkg/normalize/validate_test.go +++ b/pkg/normalize/validate_test.go @@ -324,7 +324,7 @@ func TestCheckDuplicates(t *testing.T) { } errs := checkDuplicates(records) if len(errs) != 0 { - t.Errorf("Expect duplicate NOT found but found %q", errs) + t.Errorf("Expected duplicate NOT found but found %q", errs) } } diff --git a/pkg/rejectif/txt.go b/pkg/rejectif/txt.go index 8a0883b8ce..b1d63c0ba2 100644 --- a/pkg/rejectif/txt.go +++ b/pkg/rejectif/txt.go @@ -9,6 +9,16 @@ import ( // Keep these in alphabetical order. +// TxtHasBackslash audits TXT records for strings that contains one or more backslashes. +func TxtHasBackslash(rc *models.RecordConfig) error { + for _, txt := range rc.TxtStrings { + if strings.Contains(txt, `\`) { + return fmt.Errorf("txtstring contains backslash") + } + } + return nil +} + // TxtHasBackticks audits TXT records for strings that contain backticks. func TxtHasBackticks(rc *models.RecordConfig) error { for _, txt := range rc.TxtStrings { diff --git a/providers/desec/desecProvider.go b/providers/desec/desecProvider.go index d67fa73cb4..34201f0130 100644 --- a/providers/desec/desecProvider.go +++ b/providers/desec/desecProvider.go @@ -4,7 +4,6 @@ import ( "bytes" "encoding/json" "fmt" - "sort" "github.com/StackExchange/dnscontrol/v4/models" "github.com/StackExchange/dnscontrol/v4/pkg/diff" @@ -237,7 +236,7 @@ func (c *desecProvider) GetZoneRecordsCorrections(dc *models.DomainConfig, exist // However the code doesn't seem to have such situation. All tests // pass. That said, if this breaks anything, the easiest fix might // be to just remove the sort. - sort.Slice(corrections, func(i, j int) bool { return diff.CorrectionLess(corrections, i, j) }) + //sort.Slice(corrections, func(i, j int) bool { return diff.CorrectionLess(corrections, i, j) }) return corrections, nil } diff --git a/providers/powerdns/auditrecords.go b/providers/powerdns/auditrecords.go index 7b22a7d176..1903c5d22e 100644 --- a/providers/powerdns/auditrecords.go +++ b/providers/powerdns/auditrecords.go @@ -1,10 +1,18 @@ package powerdns -import "github.com/StackExchange/dnscontrol/v4/models" +import ( + "github.com/StackExchange/dnscontrol/v4/models" + "github.com/StackExchange/dnscontrol/v4/pkg/rejectif" +) // AuditRecords returns a list of errors corresponding to the records // that aren't supported by this provider. If all records are // supported, an empty list is returned. func AuditRecords(records []*models.RecordConfig) []error { - return nil + a := rejectif.Auditor{} + + a.Add("TXT", rejectif.TxtHasDoubleQuotes) // Last verified 2023-11-11 + a.Add("TXT", rejectif.TxtHasBackslash) // Last verified 2023-11-11 + + return a.Audit(records) } diff --git a/providers/transip/auditrecords.go b/providers/transip/auditrecords.go index 814e1c7923..fd6729c449 100644 --- a/providers/transip/auditrecords.go +++ b/providers/transip/auditrecords.go @@ -10,10 +10,14 @@ import ( // supported, an empty list is returned. func AuditRecords(records []*models.RecordConfig) []error { a := rejectif.Auditor{} - a.Add("MX", rejectif.MxNull) // Last verified 2023-01-28 - a.Add("TXT", rejectif.TxtHasBackticks) // Last verified 2023-01-28 + + a.Add("MX", rejectif.MxNull) // Last verified 2023-01-28 + + a.Add("TXT", rejectif.TxtHasBackticks) // Last verified 2023-01-28 + a.Add("TXT", rejectif.TxtHasTrailingSpace) // Last verified 2023-01-28 - a.Add("TXT", rejectif.TxtIsEmpty) // Last verified 2023-01-28 + + a.Add("TXT", rejectif.TxtIsEmpty) // Last verified 2023-01-28 return a.Audit(records) } From bfa9da98c8642073dffc7c7013bcd151b2d061ae Mon Sep 17 00:00:00 2001 From: Tom Limoncelli Date: Sun, 19 Nov 2023 13:52:28 -0500 Subject: [PATCH 019/438] CHORE update deps (#2633) --- go.mod | 35 +++++++++++++++-------------- go.sum | 70 ++++++++++++++++++++++++++++++---------------------------- 2 files changed, 54 insertions(+), 51 deletions(-) diff --git a/go.mod b/go.mod index bfa26ffb6c..b5c5bb2bf8 100644 --- a/go.mod +++ b/go.mod @@ -13,17 +13,17 @@ require ( github.com/TomOnTime/utfutil v0.0.0-20230223141146-125e65197b36 github.com/akamai/AkamaiOPEN-edgegrid-golang v1.2.2 github.com/andreyvit/diff v0.0.0-20170406064948-c7f18ee00883 - github.com/aws/aws-sdk-go-v2 v1.22.2 - github.com/aws/aws-sdk-go-v2/config v1.23.0 - github.com/aws/aws-sdk-go-v2/credentials v1.15.2 - github.com/aws/aws-sdk-go-v2/service/route53 v1.34.1 - github.com/aws/aws-sdk-go-v2/service/route53domains v1.19.1 + github.com/aws/aws-sdk-go-v2 v1.23.0 + github.com/aws/aws-sdk-go-v2/config v1.25.3 + github.com/aws/aws-sdk-go-v2/credentials v1.16.2 + github.com/aws/aws-sdk-go-v2/service/route53 v1.34.2 + github.com/aws/aws-sdk-go-v2/service/route53domains v1.19.2 github.com/babolivier/go-doh-client v0.0.0-20201028162107-a76cff4cb8b6 github.com/bhendo/go-powershell v0.0.0-20190719160123-219e7fb4e41e github.com/billputer/go-namecheap v0.0.0-20210108011502-994a912fb7f9 github.com/centralnicgroup-opensource/rtldev-middleware-go-sdk/v3 v3.5.5 github.com/cloudflare/cloudflare-go v0.81.0 - github.com/digitalocean/godo v1.105.1 + github.com/digitalocean/godo v1.106.0 github.com/ditashi/jsbeautifier-go v0.0.0-20141206144643-2520a8026a9c github.com/dnsimple/dnsimple-go v1.2.0 github.com/exoscale/egoscale v0.90.2 @@ -34,7 +34,7 @@ require ( github.com/gopherjs/jquery v0.0.0-20191017083323-73f4c7416038 github.com/hashicorp/vault/api v1.10.0 github.com/jinzhu/copier v0.4.0 - github.com/miekg/dns v1.1.56 + github.com/miekg/dns v1.1.57 github.com/mittwald/go-powerdns v0.6.2 github.com/namedotcom/go v0.0.0-20180403034216-08470befbe04 github.com/nrdcg/goinwx v0.10.0 @@ -52,7 +52,7 @@ require ( github.com/xddxdd/ottoext v0.0.0-20221109171055-210517fa4419 golang.org/x/net v0.18.0 golang.org/x/oauth2 v0.14.0 - google.golang.org/api v0.150.0 + google.golang.org/api v0.151.0 gopkg.in/ns1/ns1-go.v2 v2.7.13 ) @@ -78,15 +78,16 @@ require ( github.com/Azure/go-autorest v14.2.0+incompatible // indirect github.com/AzureAD/microsoft-authentication-library-for-go v1.1.1 // indirect github.com/andybalholm/cascadia v1.3.1 // indirect - github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.14.3 // indirect - github.com/aws/aws-sdk-go-v2/internal/configsources v1.2.2 // indirect - github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.5.2 // indirect - github.com/aws/aws-sdk-go-v2/internal/ini v1.6.0 // indirect - github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.10.2 // indirect - github.com/aws/aws-sdk-go-v2/service/sso v1.17.1 // indirect - github.com/aws/aws-sdk-go-v2/service/ssooidc v1.19.1 // indirect - github.com/aws/aws-sdk-go-v2/service/sts v1.25.1 // indirect - github.com/aws/smithy-go v1.16.0 // indirect + github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.14.4 // indirect + github.com/aws/aws-sdk-go-v2/internal/configsources v1.2.3 // indirect + github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.5.3 // indirect + github.com/aws/aws-sdk-go-v2/internal/ini v1.7.1 // indirect + github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.10.1 // indirect + github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.10.3 // indirect + github.com/aws/aws-sdk-go-v2/service/sso v1.17.2 // indirect + github.com/aws/aws-sdk-go-v2/service/ssooidc v1.20.0 // indirect + github.com/aws/aws-sdk-go-v2/service/sts v1.25.3 // indirect + github.com/aws/smithy-go v1.17.0 // indirect github.com/boombuler/barcode v1.0.1 // indirect github.com/cenkalti/backoff v2.2.1+incompatible // indirect github.com/cenkalti/backoff/v3 v3.0.0 // indirect diff --git a/go.sum b/go.sum index 8da2cf52f3..7c36af7024 100644 --- a/go.sum +++ b/go.sum @@ -33,34 +33,36 @@ github.com/andreyvit/diff v0.0.0-20170406064948-c7f18ee00883/go.mod h1:rCTlJbsFo github.com/andybalholm/cascadia v1.3.1 h1:nhxRkql1kdYCc8Snf7D5/D3spOX+dBgjA6u8x004T2c= github.com/andybalholm/cascadia v1.3.1/go.mod h1:R4bJ1UQfqADjvDa4P6HZHLh/3OxWWEqc0Sk8XGwHqvA= github.com/armon/go-radix v0.0.0-20180808171621-7fddfc383310/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8= -github.com/aws/aws-sdk-go-v2 v1.22.2 h1:lV0U8fnhAnPz8YcdmZVV60+tr6CakHzqA6P8T46ExJI= -github.com/aws/aws-sdk-go-v2 v1.22.2/go.mod h1:Kd0OJtkW3Q0M0lUWGszapWjEvrXDzRW+D21JNsroB+c= -github.com/aws/aws-sdk-go-v2/config v1.23.0 h1:kqzEfGGDIrRJpfJckgwuZfFTbU9NB1jZnRcaO9MpOqE= -github.com/aws/aws-sdk-go-v2/config v1.23.0/go.mod h1:p7wbxKXXjS1GGQOss7VXOazVMFF9bjUGq85/4wR/fSw= -github.com/aws/aws-sdk-go-v2/credentials v1.15.2 h1:rKH7khRMxPdD0u3dHecd0Q7NOVw3EUe7AqdkUOkiOGI= -github.com/aws/aws-sdk-go-v2/credentials v1.15.2/go.mod h1:tXM8wmaeAhfC7nZoCxb0FzM/aRaB1m1WQ7x0qlBLq80= -github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.14.3 h1:G5KawTAkyHH6WyKQCdHiW4h3PmAXNJpOgwKg3H7sDRE= -github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.14.3/go.mod h1:hugKmSFnZB+HgNI1sYGT14BUPZkO6alC/e0AWu+0IAQ= -github.com/aws/aws-sdk-go-v2/internal/configsources v1.2.2 h1:AaQsr5vvGR7rmeSWBtTCcw16tT9r51mWijuCQhzLnq8= -github.com/aws/aws-sdk-go-v2/internal/configsources v1.2.2/go.mod h1:o1IiRn7CWocIFTXJjGKJDOwxv1ibL53NpcvcqGWyRBA= -github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.5.2 h1:UZx8SXZ0YtzRiALzYAWcjb9Y9hZUR7MBKaBQ5ouOjPs= -github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.5.2/go.mod h1:ipuRpcSaklmxR6C39G187TpBAO132gUfleTGccUPs8c= -github.com/aws/aws-sdk-go-v2/internal/ini v1.6.0 h1:hwZB07/beLiCopuRKF0t+dEHmP39iN4YtDh3X5d3hrg= -github.com/aws/aws-sdk-go-v2/internal/ini v1.6.0/go.mod h1:rdAuXeHWhI/zkpYcO5n8WCpaIgY9MUxFyBsuqq3kjyA= -github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.10.2 h1:h7j73yuAVVjic8pqswh+L/7r2IHP43QwRyOu6zcCDDE= -github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.10.2/go.mod h1:H07AHdK5LSy8F7EJUQhoxyiCNkePoHj2D8P2yGTWafo= -github.com/aws/aws-sdk-go-v2/service/route53 v1.34.1 h1:HzAQvhCCrfAtl1uc2w27CJicm0HxdLs6HI2ZTMAZObQ= -github.com/aws/aws-sdk-go-v2/service/route53 v1.34.1/go.mod h1:kEKnDzZL0k1f2sE1utJ/ljZDF17aChgH9j+jUv+jr38= -github.com/aws/aws-sdk-go-v2/service/route53domains v1.19.1 h1:jZSQwl1JAX9GRew86efQecc+pDiAu/WwnefnrUhpNxk= -github.com/aws/aws-sdk-go-v2/service/route53domains v1.19.1/go.mod h1:5uJ+xB76ttmfE0FD6f07TiF3BmwKevmfK7ixkV7mjVA= -github.com/aws/aws-sdk-go-v2/service/sso v1.17.1 h1:km+ZNjtLtpXYf42RdaDZnNHm9s7SYAuDGTafy6nd89A= -github.com/aws/aws-sdk-go-v2/service/sso v1.17.1/go.mod h1:aHBr3pvBSD5MbzOvQtYutyPLLRPbl/y9x86XyJJnUXQ= -github.com/aws/aws-sdk-go-v2/service/ssooidc v1.19.1 h1:iRFNqZH4a67IqPvK8xxtyQYnyrlsvwmpHOe9r55ggBA= -github.com/aws/aws-sdk-go-v2/service/ssooidc v1.19.1/go.mod h1:pTy5WM+6sNv2tB24JNKFtn6EvciQ5k40ZJ0pq/Iaxj0= -github.com/aws/aws-sdk-go-v2/service/sts v1.25.1 h1:txgVXIXWPXyqdiVn92BV6a/rgtpX31HYdsOYj0sVQQQ= -github.com/aws/aws-sdk-go-v2/service/sts v1.25.1/go.mod h1:VAiJiNaoP1L89STFlEMgmHX1bKixY+FaP+TpRFrmyZ4= -github.com/aws/smithy-go v1.16.0 h1:gJZEH/Fqh+RsvlJ1Zt4tVAtV6bKkp3cC+R6FCZMNzik= -github.com/aws/smithy-go v1.16.0/go.mod h1:NukqUGpCZIILqqiV0NIjeFh24kd/FAa4beRb6nbIUPE= +github.com/aws/aws-sdk-go-v2 v1.23.0 h1:PiHAzmiQQr6JULBUdvR8fKlA+UPKLT/8KbiqpFBWiAo= +github.com/aws/aws-sdk-go-v2 v1.23.0/go.mod h1:i1XDttT4rnf6vxc9AuskLc6s7XBee8rlLilKlc03uAA= +github.com/aws/aws-sdk-go-v2/config v1.25.3 h1:E4m9LbwJOoncDNt3e9MPLbz/saxWcGUlZVBydydD6+8= +github.com/aws/aws-sdk-go-v2/config v1.25.3/go.mod h1:tAByZy03nH5jcq0vZmkcVoo6tRzRHEwSFx3QW4NmDw8= +github.com/aws/aws-sdk-go-v2/credentials v1.16.2 h1:0sdZ5cwfOAipTzZ7eOL0gw4LAhk/RZnTa16cDqIt8tg= +github.com/aws/aws-sdk-go-v2/credentials v1.16.2/go.mod h1:sDdvGhXrSVT5yzBDR7qXz+rhbpiMpUYfF3vJ01QSdrc= +github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.14.4 h1:9wKDWEjwSnXZre0/O3+ZwbBl1SmlgWYBbrTV10X/H1s= +github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.14.4/go.mod h1:t4i+yGHMCcUNIX1x7YVYa6bH/Do7civ5I6cG/6PMfyA= +github.com/aws/aws-sdk-go-v2/internal/configsources v1.2.3 h1:DUwbD79T8gyQ23qVXFUthjzVMTviSHi3y4z58KvghhM= +github.com/aws/aws-sdk-go-v2/internal/configsources v1.2.3/go.mod h1:7sGSz1JCKHWWBHq98m6sMtWQikmYPpxjqOydDemiVoM= +github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.5.3 h1:AplLJCtIaUZDCbr6+gLYdsYNxne4iuaboJhVt9d+WXI= +github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.5.3/go.mod h1:ify42Rb7nKeDDPkFjKn7q1bPscVPu/+gmHH8d2c+anU= +github.com/aws/aws-sdk-go-v2/internal/ini v1.7.1 h1:uR9lXYjdPX0xY+NhvaJ4dD8rpSRz5VY81ccIIoNG+lw= +github.com/aws/aws-sdk-go-v2/internal/ini v1.7.1/go.mod h1:6fQQgfuGmw8Al/3M2IgIllycxV7ZW7WCdVSqfBeUiCY= +github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.10.1 h1:rpkF4n0CyFcrJUG/rNNohoTmhtWlFTRI4BsZOh9PvLs= +github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.10.1/go.mod h1:l9ymW25HOqymeU2m1gbUQ3rUIsTwKs8gYHXkqDQUhiI= +github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.10.3 h1:kJOolE8xBAD13xTCgOakByZkyP4D/owNmvEiioeUNAg= +github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.10.3/go.mod h1:Owv1I59vaghv1Ax8zz8ELY8DN7/Y0rGS+WWAmjgi950= +github.com/aws/aws-sdk-go-v2/service/route53 v1.34.2 h1:h9I/GZ7POL9EOyFouZi7P3v0G8Sr/nMIo9uHIyk+NSU= +github.com/aws/aws-sdk-go-v2/service/route53 v1.34.2/go.mod h1:adrwIPgzeyWkAyIlnH7SkTU/UTATCXncCR4fbxwYLhA= +github.com/aws/aws-sdk-go-v2/service/route53domains v1.19.2 h1:k2Swg+KnFtyS3GYy4sUXFUaULpiyrZJsW/8ehoT9/BA= +github.com/aws/aws-sdk-go-v2/service/route53domains v1.19.2/go.mod h1:mSL5mozBzBnMfrmjBe8eASqtOKeYZ4rFiSYAwN5PAGs= +github.com/aws/aws-sdk-go-v2/service/sso v1.17.2 h1:V47N5eKgVZoRSvx2+RQ0EpAEit/pqOhqeSQFiS4OFEQ= +github.com/aws/aws-sdk-go-v2/service/sso v1.17.2/go.mod h1:/pE21vno3q1h4bbhUOEi+6Zu/aT26UK2WKkDXd+TssQ= +github.com/aws/aws-sdk-go-v2/service/ssooidc v1.20.0 h1:/XiEU7VIFcVWRDQLabyrSjBoKIm8UkYgsvWDuFW8Img= +github.com/aws/aws-sdk-go-v2/service/ssooidc v1.20.0/go.mod h1:dWqm5G767qwKPuayKfzm4rjzFmVjiBFbOJrpSPnAMDs= +github.com/aws/aws-sdk-go-v2/service/sts v1.25.3 h1:M2w4kiMGJCCM6Ljmmx/l6mmpfa3gPJVpBencfnsgvqs= +github.com/aws/aws-sdk-go-v2/service/sts v1.25.3/go.mod h1:4EqRHDCKP78hq3zOnmFXu5k0j4bXbRFfCh/zQ6KnEfQ= +github.com/aws/smithy-go v1.17.0 h1:wWJD7LX6PBV6etBUwO0zElG0nWN9rUhp0WdYeHSHAaI= +github.com/aws/smithy-go v1.17.0/go.mod h1:NukqUGpCZIILqqiV0NIjeFh24kd/FAa4beRb6nbIUPE= github.com/babolivier/go-doh-client v0.0.0-20201028162107-a76cff4cb8b6 h1:4NNbNM2Iq/k57qEu7WfL67UrbPq1uFWxW4qODCohi+0= github.com/babolivier/go-doh-client v0.0.0-20201028162107-a76cff4cb8b6/go.mod h1:J29hk+f9lJrblVIfiJOtTFk+OblBawmib4uz/VdKzlg= github.com/bgentry/speakeasy v0.1.0/go.mod h1:+zsyZBPWlz7T6j88CTgSN5bM796AkVf0kBD4zp0CCIs= @@ -95,8 +97,8 @@ github.com/decred/dcrd/crypto/blake256 v1.0.0/go.mod h1:sQl2p6Y26YV+ZOcSTP6thNdn github.com/decred/dcrd/dcrec/secp256k1/v4 v4.0.0-20210816181553-5444fa50b93d/go.mod h1:tmAIfUFEirG/Y8jhZ9M+h36obRZAk/1fcSpXwAVlfqE= github.com/deepmap/oapi-codegen v1.9.1 h1:yHmEnA7jSTUMQgV+uN02WpZtwHnz2CBW3mZRIxr1vtI= github.com/deepmap/oapi-codegen v1.9.1/go.mod h1:PLqNAhdedP8ttRpBBkzLKU3bp+Fpy+tTgeAMlztR2cw= -github.com/digitalocean/godo v1.105.1 h1:3FjFDurw7po27Y0uHhdR+EvwNil06KCeu1Nx/0jZbmI= -github.com/digitalocean/godo v1.105.1/go.mod h1:R6EmmWI8CT1+fCtjWY9UCB+L5uufuZH13wk3YhxycCs= +github.com/digitalocean/godo v1.106.0 h1:m5iErwl3xHovGFlawd50n54ntgXHt1BLsvU6BXsVxEU= +github.com/digitalocean/godo v1.106.0/go.mod h1:R6EmmWI8CT1+fCtjWY9UCB+L5uufuZH13wk3YhxycCs= github.com/ditashi/jsbeautifier-go v0.0.0-20141206144643-2520a8026a9c h1:+Zo5Ca9GH0RoeVZQKzFJcTLoAixx5s5Gq3pTIS+n354= github.com/ditashi/jsbeautifier-go v0.0.0-20141206144643-2520a8026a9c/go.mod h1:HJGU9ULdREjOcVGZVPB5s6zYmHi1RxzT71l2wQyLmnE= github.com/dnaeon/go-vcr v1.2.0 h1:zHCHvJYTMh1N7xnV7zf1m1GPBF9Ad0Jk/whtQ1663qI= @@ -318,8 +320,8 @@ github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWE github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y= github.com/maxatome/go-testdeep v1.12.0 h1:Ql7Go8Tg0C1D/uMMX59LAoYK7LffeJQ6X2T04nTH68g= github.com/maxatome/go-testdeep v1.12.0/go.mod h1:lPZc/HAcJMP92l7yI6TRz1aZN5URwUBUAfUNvrclaNM= -github.com/miekg/dns v1.1.56 h1:5imZaSeoRNvpM9SzWNhEcP9QliKiz20/dA2QabIGVnE= -github.com/miekg/dns v1.1.56/go.mod h1:cRm6Oo2C8TY9ZS/TqsSrseAcncm74lfK5G+ikN2SWWY= +github.com/miekg/dns v1.1.57 h1:Jzi7ApEIzwEPLHWRcafCN9LZSBbqQpxjt/wpgvg7wcM= +github.com/miekg/dns v1.1.57/go.mod h1:uqRjCRUuEAA6qsOiJvDd+CFo/vW+y5WR6SNmHE55hZk= github.com/mitchellh/cli v1.0.0/go.mod h1:hNIlj7HEI86fIcpObd7a0FcrxTWetlwJDGcceTlRvqc= github.com/mitchellh/go-homedir v1.1.0 h1:lukF9ziXFxDFPkA1vsr5zpc1XuPDn/wFntq5mG+4E0Y= github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0= @@ -539,8 +541,8 @@ golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8T golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= -google.golang.org/api v0.150.0 h1:Z9k22qD289SZ8gCJrk4DrWXkNjtfvKAUo/l1ma8eBYE= -google.golang.org/api v0.150.0/go.mod h1:ccy+MJ6nrYFgE3WgRx/AMXOxOmU8Q4hSa+jjibzhxcg= +google.golang.org/api v0.151.0 h1:FhfXLO/NFdJIzQtCqjpysWwqKk8AzGWBUhMIx67cVDU= +google.golang.org/api v0.151.0/go.mod h1:ccy+MJ6nrYFgE3WgRx/AMXOxOmU8Q4hSa+jjibzhxcg= google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= google.golang.org/appengine v1.6.7 h1:FZR1q0exgwxzPzp/aF+VccGrSfxfPpkBqjIIEq3ru6c= From 2ca9c84dbea8069829191d82f2e5218863fd07c4 Mon Sep 17 00:00:00 2001 From: Tom Limoncelli Date: Wed, 22 Nov 2023 08:53:04 -0500 Subject: [PATCH 020/438] Unhide shell-completion flag (#2640) --- commands/completion.go | 1 - 1 file changed, 1 deletion(-) diff --git a/commands/completion.go b/commands/completion.go index 448004555c..7f94348b40 100644 --- a/commands/completion.go +++ b/commands/completion.go @@ -25,7 +25,6 @@ func shellCompletionCommand() *cli.Command { return &cli.Command{ Name: "shell-completion", Usage: "generate shell completion scripts", - Hidden: true, ArgsUsage: fmt.Sprintf("[ %s ]", strings.Join(supportedShells, " | ")), Description: fmt.Sprintf("Generate shell completion script for [ %s ]", strings.Join(supportedShells, " | ")), BashComplete: func(ctx *cli.Context) { From 1470144c29140cc5e930735c4bc642a5889a8e33 Mon Sep 17 00:00:00 2001 From: Costas Drogos Date: Wed, 22 Nov 2023 14:53:54 +0100 Subject: [PATCH 021/438] NS1: Downgrade ns1-go to 2.7.11 (#2642) Co-authored-by: Tom Limoncelli --- go.mod | 2 +- go.sum | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/go.mod b/go.mod index b5c5bb2bf8..649b1ba6d7 100644 --- a/go.mod +++ b/go.mod @@ -53,7 +53,7 @@ require ( golang.org/x/net v0.18.0 golang.org/x/oauth2 v0.14.0 google.golang.org/api v0.151.0 - gopkg.in/ns1/ns1-go.v2 v2.7.13 + gopkg.in/ns1/ns1-go.v2 v2.7.11 ) require ( diff --git a/go.sum b/go.sum index 7c36af7024..46812e5ec5 100644 --- a/go.sum +++ b/go.sum @@ -595,8 +595,8 @@ gopkg.in/ini.v1 v1.67.0 h1:Dgnx+6+nfE+IfzjUEISNeydPJh9AXNNsWbGP9KzCsOA= gopkg.in/ini.v1 v1.67.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k= gopkg.in/mgo.v2 v2.0.0-20160818015218-f2b6f6c918c4/go.mod h1:yeKp02qBN3iKW1OzL3MGk2IdtZzaj7SFntXj72NppTA= gopkg.in/mgo.v2 v2.0.0-20190816093944-a6b53ec6cb22/go.mod h1:yeKp02qBN3iKW1OzL3MGk2IdtZzaj7SFntXj72NppTA= -gopkg.in/ns1/ns1-go.v2 v2.7.13 h1:r07CLALg18f/L1KIK1ZJdbirBV349UtYT1rDWGjnaTk= -gopkg.in/ns1/ns1-go.v2 v2.7.13/go.mod h1:pfaU0vECVP7DIOr453z03HXS6dFJpXdNRwOyRzwmPSc= +gopkg.in/ns1/ns1-go.v2 v2.7.11 h1:fs8fkDjfdWdR2Gg//HO+LHrtC38+Z+xpUs3z4iojsn8= +gopkg.in/ns1/ns1-go.v2 v2.7.11/go.mod h1:pfaU0vECVP7DIOr453z03HXS6dFJpXdNRwOyRzwmPSc= gopkg.in/readline.v1 v1.0.0-20160726135117-62c6fe619375/go.mod h1:lNEQeAhU009zbRxng+XOj5ITVgY24WcbNnQopyfKoYQ= gopkg.in/sourcemap.v1 v1.0.5 h1:inv58fC9f9J3TK2Y2R1NPntXEn3/wjWHkonhIUODNTI= gopkg.in/sourcemap.v1 v1.0.5/go.mod h1:2RlvNNSMglmRrcvhfuzp4hQHwOtjxlbjX7UPY/GXb78= From c7065e67943e00ac412cc9adb6cc21fe7b1c9a60 Mon Sep 17 00:00:00 2001 From: Tom Limoncelli Date: Wed, 22 Nov 2023 09:30:24 -0500 Subject: [PATCH 022/438] DOCS: Expand integration tests explanation (#2645) --- documentation/integration-tests.md | 21 ++++++++++++++++++--- 1 file changed, 18 insertions(+), 3 deletions(-) diff --git a/documentation/integration-tests.md b/documentation/integration-tests.md index dd068edaaf..f47327205b 100644 --- a/documentation/integration-tests.md +++ b/documentation/integration-tests.md @@ -12,8 +12,9 @@ For each step, it will run the config once and expect changes. It will run it ag ## Running a test -1. Define all environment variables expected for the provider you wish to run. I setup a local `.env` file with the appropriate values and use [zoo](https://github.com/jsonmaur/zoo) to run my commands. -2. run `go test -v -provider $NAME` where $NAME is the name of the provider you wish to run. +1. The integration tests need a test domain to run on. All the records of this domain will be deleted! +2. Define all environment variables expected for the provider you wish to run. I setup a local `.env` file with the appropriate values and use [zoo](https://github.com/jsonmaur/zoo) to run my commands. +3. run `go test -v -provider $NAME` where $NAME is the name of the provider you wish to run. Example: @@ -37,8 +38,22 @@ export ROUTE53_DOMAIN="testdomain.tld" go test -v -verbose -provider ROUTE53 ``` +The `-start` and `-end` flags allow you to run just a portion of the tests. + +```shell +go test -v -verbose -provider ROUTE53 -start 16 +go test -v -verbose -provider ROUTE53 -end 5 +go test -v -verbose -provider ROUTE53 -start 16 -end 20 +``` + +The actual tests are in the file `integrationTest/integration_test.go`. The +tests are in a little language which can be used to describe just about any +interaction with the API. Look for the comment `START HERE` or the line +`func makeTests` for instructions. + + {% hint style="warning" %} -**WARNING**: The records in the test domain will be deleted. Only use +**WARNING**: THE RECORDS IN THE TEST DOMAIN WILL BE DELETED. Only use a domain that is not used in production. Some providers have a way to run tests on domains that aren't registered (often a test environment or a side-effect of the company not being a registrar). From 4fc88aa2dcd55bdc7f93d08b917bcd7810fe259e Mon Sep 17 00:00:00 2001 From: Tom Limoncelli Date: Wed, 22 Nov 2023 09:38:58 -0500 Subject: [PATCH 023/438] RType AAAA: Add integration test for AAAA. (#2647) --- integrationTest/integration_test.go | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/integrationTest/integration_test.go b/integrationTest/integration_test.go index 046aa6926d..2fcba9d361 100644 --- a/integrationTest/integration_test.go +++ b/integrationTest/integration_test.go @@ -464,6 +464,10 @@ func a(name, target string) *models.RecordConfig { return makeRec(name, target, "A") } +func aaaa(name, target string) *models.RecordConfig { + return makeRec(name, target, "AAAA") +} + func alias(name, target string) *models.RecordConfig { return makeRec(name, target, "ALIAS") } @@ -873,7 +877,10 @@ func makeTests(t *testing.T) []*TestGroup { // Narrative: That wasn't as hard as expected, eh? Let's test the // other basic record types like AAAA, CNAME, MX and TXT. - // AAAA: TODO(tlim) Add AAAA test. + testgroup("AAAA", + tc("Create AAAA", aaaa("testaaaa", "2607:f8b0:4006:820::2006")), + tc("Change AAAA target", aaaa("testaaaa", "2607:f8b0:4006:820::2013")), + ), // CNAME From 919b19eac3cb7a4554ce6655bf06c99da105f08e Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 22 Nov 2023 09:48:37 -0500 Subject: [PATCH 024/438] Build(deps): Bump github.com/go-jose/go-jose/v3 from 3.0.0 to 3.0.1 (#2646) Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: Tom Limoncelli --- go.mod | 2 +- go.sum | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/go.mod b/go.mod index 649b1ba6d7..14b6f7689e 100644 --- a/go.mod +++ b/go.mod @@ -95,7 +95,7 @@ require ( github.com/davecgh/go-spew v1.1.1 // indirect github.com/deepmap/oapi-codegen v1.9.1 // indirect github.com/fatih/structs v1.1.0 // indirect - github.com/go-jose/go-jose/v3 v3.0.0 // indirect + github.com/go-jose/go-jose/v3 v3.0.1 // indirect github.com/go-test/deep v1.0.3 // indirect github.com/goccy/go-json v0.10.2 // indirect github.com/gofrs/uuid v4.0.0+incompatible // indirect diff --git a/go.sum b/go.sum index 46812e5ec5..cb9d22efdd 100644 --- a/go.sum +++ b/go.sum @@ -127,8 +127,8 @@ github.com/go-acme/lego v2.7.2+incompatible/go.mod h1:yzMNe9CasVUhkquNvti5nAtPmG github.com/go-chi/chi/v5 v5.0.0/go.mod h1:BBug9lr0cqtdAhsu6R4AAdvufI0/XBzAQSsUqJpoZOs= github.com/go-gandi/go-gandi v0.6.0 h1:RgFoevggRRp7hF9XsOmWmtwbUg2axhe2ygEdd6Mtstc= github.com/go-gandi/go-gandi v0.6.0/go.mod h1:9NoYyfWCjFosClPiWjkbbRK5UViaZ4ctpT8/pKSSFlw= -github.com/go-jose/go-jose/v3 v3.0.0 h1:s6rrhirfEP/CGIoc6p+PZAeogN2SxKav6Wp7+dyMWVo= -github.com/go-jose/go-jose/v3 v3.0.0/go.mod h1:RNkWWRld676jZEYoV3+XK8L2ZnNSvIsxFMht0mSX+u8= +github.com/go-jose/go-jose/v3 v3.0.1 h1:pWmKFVtt+Jl0vBZTIpz/eAKwsm6LkIxDVVbFHKkchhA= +github.com/go-jose/go-jose/v3 v3.0.1/go.mod h1:RNkWWRld676jZEYoV3+XK8L2ZnNSvIsxFMht0mSX+u8= github.com/go-openapi/jsonpointer v0.19.5/go.mod h1:Pl9vOtqEWErmShwVjC8pYs9cog34VGT37dQOVbmoatg= github.com/go-openapi/swag v0.19.5/go.mod h1:POnQmlKehdgb5mhVOsnJFsivZCEZ/vjK9gh66Z9tfKk= github.com/go-playground/assert/v2 v2.0.1/go.mod h1:VDjEfimB/XKnb+ZQfWdccd7VUvScMdVu0Titje2rxJ4= From bf9e48d06f522dfa8cd3449d71499f369a39838a Mon Sep 17 00:00:00 2001 From: Steven Hodges <127215833+shodges-vermeer@users.noreply.github.com> Date: Fri, 24 Nov 2023 10:48:29 -0600 Subject: [PATCH 025/438] CLOUDFLARE: Update docs WRT domain creation (#2648) --- documentation/providers/cloudflareapi.md | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/documentation/providers/cloudflareapi.md b/documentation/providers/cloudflareapi.md index 05001abcc2..aa32be0d9e 100644 --- a/documentation/providers/cloudflareapi.md +++ b/documentation/providers/cloudflareapi.md @@ -197,8 +197,7 @@ D("example2.tld", REG_NONE, DnsProvider(DSP_CLOUDFLARE), ## New domains If a domain does not exist in your Cloudflare account, DNSControl -will *not* automatically add it. You'll need to do that via the -control panel manually or via the `dnscontrol create-domains` command. +will automatically add it when `dnscontrol push` is executed. ## Redirects From e783d7024cd62e29c46f4019e26d793e24c79e84 Mon Sep 17 00:00:00 2001 From: Jonathan Bouvier Date: Mon, 27 Nov 2023 17:50:21 -0500 Subject: [PATCH 026/438] ROUTE53: Allow R53_ALIAS records to enable target health evaluation (#2649) --- commands/getZones.go | 3 + commands/r53_test.go | 66 +++++++++++++++++++ commands/types/dnscontrol.d.ts | 13 +++- documentation/functions/domain/R53_ALIAS.md | 6 +- .../record/R53_EVALUATE_TARGET_HEALTH.md | 11 ++++ integrationTest/integration_test.go | 35 ++++++---- models/target.go | 4 +- pkg/js/helpers.js | 19 +++++- pkg/js/parse_tests/019-r53-alias.js | 1 + pkg/js/parse_tests/019-r53-alias.json | 45 +++++++++---- pkg/js/parse_tests/040-r53-zone.json | 3 +- pkg/prettyzone/prettyzone_test.go | 6 +- providers/route53/route53Provider.go | 12 +++- 13 files changed, 188 insertions(+), 36 deletions(-) create mode 100644 documentation/functions/record/R53_EVALUATE_TARGET_HEALTH.md diff --git a/commands/getZones.go b/commands/getZones.go index abc8349b81..97bba18168 100644 --- a/commands/getZones.go +++ b/commands/getZones.go @@ -395,6 +395,9 @@ func makeR53alias(rec *models.RecordConfig, ttl uint32) string { if z, ok := rec.R53Alias["zone_id"]; ok { items = append(items, `R53_ZONE("`+z+`")`) } + if e, ok := rec.R53Alias["evaluate_target_health"]; ok && e == "true" { + items = append(items, "R53_EVALUATE_TARGET_HEALTH(true)") + } if ttl != 0 { items = append(items, fmt.Sprintf("TTL(%d)", ttl)) } diff --git a/commands/r53_test.go b/commands/r53_test.go index 46e281e6d7..27772bc3c9 100644 --- a/commands/r53_test.go +++ b/commands/r53_test.go @@ -68,3 +68,69 @@ func TestR53Test_2ttl(t *testing.T) { t.Errorf("makeR53alias failure: got `%s` want `%s`", g, w) } } + +func TestR53Test_3(t *testing.T) { + rec := models.RecordConfig{ + Type: "R53_ALIAS", + Name: "foo", + NameFQDN: "foo.domain.tld", + } + rec.SetTarget("bar") + rec.R53Alias = make(map[string]string) + rec.R53Alias["type"] = "A" + rec.R53Alias["evaluate_target_health"] = "true" + w := `R53_ALIAS("foo", "A", "bar", R53_EVALUATE_TARGET_HEALTH(true))` + if g := makeR53alias(&rec, 0); g != w { + t.Errorf("makeR53alias failure: got `%s` want `%s`", g, w) + } +} + +func TestR53Test_3ttl(t *testing.T) { + rec := models.RecordConfig{ + Type: "R53_ALIAS", + Name: "foo", + NameFQDN: "foo.domain.tld", + } + rec.SetTarget("bar") + rec.R53Alias = make(map[string]string) + rec.R53Alias["type"] = "A" + rec.R53Alias["evaluate_target_health"] = "true" + w := `R53_ALIAS("foo", "A", "bar", R53_EVALUATE_TARGET_HEALTH(true), TTL(123))` + if g := makeR53alias(&rec, 123); g != w { + t.Errorf("makeR53alias failure: got `%s` want `%s`", g, w) + } +} + +func TestR53Test_4(t *testing.T) { + rec := models.RecordConfig{ + Type: "R53_ALIAS", + Name: "foo", + NameFQDN: "foo.domain.tld", + } + rec.SetTarget("bar") + rec.R53Alias = make(map[string]string) + rec.R53Alias["type"] = "A" + rec.R53Alias["zone_id"] = "blarg" + rec.R53Alias["evaluate_target_health"] = "true" + w := `R53_ALIAS("foo", "A", "bar", R53_ZONE("blarg"), R53_EVALUATE_TARGET_HEALTH(true))` + if g := makeR53alias(&rec, 0); g != w { + t.Errorf("makeR53alias failure: got `%s` want `%s`", g, w) + } +} + +func TestR53Test_4ttl(t *testing.T) { + rec := models.RecordConfig{ + Type: "R53_ALIAS", + Name: "foo", + NameFQDN: "foo.domain.tld", + } + rec.SetTarget("bar") + rec.R53Alias = make(map[string]string) + rec.R53Alias["type"] = "A" + rec.R53Alias["zone_id"] = "blarg" + rec.R53Alias["evaluate_target_health"] = "true" + w := `R53_ALIAS("foo", "A", "bar", R53_ZONE("blarg"), R53_EVALUATE_TARGET_HEALTH(true), TTL(123))` + if g := makeR53alias(&rec, 123); g != w { + t.Errorf("makeR53alias failure: got `%s` want `%s`", g, w) + } +} diff --git a/commands/types/dnscontrol.d.ts b/commands/types/dnscontrol.d.ts index 0fac62a7f9..58c9d8ad2a 100644 --- a/commands/types/dnscontrol.d.ts +++ b/commands/types/dnscontrol.d.ts @@ -2279,11 +2279,13 @@ declare const PURGE: DomainModifier; * * _S3 bucket_ (configured as website): specify the hosted zone ID for the region that you created the bucket in. You can find it in [the List of regions and hosted Zone IDs](https://docs.aws.amazon.com/general/latest/gr/rande.html#s3_region) * * _Another Route 53 record_: you can either specify the correct zone id or do not specify anything and DNSControl will figure out the right zone id. (Note: Route53 alias can't reference a record in a different zone). * + * Target health evaluation can be enabled with the [`R53_EVALUATE_TARGET_HEALTH`](../record/R53_EVALUATE_TARGET_HEALTH.md) record modifier. + * * ```javascript * D("example.com", REG_MY_PROVIDER, DnsProvider("ROUTE53"), * R53_ALIAS("foo", "A", "bar"), // record in same zone * R53_ALIAS("foo", "A", "bar", R53_ZONE("Z35SXDOTRQ7X7K")), // record in same zone, zone specified - * R53_ALIAS("foo", "A", "blahblah.elasticloadbalancing.us-west-1.amazonaws.com.", R53_ZONE("Z368ELLRRE2KJ0")), // a classic ELB in us-west-1 + * R53_ALIAS("foo", "A", "blahblah.elasticloadbalancing.us-west-1.amazonaws.com.", R53_ZONE("Z368ELLRRE2KJ0"), R53_EVALUATE_TARGET_HEALTH(true)), // a classic ELB in us-west-1 with target health evaluation enabled * R53_ALIAS("foo", "A", "blahblah.elasticbeanstalk.us-west-2.amazonaws.com.", R53_ZONE("Z38NKT9BP95V3O")), // an Elastic Beanstalk environment in us-west-2 * R53_ALIAS("foo", "A", "blahblah-bucket.s3-website-us-west-1.amazonaws.com.", R53_ZONE("Z2F56UZL2M1ACD")), // a website S3 Bucket in us-west-1 * ); @@ -2291,7 +2293,14 @@ declare const PURGE: DomainModifier; * * @see https://docs.dnscontrol.org/language-reference/domain-modifiers/service-provider-specific/amazon-route-53/r53_alias */ -declare function R53_ALIAS(name: string, target: string, zone_idModifier: DomainModifier & RecordModifier): DomainModifier; +declare function R53_ALIAS(name: string, target: string, zone_idModifier: DomainModifier & RecordModifier, evaluatetargethealthModifier: RecordModifier): DomainModifier; + +/** + * `R53_EVALUATE_TARGET_HEALTH` lets you enable target health evaluation for a [`R53_ALIAS()`](../domain/R53_ALIAS.md) record. Omitting `R53_EVALUATE_TARGET_HEALTH()` from `R53_ALIAS()` set the behavior to false. + * + * @see https://docs.dnscontrol.org/language-reference/record-modifiers/service-provider-specific/amazon-route-53/r53_evaluate_target_health + */ +declare function R53_EVALUATE_TARGET_HEALTH(enabled: bool): RecordModifier; /** * `R53_ZONE` lets you specify the AWS Zone ID for an entire domain ([`D()`](../global/D.md)) or a specific [`R53_ALIAS()`](../domain/R53_ALIAS.md) record. diff --git a/documentation/functions/domain/R53_ALIAS.md b/documentation/functions/domain/R53_ALIAS.md index 3754a22c39..cd0e3737f5 100644 --- a/documentation/functions/domain/R53_ALIAS.md +++ b/documentation/functions/domain/R53_ALIAS.md @@ -4,10 +4,12 @@ parameters: - name - target - ZONE_ID modifier + - EvaluateTargetHealth modifier parameter_types: name: string target: string ZONE_ID modifier: DomainModifier & RecordModifier + EvaluateTargetHealth modifier: RecordModifier provider: ROUTE53 --- @@ -37,12 +39,14 @@ The zone id can be found depending on the target type: * _S3 bucket_ (configured as website): specify the hosted zone ID for the region that you created the bucket in. You can find it in [the List of regions and hosted Zone IDs](https://docs.aws.amazon.com/general/latest/gr/rande.html#s3_region) * _Another Route 53 record_: you can either specify the correct zone id or do not specify anything and DNSControl will figure out the right zone id. (Note: Route53 alias can't reference a record in a different zone). +Target health evaluation can be enabled with the [`R53_EVALUATE_TARGET_HEALTH`](../record/R53_EVALUATE_TARGET_HEALTH.md) record modifier. + {% code title="dnsconfig.js" %} ```javascript D("example.com", REG_MY_PROVIDER, DnsProvider("ROUTE53"), R53_ALIAS("foo", "A", "bar"), // record in same zone R53_ALIAS("foo", "A", "bar", R53_ZONE("Z35SXDOTRQ7X7K")), // record in same zone, zone specified - R53_ALIAS("foo", "A", "blahblah.elasticloadbalancing.us-west-1.amazonaws.com.", R53_ZONE("Z368ELLRRE2KJ0")), // a classic ELB in us-west-1 + R53_ALIAS("foo", "A", "blahblah.elasticloadbalancing.us-west-1.amazonaws.com.", R53_ZONE("Z368ELLRRE2KJ0"), R53_EVALUATE_TARGET_HEALTH(true)), // a classic ELB in us-west-1 with target health evaluation enabled R53_ALIAS("foo", "A", "blahblah.elasticbeanstalk.us-west-2.amazonaws.com.", R53_ZONE("Z38NKT9BP95V3O")), // an Elastic Beanstalk environment in us-west-2 R53_ALIAS("foo", "A", "blahblah-bucket.s3-website-us-west-1.amazonaws.com.", R53_ZONE("Z2F56UZL2M1ACD")), // a website S3 Bucket in us-west-1 ); diff --git a/documentation/functions/record/R53_EVALUATE_TARGET_HEALTH.md b/documentation/functions/record/R53_EVALUATE_TARGET_HEALTH.md new file mode 100644 index 0000000000..7ed12b3853 --- /dev/null +++ b/documentation/functions/record/R53_EVALUATE_TARGET_HEALTH.md @@ -0,0 +1,11 @@ +--- +name: R53_EVALUATE_TARGET_HEALTH +parameters: + - enabled +parameter_types: + enabled: bool +ts_return: RecordModifier +provider: ROUTE53 +--- + +`R53_EVALUATE_TARGET_HEALTH` lets you enable target health evaluation for a [`R53_ALIAS()`](../domain/R53_ALIAS.md) record. Omitting `R53_EVALUATE_TARGET_HEALTH()` from `R53_ALIAS()` set the behavior to false. diff --git a/integrationTest/integration_test.go b/integrationTest/integration_test.go index 2fcba9d361..821d1f09e5 100644 --- a/integrationTest/integration_test.go +++ b/integrationTest/integration_test.go @@ -597,10 +597,11 @@ func ptr(name, target string) *models.RecordConfig { return makeRec(name, target, "PTR") } -func r53alias(name, aliasType, target string) *models.RecordConfig { +func r53alias(name, aliasType, target, evalTargetHealth string) *models.RecordConfig { r := makeRec(name, target, "R53_ALIAS") r.R53Alias = map[string]string{ - "type": aliasType, + "type": aliasType, + "evaluate_target_health": evalTargetHealth, } return r } @@ -1581,12 +1582,12 @@ func makeTests(t *testing.T) []*TestGroup { tc("ALIAS to A record in same zone", a("kyle", "1.2.3.4"), a("cartman", "2.3.4.5"), - r53alias("kenny", "A", "kyle.**current-domain**"), + r53alias("kenny", "A", "kyle.**current-domain**", "false"), ), tc("modify an r53 alias", a("kyle", "1.2.3.4"), a("cartman", "2.3.4.5"), - r53alias("kenny", "A", "cartman.**current-domain**"), + r53alias("kenny", "A", "cartman.**current-domain**", "false"), ), ), @@ -1599,12 +1600,12 @@ func makeTests(t *testing.T) []*TestGroup { tc("add an alias to 18", cname("dev-system18", "ec2-54-91-33-155.compute-1.amazonaws.com."), cname("dev-system19", "ec2-54-91-99-999.compute-1.amazonaws.com."), - r53alias("dev-system", "CNAME", "dev-system18.**current-domain**"), + r53alias("dev-system", "CNAME", "dev-system18.**current-domain**", "false"), ), tc("modify alias to 19", cname("dev-system18", "ec2-54-91-33-155.compute-1.amazonaws.com."), cname("dev-system19", "ec2-54-91-99-999.compute-1.amazonaws.com."), - r53alias("dev-system", "CNAME", "dev-system19.**current-domain**"), + r53alias("dev-system", "CNAME", "dev-system19.**current-domain**", "false"), ), tc("remove alias", cname("dev-system18", "ec2-54-91-33-155.compute-1.amazonaws.com."), @@ -1613,17 +1614,17 @@ func makeTests(t *testing.T) []*TestGroup { tc("add an alias back", cname("dev-system18", "ec2-54-91-33-155.compute-1.amazonaws.com."), cname("dev-system19", "ec2-54-91-99-999.compute-1.amazonaws.com."), - r53alias("dev-system", "CNAME", "dev-system19.**current-domain**"), + r53alias("dev-system", "CNAME", "dev-system19.**current-domain**", "false"), ), tc("remove cnames", - r53alias("dev-system", "CNAME", "dev-system19.**current-domain**"), + r53alias("dev-system", "CNAME", "dev-system19.**current-domain**", "false"), ), ), testgroup("R53_ALIAS_CNAME", requires(providers.CanUseRoute53Alias), tc("create alias+cname in one step", - r53alias("dev-system", "CNAME", "dev-system18.**current-domain**"), + r53alias("dev-system", "CNAME", "dev-system18.**current-domain**", "false"), cname("dev-system18", "ec2-54-91-33-155.compute-1.amazonaws.com."), ), ), @@ -1634,7 +1635,7 @@ func makeTests(t *testing.T) []*TestGroup { // See https://github.com/StackExchange/dnscontrol/issues/2107 requires(providers.CanUseRoute53Alias), tc("loop should fail", - r53alias("test-islandora", "CNAME", "test-islandora.**current-domain**"), + r53alias("test-islandora", "CNAME", "test-islandora.**current-domain**", "false"), ), ), @@ -1642,7 +1643,7 @@ func makeTests(t *testing.T) []*TestGroup { testgroup("R53_alias pre-existing", requires(providers.CanUseRoute53Alias), tc("Create some records", - r53alias("dev-system", "CNAME", "dev-system18.**current-domain**"), + r53alias("dev-system", "CNAME", "dev-system18.**current-domain**", "false"), cname("dev-system18", "ec2-54-91-33-155.compute-1.amazonaws.com."), ), tc("Add a new record - ignoring foo", @@ -1651,6 +1652,18 @@ func makeTests(t *testing.T) []*TestGroup { ), ), + testgroup("R53_alias evaluate_target_health", + requires(providers.CanUseRoute53Alias), + tc("Create alias and cname", + r53alias("test-record", "CNAME", "test-record-1.**current-domain**", "false"), + cname("test-record-1", "ec2-54-91-33-155.compute-1.amazonaws.com."), + ), + tc("modify evaluate target health", + r53alias("test-record", "CNAME", "test-record-1.**current-domain**", "true"), + cname("test-record-1", "ec2-54-91-33-155.compute-1.amazonaws.com."), + ), + ), + // CLOUDFLAREAPI features testgroup("CF_REDIRECT", diff --git a/models/target.go b/models/target.go index 5602c3a71e..55a843c937 100644 --- a/models/target.go +++ b/models/target.go @@ -49,7 +49,7 @@ func (rc *RecordConfig) GetTargetCombined() string { switch rc.Type { // #rtype_variations case "R53_ALIAS": // Differentiate between multiple R53_ALIASs on the same label. - return fmt.Sprintf("%s atype=%s zone_id=%s", rc.target, rc.R53Alias["type"], rc.R53Alias["zone_id"]) + return fmt.Sprintf("%s atype=%s zone_id=%s evaluate_target_health=%s", rc.target, rc.R53Alias["type"], rc.R53Alias["zone_id"], rc.R53Alias["evaluate_target_health"]) case "AZURE_ALIAS": // Differentiate between multiple AZURE_ALIASs on the same label. return fmt.Sprintf("%s atype=%s", rc.target, rc.AzureAlias["type"]) @@ -115,7 +115,7 @@ func (rc *RecordConfig) GetTargetDebug() string { case "NAPTR": content += fmt.Sprintf(" naptrorder=%d naptrpreference=%d naptrflags=%s naptrservice=%s naptrregexp=%s", rc.NaptrOrder, rc.NaptrPreference, rc.NaptrFlags, rc.NaptrService, rc.NaptrRegexp) case "R53_ALIAS": - content += fmt.Sprintf(" type=%s zone_id=%s", rc.R53Alias["type"], rc.R53Alias["zone_id"]) + content += fmt.Sprintf(" type=%s zone_id=%s evaluate_target_health=%s", rc.R53Alias["type"], rc.R53Alias["zone_id"], rc.R53Alias["evaluate_target_health"]) case "SOA": content = fmt.Sprintf("%s ns=%v mbox=%v serial=%v refresh=%v retry=%v expire=%v minttl=%v", rc.Type, rc.target, rc.SoaMbox, rc.SoaSerial, rc.SoaRefresh, rc.SoaRetry, rc.SoaExpire, rc.SoaMinttl) case "SRV": diff --git a/pkg/js/helpers.js b/pkg/js/helpers.js index df15af2ca2..ac817adc53 100644 --- a/pkg/js/helpers.js +++ b/pkg/js/helpers.js @@ -328,8 +328,14 @@ var R53_ALIAS = recordBuilder('R53_ALIAS', { record.target = args.target; if (_.isObject(record.r53_alias)) { record.r53_alias['type'] = args.type; + if (!_.isString(record.r53_alias['evaluate_target_health'])) { + record.r53_alias['evaluate_target_health'] = 'false'; + } } else { - record.r53_alias = { type: args.type }; + record.r53_alias = { + type: args.type, + evaluate_target_health: 'false', + }; } }, }); @@ -347,6 +353,17 @@ function R53_ZONE(zone_id) { }; } +// R53_EVALUATE_TARGET_HEALTH(enabled) +function R53_EVALUATE_TARGET_HEALTH(enabled) { + return function (r) { + if (_.isObject(r.r53_alias)) { + r.r53_alias['evaluate_target_health'] = enabled.toString(); + } else { + r.r53_alias = { evaluate_target_health: enabled.toString() }; + } + }; +} + function validateR53AliasType(value) { if (!_.isString(value)) { return false; diff --git a/pkg/js/parse_tests/019-r53-alias.js b/pkg/js/parse_tests/019-r53-alias.js index 9fae124639..6c3f55a5e1 100644 --- a/pkg/js/parse_tests/019-r53-alias.js +++ b/pkg/js/parse_tests/019-r53-alias.js @@ -2,6 +2,7 @@ D("foo.com", "none", R53_ALIAS("mxtest", "MX", "foo.com."), R53_ALIAS("atest", "A", "foo.com."), R53_ALIAS("atest", "A", "foo.com.", R53_ZONE("Z2FTEDLFRTF")), + R53_ALIAS("aevaltargethealthtest", "A", "foo.com.", R53_EVALUATE_TARGET_HEALTH(true)), R53_ALIAS("aaaatest", "AAAA", "foo.com."), R53_ALIAS("aaaatest", "AAAA", "foo.com.", R53_ZONE("ERERTFGFGF")), R53_ALIAS("cnametest", "CNAME", "foo.com."), diff --git a/pkg/js/parse_tests/019-r53-alias.json b/pkg/js/parse_tests/019-r53-alias.json index 8e91cec69b..40136a072c 100644 --- a/pkg/js/parse_tests/019-r53-alias.json +++ b/pkg/js/parse_tests/019-r53-alias.json @@ -12,7 +12,8 @@ "name": "mxtest", "target": "foo.com.", "r53_alias": { - "type": "MX" + "type": "MX", + "evaluate_target_health": "false" } }, { @@ -20,7 +21,8 @@ "name": "atest", "target": "foo.com.", "r53_alias": { - "type": "A" + "type": "A", + "evaluate_target_health": "false" } }, { @@ -29,7 +31,17 @@ "target": "foo.com.", "r53_alias": { "type": "A", - "zone_id": "Z2FTEDLFRTF" + "zone_id": "Z2FTEDLFRTF", + "evaluate_target_health": "false" + } + }, + { + "type": "R53_ALIAS", + "name": "aevaltargethealthtest", + "target": "foo.com.", + "r53_alias": { + "type": "A", + "evaluate_target_health": "true" } }, { @@ -37,7 +49,8 @@ "name": "aaaatest", "target": "foo.com.", "r53_alias": { - "type": "AAAA" + "type": "AAAA", + "evaluate_target_health": "false" } }, { @@ -46,7 +59,8 @@ "target": "foo.com.", "r53_alias": { "type": "AAAA", - "zone_id": "ERERTFGFGF" + "zone_id": "ERERTFGFGF", + "evaluate_target_health": "false" } }, { @@ -54,7 +68,8 @@ "name": "cnametest", "target": "foo.com.", "r53_alias": { - "type": "CNAME" + "type": "CNAME", + "evaluate_target_health": "false" } }, { @@ -62,7 +77,8 @@ "name": "ptrtest", "target": "foo.com.", "r53_alias": { - "type": "PTR" + "type": "PTR", + "evaluate_target_health": "false" } }, { @@ -70,7 +86,8 @@ "name": "txttest", "target": "foo.com.", "r53_alias": { - "type": "TXT" + "type": "TXT", + "evaluate_target_health": "false" } }, { @@ -78,7 +95,8 @@ "name": "srvtest", "target": "foo.com.", "r53_alias": { - "type": "SRV" + "type": "SRV", + "evaluate_target_health": "false" } }, { @@ -86,7 +104,8 @@ "name": "spftest", "target": "foo.com.", "r53_alias": { - "type": "SPF" + "type": "SPF", + "evaluate_target_health": "false" } }, { @@ -94,7 +113,8 @@ "name": "caatest", "target": "foo.com.", "r53_alias": { - "type": "CAA" + "type": "CAA", + "evaluate_target_health": "false" } }, { @@ -102,7 +122,8 @@ "name": "naptrtest", "target": "foo.com.", "r53_alias": { - "type": "NAPTR" + "type": "NAPTR", + "evaluate_target_health": "false" } } ] diff --git a/pkg/js/parse_tests/040-r53-zone.json b/pkg/js/parse_tests/040-r53-zone.json index 08ab64f213..96f2fae7c1 100644 --- a/pkg/js/parse_tests/040-r53-zone.json +++ b/pkg/js/parse_tests/040-r53-zone.json @@ -21,7 +21,8 @@ "name": "atest", "r53_alias": { "type": "A", - "zone_id": "Z2FTEDLFRTZ" + "zone_id": "Z2FTEDLFRTZ", + "evaluate_target_health": "false" }, "target": "foo.com." } diff --git a/pkg/prettyzone/prettyzone_test.go b/pkg/prettyzone/prettyzone_test.go index 88f93454dd..38070d9e34 100644 --- a/pkg/prettyzone/prettyzone_test.go +++ b/pkg/prettyzone/prettyzone_test.go @@ -323,10 +323,10 @@ func TestWriteZoneFileSynth(t *testing.T) { ; c4 @ IN A 192.30.252.153 IN A 192.30.252.154 -;myalias IN R53_ALIAS atype= zone_id= -;myalias IN R53_ALIAS atype= zone_id= +;myalias IN R53_ALIAS atype= zone_id= evaluate_target_health= +;myalias IN R53_ALIAS atype= zone_id= evaluate_target_health= www IN CNAME bosun.org. -;zalias IN R53_ALIAS atype= zone_id= +;zalias IN R53_ALIAS atype= zone_id= evaluate_target_health= ` if buf.String() != expected { t.Log(buf.String()) diff --git a/providers/route53/route53Provider.go b/providers/route53/route53Provider.go index fd3e7dd1f9..b1458d370c 100644 --- a/providers/route53/route53Provider.go +++ b/providers/route53/route53Provider.go @@ -7,6 +7,7 @@ import ( "fmt" "log" "sort" + "strconv" "strings" "time" "unicode/utf8" @@ -435,8 +436,9 @@ func nativeToRecords(set r53Types.ResourceRecordSet, origin string) ([]*models.R Type: "R53_ALIAS", TTL: 300, R53Alias: map[string]string{ - "type": string(set.Type), - "zone_id": aws.ToString(set.AliasTarget.HostedZoneId), + "type": string(set.Type), + "zone_id": aws.ToString(set.AliasTarget.HostedZoneId), + "evaluate_target_health": strconv.FormatBool(set.AliasTarget.EvaluateTargetHealth), }, } rc.SetLabelFromFQDN(unescape(set.Name), origin) @@ -510,12 +512,16 @@ func nativeToRecords(set r53Types.ResourceRecordSet, origin string) ([]*models.R func aliasToRRSet(zone r53Types.HostedZone, r *models.RecordConfig) *r53Types.ResourceRecordSet { target := r.GetTargetField() zoneID := getZoneID(zone, r) + evalTargetHealth, err := strconv.ParseBool(r.R53Alias["evaluate_target_health"]) + if err != nil { + evalTargetHealth = false + } rrset := &r53Types.ResourceRecordSet{ Type: r53Types.RRType(r.R53Alias["type"]), AliasTarget: &r53Types.AliasTarget{ DNSName: &target, HostedZoneId: aws.String(zoneID), - EvaluateTargetHealth: false, + EvaluateTargetHealth: evalTargetHealth, }, } return rrset From b5010e7d9ca060029c4c5235a3476fcfc6e29e17 Mon Sep 17 00:00:00 2001 From: Tom Limoncelli Date: Mon, 27 Nov 2023 18:04:48 -0500 Subject: [PATCH 027/438] DOCS: Warn against common integration test mistake (#2653) --- documentation/adding-new-rtypes.md | 3 ++- documentation/integration-tests.md | 3 ++- documentation/providers/cloudflareapi.md | 1 + documentation/providers/hexonet.md | 2 +- documentation/writing-providers.md | 3 ++- 5 files changed, 8 insertions(+), 4 deletions(-) diff --git a/documentation/adding-new-rtypes.md b/documentation/adding-new-rtypes.md index 264bef43cc..02f486c092 100644 --- a/documentation/adding-new-rtypes.md +++ b/documentation/adding-new-rtypes.md @@ -252,7 +252,7 @@ in the source code. To run the integration test with the BIND provider: ```shell -cd integrationTest/ +cd integrationTest # NOTE: Not needed if already in that subdirectory go test -v -verbose -provider BIND ``` @@ -275,6 +275,7 @@ For example, this will run the tests on Amazon AWS Route53: export R53_DOMAIN=dnscontroltest-r53.com # Use a test domain. export R53_KEY_ID=CHANGE_TO_THE_ID export R53_KEY='CHANGE_TO_THE_KEY' +cd integrationTest # NOTE: Not needed if already in that subdirectory go test -v -verbose -provider ROUTE53 ``` diff --git a/documentation/integration-tests.md b/documentation/integration-tests.md index f47327205b..af81388071 100644 --- a/documentation/integration-tests.md +++ b/documentation/integration-tests.md @@ -14,7 +14,7 @@ For each step, it will run the config once and expect changes. It will run it ag 1. The integration tests need a test domain to run on. All the records of this domain will be deleted! 2. Define all environment variables expected for the provider you wish to run. I setup a local `.env` file with the appropriate values and use [zoo](https://github.com/jsonmaur/zoo) to run my commands. -3. run `go test -v -provider $NAME` where $NAME is the name of the provider you wish to run. +3. run `cd integrationTest && go test -v -provider $NAME` where $NAME is the name of the provider you wish to run. Example: @@ -35,6 +35,7 @@ export ROUTE53_DOMAIN="testdomain.tld" ``` ```shell +cd integrationTest # NOTE: Not needed if already in that subdirectory go test -v -verbose -provider ROUTE53 ``` diff --git a/documentation/providers/cloudflareapi.md b/documentation/providers/cloudflareapi.md index aa32be0d9e..2a181fcb0b 100644 --- a/documentation/providers/cloudflareapi.md +++ b/documentation/providers/cloudflareapi.md @@ -265,6 +265,7 @@ This flag is intended for use with legacy domains where the integration test cre have access to read/edit Workers. This flag will eventually go away. ```shell +cd integrationTest # NOTE: Not needed if already in that subdirectory go test -v -verbose -provider CLOUDFLAREAPI -cfworkers=false ``` diff --git a/documentation/providers/hexonet.md b/documentation/providers/hexonet.md index 5fc8539fbe..5a2dbcbec1 100644 --- a/documentation/providers/hexonet.md +++ b/documentation/providers/hexonet.md @@ -57,11 +57,11 @@ dnscontrol get-zones --format=nameonly hexonet HEXONET all ``` ```shell # Review the output. Pick one domain and set HEXONET_DOMAIN. -cd integrationTest/ export HEXONET_DOMAIN=yodream.com # Pick a domain name. export HEXONET_ENTITY=OTE export HEXONET_UID=test.user export HEXONET_PW=test.passw0rd +cd integrationTest # NOTE: Not needed if already in that subdirectory go test -v -verbose -provider HEXONET ``` diff --git a/documentation/writing-providers.md b/documentation/writing-providers.md index b83e83f962..2f1435366a 100644 --- a/documentation/writing-providers.md +++ b/documentation/writing-providers.md @@ -181,7 +181,7 @@ Integration tests use a test account and a real domain. For example, this will run the tests using BIND: ```shell -cd integrationTest/ +cd integrationTest # NOTE: Not needed if already in that subdirectory go test -v -verbose -provider BIND ``` @@ -193,6 +193,7 @@ This will run the tests on Amazon AWS Route53: export R53_DOMAIN=dnscontroltest-r53.com # Use a test domain. export R53_KEY_ID='CHANGE_TO_THE_ID' export R53_KEY='CHANGE_TO_THE_KEY' +cd integrationTest # NOTE: Not needed if already in that subdirectory go test -v -verbose -provider ROUTE53 ``` From 69fb3b26d3f53bd1ebc9cc3034337f04c7c27c6b Mon Sep 17 00:00:00 2001 From: Brice Figureau Date: Tue, 28 Nov 2023 00:18:24 +0100 Subject: [PATCH 028/438] OVH: Allow ovh provider to connect to other endpoints than EU (#2625) (#2651) Co-authored-by: Tom Limoncelli --- documentation/providers/ovh.md | 21 +++++++++++-- integrationTest/providers.json | 3 +- providers/ovh/ovhProvider.go | 29 ++++++++++++++++-- providers/ovh/ovhProvider_test.go | 51 +++++++++++++++++++++++++++++++ 4 files changed, 98 insertions(+), 6 deletions(-) create mode 100644 providers/ovh/ovhProvider_test.go diff --git a/documentation/providers/ovh.md b/documentation/providers/ovh.md index 70d0153ede..dd19ccd7c6 100644 --- a/documentation/providers/ovh.md +++ b/documentation/providers/ovh.md @@ -1,7 +1,7 @@ ## Configuration To use this provider, add an entry to `creds.json` with `TYPE` set to `OVH` -along with a OVH app-key, app-secret-key and consumer-key. +along with a OVH app-key, app-secret-key, consumer-key and optionally endpoint. Example: @@ -12,7 +12,8 @@ Example: "TYPE": "OVH", "app-key": "your app key", "app-secret-key": "your app secret key", - "consumer-key": "your consumer key" + "consumer-key": "your consumer key", + "endpoint": "eu" } } ``` @@ -20,6 +21,13 @@ Example: See [the Activation section](#activation) for details on obtaining these credentials. +`endpoint` can take the following values: + +* `eu` (the default), for connecting to the OVH European endpoint +* `ca` for connecting to OVH Canada API endpoint +* `us` for connecting to the OVH USA API endpoint +* an url for connecting to a different endpoint than the ones above + ## Metadata This provider does not recognize any special metadata fields unique to OVH. @@ -58,7 +66,7 @@ To obtain the OVH keys, one need to register an app at OVH by following the [OVH API Getting Started](https://docs.ovh.com/gb/en/customer/first-steps-with-ovh-api/) It consist in declaring the app at https://eu.api.ovh.com/createApp/ -which gives the `app-key` and `app-secret-key`. +which gives the `app-key` and `app-secret-key`. If your domains and zones are located in another region, see below for the correct url to use. Once done, to obtain the `consumer-key` it is necessary to authorize the just created app to access the data in a specific account: @@ -115,6 +123,13 @@ authorizing it to access your zones and domains. Do not forget to fill the `consumer-key` of your `creds.json`. +For accessing the other international endpoints such as US and CA, change the `https://eu.api.ovh.com` used above to one of the following: + +* Canada endpoint: `https://ca.api.ovh.com` +* US endpoint: `https://api.us.ovhcloud.com` + +Do not forget to fill the `endpoint` of your `creds.json` if you use an endpoint different than the EU one. + ## New domains If a domain does not exist in your OVH account, DNSControl diff --git a/integrationTest/providers.json b/integrationTest/providers.json index 019876b8d5..ac55cbe51c 100644 --- a/integrationTest/providers.json +++ b/integrationTest/providers.json @@ -232,7 +232,8 @@ "app-key": "$OVH_APP_KEY", "app-secret-key": "$OVH_APP_SECRET_KEY", "consumer-key": "$OVH_CONSUMER_KEY", - "domain": "$OVH_DOMAIN" + "domain": "$OVH_DOMAIN", + "endpoint": "$OVH_ENDPOINT" }, "PACKETFRAME": { "TYPE": "PACKETFRAME", diff --git a/providers/ovh/ovhProvider.go b/providers/ovh/ovhProvider.go index d3db32430b..c10f00e818 100644 --- a/providers/ovh/ovhProvider.go +++ b/providers/ovh/ovhProvider.go @@ -34,7 +34,7 @@ var features = providers.DocumentationNotes{ func newOVH(m map[string]string, metadata json.RawMessage) (*ovhProvider, error) { appKey, appSecretKey, consumerKey := m["app-key"], m["app-secret-key"], m["consumer-key"] - c, err := ovh.NewClient(ovh.OvhEU, appKey, appSecretKey, consumerKey) + c, err := ovh.NewClient(getOVHEndpoint(m), appKey, appSecretKey, consumerKey) if c == nil { return nil, err } @@ -46,6 +46,22 @@ func newOVH(m map[string]string, metadata json.RawMessage) (*ovhProvider, error) return ovh, nil } +func getOVHEndpoint(params map[string]string) string { + if ep, ok := params["endpoint"]; ok && ep != "" { + switch strings.ToLower(ep) { + case "eu": + return ovh.OvhEU + case "ca": + return ovh.OvhCA + case "us": + return ovh.OvhUS + default: + return ep + } + } + return ovh.OvhEU +} + func newDsp(conf map[string]string, metadata json.RawMessage) (providers.DNSServiceProvider, error) { return newOVH(conf, metadata) } @@ -126,7 +142,16 @@ func (c *ovhProvider) GetZoneRecordsCorrections(dc *models.DomainConfig, actual return nil, err } - if len(corrections) > 0 { + // Only refresh zone if there's a real modification + reportOnlyCorrections := true + for _, c := range corrections { + if c.F != nil { + reportOnlyCorrections = false + break + } + } + + if !reportOnlyCorrections { corrections = append(corrections, &models.Correction{ Msg: "REFRESH zone " + dc.Name, F: func() error { diff --git a/providers/ovh/ovhProvider_test.go b/providers/ovh/ovhProvider_test.go new file mode 100644 index 0000000000..b5a07cea88 --- /dev/null +++ b/providers/ovh/ovhProvider_test.go @@ -0,0 +1,51 @@ +package ovh + +import ( + "testing" + + "github.com/ovh/go-ovh/ovh" +) + +func Test_getOVHEndpoint(t *testing.T) { + tests := []struct { + name string + endpoint string + want string + }{ + { + "default to EU", "", ovh.OvhEU, + }, + { + "default to EU if omitted", "omitted", ovh.OvhEU, + }, + { + "set to EU", "eu", ovh.OvhEU, + }, + { + "set to CA", "ca", ovh.OvhCA, + }, + { + "set to US", "us", ovh.OvhUS, + }, + { + "case insensitive", "Eu", ovh.OvhEU, + }, + { + "case insensitive ca", "CA", ovh.OvhCA, + }, + { + "arbitratry", "https://blah", "https://blah", + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + params := make(map[string]string) + if tt.endpoint != "" && tt.endpoint != "omitted" { + params["endpoint"] = tt.endpoint + } + if got := getOVHEndpoint(params); got != tt.want { + t.Errorf("getOVHEndpoint() = %v, want %v", got, tt.want) + } + }) + } +} From 51104ce775913aed6f9c8e69fd1973f7fe145c42 Mon Sep 17 00:00:00 2001 From: Tom Limoncelli Date: Tue, 28 Nov 2023 07:06:14 -0500 Subject: [PATCH 029/438] CICD: Use GHA concurrency groups to prevent tests from clobbering each other (#2654) --- .github/workflows/pr_test.yml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.github/workflows/pr_test.yml b/.github/workflows/pr_test.yml index ec3601f0c4..8727f721c1 100644 --- a/.github/workflows/pr_test.yml +++ b/.github/workflows/pr_test.yml @@ -171,7 +171,8 @@ jobs: TRANSIP_ACCOUNT_NAME: ${{ secrets.TRANSIP_ACCOUNT_NAME }} TRANSIP_PRIVATE_KEY: ${{ secrets.TRANSIP_PRIVATE_KEY }} - concurrency: ${{ matrix.provider }} + concurrency: + group: ${{ github.workflow }}-${{ matrix.provider }} strategy: fail-fast: false matrix: From 37e21030a21089b8989786caa0792fb7f349582a Mon Sep 17 00:00:00 2001 From: Matthew Gamble Date: Tue, 28 Nov 2023 16:26:08 -0500 Subject: [PATCH 030/438] NEW PROVIDER: Azure Private DNS Zones (#2626) Co-authored-by: Tom Limoncelli --- OWNERS | 1 + README.md | 1 + documentation/SUMMARY.md | 1 + documentation/providers.md | 1 + documentation/providers/azure_private_dns.md | 74 +++ go.mod | 1 + go.sum | 6 + providers/azure_private_dns/auditrecords.go | 17 + .../azurePrivateDnsProvider.go | 534 ++++++++++++++++++ 9 files changed, 636 insertions(+) create mode 100644 documentation/providers/azure_private_dns.md create mode 100644 providers/azure_private_dns/auditrecords.go create mode 100644 providers/azure_private_dns/azurePrivateDnsProvider.go diff --git a/OWNERS b/OWNERS index b1b524718e..7c34732a41 100644 --- a/OWNERS +++ b/OWNERS @@ -2,6 +2,7 @@ providers/akamaiedgedns @svernick providers/autodns @arnoschoon providers/axfrddns @hnrgrgr providers/azuredns @vatsalyagoel +providers/azure_private_dns @matthewmgamble providers/bind @tlimoncelli providers/cloudflare @tresni providers/cloudns @pragmaton diff --git a/README.md b/README.md index 1b658f66b0..bacfcf734a 100644 --- a/README.md +++ b/README.md @@ -21,6 +21,7 @@ Currently supported DNS providers: - AWS Route 53 - AXFR+DDNS - Azure DNS +- Azure Private DNS - BIND - Cloudflare - ClouDNS diff --git a/documentation/SUMMARY.md b/documentation/SUMMARY.md index b8e9f87910..b26e56638b 100644 --- a/documentation/SUMMARY.md +++ b/documentation/SUMMARY.md @@ -100,6 +100,7 @@ * [AutoDNS](providers/autodns.md) * [AXFR+DDNS](providers/axfrddns.md) * [Azure DNS](providers/azure_dns.md) + * [Azure Private DNS](providers/azure_private_dns.md) * [BIND](providers/bind.md) * [Cloudflare](providers/cloudflareapi.md) * [ClouDNS](providers/cloudns.md) diff --git a/documentation/providers.md b/documentation/providers.md index 4f2c37a2ab..798450a838 100644 --- a/documentation/providers.md +++ b/documentation/providers.md @@ -76,6 +76,7 @@ Providers in this category and their maintainers are: |Name|Maintainer| |---|---| |[`AZURE_DNS`](providers/azure_dns.md)|@vatsalyagoel| +[[`AZURE_PRIVATE_DNS`](providers/azure_private_dns.md)|@matthewmgamble] |[`BIND`](providers/bind.md)|@tlimoncelli| |[`CLOUDFLAREAPI`](providers/cloudflareapi.md)|@tresni| |[`CSCGLOBAL`](providers/cscglobal.md)|@mikenz| diff --git a/documentation/providers/azure_private_dns.md b/documentation/providers/azure_private_dns.md new file mode 100644 index 0000000000..b55feccd7e --- /dev/null +++ b/documentation/providers/azure_private_dns.md @@ -0,0 +1,74 @@ +## Configuration + +This provider is for the [Azure Private DNS Service](https://learn.microsoft.com/en-us/azure/dns/private-dns-overview). This provider can only manage Azure Private DNS zones and will not manage public Azure DNS zones. To use this provider, add an entry to `creds.json` with `TYPE` set to `AZURE_PRIVATE_DNS` +along with the API credentials. + +Example: + +{% code title="creds.json" %} +```json +{ + "azure_private_dns_main": { + "TYPE": "AZURE_PRIVATE_DNS", + "SubscriptionID": "AZURE_PRIVATE_SUBSCRIPTION_ID", + "ResourceGroup": "AZURE_PRIVATE_RESOURCE_GROUP", + "TenantID": "AZURE_PRIVATE_TENANT_ID", + "ClientID": "AZURE_PRIVATE_CLIENT_ID", + "ClientSecret": "AZURE_PRIVATE_CLIENT_SECRET" + } +} +``` +{% endcode %} + +You can also use environment variables: + +```shell +export AZURE_SUBSCRIPTION_ID=XXXXXXXXX +export AZURE_RESOURCE_GROUP=YYYYYYYYY +export AZURE_TENANT_ID=ZZZZZZZZ +export AZURE_CLIENT_ID=AAAAAAAAA +export AZURE_CLIENT_SECRET=BBBBBBBBB +``` + +{% code title="creds.json" %} +```json +{ + "azure_private_dns_main": { + "TYPE": "AZURE_PRIVATE_DNS", + "SubscriptionID": "$AZURE_PRIVATE_SUBSCRIPTION_ID", + "ResourceGroup": "$AZURE_PRIVATE_RESOURCE_GROUP", + "ClientID": "$AZURE_PRIVATE_CLIENT_ID", + "TenantID": "$AZURE_PRIVATE_TENANT_ID", + "ClientSecret": "$AZURE_PRIVATE_CLIENT_SECRET" + } +} +``` +{% endcode %} + +## Metadata +This provider does not recognize any special metadata fields unique to Azure Private DNS. + +## Usage +An example configuration: + +{% code title="dnsconfig.js" %} +```javascript +var REG_NONE = NewRegistrar("none"); +var DSP_AZURE_PRIVATE_MAIN = NewDnsProvider("azure_private_dns_main"); + +D("example.com", REG_NONE, DnsProvider(DSP_AZURE_PRIVATE_MAIN), + A("test", "1.2.3.4") +); +``` +{% endcode %} + +## Activation +DNSControl depends on a standard [Client credentials Authentication](https://docs.microsoft.com/en-us/cli/azure/create-an-azure-service-principal-azure-cli?view=azure-cli-latest) with permission to list, create and update private zones. + +## New domains + +If a domain does not exist in your Azure account, DNSControl will *not* automatically add it with the `push` command. You can do that manually via the control panel. + +## Caveats + +The ResourceGroup is case sensitive. diff --git a/go.mod b/go.mod index 14b6f7689e..38f253058a 100644 --- a/go.mod +++ b/go.mod @@ -7,6 +7,7 @@ toolchain go1.21.1 require ( github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.4.0 github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/dns/armdns v1.1.0 + github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/privatedns/armprivatedns v1.1.0 github.com/Azure/go-autorest/autorest/to v0.4.0 github.com/DisposaBoy/JsonConfigReader v0.0.0-20201129172854-99cf318d67e7 github.com/PuerkitoBio/goquery v1.8.1 diff --git a/go.sum b/go.sum index cb9d22efdd..885ea93a7f 100644 --- a/go.sum +++ b/go.sum @@ -11,6 +11,12 @@ github.com/Azure/azure-sdk-for-go/sdk/internal v1.5.0 h1:d81/ng9rET2YqdVkVwkb6EX github.com/Azure/azure-sdk-for-go/sdk/internal v1.5.0/go.mod h1:s4kgfzA0covAXNicZHDMN58jExvcng2mC/DepXiF1EI= github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/dns/armdns v1.1.0 h1:8iR6OLffWWorFdzL2JFCab5xpD8VKEE2DUBBl+HNTDY= github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/dns/armdns v1.1.0/go.mod h1:copqlcjMWc/wgQ1N2fzsJFQxDdqKGg1EQt8T5wJMOGE= +github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/internal v1.1.2 h1:mLY+pNLjCUeKhgnAJWAKhEUQM+RJQo2H1fuGSw1Ky1E= +github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/internal v1.1.2/go.mod h1:FbdwsQ2EzwvXxOPcMFYO8ogEc9uMMIj3YkmCdXdAFmk= +github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/privatedns/armprivatedns v1.1.0 h1:rR8ZW79lE/ppfXTfiYSnMFv5EzmVuY4pfZWIkscIJ64= +github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/privatedns/armprivatedns v1.1.0/go.mod h1:y2zXtLSMM/X5Mfawq0lOftpWn3f4V6OCsRdINsvWBPI= +github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/resources/armresources v1.0.0 h1:ECsQtyERDVz3NP3kvDOTLvbQhqWp/x9EsGKtb4ogUr8= +github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/resources/armresources v1.0.0/go.mod h1:s1tW/At+xHqjNFvWU4G0c0Qv33KOhvbGNj0RCTQDV8s= github.com/Azure/go-autorest v14.2.0+incompatible h1:V5VMDjClD3GiElqLWO7mz2MxNAK/vTfRHdAubSIPRgs= github.com/Azure/go-autorest v14.2.0+incompatible/go.mod h1:r+4oMnoxhatjLLJ6zxSWATqVooLgysK6ZNox3g/xq24= github.com/Azure/go-autorest/autorest/to v0.4.0 h1:oXVqrxakqqV1UZdSazDOPOLvOIz+XA683u8EctwboHk= diff --git a/providers/azure_private_dns/auditrecords.go b/providers/azure_private_dns/auditrecords.go new file mode 100644 index 0000000000..6c478a955d --- /dev/null +++ b/providers/azure_private_dns/auditrecords.go @@ -0,0 +1,17 @@ +package azure_private_dns + +import ( + "github.com/StackExchange/dnscontrol/v4/models" + "github.com/StackExchange/dnscontrol/v4/pkg/rejectif" +) + +// AuditRecords returns a list of errors corresponding to the records +// that aren't supported by this provider. If all records are +// supported, an empty list is returned. +func AuditRecords(records []*models.RecordConfig) []error { + a := rejectif.Auditor{} + + a.Add("MX", rejectif.MxNull) // Last verified 2020-12-28 + + return a.Audit(records) +} diff --git a/providers/azure_private_dns/azurePrivateDnsProvider.go b/providers/azure_private_dns/azurePrivateDnsProvider.go new file mode 100644 index 0000000000..7ba34adc03 --- /dev/null +++ b/providers/azure_private_dns/azurePrivateDnsProvider.go @@ -0,0 +1,534 @@ +package azure_private_dns + +import ( + "context" + "encoding/json" + "fmt" + "strings" + "time" + + "github.com/Azure/azure-sdk-for-go/sdk/azcore" + aauth "github.com/Azure/azure-sdk-for-go/sdk/azidentity" + adns "github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/privatedns/armprivatedns" + "github.com/Azure/go-autorest/autorest/to" + "github.com/StackExchange/dnscontrol/v4/models" + "github.com/StackExchange/dnscontrol/v4/pkg/diff2" + "github.com/StackExchange/dnscontrol/v4/pkg/printer" + "github.com/StackExchange/dnscontrol/v4/pkg/txtutil" + "github.com/StackExchange/dnscontrol/v4/providers" +) + +type azurednsProvider struct { + zonesClient *adns.PrivateZonesClient + recordsClient *adns.RecordSetsClient + zones map[string]*adns.PrivateZone + resourceGroup *string + subscriptionID *string + rawRecords map[string][]*adns.RecordSet + zoneName map[string]string +} + +func newAzureDNSDsp(conf map[string]string, metadata json.RawMessage) (providers.DNSServiceProvider, error) { + return newAzureDNS(conf, metadata) +} + +func newAzureDNS(m map[string]string, metadata json.RawMessage) (*azurednsProvider, error) { + subID, rg := m["SubscriptionID"], m["ResourceGroup"] + clientID, clientSecret, tenantID := m["ClientID"], m["ClientSecret"], m["TenantID"] + credential, authErr := aauth.NewClientSecretCredential(tenantID, clientID, clientSecret, nil) + if authErr != nil { + return nil, authErr + } + zonesClient, zoneErr := adns.NewPrivateZonesClient(subID, credential, nil) + if zoneErr != nil { + return nil, zoneErr + } + recordsClient, recordErr := adns.NewRecordSetsClient(subID, credential, nil) + if recordErr != nil { + return nil, recordErr + } + + api := &azurednsProvider{ + zonesClient: zonesClient, + recordsClient: recordsClient, + resourceGroup: to.StringPtr(rg), + subscriptionID: to.StringPtr(subID), + rawRecords: map[string][]*adns.RecordSet{}, + zoneName: map[string]string{}, + } + err := api.getZones() + if err != nil { + return nil, err + } + return api, nil +} + +var features = providers.DocumentationNotes{ + providers.CanGetZones: providers.Can(), + providers.CanUseAlias: providers.Cannot("Azure DNS does not provide a generic ALIAS functionality. Use AZURE_ALIAS instead."), + providers.CanUseAzureAlias: providers.Can(), + providers.CanUseCAA: providers.Cannot("Azure Private DNS does not support CAA records"), + providers.CanUseLOC: providers.Cannot(), + providers.CanUseNAPTR: providers.Cannot(), + providers.CanUsePTR: providers.Can(), + providers.CanUseSRV: providers.Can(), + providers.CanUseSSHFP: providers.Cannot(), + providers.CanUseTLSA: providers.Cannot(), + providers.DocCreateDomains: providers.Can(), + providers.DocDualHost: providers.Can("Azure does not permit modifying the existing NS records, only adding/removing additional records."), + providers.DocOfficiallySupported: providers.Can(), +} + +func init() { + fns := providers.DspFuncs{ + Initializer: newAzureDNSDsp, + RecordAuditor: AuditRecords, + } + providers.RegisterDomainServiceProviderType("AZURE_PRIVATE_DNS", fns, features) + providers.RegisterCustomRecordType("AZURE_ALIAS", "AZURE_PRIVATE_DNS", "") +} + +func (a *azurednsProvider) getExistingZones() ([]*adns.PrivateZone, error) { + ctx, cancel := context.WithTimeout(context.Background(), 6000*time.Second) + defer cancel() + zonesPager := a.zonesClient.NewListByResourceGroupPager(*a.resourceGroup, nil) + var zones []*adns.PrivateZone + for zonesPager.More() { + nextResult, zonesErr := zonesPager.NextPage(ctx) + if zonesErr != nil { + return nil, zonesErr + } + zones = append(zones, nextResult.Value...) + } + return zones, nil +} + +func (a *azurednsProvider) getZones() error { + a.zones = make(map[string]*adns.PrivateZone) + + zones, err := a.getExistingZones() + if err != nil { + return err + } + + for _, z := range zones { + zone := z + domain := strings.TrimSuffix(*z.Name, ".") + a.zones[domain] = zone + } + + return nil +} + +type errNoExist struct { + domain string +} + +func (e errNoExist) Error() string { + return fmt.Sprintf("Private Domain %s not found in you Azure account", e.domain) +} + +func (a *azurednsProvider) GetNameservers(domain string) ([]*models.Nameserver, error) { + // Azure Private DNS does not have the concept of "Name Servers" since these are local, private views of zones unique to the Azure environment + var nss []string + return models.ToNameserversStripTD(nss) +} + +func (a *azurednsProvider) ListZones() ([]string, error) { + zonesResult, err := a.getExistingZones() + if err != nil { + return nil, err + } + var zones []string + + for _, z := range zonesResult { + domain := strings.TrimSuffix(*z.Name, ".") + zones = append(zones, domain) + } + + return zones, nil +} + +// GetZoneRecords gets the records of a zone and returns them in RecordConfig format. +func (a *azurednsProvider) GetZoneRecords(domain string, meta map[string]string) (models.Records, error) { + existingRecords, _, _, err := a.getExistingRecords(domain) + if err != nil { + return nil, err + } + + return existingRecords, nil +} + +func (a *azurednsProvider) getExistingRecords(domain string) (models.Records, []*adns.RecordSet, string, error) { + zone, ok := a.zones[domain] + if !ok { + return nil, nil, "", errNoExist{domain} + } + zoneName := *zone.Name + rawRecords, err := a.fetchRecordSets(zoneName) + if err != nil { + return nil, nil, "", err + } + + var existingRecords models.Records + for _, set := range rawRecords { + existingRecords = append(existingRecords, nativeToRecords(set, zoneName)...) + } + + a.rawRecords[domain] = rawRecords + a.zoneName[domain] = zoneName + + return existingRecords, rawRecords, zoneName, nil +} + +// GetZoneRecordsCorrections returns a list of corrections that will turn existing records into dc.Records. +func (a *azurednsProvider) GetZoneRecordsCorrections(dc *models.DomainConfig, existingRecords models.Records) ([]*models.Correction, error) { + txtutil.SplitSingleLongTxt(existingRecords) // Autosplit long TXT records + + var corrections []*models.Correction + + changes, err := diff2.ByRecordSet(existingRecords, dc, nil) + if err != nil { + return nil, err + } + + for _, change := range changes { + + // Copy all param values to local variables to avoid overwrites + msgs := change.MsgsJoined + dcn := dc.Name + chaKey := change.Key + + switch change.Type { + case diff2.REPORT: + corrections = append(corrections, &models.Correction{Msg: change.MsgsJoined}) + case diff2.CHANGE, diff2.CREATE: + changeNew := change.New + corrections = append(corrections, &models.Correction{ + Msg: msgs, + F: func() error { + return a.recordCreate(dcn, chaKey, changeNew) + }, + }) + case diff2.DELETE: + corrections = append(corrections, &models.Correction{ + Msg: msgs, + F: func() error { + return a.recordDelete(dcn, chaKey, change.Old) + }, + }) + default: + panic(fmt.Sprintf("unhandled change.Type %s", change.Type)) + } + } + + return corrections, nil +} + +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 + } + + var recordName string + var i int64 + for _, r := range recs { + i = int64(r.TTL) + recordName = r.Name + } + rrset.Properties.TTL = &i + + waitTime := 1 +retry: + + ctx, cancel := context.WithTimeout(context.Background(), 6000*time.Second) + defer cancel() + _, err = a.recordsClient.CreateOrUpdate(ctx, *a.resourceGroup, zoneName, azRecType, recordName, *rrset, nil) + + if e, ok := err.(*azcore.ResponseError); ok { + if e.StatusCode == 429 { + waitTime = waitTime * 2 + if waitTime > 300 { + return err + } + printer.Printf("AZURE_PRIVATE_DNS: rate-limit paused for %v.\n", waitTime) + time.Sleep(time.Duration(waitTime+1) * time.Second) + goto retry + } + } + + return err +} + +func (a *azurednsProvider) recordDelete(zoneName string, reckey models.RecordKey, recs models.Records) error { + + shortName := strings.TrimSuffix(reckey.NameFQDN, "."+zoneName) + if shortName == zoneName { + shortName = "@" + } + + azRecType, err := nativeToRecordTypeDiff(to.StringPtr(reckey.Type)) + if err != nil { + return nil + } + + waitTime := 1 +retry: + + ctx, cancel := context.WithTimeout(context.Background(), 6000*time.Second) + defer cancel() + _, err = a.recordsClient.Delete(ctx, *a.resourceGroup, zoneName, azRecType, shortName, nil) + + if e, ok := err.(*azcore.ResponseError); ok { + if e.StatusCode == 429 { + waitTime = waitTime * 2 + if waitTime > 300 { + return err + } + printer.Printf("AZURE_PRIVATE_DNS: rate-limit paused for %v.\n", waitTime) + time.Sleep(time.Duration(waitTime+1) * time.Second) + goto retry + } + } + + return err +} + +func nativeToRecordTypeDiff(recordType *string) (adns.RecordType, error) { + recordTypeStripped := strings.TrimPrefix(*recordType, "Microsoft.Network/dnszones/") + switch recordTypeStripped { + case "A", "AZURE_ALIAS_A": + return adns.RecordTypeA, nil + case "AAAA", "AZURE_ALIAS_AAAA": + return adns.RecordTypeAAAA, nil + case "CAA": + // CAA doesn't make any senese in a private dns zone in azure + return adns.RecordTypeA, fmt.Errorf("nativeToRecordTypeDiff RTYPE %v UNIMPLEMENTED", *recordType) + case "CNAME", "AZURE_ALIAS_CNAME": + return adns.RecordTypeCNAME, nil + case "MX": + return adns.RecordTypeMX, nil + case "NS": + // NS record types don't make any sense in a private azure dns zone + return adns.RecordTypeA, fmt.Errorf("nativeToRecordTypeDiff RTYPE %v UNIMPLEMENTED", *recordType) + case "PTR": + return adns.RecordTypePTR, nil + case "SRV": + return adns.RecordTypeSRV, nil + case "TXT": + return adns.RecordTypeTXT, nil + case "SOA": + return adns.RecordTypeSOA, nil + default: + // Unimplemented type. Return adns.A as a decoy, but send an error. + return adns.RecordTypeA, fmt.Errorf("nativeToRecordTypeDiff RTYPE %v UNIMPLEMENTED", *recordType) + } +} + +func nativeToRecords(set *adns.RecordSet, origin string) []*models.RecordConfig { + var results []*models.RecordConfig + switch rtype := *set.Type; rtype { + case "Microsoft.Network/privateDnsZones/A": + if set.Properties.ARecords != nil { + // This is an A recordset. Process all the targets there. + for _, rec := range set.Properties.ARecords { + rc := &models.RecordConfig{TTL: uint32(*set.Properties.TTL), Original: set} + rc.SetLabelFromFQDN(*set.Properties.Fqdn, origin) + rc.Type = "A" + _ = rc.SetTarget(*rec.IPv4Address) + results = append(results, rc) + } + } else { + panic(fmt.Errorf("nativeToRecords rtype %v unimplemented", *set.Type)) + + } + case "Microsoft.Network/privateDnsZones/AAAA": + if set.Properties.AaaaRecords != nil { + // This is an AAAA recordset. Process all the targets there. + for _, rec := range set.Properties.AaaaRecords { + rc := &models.RecordConfig{TTL: uint32(*set.Properties.TTL), Original: set} + rc.SetLabelFromFQDN(*set.Properties.Fqdn, origin) + rc.Type = "AAAA" + _ = rc.SetTarget(*rec.IPv6Address) + results = append(results, rc) + } + } else { + panic(fmt.Errorf("nativeToRecords rtype %v unimplemented", *set.Type)) + } + case "Microsoft.Network/privateDnsZones/CNAME": + if set.Properties.CnameRecord != nil { + // This is a CNAME recordset. Process the targets. (there can only be one) + rc := &models.RecordConfig{TTL: uint32(*set.Properties.TTL), Original: set} + rc.SetLabelFromFQDN(*set.Properties.Fqdn, origin) + rc.Type = "CNAME" + _ = rc.SetTarget(*set.Properties.CnameRecord.Cname) + results = append(results, rc) + } else { + panic(fmt.Errorf("nativeToRecords rtype %v unimplemented", *set.Type)) + } + case "Microsoft.Network/privateDnsZones/PTR": + for _, rec := range set.Properties.PtrRecords { + rc := &models.RecordConfig{TTL: uint32(*set.Properties.TTL), Original: set} + rc.SetLabelFromFQDN(*set.Properties.Fqdn, origin) + rc.Type = "PTR" + _ = rc.SetTarget(*rec.Ptrdname) + results = append(results, rc) + } + case "Microsoft.Network/privateDnsZones/TXT": + if len(set.Properties.TxtRecords) == 0 { // Empty String Record Parsing + // This is a null TXT record. + rc := &models.RecordConfig{TTL: uint32(*set.Properties.TTL), Original: set} + rc.SetLabelFromFQDN(*set.Properties.Fqdn, origin) + rc.Type = "TXT" + _ = rc.SetTargetTXT("") + results = append(results, rc) + } else { + // This is a normal TXT record. Collect all its segments. + for _, rec := range set.Properties.TxtRecords { + rc := &models.RecordConfig{TTL: uint32(*set.Properties.TTL), Original: set} + rc.SetLabelFromFQDN(*set.Properties.Fqdn, origin) + rc.Type = "TXT" + var txts []string + for _, txt := range rec.Value { + txts = append(txts, *txt) + } + _ = rc.SetTargetTXTs(txts) + results = append(results, rc) + } + } + case "Microsoft.Network/privateDnsZones/MX": + for _, rec := range set.Properties.MxRecords { + rc := &models.RecordConfig{TTL: uint32(*set.Properties.TTL), Original: set} + rc.SetLabelFromFQDN(*set.Properties.Fqdn, origin) + rc.Type = "MX" + _ = rc.SetTargetMX(uint16(*rec.Preference), *rec.Exchange) + results = append(results, rc) + } + case "Microsoft.Network/privateDnsZones/SRV": + for _, rec := range set.Properties.SrvRecords { + rc := &models.RecordConfig{TTL: uint32(*set.Properties.TTL), Original: set} + rc.SetLabelFromFQDN(*set.Properties.Fqdn, origin) + rc.Type = "SRV" + _ = rc.SetTargetSRV(uint16(*rec.Priority), uint16(*rec.Weight), uint16(*rec.Port), *rec.Target) + results = append(results, rc) + } + case "Microsoft.Network/privateDnsZones/SOA": + default: + panic(fmt.Errorf("nativeToRecords rtype %v unimplemented", *set.Type)) + } + return results +} + +// 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) + // } + + recordSet := &adns.RecordSet{Type: to.StringPtr(recordKeyType), Properties: &adns.RecordSetProperties{}} + for _, rec := range recordConfig { + switch recordKeyType { + case "A": + if recordSet.Properties.ARecords == nil { + recordSet.Properties.ARecords = []*adns.ARecord{} + } + recordSet.Properties.ARecords = append(recordSet.Properties.ARecords, &adns.ARecord{IPv4Address: to.StringPtr(rec.GetTargetField())}) + case "AAAA": + if recordSet.Properties.AaaaRecords == nil { + recordSet.Properties.AaaaRecords = []*adns.AaaaRecord{} + } + recordSet.Properties.AaaaRecords = append(recordSet.Properties.AaaaRecords, &adns.AaaaRecord{IPv6Address: to.StringPtr(rec.GetTargetField())}) + case "CNAME": + recordSet.Properties.CnameRecord = &adns.CnameRecord{Cname: to.StringPtr(rec.GetTargetField())} + case "PTR": + if recordSet.Properties.PtrRecords == nil { + recordSet.Properties.PtrRecords = []*adns.PtrRecord{} + } + recordSet.Properties.PtrRecords = append(recordSet.Properties.PtrRecords, &adns.PtrRecord{Ptrdname: to.StringPtr(rec.GetTargetField())}) + case "TXT": + if recordSet.Properties.TxtRecords == nil { + recordSet.Properties.TxtRecords = []*adns.TxtRecord{} + } + // Empty TXT record needs to have no value set in it's properties + if rec.GetTargetTXTJoined() == "" { + var txts []*string + for _, txt := range rec.GetTargetTXTSegmented() { + txts = append(txts, to.StringPtr(txt)) + } + recordSet.Properties.TxtRecords = append(recordSet.Properties.TxtRecords, &adns.TxtRecord{Value: txts}) + } + case "MX": + if recordSet.Properties.MxRecords == nil { + recordSet.Properties.MxRecords = []*adns.MxRecord{} + } + recordSet.Properties.MxRecords = append(recordSet.Properties.MxRecords, &adns.MxRecord{Exchange: to.StringPtr(rec.GetTargetField()), Preference: to.Int32Ptr(int32(rec.MxPreference))}) + case "SRV": + if recordSet.Properties.SrvRecords == nil { + recordSet.Properties.SrvRecords = []*adns.SrvRecord{} + } + recordSet.Properties.SrvRecords = append(recordSet.Properties.SrvRecords, &adns.SrvRecord{Target: to.StringPtr(rec.GetTargetField()), Port: to.Int32Ptr(int32(rec.SrvPort)), Weight: to.Int32Ptr(int32(rec.SrvWeight)), Priority: to.Int32Ptr(int32(rec.SrvPriority))}) + /* CAA records don't work in a private zone */ + case "AZURE_ALIAS_A", "AZURE_ALIAS_AAAA", "AZURE_ALIAS_CNAME": + return nil, adns.RecordTypeA, fmt.Errorf("recordToNativeDiff2 RTYPE %v UNIMPLEMENTED", recordKeyType) // ands.A is a placeholder + default: + return nil, adns.RecordTypeA, fmt.Errorf("recordToNativeDiff2 RTYPE %v UNIMPLEMENTED", recordKeyType) // ands.A is a placeholder + } + } + + rt, err := nativeToRecordTypeDiff(to.StringPtr(*recordSet.Type)) + if err != nil { + return nil, adns.RecordTypeA, err // adns.A is a placeholder + } + return recordSet, rt, nil +} + +func (a *azurednsProvider) fetchRecordSets(zoneName string) ([]*adns.RecordSet, error) { + if zoneName == "" { + return nil, nil + } + var records []*adns.RecordSet + ctx, cancel := context.WithTimeout(context.Background(), 6000*time.Second) + defer cancel() + + recordsPager := a.recordsClient.NewListPager(*a.resourceGroup, zoneName, nil) + + for recordsPager.More() { + + waitTime := 1 + retry: + + nextResult, recordsErr := recordsPager.NextPage(ctx) + + if recordsErr != nil { + err := recordsErr + if e, ok := err.(*azcore.ResponseError); ok { + + if e.StatusCode == 429 { + waitTime = waitTime * 2 + if waitTime > 300 { + return nil, err + } + printer.Printf("AZURE_PRIVATE_DNS: rate-limit paused for %v.\n", waitTime) + time.Sleep(time.Duration(waitTime+1) * time.Second) + goto retry + } + } + } + + records = append(records, nextResult.Value...) + } + + return records, nil +} + +func (a *azurednsProvider) EnsureZoneExists(domain string) error { + if _, ok := a.zones[domain]; ok { + return nil + } + return nil +} From 5b93f94ad64c88b4e53e2e31da05fab7826f00ff Mon Sep 17 00:00:00 2001 From: Tom Limoncelli Date: Tue, 28 Nov 2023 16:28:37 -0500 Subject: [PATCH 031/438] Update docs and move Azure Private DNS to the "community support" list (#2657) Co-authored-by: Matthew Gamble --- documentation/providers.md | 7 ++++--- documentation/writing-providers.md | 2 +- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/documentation/providers.md b/documentation/providers.md index 798450a838..16c803cc40 100644 --- a/documentation/providers.md +++ b/documentation/providers.md @@ -76,7 +76,6 @@ Providers in this category and their maintainers are: |Name|Maintainer| |---|---| |[`AZURE_DNS`](providers/azure_dns.md)|@vatsalyagoel| -[[`AZURE_PRIVATE_DNS`](providers/azure_private_dns.md)|@matthewmgamble] |[`BIND`](providers/bind.md)|@tlimoncelli| |[`CLOUDFLAREAPI`](providers/cloudflareapi.md)|@tresni| |[`CSCGLOBAL`](providers/cscglobal.md)|@mikenz| @@ -95,16 +94,18 @@ provided to help community members support their code independently. Expectations of maintainers: -* Maintainers are expected to support their provider and/or find a new maintainer. +* Maintainers are expected to support their provider and/or help find a new maintainer. * Maintainers should set up test accounts and periodically verify that all tests pass (`pkg/js/parse_tests` and `integrationTest`). * Contributors are encouraged to add new tests and refine old ones. (Test-driven development is encouraged.) * Bugs will be referred to the maintainer or their designate. -* Maintainers must be responsible to bug reports and PRs. If a maintainer is unresponsive for more than 2 months, we will consider disabling the provider. First we will put out a call for new maintainer. If noboby volunteers, the provider will be disabled. +* Maintainers must be responsible to bug reports and PRs. If a maintainer is unresponsive for more than 2 months, we will consider disabling the provider. First we will put out a call for new maintainer. If nobody volunteers, the provider may be disabled. +* Tom needs to know your real email address. Please email tlimoncelli at stack over flow dot com so he has it. Providers in this category and their maintainers are: |Name|Maintainer| |---|---| +[[`AZURE_PRIVATE_DNS`](providers/azure_private_dns.md)|@matthewmgamble] |[`AKAMAIEDGEDNS`](providers/akamaiedgedns.md)|@svernick| |[`AXFRDDNS`](providers/axfrddns.md)|@hnrgrgr| |[`CLOUDFLAREAPI`](providers/cloudflareapi.md)|@tresni| diff --git a/documentation/writing-providers.md b/documentation/writing-providers.md index 2f1435366a..791a2bc6dd 100644 --- a/documentation/writing-providers.md +++ b/documentation/writing-providers.md @@ -316,7 +316,7 @@ Here are some last-minute things to check before you submit your PR. 2. Make sure all appropriate documentation is current. (See [Step 8](#step-8-manual-tests)) 3. Check that dependencies are current (See [Step 13](#step-13-dependencies)) 4. Re-run the integration test one last time (See [Step 7](#step-7-integration-test)) -5. Re-read the [maintainer's responsibilities](providers.md) bullet list. By submitting a provider you agree to maintain it, respond to bugs, perioidically re-run the integration test to verify nothing has broken, and if we don't hear from you for 2 months we may disable the provider. +5. Re-read the [maintainer's responsibilities](providers.md) bullet list. By submitting a provider you agree to maintain it, respond to bugs, periodically re-run the integration test to verify nothing has broken, and if we don't hear from you for 2 months we may disable the provider. ## Step 16: After the PR is merged From 88f007cd1dca4587e8fffefc1c4e53da948a5bd8 Mon Sep 17 00:00:00 2001 From: Jonathan Bouvier Date: Wed, 29 Nov 2023 11:34:27 -0500 Subject: [PATCH 032/438] ROUTE53: fix parameter type for R53_EVALUATE_TARGET_HEALTH (#2658) --- commands/types/dnscontrol.d.ts | 2 +- documentation/functions/record/R53_EVALUATE_TARGET_HEALTH.md | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/commands/types/dnscontrol.d.ts b/commands/types/dnscontrol.d.ts index 58c9d8ad2a..8715383ccb 100644 --- a/commands/types/dnscontrol.d.ts +++ b/commands/types/dnscontrol.d.ts @@ -2300,7 +2300,7 @@ declare function R53_ALIAS(name: string, target: string, zone_idModifier: Domain * * @see https://docs.dnscontrol.org/language-reference/record-modifiers/service-provider-specific/amazon-route-53/r53_evaluate_target_health */ -declare function R53_EVALUATE_TARGET_HEALTH(enabled: bool): RecordModifier; +declare function R53_EVALUATE_TARGET_HEALTH(enabled: boolean): RecordModifier; /** * `R53_ZONE` lets you specify the AWS Zone ID for an entire domain ([`D()`](../global/D.md)) or a specific [`R53_ALIAS()`](../domain/R53_ALIAS.md) record. diff --git a/documentation/functions/record/R53_EVALUATE_TARGET_HEALTH.md b/documentation/functions/record/R53_EVALUATE_TARGET_HEALTH.md index 7ed12b3853..72f3ffedc9 100644 --- a/documentation/functions/record/R53_EVALUATE_TARGET_HEALTH.md +++ b/documentation/functions/record/R53_EVALUATE_TARGET_HEALTH.md @@ -3,7 +3,7 @@ name: R53_EVALUATE_TARGET_HEALTH parameters: - enabled parameter_types: - enabled: bool + enabled: boolean ts_return: RecordModifier provider: ROUTE53 --- From 74a9e5e8706085d810886033431405611361181d Mon Sep 17 00:00:00 2001 From: Jonathan Bouvier Date: Wed, 29 Nov 2023 13:25:20 -0500 Subject: [PATCH 033/438] ROUTE53: add R53_EVALUATE_TARGET_HEALTH to documentation summary (#2659) --- documentation/SUMMARY.md | 1 + 1 file changed, 1 insertion(+) diff --git a/documentation/SUMMARY.md b/documentation/SUMMARY.md index b26e56638b..44034380e0 100644 --- a/documentation/SUMMARY.md +++ b/documentation/SUMMARY.md @@ -90,6 +90,7 @@ * Service Provider specific * Amazon Route 53 * [R53_ZONE](functions/record/R53_ZONE.md) + * [R53_EVALUATE_TARGET_HEALTH](functions/record/R53_EVALUATE_TARGET_HEALTH.md) * [Why CNAME/MX/NS targets require a "dot"](why-the-dot.md) ## Service Providers From bc22690fc1514f89edf1ba15019a982e18d73fe8 Mon Sep 17 00:00:00 2001 From: Jeffrey Cafferata Date: Wed, 29 Nov 2023 20:24:22 +0100 Subject: [PATCH 034/438] DOCS: Fixed providers with "contributor support" table. (#2660) --- documentation/providers.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/documentation/providers.md b/documentation/providers.md index 16c803cc40..18a94ab7c3 100644 --- a/documentation/providers.md +++ b/documentation/providers.md @@ -105,7 +105,7 @@ Providers in this category and their maintainers are: |Name|Maintainer| |---|---| -[[`AZURE_PRIVATE_DNS`](providers/azure_private_dns.md)|@matthewmgamble] +|[`AZURE_PRIVATE_DNS`](providers/azure_private_dns.md)|@matthewmgamble| |[`AKAMAIEDGEDNS`](providers/akamaiedgedns.md)|@svernick| |[`AXFRDDNS`](providers/axfrddns.md)|@hnrgrgr| |[`CLOUDFLAREAPI`](providers/cloudflareapi.md)|@tresni| From fd413a9b08e578b7c8749e3b8895d162d5cf4f7d Mon Sep 17 00:00:00 2001 From: Jeffrey Cafferata Date: Wed, 29 Nov 2023 21:18:14 +0100 Subject: [PATCH 035/438] AZURE_PRIVATE_DNS: GoReleaser provider-specific changelog regexp (#2661) --- .goreleaser.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.goreleaser.yml b/.goreleaser.yml index ac5568685d..a181427b63 100644 --- a/.goreleaser.yml +++ b/.goreleaser.yml @@ -33,7 +33,7 @@ changelog: regexp: "(?i)^.*(major|new provider|feature)[(\\w)]*:+.*$" order: 1 - title: 'Provider-specific changes:' - regexp: "(?i)((akamaiedge|autodns|axfrd|azure|bind|cloudflare|cloudflareapi_old|cloudns|cscglobal|desec|digitalocean|dnsimple|dnsmadeeasy|doh|domainnameshop|easyname|exoscale|gandi|gcloud|gcore|hedns|hetzner|hexonet|hostingde|inwx|linode|loopia|luadns|msdns|mythicbeasts|namecheap|namedotcom|netcup|netlify|ns1|opensrs|oracle|ovh|packetframe|porkbun|powerdns|route53|rwth|softlayer|transip|vultr).*:)+.*" + regexp: "(?i)((akamaiedge|autodns|axfrd|azure|azure_private_dns|bind|cloudflare|cloudflareapi_old|cloudns|cscglobal|desec|digitalocean|dnsimple|dnsmadeeasy|doh|domainnameshop|easyname|exoscale|gandi|gcloud|gcore|hedns|hetzner|hexonet|hostingde|inwx|linode|loopia|luadns|msdns|mythicbeasts|namecheap|namedotcom|netcup|netlify|ns1|opensrs|oracle|ovh|packetframe|porkbun|powerdns|route53|rwth|softlayer|transip|vultr).*:)+.*" order: 2 - title: 'Deprecation warnings:' regexp: "(?i)^.*Deprecate[(\\w)]*:+.*$" From 31cd4e10a8903d3fc261f98cf41bf44955bdd914 Mon Sep 17 00:00:00 2001 From: Jeffrey Cafferata Date: Wed, 29 Nov 2023 21:22:01 +0100 Subject: [PATCH 036/438] DOCS: Fixed the broken provider `ClouDNS` link in the providers table (#2663) --- documentation/providers.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/documentation/providers.md b/documentation/providers.md index 18a94ab7c3..b7812f6b4c 100644 --- a/documentation/providers.md +++ b/documentation/providers.md @@ -109,7 +109,7 @@ Providers in this category and their maintainers are: |[`AKAMAIEDGEDNS`](providers/akamaiedgedns.md)|@svernick| |[`AXFRDDNS`](providers/axfrddns.md)|@hnrgrgr| |[`CLOUDFLAREAPI`](providers/cloudflareapi.md)|@tresni| -|[`CLOUDNS`](providers/CLOUDNS.md)|@pragmaton| +|[`CLOUDNS`](providers/cloudns.md)|@pragmaton| |[`CSCGLOBAL`](providers/cscglobal.md)|@Air-New-Zealand| |[`DESEC`](providers/desec.md)|@D3luxee| |[`DIGITALOCEAN`](providers/digitalocean.md)|@Deraen| From 9397eed84b1e66fc2f35c5ce38d5979a770417ee Mon Sep 17 00:00:00 2001 From: Jeffrey Cafferata Date: Wed, 29 Nov 2023 21:22:24 +0100 Subject: [PATCH 037/438] DOCS: Fixed the maintainer of provider `OPENSRS` (#2662) --- documentation/providers.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/documentation/providers.md b/documentation/providers.md index b7812f6b4c..1ab8aac789 100644 --- a/documentation/providers.md +++ b/documentation/providers.md @@ -134,7 +134,7 @@ Providers in this category and their maintainers are: |[`NETCUP`](providers/netcup.md)|@kordianbruck| |[`NETLIFY`](providers/netlify.md)|@SphericalKat| |[`NS1`](providers/ns1.md)|@costasd| -|[`OPENSRS`](providers/opensrs.md)|@pierre-emmanuelJ| +|[`OPENSRS`](providers/opensrs.md)|@philhug| |[`ORACLE`](providers/oracle.md)|@kallsyms| |[`OVH`](providers/ovh.md)|@masterzen| |[`PACKETFRAME`](providers/packetframe.md)|@hamptonmoore| From d3112f53df84eb360539bf3c1cf0e272bfedbf01 Mon Sep 17 00:00:00 2001 From: Asif Nawaz <107853964+AsifNawaz-cnic@users.noreply.github.com> Date: Thu, 30 Nov 2023 16:33:02 +0000 Subject: [PATCH 038/438] HEXONET: Update GO-SDK dependency version from 3.5.5 to 3.5.6 (#2667) --- go.mod | 2 +- go.sum | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/go.mod b/go.mod index 38f253058a..5c773a7c44 100644 --- a/go.mod +++ b/go.mod @@ -22,7 +22,7 @@ require ( github.com/babolivier/go-doh-client v0.0.0-20201028162107-a76cff4cb8b6 github.com/bhendo/go-powershell v0.0.0-20190719160123-219e7fb4e41e github.com/billputer/go-namecheap v0.0.0-20210108011502-994a912fb7f9 - github.com/centralnicgroup-opensource/rtldev-middleware-go-sdk/v3 v3.5.5 + github.com/centralnicgroup-opensource/rtldev-middleware-go-sdk/v3 v3.5.6 github.com/cloudflare/cloudflare-go v0.81.0 github.com/digitalocean/godo v1.106.0 github.com/ditashi/jsbeautifier-go v0.0.0-20141206144643-2520a8026a9c diff --git a/go.sum b/go.sum index 885ea93a7f..75ee55f5b6 100644 --- a/go.sum +++ b/go.sum @@ -84,8 +84,8 @@ github.com/cenkalti/backoff v2.2.1+incompatible/go.mod h1:90ReRw6GdpyfrHakVjL/QH github.com/cenkalti/backoff/v3 v3.0.0 h1:ske+9nBpD9qZsTBoF41nW5L+AIuFBKMeze18XQ3eG1c= github.com/cenkalti/backoff/v3 v3.0.0/go.mod h1:cIeZDE3IrqwwJl6VUwCN6trj1oXrTS4rc0ij+ULvLYs= github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= -github.com/centralnicgroup-opensource/rtldev-middleware-go-sdk/v3 v3.5.5 h1:awE2kiwdJa409MC5i3OH9fJHCr2yE75yHuWWoA5zx8Q= -github.com/centralnicgroup-opensource/rtldev-middleware-go-sdk/v3 v3.5.5/go.mod h1:1usm1EQvugrIio3ODIAMrDG9NzA86AHIqhZCxJgNdxY= +github.com/centralnicgroup-opensource/rtldev-middleware-go-sdk/v3 v3.5.6 h1:NwzyMBDEihBaPYlsguXbiraAofgFL0dIokr7haRptng= +github.com/centralnicgroup-opensource/rtldev-middleware-go-sdk/v3 v3.5.6/go.mod h1:AuVFPx7rRMTT6MstyP2eWwinthewLFWv+zbaoQ3A+fY= github.com/chzyer/logex v1.2.1/go.mod h1:JLbx6lG2kDbNRFnfkgvh4eRJRPX1QCoOIWomwysCBrQ= github.com/chzyer/test v1.0.0/go.mod h1:2JlltgoNkt4TW/z9V/IzDdFaMTM2JPIi26O1pF38GC8= github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= From a653499655fe27d04e87782ffb40c5d565fa90d7 Mon Sep 17 00:00:00 2001 From: Tom Limoncelli Date: Thu, 30 Nov 2023 13:51:54 -0500 Subject: [PATCH 039/438] CHORE: Update deps (#2668) --- go.mod | 58 ++++++++++++------------- go.sum | 132 ++++++++++++++++++++++++++++----------------------------- 2 files changed, 95 insertions(+), 95 deletions(-) diff --git a/go.mod b/go.mod index 5c773a7c44..a3fe3d97f4 100644 --- a/go.mod +++ b/go.mod @@ -6,30 +6,30 @@ toolchain go1.21.1 require ( github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.4.0 - github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/dns/armdns v1.1.0 - github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/privatedns/armprivatedns v1.1.0 + github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/dns/armdns v1.2.0 + github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/privatedns/armprivatedns v1.2.0 github.com/Azure/go-autorest/autorest/to v0.4.0 github.com/DisposaBoy/JsonConfigReader v0.0.0-20201129172854-99cf318d67e7 github.com/PuerkitoBio/goquery v1.8.1 github.com/TomOnTime/utfutil v0.0.0-20230223141146-125e65197b36 github.com/akamai/AkamaiOPEN-edgegrid-golang v1.2.2 github.com/andreyvit/diff v0.0.0-20170406064948-c7f18ee00883 - github.com/aws/aws-sdk-go-v2 v1.23.0 - github.com/aws/aws-sdk-go-v2/config v1.25.3 - github.com/aws/aws-sdk-go-v2/credentials v1.16.2 - github.com/aws/aws-sdk-go-v2/service/route53 v1.34.2 - github.com/aws/aws-sdk-go-v2/service/route53domains v1.19.2 + github.com/aws/aws-sdk-go-v2 v1.23.4 + github.com/aws/aws-sdk-go-v2/config v1.25.10 + github.com/aws/aws-sdk-go-v2/credentials v1.16.8 + github.com/aws/aws-sdk-go-v2/service/route53 v1.35.1 + github.com/aws/aws-sdk-go-v2/service/route53domains v1.20.1 github.com/babolivier/go-doh-client v0.0.0-20201028162107-a76cff4cb8b6 github.com/bhendo/go-powershell v0.0.0-20190719160123-219e7fb4e41e github.com/billputer/go-namecheap v0.0.0-20210108011502-994a912fb7f9 github.com/centralnicgroup-opensource/rtldev-middleware-go-sdk/v3 v3.5.6 - github.com/cloudflare/cloudflare-go v0.81.0 + github.com/cloudflare/cloudflare-go v0.82.0 github.com/digitalocean/godo v1.106.0 github.com/ditashi/jsbeautifier-go v0.0.0-20141206144643-2520a8026a9c github.com/dnsimple/dnsimple-go v1.2.0 github.com/exoscale/egoscale v0.90.2 github.com/go-acme/lego v2.7.2+incompatible - github.com/go-gandi/go-gandi v0.6.0 + github.com/go-gandi/go-gandi v0.7.0 github.com/gobwas/glob v0.2.4-0.20181002190808-e7a84e9525fe github.com/google/go-github/v35 v35.3.0 github.com/gopherjs/jquery v0.0.0-20191017083323-73f4c7416038 @@ -51,9 +51,9 @@ require ( github.com/transip/gotransip/v6 v6.23.0 github.com/urfave/cli/v2 v2.25.7 github.com/xddxdd/ottoext v0.0.0-20221109171055-210517fa4419 - golang.org/x/net v0.18.0 - golang.org/x/oauth2 v0.14.0 - google.golang.org/api v0.151.0 + golang.org/x/net v0.19.0 + golang.org/x/oauth2 v0.15.0 + google.golang.org/api v0.152.0 gopkg.in/ns1/ns1-go.v2 v2.7.11 ) @@ -67,28 +67,28 @@ require ( github.com/kylelemons/godebug v1.1.0 github.com/mattn/go-isatty v0.0.20 github.com/vultr/govultr/v2 v2.17.2 - golang.org/x/exp v0.0.0-20231110203233-9a3e6036ecaa + golang.org/x/exp v0.0.0-20231127185646-65229373498e golang.org/x/text v0.14.0 gopkg.in/yaml.v3 v3.0.1 ) require ( - cloud.google.com/go/compute v1.23.1 // indirect + cloud.google.com/go/compute v1.23.3 // indirect cloud.google.com/go/compute/metadata v0.2.3 // indirect github.com/Azure/azure-sdk-for-go/sdk/internal v1.5.0 // indirect github.com/Azure/go-autorest v14.2.0+incompatible // indirect github.com/AzureAD/microsoft-authentication-library-for-go v1.1.1 // indirect github.com/andybalholm/cascadia v1.3.1 // indirect - github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.14.4 // indirect - github.com/aws/aws-sdk-go-v2/internal/configsources v1.2.3 // indirect - github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.5.3 // indirect + github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.14.8 // indirect + github.com/aws/aws-sdk-go-v2/internal/configsources v1.2.7 // indirect + github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.5.7 // indirect github.com/aws/aws-sdk-go-v2/internal/ini v1.7.1 // indirect - github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.10.1 // indirect - github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.10.3 // indirect - github.com/aws/aws-sdk-go-v2/service/sso v1.17.2 // indirect - github.com/aws/aws-sdk-go-v2/service/ssooidc v1.20.0 // indirect - github.com/aws/aws-sdk-go-v2/service/sts v1.25.3 // indirect - github.com/aws/smithy-go v1.17.0 // indirect + github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.10.3 // indirect + github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.10.7 // indirect + github.com/aws/aws-sdk-go-v2/service/sso v1.18.1 // indirect + github.com/aws/aws-sdk-go-v2/service/ssooidc v1.21.1 // indirect + github.com/aws/aws-sdk-go-v2/service/sts v1.26.1 // indirect + github.com/aws/smithy-go v1.18.1 // indirect github.com/boombuler/barcode v1.0.1 // indirect github.com/cenkalti/backoff v2.2.1+incompatible // indirect github.com/cenkalti/backoff/v3 v3.0.0 // indirect @@ -112,7 +112,7 @@ require ( github.com/hashicorp/errwrap v1.1.0 // indirect github.com/hashicorp/go-cleanhttp v0.5.2 // indirect github.com/hashicorp/go-multierror v1.1.1 // indirect - github.com/hashicorp/go-retryablehttp v0.7.4 // indirect + github.com/hashicorp/go-retryablehttp v0.7.5 // indirect github.com/hashicorp/go-rootcerts v1.0.2 // indirect github.com/hashicorp/go-secure-stdlib/parseutil v0.1.6 // indirect github.com/hashicorp/go-secure-stdlib/strutil v0.1.2 // indirect @@ -137,14 +137,14 @@ require ( github.com/stretchr/objx v0.5.0 // indirect github.com/xrash/smetrics v0.0.0-20201216005158-039620a65673 // indirect go.opencensus.io v0.24.0 // indirect - golang.org/x/crypto v0.15.0 // indirect + golang.org/x/crypto v0.16.0 // indirect golang.org/x/mod v0.14.0 // indirect golang.org/x/sync v0.5.0 // indirect - golang.org/x/sys v0.14.0 // indirect - golang.org/x/time v0.4.0 // indirect - golang.org/x/tools v0.15.0 // indirect + golang.org/x/sys v0.15.0 // indirect + golang.org/x/time v0.5.0 // indirect + golang.org/x/tools v0.16.0 // indirect google.golang.org/appengine v1.6.7 // indirect - google.golang.org/genproto/googleapis/rpc v0.0.0-20231030173426-d783a09b4405 // indirect + google.golang.org/genproto/googleapis/rpc v0.0.0-20231120223509-83a465c0220f // indirect google.golang.org/grpc v1.59.0 // indirect google.golang.org/protobuf v1.31.0 // indirect gopkg.in/ini.v1 v1.67.0 // indirect diff --git a/go.sum b/go.sum index 75ee55f5b6..2ee0953521 100644 --- a/go.sum +++ b/go.sum @@ -1,6 +1,6 @@ cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= -cloud.google.com/go/compute v1.23.1 h1:V97tBoDaZHb6leicZ1G6DLK2BAaZLJ/7+9BB/En3hR0= -cloud.google.com/go/compute v1.23.1/go.mod h1:CqB3xpmPKKt3OJpW2ndFIXnA9A4xAy/F3Xp1ixncW78= +cloud.google.com/go/compute v1.23.3 h1:6sVlXXBmbd7jNX0Ipq0trII3e4n1/MsADLK6a+aiVlk= +cloud.google.com/go/compute v1.23.3/go.mod h1:VCgBUoMnIVIR0CscqQiPJLAG25E3ZRZMzcFZeQ+h8CI= cloud.google.com/go/compute/metadata v0.2.3 h1:mg4jlk7mCAj6xXp9UJ4fjI9VUI5rubuGBW5aJ7UnBMY= cloud.google.com/go/compute/metadata v0.2.3/go.mod h1:VAV5nSsACxMJvgaAuX6Pk2AawlZn8kiOGuCv6gTkwuA= github.com/Azure/azure-sdk-for-go/sdk/azcore v1.9.0 h1:fb8kj/Dh4CSwgsOzHeZY4Xh68cFVbzXx+ONXGMY//4w= @@ -9,14 +9,14 @@ github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.4.0 h1:BMAjVKJM0U/CYF27gA0ZM github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.4.0/go.mod h1:1fXstnBMas5kzG+S3q8UoJcmyU6nUeunJcMDHcRYHhs= github.com/Azure/azure-sdk-for-go/sdk/internal v1.5.0 h1:d81/ng9rET2YqdVkVwkb6EXeRrLJIwyGnJcAlAWKwhs= github.com/Azure/azure-sdk-for-go/sdk/internal v1.5.0/go.mod h1:s4kgfzA0covAXNicZHDMN58jExvcng2mC/DepXiF1EI= -github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/dns/armdns v1.1.0 h1:8iR6OLffWWorFdzL2JFCab5xpD8VKEE2DUBBl+HNTDY= -github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/dns/armdns v1.1.0/go.mod h1:copqlcjMWc/wgQ1N2fzsJFQxDdqKGg1EQt8T5wJMOGE= -github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/internal v1.1.2 h1:mLY+pNLjCUeKhgnAJWAKhEUQM+RJQo2H1fuGSw1Ky1E= -github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/internal v1.1.2/go.mod h1:FbdwsQ2EzwvXxOPcMFYO8ogEc9uMMIj3YkmCdXdAFmk= -github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/privatedns/armprivatedns v1.1.0 h1:rR8ZW79lE/ppfXTfiYSnMFv5EzmVuY4pfZWIkscIJ64= -github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/privatedns/armprivatedns v1.1.0/go.mod h1:y2zXtLSMM/X5Mfawq0lOftpWn3f4V6OCsRdINsvWBPI= -github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/resources/armresources v1.0.0 h1:ECsQtyERDVz3NP3kvDOTLvbQhqWp/x9EsGKtb4ogUr8= -github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/resources/armresources v1.0.0/go.mod h1:s1tW/At+xHqjNFvWU4G0c0Qv33KOhvbGNj0RCTQDV8s= +github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/dns/armdns v1.2.0 h1:lpOxwrQ919lCZoNCd69rVt8u1eLZuMORrGXqy8sNf3c= +github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/dns/armdns v1.2.0/go.mod h1:fSvRkb8d26z9dbL40Uf/OO6Vo9iExtZK3D0ulRV+8M0= +github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/internal/v2 v2.0.0 h1:PTFGRSlMKCQelWwxUyYVEUqseBJVemLyqWJjvMyt0do= +github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/internal/v2 v2.0.0/go.mod h1:LRr2FzBTQlONPPa5HREE5+RjSCTXl7BwOvYOaWTqCaI= +github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/privatedns/armprivatedns v1.2.0 h1:9Eih8XcEeQnFD0ntMlUDleKMzfeCeUfa+VbnDCI4AZs= +github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/privatedns/armprivatedns v1.2.0/go.mod h1:wGPyTi+aURdqPAGMZDQqnNs9IrShADF8w2WZb6bKeq0= +github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/resources/armresources v1.1.1 h1:7CBQ+Ei8SP2c6ydQTGCCrS35bDxgTMfoP2miAwK++OU= +github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/resources/armresources v1.1.1/go.mod h1:c/wcGeGx5FUPbM/JltUYHZcKmigwyVLJlDq+4HdtXaw= github.com/Azure/go-autorest v14.2.0+incompatible h1:V5VMDjClD3GiElqLWO7mz2MxNAK/vTfRHdAubSIPRgs= github.com/Azure/go-autorest v14.2.0+incompatible/go.mod h1:r+4oMnoxhatjLLJ6zxSWATqVooLgysK6ZNox3g/xq24= github.com/Azure/go-autorest/autorest/to v0.4.0 h1:oXVqrxakqqV1UZdSazDOPOLvOIz+XA683u8EctwboHk= @@ -39,36 +39,36 @@ github.com/andreyvit/diff v0.0.0-20170406064948-c7f18ee00883/go.mod h1:rCTlJbsFo github.com/andybalholm/cascadia v1.3.1 h1:nhxRkql1kdYCc8Snf7D5/D3spOX+dBgjA6u8x004T2c= github.com/andybalholm/cascadia v1.3.1/go.mod h1:R4bJ1UQfqADjvDa4P6HZHLh/3OxWWEqc0Sk8XGwHqvA= github.com/armon/go-radix v0.0.0-20180808171621-7fddfc383310/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8= -github.com/aws/aws-sdk-go-v2 v1.23.0 h1:PiHAzmiQQr6JULBUdvR8fKlA+UPKLT/8KbiqpFBWiAo= -github.com/aws/aws-sdk-go-v2 v1.23.0/go.mod h1:i1XDttT4rnf6vxc9AuskLc6s7XBee8rlLilKlc03uAA= -github.com/aws/aws-sdk-go-v2/config v1.25.3 h1:E4m9LbwJOoncDNt3e9MPLbz/saxWcGUlZVBydydD6+8= -github.com/aws/aws-sdk-go-v2/config v1.25.3/go.mod h1:tAByZy03nH5jcq0vZmkcVoo6tRzRHEwSFx3QW4NmDw8= -github.com/aws/aws-sdk-go-v2/credentials v1.16.2 h1:0sdZ5cwfOAipTzZ7eOL0gw4LAhk/RZnTa16cDqIt8tg= -github.com/aws/aws-sdk-go-v2/credentials v1.16.2/go.mod h1:sDdvGhXrSVT5yzBDR7qXz+rhbpiMpUYfF3vJ01QSdrc= -github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.14.4 h1:9wKDWEjwSnXZre0/O3+ZwbBl1SmlgWYBbrTV10X/H1s= -github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.14.4/go.mod h1:t4i+yGHMCcUNIX1x7YVYa6bH/Do7civ5I6cG/6PMfyA= -github.com/aws/aws-sdk-go-v2/internal/configsources v1.2.3 h1:DUwbD79T8gyQ23qVXFUthjzVMTviSHi3y4z58KvghhM= -github.com/aws/aws-sdk-go-v2/internal/configsources v1.2.3/go.mod h1:7sGSz1JCKHWWBHq98m6sMtWQikmYPpxjqOydDemiVoM= -github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.5.3 h1:AplLJCtIaUZDCbr6+gLYdsYNxne4iuaboJhVt9d+WXI= -github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.5.3/go.mod h1:ify42Rb7nKeDDPkFjKn7q1bPscVPu/+gmHH8d2c+anU= +github.com/aws/aws-sdk-go-v2 v1.23.4 h1:2P20ZjH0ouSAu/6yZep8oCmTReathLuEu6dwoqEgjts= +github.com/aws/aws-sdk-go-v2 v1.23.4/go.mod h1:t3szzKfP0NeRU27uBFczDivYJjsmSnqI8kIvKyWb9ds= +github.com/aws/aws-sdk-go-v2/config v1.25.10 h1:qw/e8emDtNufTkrAU86DlQ18DruMyyM7ttW6Lgwp4v0= +github.com/aws/aws-sdk-go-v2/config v1.25.10/go.mod h1:203YiAtb6XyoGxXMPsUVwEcuxCiTQY/r8P27IDjfvMc= +github.com/aws/aws-sdk-go-v2/credentials v1.16.8 h1:phw9nRLy/77bPk6Mfu2SHCOnHwfVB7WWrOa5rZIY2Fc= +github.com/aws/aws-sdk-go-v2/credentials v1.16.8/go.mod h1:MrS4SOin6adbO6wgWhdifyPiq+TX7fPPwyA/ZLC1F5M= +github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.14.8 h1:tQZLSPC2Zj2CqZHonLmWEvCsbpMX5tQvaYJWHadcPek= +github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.14.8/go.mod h1:5+YpvTHDFffykWr5qAGjqwoh8oVYZOddL3sSrEN7lws= +github.com/aws/aws-sdk-go-v2/internal/configsources v1.2.7 h1:eMqD7ku6WGdmcWWXPYun9m6yk6feSULLhJlAtN6rYG4= +github.com/aws/aws-sdk-go-v2/internal/configsources v1.2.7/go.mod h1:0oBIfcDV6LScxEW0VgOqxT3e4aqKRp+SYhB9wAd5E3Q= +github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.5.7 h1:+XYhWhgWs5F3Zx8oa49CXzNvfXrItaDjZB/M172fcHQ= +github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.5.7/go.mod h1:L6tcSRyCGxcKfDWUrmv2jv8G1cLDU7d0FUpEFpG9bVE= github.com/aws/aws-sdk-go-v2/internal/ini v1.7.1 h1:uR9lXYjdPX0xY+NhvaJ4dD8rpSRz5VY81ccIIoNG+lw= github.com/aws/aws-sdk-go-v2/internal/ini v1.7.1/go.mod h1:6fQQgfuGmw8Al/3M2IgIllycxV7ZW7WCdVSqfBeUiCY= -github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.10.1 h1:rpkF4n0CyFcrJUG/rNNohoTmhtWlFTRI4BsZOh9PvLs= -github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.10.1/go.mod h1:l9ymW25HOqymeU2m1gbUQ3rUIsTwKs8gYHXkqDQUhiI= -github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.10.3 h1:kJOolE8xBAD13xTCgOakByZkyP4D/owNmvEiioeUNAg= -github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.10.3/go.mod h1:Owv1I59vaghv1Ax8zz8ELY8DN7/Y0rGS+WWAmjgi950= -github.com/aws/aws-sdk-go-v2/service/route53 v1.34.2 h1:h9I/GZ7POL9EOyFouZi7P3v0G8Sr/nMIo9uHIyk+NSU= -github.com/aws/aws-sdk-go-v2/service/route53 v1.34.2/go.mod h1:adrwIPgzeyWkAyIlnH7SkTU/UTATCXncCR4fbxwYLhA= -github.com/aws/aws-sdk-go-v2/service/route53domains v1.19.2 h1:k2Swg+KnFtyS3GYy4sUXFUaULpiyrZJsW/8ehoT9/BA= -github.com/aws/aws-sdk-go-v2/service/route53domains v1.19.2/go.mod h1:mSL5mozBzBnMfrmjBe8eASqtOKeYZ4rFiSYAwN5PAGs= -github.com/aws/aws-sdk-go-v2/service/sso v1.17.2 h1:V47N5eKgVZoRSvx2+RQ0EpAEit/pqOhqeSQFiS4OFEQ= -github.com/aws/aws-sdk-go-v2/service/sso v1.17.2/go.mod h1:/pE21vno3q1h4bbhUOEi+6Zu/aT26UK2WKkDXd+TssQ= -github.com/aws/aws-sdk-go-v2/service/ssooidc v1.20.0 h1:/XiEU7VIFcVWRDQLabyrSjBoKIm8UkYgsvWDuFW8Img= -github.com/aws/aws-sdk-go-v2/service/ssooidc v1.20.0/go.mod h1:dWqm5G767qwKPuayKfzm4rjzFmVjiBFbOJrpSPnAMDs= -github.com/aws/aws-sdk-go-v2/service/sts v1.25.3 h1:M2w4kiMGJCCM6Ljmmx/l6mmpfa3gPJVpBencfnsgvqs= -github.com/aws/aws-sdk-go-v2/service/sts v1.25.3/go.mod h1:4EqRHDCKP78hq3zOnmFXu5k0j4bXbRFfCh/zQ6KnEfQ= -github.com/aws/smithy-go v1.17.0 h1:wWJD7LX6PBV6etBUwO0zElG0nWN9rUhp0WdYeHSHAaI= -github.com/aws/smithy-go v1.17.0/go.mod h1:NukqUGpCZIILqqiV0NIjeFh24kd/FAa4beRb6nbIUPE= +github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.10.3 h1:e3PCNeEaev/ZF01cQyNZgmYE9oYYePIMJs2mWSKG514= +github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.10.3/go.mod h1:gIeeNyaL8tIEqZrzAnTeyhHcE0yysCtcaP+N9kxLZ+E= +github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.10.7 h1:dU+ZyhvqMB/T/TxjGagHMCdyUiqaThRIaMu3YvKiSQI= +github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.10.7/go.mod h1:SGORuNqoXyWfTvTp/gBGJfv8jRvW/+nha0XhnIXVI+o= +github.com/aws/aws-sdk-go-v2/service/route53 v1.35.1 h1:v/3D+QsF91AdkF6REEPq6RePxy0vJiHv70CzzLdHrqs= +github.com/aws/aws-sdk-go-v2/service/route53 v1.35.1/go.mod h1:KvdP5Uk34wpr49287kAZJOUJtJXqVZmUTVAbYfknrnM= +github.com/aws/aws-sdk-go-v2/service/route53domains v1.20.1 h1:5T+BONhULX+UXFTSoebZ+wX0QGfO8lZMj6E+OwGS44A= +github.com/aws/aws-sdk-go-v2/service/route53domains v1.20.1/go.mod h1:KFZcLBA2BplaxYAOM806i6F5A7EMJDYDR1FnAR3VHkI= +github.com/aws/aws-sdk-go-v2/service/sso v1.18.1 h1:V40g2daNO3l1J94JYwqfkyvQMYXi5I25fs3fNQW8iDs= +github.com/aws/aws-sdk-go-v2/service/sso v1.18.1/go.mod h1:0ZWQJP/mBOUxkCvZKybZNz1XmdUKSBxoF0dzgfxtvDs= +github.com/aws/aws-sdk-go-v2/service/ssooidc v1.21.1 h1:uQrj7SpUNC3r55vc1CDh3qV9wJC66lz546xM9dhSo5s= +github.com/aws/aws-sdk-go-v2/service/ssooidc v1.21.1/go.mod h1:oyaTk5xEAOuPXX1kCD7HmIeuLqdj3Bk5yGkqGXtGi14= +github.com/aws/aws-sdk-go-v2/service/sts v1.26.1 h1:K33V7L0XDdb23FMOZySr8bon1jou5SHn1fiv7NJ1SUg= +github.com/aws/aws-sdk-go-v2/service/sts v1.26.1/go.mod h1:YtXUl/sfnS06VksYhr855hTQf2HphfT1Xv/EwuzbPjg= +github.com/aws/smithy-go v1.18.1 h1:pOdBTUfXNazOlxLrgeYalVnuTpKreACHtc62xLwIB3c= +github.com/aws/smithy-go v1.18.1/go.mod h1:NukqUGpCZIILqqiV0NIjeFh24kd/FAa4beRb6nbIUPE= github.com/babolivier/go-doh-client v0.0.0-20201028162107-a76cff4cb8b6 h1:4NNbNM2Iq/k57qEu7WfL67UrbPq1uFWxW4qODCohi+0= github.com/babolivier/go-doh-client v0.0.0-20201028162107-a76cff4cb8b6/go.mod h1:J29hk+f9lJrblVIfiJOtTFk+OblBawmib4uz/VdKzlg= github.com/bgentry/speakeasy v0.1.0/go.mod h1:+zsyZBPWlz7T6j88CTgSN5bM796AkVf0kBD4zp0CCIs= @@ -89,8 +89,8 @@ github.com/centralnicgroup-opensource/rtldev-middleware-go-sdk/v3 v3.5.6/go.mod github.com/chzyer/logex v1.2.1/go.mod h1:JLbx6lG2kDbNRFnfkgvh4eRJRPX1QCoOIWomwysCBrQ= github.com/chzyer/test v1.0.0/go.mod h1:2JlltgoNkt4TW/z9V/IzDdFaMTM2JPIi26O1pF38GC8= github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= -github.com/cloudflare/cloudflare-go v0.81.0 h1:NSLpR2cBn5K1cFXkYsZ7skVNFN+AAJBKdUWAj8v1PGA= -github.com/cloudflare/cloudflare-go v0.81.0/go.mod h1:TIT8ltdOkZthsC+6owWe0ODSgl84sq3f8iAsja8E1KQ= +github.com/cloudflare/cloudflare-go v0.82.0 h1:t4G5BcutMcd+3U1FJHifo7Gv3m3LCzhARKZDinSi9Qs= +github.com/cloudflare/cloudflare-go v0.82.0/go.mod h1:W9Tg8ntSvkoWs/YpwuucBf6ZaG5wTcUSLhyg6GH/zBg= github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc= github.com/cpuguy83/go-md2man/v2 v2.0.2 h1:p1EgwI/C7NhT0JmVkwCD2ZBK8j4aeHQX2pMHHBfMQ6w= github.com/cpuguy83/go-md2man/v2 v2.0.2/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o= @@ -131,8 +131,8 @@ github.com/gin-gonic/gin v1.7.4/go.mod h1:jD2toBW3GZUr5UMcdrwQA10I7RuaFOl/SGeDjX github.com/go-acme/lego v2.7.2+incompatible h1:ThhpPBgf6oa9X/vRd0kEmWOsX7+vmYdckmGZSb+FEp0= github.com/go-acme/lego v2.7.2+incompatible/go.mod h1:yzMNe9CasVUhkquNvti5nAtPmG94USbYxYrZfTkIn0M= github.com/go-chi/chi/v5 v5.0.0/go.mod h1:BBug9lr0cqtdAhsu6R4AAdvufI0/XBzAQSsUqJpoZOs= -github.com/go-gandi/go-gandi v0.6.0 h1:RgFoevggRRp7hF9XsOmWmtwbUg2axhe2ygEdd6Mtstc= -github.com/go-gandi/go-gandi v0.6.0/go.mod h1:9NoYyfWCjFosClPiWjkbbRK5UViaZ4ctpT8/pKSSFlw= +github.com/go-gandi/go-gandi v0.7.0 h1:gsP33dUspsN1M+ZW9HEgHchK9HiaSkYnltO73RHhSZA= +github.com/go-gandi/go-gandi v0.7.0/go.mod h1:9NoYyfWCjFosClPiWjkbbRK5UViaZ4ctpT8/pKSSFlw= github.com/go-jose/go-jose/v3 v3.0.1 h1:pWmKFVtt+Jl0vBZTIpz/eAKwsm6LkIxDVVbFHKkchhA= github.com/go-jose/go-jose/v3 v3.0.1/go.mod h1:RNkWWRld676jZEYoV3+XK8L2ZnNSvIsxFMht0mSX+u8= github.com/go-openapi/jsonpointer v0.19.5/go.mod h1:Pl9vOtqEWErmShwVjC8pYs9cog34VGT37dQOVbmoatg= @@ -225,8 +225,8 @@ github.com/hashicorp/go-hclog v1.2.0/go.mod h1:whpDNt7SSdeAju8AWKIWsul05p54N/39E github.com/hashicorp/go-multierror v1.0.0/go.mod h1:dHtQlpGsu+cZNNAkkCN/P3hoUDHhCYQXV3UM06sGGrk= github.com/hashicorp/go-multierror v1.1.1 h1:H5DkEtf6CXdFp0N0Em5UCwQpXMWke8IA0+lD48awMYo= github.com/hashicorp/go-multierror v1.1.1/go.mod h1:iw975J/qwKPdAO1clOe2L8331t/9/fmwbPZ6JB6eMoM= -github.com/hashicorp/go-retryablehttp v0.7.4 h1:ZQgVdpTdAL7WpMIwLzCfbalOcSUdkDZnpUv3/+BxzFA= -github.com/hashicorp/go-retryablehttp v0.7.4/go.mod h1:Jy/gPYAdjqffZ/yFGCFV2doI5wjtH1ewM9u8iYVjtX8= +github.com/hashicorp/go-retryablehttp v0.7.5 h1:bJj+Pj19UZMIweq/iie+1u5YCdGrnxCT9yvm0e+Nd5M= +github.com/hashicorp/go-retryablehttp v0.7.5/go.mod h1:Jy/gPYAdjqffZ/yFGCFV2doI5wjtH1ewM9u8iYVjtX8= github.com/hashicorp/go-rootcerts v1.0.2 h1:jzhAVGtqPKbwpyCPELlgNWhE1znq+qwJtW5Oi2viEzc= github.com/hashicorp/go-rootcerts v1.0.2/go.mod h1:pqUvnprVnM5bf7AOirdbb01K4ccR319Vf4pU3K5EGc8= github.com/hashicorp/go-secure-stdlib/parseutil v0.1.6 h1:om4Al8Oy7kCm/B86rLCLah4Dt5Aa0Fr5rYBG60OzwHQ= @@ -446,11 +446,11 @@ golang.org/x/crypto v0.0.0-20201217014255-9d1352758620/go.mod h1:jdWPYTVW3xRLrWP golang.org/x/crypto v0.0.0-20210711020723-a769d52b0f97/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= golang.org/x/crypto v0.0.0-20210817164053-32db794688a5/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= -golang.org/x/crypto v0.15.0 h1:frVn1TEaCEaZcn3Tmd7Y2b5KKPaZ+I32Q2OA3kYp5TA= -golang.org/x/crypto v0.15.0/go.mod h1:4ChreQoLWfG3xLDer1WdlH5NdlQ3+mwnQq1YTKY+72g= +golang.org/x/crypto v0.16.0 h1:mMMrFzRSCF0GvB7Ne27XVtVAaXLrPmgPC7/v0tkwHaY= +golang.org/x/crypto v0.16.0/go.mod h1:gCAAfMLgwOJRpTjQ2zCCt2OcSfYMTeZVSRtQlPC7Nq4= golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= -golang.org/x/exp v0.0.0-20231110203233-9a3e6036ecaa h1:FRnLl4eNAQl8hwxVVC17teOw8kdjVDVAiFMtgUdTSRQ= -golang.org/x/exp v0.0.0-20231110203233-9a3e6036ecaa/go.mod h1:zk2irFbV9DP96SEBUUAy67IdHUaZuSnrz1n472HUCLE= +golang.org/x/exp v0.0.0-20231127185646-65229373498e h1:Gvh4YaCaXNs6dKTlfgismwWZKyjVZXwOPfIyUaqU3No= +golang.org/x/exp v0.0.0-20231127185646-65229373498e/go.mod h1:iRJReGqOEeBhDZGkGbynYwcHlctCvnjTYIamk7uXpHI= golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU= golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= @@ -476,11 +476,11 @@ golang.org/x/net v0.0.0-20210913180222-943fd674d43e/go.mod h1:9nx3DQGgdP8bBQD5qx golang.org/x/net v0.0.0-20210916014120-12bc252f5db8/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= golang.org/x/net v0.7.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs= -golang.org/x/net v0.18.0 h1:mIYleuAkSbHh0tCv7RvjL3F6ZVbLjq4+R7zbOn3Kokg= -golang.org/x/net v0.18.0/go.mod h1:/czyP5RqHAH4odGYxBJ1qz0+CE5WZ+2j1YgoEo8F2jQ= +golang.org/x/net v0.19.0 h1:zTwKpTd2XuCqf8huc7Fo2iSy+4RHPd10s4KzeTnVr1c= +golang.org/x/net v0.19.0/go.mod h1:CfAk/cbD4CthTvqiEl8NpboMuiuOYsAr/7NOjZJtv1U= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= -golang.org/x/oauth2 v0.14.0 h1:P0Vrf/2538nmC0H+pEQ3MNFRRnVR7RlqyVw+bvm26z0= -golang.org/x/oauth2 v0.14.0/go.mod h1:lAtNWgaWfL4cm7j2OV8TxGi9Qb7ECORx8DktCY74OwM= +golang.org/x/oauth2 v0.15.0 h1:s8pnnxNVzjWyrvYdFUQq5llS1PX2zhPXmccZv99h7uQ= +golang.org/x/oauth2 v0.15.0/go.mod h1:q48ptWNTY5XWf+JNten23lcvHpLJ0ZSxF5ttTHKVCAM= golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= @@ -512,8 +512,8 @@ golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBc golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.14.0 h1:Vz7Qs629MkJkGyHxUlRHizWJRG2j8fbQKjELVSNhy7Q= -golang.org/x/sys v0.14.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/sys v0.15.0 h1:h48lPFYpsTvQJZF4EKyI4aLHaev3CxivZmv7yZig9pc= +golang.org/x/sys v0.15.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= @@ -529,8 +529,8 @@ golang.org/x/text v0.14.0 h1:ScX5w1eTa3QqT8oi6+ziP7dTV1S2+ALU0bI+0zXKWiQ= golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU= golang.org/x/time v0.0.0-20201208040808-7e3f01d25324/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20210220033141-f8bda1e9f3ba/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= -golang.org/x/time v0.4.0 h1:Z81tqI5ddIoXDPvVQ7/7CC9TnLM7ubaFG2qXYd5BbYY= -golang.org/x/time v0.4.0/go.mod h1:3BpzKBy/shNhVucY/MWOyx10tF3SFh9QdLuxbVysPQM= +golang.org/x/time v0.5.0 h1:o7cqy6amK/52YcAKIPlM3a+Fpj35zvRj2TP+e1xFSfk= +golang.org/x/time v0.5.0/go.mod h1:3BpzKBy/shNhVucY/MWOyx10tF3SFh9QdLuxbVysPQM= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY= @@ -541,14 +541,14 @@ golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtn golang.org/x/tools v0.0.0-20200918232735-d647fc253266/go.mod h1:z6u4i615ZeAfBE4XtMziQW1fSVJXACjjbWkB/mvPzlU= golang.org/x/tools v0.0.0-20210114065538-d78b04bdf963/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc= -golang.org/x/tools v0.15.0 h1:zdAyfUGbYmuVokhzVmghFl2ZJh5QhcfebBgmVPFYA+8= -golang.org/x/tools v0.15.0/go.mod h1:hpksKq4dtpQWS1uQ61JkdqWM3LscIS6Slf+VVkm+wQk= +golang.org/x/tools v0.16.0 h1:GO788SKMRunPIBCXiQyo2AaexLstOrVhuAL5YwsckQM= +golang.org/x/tools v0.16.0/go.mod h1:kYVVN6I1mBNoB1OX+noeBjbRk4IUEPa7JJ+TJMEooJ0= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= -google.golang.org/api v0.151.0 h1:FhfXLO/NFdJIzQtCqjpysWwqKk8AzGWBUhMIx67cVDU= -google.golang.org/api v0.151.0/go.mod h1:ccy+MJ6nrYFgE3WgRx/AMXOxOmU8Q4hSa+jjibzhxcg= +google.golang.org/api v0.152.0 h1:t0r1vPnfMc260S2Ci+en7kfCZaLOPs5KI0sVV/6jZrY= +google.golang.org/api v0.152.0/go.mod h1:3qNJX5eOmhiWYc67jRA/3GsDw97UFb5ivv7Y2PrriAY= google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= google.golang.org/appengine v1.6.7 h1:FZR1q0exgwxzPzp/aF+VccGrSfxfPpkBqjIIEq3ru6c= @@ -556,12 +556,12 @@ google.golang.org/appengine v1.6.7/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCID google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc= google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo= -google.golang.org/genproto v0.0.0-20231016165738-49dd2c1f3d0b h1:+YaDE2r2OG8t/z5qmsh7Y+XXwCbvadxxZ0YY6mTdrVA= -google.golang.org/genproto v0.0.0-20231016165738-49dd2c1f3d0b/go.mod h1:CgAqfJo+Xmu0GwA0411Ht3OU3OntXwsGmrmjI8ioGXI= -google.golang.org/genproto/googleapis/api v0.0.0-20231016165738-49dd2c1f3d0b h1:CIC2YMXmIhYw6evmhPxBKJ4fmLbOFtXQN/GV3XOZR8k= -google.golang.org/genproto/googleapis/api v0.0.0-20231016165738-49dd2c1f3d0b/go.mod h1:IBQ646DjkDkvUIsVq/cc03FUFQ9wbZu7yE396YcL870= -google.golang.org/genproto/googleapis/rpc v0.0.0-20231030173426-d783a09b4405 h1:AB/lmRny7e2pLhFEYIbl5qkDAUt2h0ZRO4wGPhZf+ik= -google.golang.org/genproto/googleapis/rpc v0.0.0-20231030173426-d783a09b4405/go.mod h1:67X1fPuzjcrkymZzZV1vvkFeTn2Rvc6lYF9MYFGCcwE= +google.golang.org/genproto v0.0.0-20231106174013-bbf56f31fb17 h1:wpZ8pe2x1Q3f2KyT5f8oP/fa9rHAKgFPr/HZdNuS+PQ= +google.golang.org/genproto v0.0.0-20231106174013-bbf56f31fb17/go.mod h1:J7XzRzVy1+IPwWHZUzoD0IccYZIrXILAQpc+Qy9CMhY= +google.golang.org/genproto/googleapis/api v0.0.0-20231106174013-bbf56f31fb17 h1:JpwMPBpFN3uKhdaekDpiNlImDdkUAyiJ6ez/uxGaUSo= +google.golang.org/genproto/googleapis/api v0.0.0-20231106174013-bbf56f31fb17/go.mod h1:0xJLfVdJqpAPl8tDg1ujOCGzx6LFLttXT5NhllGOXY4= +google.golang.org/genproto/googleapis/rpc v0.0.0-20231120223509-83a465c0220f h1:ultW7fxlIvee4HYrtnaRPon9HpEgFk5zYpmfMgtKB5I= +google.golang.org/genproto/googleapis/rpc v0.0.0-20231120223509-83a465c0220f/go.mod h1:L9KNLi232K1/xB6f7AlSX692koaRnKaWSR0stBki0Yc= google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg= google.golang.org/grpc v1.25.1/go.mod h1:c3i+UQWmh7LiEpx4sFZnkU36qjEYZ0imhYfXVyQciAY= From a1e70c93b9e995e27261812df251ba10b160201f Mon Sep 17 00:00:00 2001 From: Jeffrey Cafferata Date: Thu, 30 Nov 2023 19:53:35 +0100 Subject: [PATCH 040/438] DOCS: Fix `R53_` broken links (#2669) --- documentation/SUMMARY.md | 2 +- documentation/functions/domain/R53_ALIAS.md | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/documentation/SUMMARY.md b/documentation/SUMMARY.md index 44034380e0..5893be97fe 100644 --- a/documentation/SUMMARY.md +++ b/documentation/SUMMARY.md @@ -90,7 +90,7 @@ * Service Provider specific * Amazon Route 53 * [R53_ZONE](functions/record/R53_ZONE.md) - * [R53_EVALUATE_TARGET_HEALTH](functions/record/R53_EVALUATE_TARGET_HEALTH.md) + * [R53_EVALUATE_TARGET_HEALTH](functions/record/R53\_EVALUATE\_TARGET\_HEALTH.md) * [Why CNAME/MX/NS targets require a "dot"](why-the-dot.md) ## Service Providers diff --git a/documentation/functions/domain/R53_ALIAS.md b/documentation/functions/domain/R53_ALIAS.md index cd0e3737f5..d247f4e8b0 100644 --- a/documentation/functions/domain/R53_ALIAS.md +++ b/documentation/functions/domain/R53_ALIAS.md @@ -39,7 +39,7 @@ The zone id can be found depending on the target type: * _S3 bucket_ (configured as website): specify the hosted zone ID for the region that you created the bucket in. You can find it in [the List of regions and hosted Zone IDs](https://docs.aws.amazon.com/general/latest/gr/rande.html#s3_region) * _Another Route 53 record_: you can either specify the correct zone id or do not specify anything and DNSControl will figure out the right zone id. (Note: Route53 alias can't reference a record in a different zone). -Target health evaluation can be enabled with the [`R53_EVALUATE_TARGET_HEALTH`](../record/R53_EVALUATE_TARGET_HEALTH.md) record modifier. +Target health evaluation can be enabled with the [`R53_EVALUATE_TARGET_HEALTH`](../record/R53\_EVALUATE\_TARGET\_HEALTH.md) record modifier. {% code title="dnsconfig.js" %} ```javascript From 811fa5477fe304a83c303c47bb74bdf2cff8d96b Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 1 Dec 2023 12:04:31 -0500 Subject: [PATCH 041/438] Build(deps): Bump alpine from 3.18.4 to 3.18.5 (#2671) Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- Dockerfile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Dockerfile b/Dockerfile index f392fc6ff1..7d9c386e67 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,6 +1,6 @@ # syntax = docker/dockerfile:1.4 -FROM alpine:3.18.4@sha256:eece025e432126ce23f223450a0326fbebde39cdf496a85d8c016293fc851978 as RUN +FROM alpine:3.18.5@sha256:34871e7290500828b39e22294660bee86d966bc0017544e848dd9a255cdf59e0 as RUN # Add runtime dependencies # - tzdata: Go time required external dependency eg: TRANSIP and possibly others From 609de61669fde1784f5997022f25298e0ea8bd92 Mon Sep 17 00:00:00 2001 From: Jeffrey Cafferata Date: Mon, 4 Dec 2023 16:04:55 +0100 Subject: [PATCH 042/438] DOCS: Added the missing provider `OpenSRS` page (#2665) --- documentation/SUMMARY.md | 1 + documentation/providers/opensrs.md | 19 +++++++++++++++++++ 2 files changed, 20 insertions(+) create mode 100644 documentation/providers/opensrs.md diff --git a/documentation/SUMMARY.md b/documentation/SUMMARY.md index 5893be97fe..810851643b 100644 --- a/documentation/SUMMARY.md +++ b/documentation/SUMMARY.md @@ -132,6 +132,7 @@ * [Netcup](providers/netcup.md) * [Netlify](providers/netlify.md) * [NS1](providers/ns1.md) + * [OpenSRS](providers/opensrs.md) * [Oracle Cloud](providers/oracle.md) * [OVH](providers/ovh.md) * [Packetframe](providers/packetframe.md) diff --git a/documentation/providers/opensrs.md b/documentation/providers/opensrs.md new file mode 100644 index 0000000000..e3d43eedb4 --- /dev/null +++ b/documentation/providers/opensrs.md @@ -0,0 +1,19 @@ +## Configuration + +To use this provider, add an entry to `creds.json` with `TYPE` set to `OpenSRS` +along with your OpenSRS credentials. + +## Usage + +An example configuration: + +{% code title="dnsconfig.js" %} +```javascript +var REG_NONE = NewRegistrar("none"); +var DSP_OPENSRS = NewDnsProvider("opensrs"); + +D("example.com", REG_NONE, DnsProvider(DSP_OPENSRS), + A("test", "1.2.3.4") +); +``` +{% endcode %} From c1f5a8c41839d6b665e9068fe74816bf44383b42 Mon Sep 17 00:00:00 2001 From: Jeffrey Cafferata Date: Mon, 4 Dec 2023 16:30:30 +0100 Subject: [PATCH 043/438] DOCS: Added the missing provider `Exoscale` page (#2664) --- documentation/SUMMARY.md | 1 + documentation/providers/exoscale.md | 19 +++++++++++++++++++ 2 files changed, 20 insertions(+) create mode 100644 documentation/providers/exoscale.md diff --git a/documentation/SUMMARY.md b/documentation/SUMMARY.md index 810851643b..78d2fa779c 100644 --- a/documentation/SUMMARY.md +++ b/documentation/SUMMARY.md @@ -113,6 +113,7 @@ * [DNS-over-HTTPS](providers/dnsoverhttps.md) * [DOMAINNAMESHOP](providers/domainnameshop.md) * [easyname](providers/easyname.md) + * [Exoscale](providers/exoscale.md) * [Gandi_v5](providers/gandi_v5.md) * [Gcore](providers/gcore.md) * [Google Cloud DNS](providers/gcloud.md) diff --git a/documentation/providers/exoscale.md b/documentation/providers/exoscale.md new file mode 100644 index 0000000000..e245bdd476 --- /dev/null +++ b/documentation/providers/exoscale.md @@ -0,0 +1,19 @@ +## Configuration + +To use this provider, add an entry to `creds.json` with `TYPE` set to `EXOSCALE` +along with your Exoscale credentials. + +## Usage + +An example configuration: + +{% code title="dnsconfig.js" %} +```javascript +var REG_NONE = NewRegistrar("none"); +var DSP_EXOSCALE = NewDnsProvider("exoscale"); + +D("example.com", REG_NONE, DnsProvider(DSP_EXOSCALE), + A("test", "1.2.3.4") +); +``` +{% endcode %} From a366e4bc4d9348866b9cd836d5cabd9749fea491 Mon Sep 17 00:00:00 2001 From: Jeffrey Cafferata Date: Mon, 4 Dec 2023 16:35:29 +0100 Subject: [PATCH 044/438] CI/CD: Release changelog sections (#2674) Co-authored-by: Tom Limoncelli --- .github/pull_request_template.md | 16 ++++++++++++++-- .goreleaser.yml | 13 +++++++++++-- 2 files changed, 25 insertions(+), 4 deletions(-) diff --git a/.github/pull_request_template.md b/.github/pull_request_template.md index 0789ab8253..f82f3e27fd 100644 --- a/.github/pull_request_template.md +++ b/.github/pull_request_template.md @@ -1,9 +1,21 @@ +## Release changelog section + +Help keep the release changelog clear by pre-naming the proper section in the GitHub pull request title. + +Some examples: +* CICD: Add required GHA permissions for goreleaser +* DOCS: Fixed providers with "contributor support" table +* ROUTE53: Allow R53_ALIAS records to enable target health evaluation + +More examples/context can be found in the file .goreleaser.yml under the 'build' > 'changelog' key. +!--> diff --git a/.goreleaser.yml b/.goreleaser.yml index a181427b63..f92d6db0d8 100644 --- a/.goreleaser.yml +++ b/.goreleaser.yml @@ -35,11 +35,20 @@ changelog: - title: 'Provider-specific changes:' regexp: "(?i)((akamaiedge|autodns|axfrd|azure|azure_private_dns|bind|cloudflare|cloudflareapi_old|cloudns|cscglobal|desec|digitalocean|dnsimple|dnsmadeeasy|doh|domainnameshop|easyname|exoscale|gandi|gcloud|gcore|hedns|hetzner|hexonet|hostingde|inwx|linode|loopia|luadns|msdns|mythicbeasts|namecheap|namedotcom|netcup|netlify|ns1|opensrs|oracle|ovh|packetframe|porkbun|powerdns|route53|rwth|softlayer|transip|vultr).*:)+.*" order: 2 + - title: 'Documentation:' + regexp: "(?i)^.*(docs)[(\\w)]*:+.*$" + order: 3 + - title: 'CI/CD:' + regexp: "(?i)^.*(build|ci|cicd)[(\\w)]*:+.*$" + order: 4 + - title: 'Dependencies:' + regexp: "(?i)^.*Build\(deps\)*:+.*$|(?i)^.*update deps+.*$" + order: 5 + - title: 'Other changes and improvements:' + order: 9 - title: 'Deprecation warnings:' regexp: "(?i)^.*Deprecate[(\\w)]*:+.*$" order: 10 - - title: 'Other changes and improvements:' - order: 9 filters: exclude: - '^test:' From ef081da1a6c8327ac1b27672f21a23c836b6ca7d Mon Sep 17 00:00:00 2001 From: Vincent Hagen Date: Mon, 4 Dec 2023 17:54:03 +0100 Subject: [PATCH 045/438] TRANSIP: Fixed integration tests: Edge cases and TXT records fixed (#2673) Co-authored-by: Tom Limoncelli --- integrationTest/integration_test.go | 18 ++++++++-- providers/transip/slashes.go | 11 ++++++ providers/transip/slashes_test.go | 25 +++++++++++++ providers/transip/transipProvider.go | 53 ++++++++++++++++++++-------- 4 files changed, 90 insertions(+), 17 deletions(-) create mode 100644 providers/transip/slashes.go create mode 100644 providers/transip/slashes_test.go diff --git a/integrationTest/integration_test.go b/integrationTest/integration_test.go index 821d1f09e5..52398cb184 100644 --- a/integrationTest/integration_test.go +++ b/integrationTest/integration_test.go @@ -1035,11 +1035,17 @@ func makeTests(t *testing.T) []*TestGroup { // that. testgroup("CNAME", - tc("Record pointing to @", cname("foo", "**current-domain**")), + tc("Record pointing to @", + cname("foo", "**current-domain**"), + a("@", "1.2.3.4"), + ), ), testgroup("MX", - tc("Record pointing to @", mx("foo", 8, "**current-domain**")), + tc("Record pointing to @", + mx("foo", 8, "**current-domain**"), + a("@", "1.2.3.4"), + ), tc("Null MX", mx("@", 0, ".")), // RFC 7505 ), @@ -1246,6 +1252,7 @@ func makeTests(t *testing.T) []*TestGroup { "NAMEDOTCOM", // Their API is so damn slow. We'll add it back as needed. "NS1", // Free acct only allows 50 records, therefore we skip //"ROUTE53", // Batches up changes in pages. + "TRANSIP", // Doesn't page. Works fine. Due to the slow API we skip. ), tc("99 records", manyA("rec%04d", "1.2.3.4", 99)...), tc("100 records", manyA("rec%04d", "1.2.3.4", 100)...), @@ -1515,10 +1522,15 @@ func makeTests(t *testing.T) []*TestGroup { // them here. If you are writing a new provider, I have some good // news: These don't apply to you! - testgroup("ALIAS", + testgroup("ALIAS on apex", requires(providers.CanUseAlias), tc("ALIAS at root", alias("@", "foo.com.")), tc("change it", alias("@", "foo2.com.")), + ), + + testgroup("ALIAS on subdomain", + requires(providers.CanUseAlias), + not("TRANSIP"), // TransIP does support ALIAS records, but only for apex records (@) tc("ALIAS at subdomain", alias("test", "foo.com.")), tc("change it", alias("test", "foo2.com.")), ), diff --git a/providers/transip/slashes.go b/providers/transip/slashes.go new file mode 100644 index 0000000000..1f322da32c --- /dev/null +++ b/providers/transip/slashes.go @@ -0,0 +1,11 @@ +package transip + +import ( + "regexp" +) + +var removeSlashesRegexp = regexp.MustCompile(`(?:\\(\\)+)|(?:\\)`) + +func removeSlashes(s string) string { + return removeSlashesRegexp.ReplaceAllString(s, "$1") +} diff --git a/providers/transip/slashes_test.go b/providers/transip/slashes_test.go new file mode 100644 index 0000000000..e17778032b --- /dev/null +++ b/providers/transip/slashes_test.go @@ -0,0 +1,25 @@ +package transip + +import ( + "testing" +) + +func TestRemoveSlashes(t *testing.T) { + + data := [][]string{ + { + `quote"d`, `quote"d`, + `quote\"d`, `quote"d`, + `quote\\"d`, `quote\"d`, + `m\o\\r\\\\e`, `mo\r\\e`, + }, + } + + for _, testCase := range data { + result := removeSlashes(testCase[0]) + if result != testCase[1] { + t.Fatalf(`Failed on "%s". Expected "%s"; got "%s".`, testCase[0], testCase[1], result) + } + } + +} diff --git a/providers/transip/transipProvider.go b/providers/transip/transipProvider.go index aadb707824..f273c9241b 100644 --- a/providers/transip/transipProvider.go +++ b/providers/transip/transipProvider.go @@ -156,22 +156,9 @@ func (n *transipProvider) getCorrectionsUsingDiff2(dc *models.DomainConfig, reco ) corrections = append(corrections, correction) } else { - - oldEntries, err := recordsToNative(change.Old, true) - if err != nil { - return corrections, err - } - newEntries, err := recordsToNative(change.New, false) - if err != nil { - return corrections, err - } - - deleteCorrection := wrapChangeFunction(oldEntries, func(rec domain.DNSEntry) error { return n.domains.RemoveDNSEntry(dc.Name, rec) }) - createCorrection := wrapChangeFunction(newEntries, func(rec domain.DNSEntry) error { return n.domains.AddDNSEntry(dc.Name, rec) }) corrections = append( corrections, - change.CreateCorrectionWithMessage("[1/2] delete", deleteCorrection), - change.CreateCorrectionWithMessage("[2/2] create", createCorrection), + n.recreateRecordSet(dc, change)..., ) } case diff2.REPORT: @@ -183,6 +170,42 @@ func (n *transipProvider) getCorrectionsUsingDiff2(dc *models.DomainConfig, reco return corrections, nil } +func (n *transipProvider) recreateRecordSet(dc *models.DomainConfig, change diff2.Change) []*models.Correction { + var corrections []*models.Correction + + for _, rec := range change.Old { + if existsInRecords(rec, change.New) { + continue + } + + nativeRec, _ := recordToNative(rec, true) + createCorrection := change.CreateCorrectionWithMessage("[2/2] delete", func() error { return n.domains.RemoveDNSEntry(dc.Name, nativeRec) }) + corrections = append(corrections, createCorrection) + } + + for _, rec := range change.New { + if existsInRecords(rec, change.Old) { + continue + } + + nativeRec, _ := recordToNative(rec, false) + createCorrection := change.CreateCorrectionWithMessage("[1/2] create", func() error { return n.domains.AddDNSEntry(dc.Name, nativeRec) }) + corrections = append(corrections, createCorrection) + } + + return corrections +} + +func existsInRecords(rec *models.RecordConfig, set models.Records) bool { + for _, existing := range set { + if rec.ToComparableNoTTL() == existing.ToComparableNoTTL() && rec.TTL == existing.TTL { + return true + } + } + + return false +} + func recordsToNative(records models.Records, useOriginal bool) ([]domain.DNSEntry, error) { entries := make([]domain.DNSEntry, len(records)) @@ -324,6 +347,8 @@ func getTargetRecordContent(rc *models.RecordConfig) string { return fmt.Sprintf("%d %d %d %s", rc.DsKeyTag, rc.DsAlgorithm, rc.DsDigestType, rc.DsDigest) case "SRV": return fmt.Sprintf("%d %d %d %s", rc.SrvPriority, rc.SrvWeight, rc.SrvPort, rc.GetTargetField()) + case "TXT": + return removeSlashes(models.StripQuotes(rc.GetTargetCombined())) default: return models.StripQuotes(rc.GetTargetCombined()) } From c29a6486be9aac049f4d44ad96eb5910b939663f Mon Sep 17 00:00:00 2001 From: Tom Limoncelli Date: Thu, 30 Nov 2023 14:38:01 -0500 Subject: [PATCH 046/438] Update generated files for v4.6.2 --- commands/types/dnscontrol.d.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/commands/types/dnscontrol.d.ts b/commands/types/dnscontrol.d.ts index 8715383ccb..a850f30275 100644 --- a/commands/types/dnscontrol.d.ts +++ b/commands/types/dnscontrol.d.ts @@ -2279,7 +2279,7 @@ declare const PURGE: DomainModifier; * * _S3 bucket_ (configured as website): specify the hosted zone ID for the region that you created the bucket in. You can find it in [the List of regions and hosted Zone IDs](https://docs.aws.amazon.com/general/latest/gr/rande.html#s3_region) * * _Another Route 53 record_: you can either specify the correct zone id or do not specify anything and DNSControl will figure out the right zone id. (Note: Route53 alias can't reference a record in a different zone). * - * Target health evaluation can be enabled with the [`R53_EVALUATE_TARGET_HEALTH`](../record/R53_EVALUATE_TARGET_HEALTH.md) record modifier. + * Target health evaluation can be enabled with the [`R53_EVALUATE_TARGET_HEALTH`](../record/R53\_EVALUATE\_TARGET\_HEALTH.md) record modifier. * * ```javascript * D("example.com", REG_MY_PROVIDER, DnsProvider("ROUTE53"), From e364d046290c542652d372e8d8bdbb32e4f3cc3e Mon Sep 17 00:00:00 2001 From: Tom Limoncelli Date: Mon, 4 Dec 2023 12:31:07 -0500 Subject: [PATCH 047/438] CICD: Fix YAML (#2677) --- .goreleaser.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.goreleaser.yml b/.goreleaser.yml index f92d6db0d8..dc77e4f7da 100644 --- a/.goreleaser.yml +++ b/.goreleaser.yml @@ -42,7 +42,7 @@ changelog: regexp: "(?i)^.*(build|ci|cicd)[(\\w)]*:+.*$" order: 4 - title: 'Dependencies:' - regexp: "(?i)^.*Build\(deps\)*:+.*$|(?i)^.*update deps+.*$" + regexp: "(?i)^.*Build\\(deps\\)*:+.*$|(?i)^.*update deps+.*$" order: 5 - title: 'Other changes and improvements:' order: 9 From 88d26c3ea2458d01c0b680013bf050068b0c123d Mon Sep 17 00:00:00 2001 From: Tom Limoncelli Date: Mon, 4 Dec 2023 13:10:30 -0500 Subject: [PATCH 048/438] CHORE: Update deps (#2678) --- go.mod | 26 +++++++++++++------------- go.sum | 52 ++++++++++++++++++++++++++-------------------------- 2 files changed, 39 insertions(+), 39 deletions(-) diff --git a/go.mod b/go.mod index a3fe3d97f4..64c2bc5965 100644 --- a/go.mod +++ b/go.mod @@ -14,11 +14,11 @@ require ( github.com/TomOnTime/utfutil v0.0.0-20230223141146-125e65197b36 github.com/akamai/AkamaiOPEN-edgegrid-golang v1.2.2 github.com/andreyvit/diff v0.0.0-20170406064948-c7f18ee00883 - github.com/aws/aws-sdk-go-v2 v1.23.4 - github.com/aws/aws-sdk-go-v2/config v1.25.10 - github.com/aws/aws-sdk-go-v2/credentials v1.16.8 - github.com/aws/aws-sdk-go-v2/service/route53 v1.35.1 - github.com/aws/aws-sdk-go-v2/service/route53domains v1.20.1 + github.com/aws/aws-sdk-go-v2 v1.23.5 + github.com/aws/aws-sdk-go-v2/config v1.25.11 + github.com/aws/aws-sdk-go-v2/credentials v1.16.9 + github.com/aws/aws-sdk-go-v2/service/route53 v1.35.2 + github.com/aws/aws-sdk-go-v2/service/route53domains v1.20.2 github.com/babolivier/go-doh-client v0.0.0-20201028162107-a76cff4cb8b6 github.com/bhendo/go-powershell v0.0.0-20190719160123-219e7fb4e41e github.com/billputer/go-namecheap v0.0.0-20210108011502-994a912fb7f9 @@ -49,7 +49,7 @@ require ( github.com/softlayer/softlayer-go v1.1.2 github.com/stretchr/testify v1.8.4 github.com/transip/gotransip/v6 v6.23.0 - github.com/urfave/cli/v2 v2.25.7 + github.com/urfave/cli/v2 v2.26.0 github.com/xddxdd/ottoext v0.0.0-20221109171055-210517fa4419 golang.org/x/net v0.19.0 golang.org/x/oauth2 v0.15.0 @@ -79,15 +79,15 @@ require ( github.com/Azure/go-autorest v14.2.0+incompatible // indirect github.com/AzureAD/microsoft-authentication-library-for-go v1.1.1 // indirect github.com/andybalholm/cascadia v1.3.1 // indirect - github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.14.8 // indirect - github.com/aws/aws-sdk-go-v2/internal/configsources v1.2.7 // indirect - github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.5.7 // indirect + github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.14.9 // indirect + github.com/aws/aws-sdk-go-v2/internal/configsources v1.2.8 // indirect + github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.5.8 // indirect github.com/aws/aws-sdk-go-v2/internal/ini v1.7.1 // indirect github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.10.3 // indirect - github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.10.7 // indirect - github.com/aws/aws-sdk-go-v2/service/sso v1.18.1 // indirect - github.com/aws/aws-sdk-go-v2/service/ssooidc v1.21.1 // indirect - github.com/aws/aws-sdk-go-v2/service/sts v1.26.1 // indirect + github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.10.8 // indirect + github.com/aws/aws-sdk-go-v2/service/sso v1.18.2 // indirect + github.com/aws/aws-sdk-go-v2/service/ssooidc v1.21.2 // indirect + github.com/aws/aws-sdk-go-v2/service/sts v1.26.2 // indirect github.com/aws/smithy-go v1.18.1 // indirect github.com/boombuler/barcode v1.0.1 // indirect github.com/cenkalti/backoff v2.2.1+incompatible // indirect diff --git a/go.sum b/go.sum index 2ee0953521..a973a1a689 100644 --- a/go.sum +++ b/go.sum @@ -39,34 +39,34 @@ github.com/andreyvit/diff v0.0.0-20170406064948-c7f18ee00883/go.mod h1:rCTlJbsFo github.com/andybalholm/cascadia v1.3.1 h1:nhxRkql1kdYCc8Snf7D5/D3spOX+dBgjA6u8x004T2c= github.com/andybalholm/cascadia v1.3.1/go.mod h1:R4bJ1UQfqADjvDa4P6HZHLh/3OxWWEqc0Sk8XGwHqvA= github.com/armon/go-radix v0.0.0-20180808171621-7fddfc383310/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8= -github.com/aws/aws-sdk-go-v2 v1.23.4 h1:2P20ZjH0ouSAu/6yZep8oCmTReathLuEu6dwoqEgjts= -github.com/aws/aws-sdk-go-v2 v1.23.4/go.mod h1:t3szzKfP0NeRU27uBFczDivYJjsmSnqI8kIvKyWb9ds= -github.com/aws/aws-sdk-go-v2/config v1.25.10 h1:qw/e8emDtNufTkrAU86DlQ18DruMyyM7ttW6Lgwp4v0= -github.com/aws/aws-sdk-go-v2/config v1.25.10/go.mod h1:203YiAtb6XyoGxXMPsUVwEcuxCiTQY/r8P27IDjfvMc= -github.com/aws/aws-sdk-go-v2/credentials v1.16.8 h1:phw9nRLy/77bPk6Mfu2SHCOnHwfVB7WWrOa5rZIY2Fc= -github.com/aws/aws-sdk-go-v2/credentials v1.16.8/go.mod h1:MrS4SOin6adbO6wgWhdifyPiq+TX7fPPwyA/ZLC1F5M= -github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.14.8 h1:tQZLSPC2Zj2CqZHonLmWEvCsbpMX5tQvaYJWHadcPek= -github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.14.8/go.mod h1:5+YpvTHDFffykWr5qAGjqwoh8oVYZOddL3sSrEN7lws= -github.com/aws/aws-sdk-go-v2/internal/configsources v1.2.7 h1:eMqD7ku6WGdmcWWXPYun9m6yk6feSULLhJlAtN6rYG4= -github.com/aws/aws-sdk-go-v2/internal/configsources v1.2.7/go.mod h1:0oBIfcDV6LScxEW0VgOqxT3e4aqKRp+SYhB9wAd5E3Q= -github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.5.7 h1:+XYhWhgWs5F3Zx8oa49CXzNvfXrItaDjZB/M172fcHQ= -github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.5.7/go.mod h1:L6tcSRyCGxcKfDWUrmv2jv8G1cLDU7d0FUpEFpG9bVE= +github.com/aws/aws-sdk-go-v2 v1.23.5 h1:xK6C4udTyDMd82RFvNkDQxtAd00xlzFUtX4fF2nMZyg= +github.com/aws/aws-sdk-go-v2 v1.23.5/go.mod h1:t3szzKfP0NeRU27uBFczDivYJjsmSnqI8kIvKyWb9ds= +github.com/aws/aws-sdk-go-v2/config v1.25.11 h1:RWzp7jhPRliIcACefGkKp03L0Yofmd2p8M25kbiyvno= +github.com/aws/aws-sdk-go-v2/config v1.25.11/go.mod h1:BVUs0chMdygHsQtvaMyEOpW2GIW+ubrxJLgIz/JU29s= +github.com/aws/aws-sdk-go-v2/credentials v1.16.9 h1:LQo3MUIOzod9JdUK+wxmSdgzLVYUbII3jXn3S/HJZU0= +github.com/aws/aws-sdk-go-v2/credentials v1.16.9/go.mod h1:R7mDuIJoCjH6TxGUc/cylE7Lp/o0bhKVoxdBThsjqCM= +github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.14.9 h1:FZVFahMyZle6WcogZCOxo6D/lkDA2lqKIn4/ueUmVXw= +github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.14.9/go.mod h1:kjq7REMIkxdtcEC9/4BVXjOsNY5isz6jQbEgk6osRTU= +github.com/aws/aws-sdk-go-v2/internal/configsources v1.2.8 h1:8GVZIR0y6JRIUNSYI1xAMF4HDfV8H/bOsZ/8AD/uY5Q= +github.com/aws/aws-sdk-go-v2/internal/configsources v1.2.8/go.mod h1:rwBfu0SoUkBUZndVgPZKAD9Y2JigaZtRP68unRiYToQ= +github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.5.8 h1:ZE2ds/qeBkhk3yqYvS3CDCFNvd9ir5hMjlVStLZWrvM= +github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.5.8/go.mod h1:/lAPPymDYL023+TS6DJmjuL42nxix2AvEvfjqOBRODk= github.com/aws/aws-sdk-go-v2/internal/ini v1.7.1 h1:uR9lXYjdPX0xY+NhvaJ4dD8rpSRz5VY81ccIIoNG+lw= github.com/aws/aws-sdk-go-v2/internal/ini v1.7.1/go.mod h1:6fQQgfuGmw8Al/3M2IgIllycxV7ZW7WCdVSqfBeUiCY= github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.10.3 h1:e3PCNeEaev/ZF01cQyNZgmYE9oYYePIMJs2mWSKG514= github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.10.3/go.mod h1:gIeeNyaL8tIEqZrzAnTeyhHcE0yysCtcaP+N9kxLZ+E= -github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.10.7 h1:dU+ZyhvqMB/T/TxjGagHMCdyUiqaThRIaMu3YvKiSQI= -github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.10.7/go.mod h1:SGORuNqoXyWfTvTp/gBGJfv8jRvW/+nha0XhnIXVI+o= -github.com/aws/aws-sdk-go-v2/service/route53 v1.35.1 h1:v/3D+QsF91AdkF6REEPq6RePxy0vJiHv70CzzLdHrqs= -github.com/aws/aws-sdk-go-v2/service/route53 v1.35.1/go.mod h1:KvdP5Uk34wpr49287kAZJOUJtJXqVZmUTVAbYfknrnM= -github.com/aws/aws-sdk-go-v2/service/route53domains v1.20.1 h1:5T+BONhULX+UXFTSoebZ+wX0QGfO8lZMj6E+OwGS44A= -github.com/aws/aws-sdk-go-v2/service/route53domains v1.20.1/go.mod h1:KFZcLBA2BplaxYAOM806i6F5A7EMJDYDR1FnAR3VHkI= -github.com/aws/aws-sdk-go-v2/service/sso v1.18.1 h1:V40g2daNO3l1J94JYwqfkyvQMYXi5I25fs3fNQW8iDs= -github.com/aws/aws-sdk-go-v2/service/sso v1.18.1/go.mod h1:0ZWQJP/mBOUxkCvZKybZNz1XmdUKSBxoF0dzgfxtvDs= -github.com/aws/aws-sdk-go-v2/service/ssooidc v1.21.1 h1:uQrj7SpUNC3r55vc1CDh3qV9wJC66lz546xM9dhSo5s= -github.com/aws/aws-sdk-go-v2/service/ssooidc v1.21.1/go.mod h1:oyaTk5xEAOuPXX1kCD7HmIeuLqdj3Bk5yGkqGXtGi14= -github.com/aws/aws-sdk-go-v2/service/sts v1.26.1 h1:K33V7L0XDdb23FMOZySr8bon1jou5SHn1fiv7NJ1SUg= -github.com/aws/aws-sdk-go-v2/service/sts v1.26.1/go.mod h1:YtXUl/sfnS06VksYhr855hTQf2HphfT1Xv/EwuzbPjg= +github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.10.8 h1:EamsKe+ZjkOQjDdHd86/JCEucjFKQ9T0atWKO4s2Lgs= +github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.10.8/go.mod h1:Q0vV3/csTpbkfKLI5Sb56cJQTCTtJ0ixdb7P+Wedqiw= +github.com/aws/aws-sdk-go-v2/service/route53 v1.35.2 h1:Dd8CLHufmDFPt+ccGpJx4S0/tS9MnUGPZ9PqU9k6z08= +github.com/aws/aws-sdk-go-v2/service/route53 v1.35.2/go.mod h1:D58n83ihSAC0wtkcvU6PavqmO839sqYQ+HvpqbD7tKE= +github.com/aws/aws-sdk-go-v2/service/route53domains v1.20.2 h1:dYbN6BSr4hZdgPQp+tZbGtmt8mr7Uqxl3T1nqc9Vw6Y= +github.com/aws/aws-sdk-go-v2/service/route53domains v1.20.2/go.mod h1:jASD8WWGPoh1gFNwhYOlCQhO+zD+bbq1Hy2Ms/1qe5c= +github.com/aws/aws-sdk-go-v2/service/sso v1.18.2 h1:xJPydhNm0Hiqct5TVKEuHG7weC0+sOs4MUnd7A5n5F4= +github.com/aws/aws-sdk-go-v2/service/sso v1.18.2/go.mod h1:zxk6y1X2KXThESWMS5CrKRvISD8mbIMab6nZrCGxDG0= +github.com/aws/aws-sdk-go-v2/service/ssooidc v1.21.2 h1:8dU9zqA77C5egbU6yd4hFLaiIdPv3rU+6cp7sz5FjCU= +github.com/aws/aws-sdk-go-v2/service/ssooidc v1.21.2/go.mod h1:7Lt5mjQ8x5rVdKqg+sKKDeuwoszDJIIPmkd8BVsEdS0= +github.com/aws/aws-sdk-go-v2/service/sts v1.26.2 h1:fFrLsy08wEbAisqW3KDl/cPHrF43GmV79zXB9EwJiZw= +github.com/aws/aws-sdk-go-v2/service/sts v1.26.2/go.mod h1:7Ld9eTqocTvJqqJ5K/orbSDwmGcpRdlDiLjz2DO+SL8= github.com/aws/smithy-go v1.18.1 h1:pOdBTUfXNazOlxLrgeYalVnuTpKreACHtc62xLwIB3c= github.com/aws/smithy-go v1.18.1/go.mod h1:NukqUGpCZIILqqiV0NIjeFh24kd/FAa4beRb6nbIUPE= github.com/babolivier/go-doh-client v0.0.0-20201028162107-a76cff4cb8b6 h1:4NNbNM2Iq/k57qEu7WfL67UrbPq1uFWxW4qODCohi+0= @@ -419,8 +419,8 @@ github.com/ugorji/go v1.1.7/go.mod h1:kZn38zHttfInRq0xu/PH0az30d+z6vm202qpg1oXVM github.com/ugorji/go v1.2.6/go.mod h1:anCg0y61KIhDlPZmnH+so+RQbysYVyDko0IMgJv0Nn0= github.com/ugorji/go/codec v1.1.7/go.mod h1:Ax+UKWsSmolVDwsd+7N3ZtXu+yMGCf907BLYF3GoBXY= github.com/ugorji/go/codec v1.2.6/go.mod h1:V6TCNZ4PHqoHGFZuSG1W8nrCzzdgA2DozYxWFFpvxTw= -github.com/urfave/cli/v2 v2.25.7 h1:VAzn5oq403l5pHjc4OhD54+XGO9cdKVL/7lDjF+iKUs= -github.com/urfave/cli/v2 v2.25.7/go.mod h1:8qnjx1vcq5s2/wpsqoZFndg2CE5tNFyrTvS6SinrnYQ= +github.com/urfave/cli/v2 v2.26.0 h1:3f3AMg3HpThFNT4I++TKOejZO8yU55t3JnnSr4S4QEI= +github.com/urfave/cli/v2 v2.26.0/go.mod h1:8qnjx1vcq5s2/wpsqoZFndg2CE5tNFyrTvS6SinrnYQ= github.com/valyala/bytebufferpool v1.0.0/go.mod h1:6bBcMArwyJ5K/AmCkWv1jt77kVWyCJ6HpOuEn7z0Csc= github.com/valyala/fasttemplate v1.2.1/go.mod h1:KHLXt3tVN2HBp8eijSv/kGJopbvo7S+qRAEEKiv+SiQ= github.com/vultr/govultr/v2 v2.17.2 h1:gej/rwr91Puc/tgh+j33p/BLR16UrIPnSr+AIwYWZQs= From cbccbbeb8d981bcd688de1ee6ef8efe8df8a56d9 Mon Sep 17 00:00:00 2001 From: Tom Limoncelli Date: Mon, 4 Dec 2023 17:45:25 -0500 Subject: [PATCH 049/438] REFACTOR: Opinion: TXT records are one long string (#2631) Co-authored-by: Costas Drogos Co-authored-by: imlonghao Co-authored-by: Jeffrey Cafferata Co-authored-by: Vincent Hagen --- commands/getZones.go | 8 +- commands/previewPush.go | 1 + commands/test_data/example.org.zone.djs | 14 +- commands/test_data/example.org.zone.js | 14 +- commands/test_data/example.org.zone.tsv | 90 +++++----- commands/test_data/example.org.zone.zone | 14 +- commands/test_data/simple.com.zone.tsv | 8 +- documentation/opinions.md | 32 +++- integrationTest/integration_test.go | 97 ++++++---- models/dnsrr.go | 20 ++- models/quotes.go | 12 +- models/quotes_test.go | 29 ++- models/record.go | 54 ++---- models/record_test.go | 4 - models/t_parse.go | 148 ++++++++++++--- models/t_txt.go | 169 +++--------------- models/target.go | 49 ++--- pkg/diff/diff.go | 9 +- pkg/diff/diff2compat.go | 2 + pkg/diff2/handsoff_test.go | 2 +- pkg/js/helpers.js | 6 +- pkg/js/parse_tests/016-backslash.js | 13 -- pkg/js/parse_tests/016-backslash.json | 22 --- pkg/js/parse_tests/016-backslash/foo.com.zone | 2 - pkg/js/parse_tests/017-txt.json | 28 +-- pkg/js/parse_tests/017-txt/foo.com.zone | 4 +- pkg/js/parse_tests/018-dkim.json | 5 +- pkg/js/parse_tests/018-dkim/foo.com.zone | 2 +- pkg/normalize/flatten.go | 2 +- pkg/normalize/validate.go | 2 +- pkg/normalize/validate_test.go | 4 +- pkg/prettyzone/prettyzone.go | 3 +- pkg/prettyzone/prettyzone_test.go | 41 +++++ pkg/rejectif/txt.go | 89 +++------ pkg/txtutil/txtcode.go | 155 ++++++++++++++++ pkg/txtutil/txtcode_test.go | 97 ++++++++++ pkg/txtutil/txtcombined.go | 53 ++++++ pkg/txtutil/txtutil.go | 21 +-- providers/azuredns/auditrecords.go | 2 + providers/bind/bindProvider.go | 2 +- providers/cloudflare/auditrecords.go | 2 - providers/cloudns/auditrecords.go | 2 - providers/cscglobal/api.go | 12 +- providers/cscglobal/auditrecords.go | 6 +- providers/cscglobal/convert.go | 2 + providers/cscglobal/dns.go | 1 - providers/digitalocean/auditrecords.go | 4 + providers/dnsimple/auditrecords.go | 2 +- providers/gandiv5/convert.go | 9 +- providers/gandiv5/gandi_v5Provider.go | 5 +- providers/gcloud/gcloudProvider.go | 10 +- providers/hedns/hednsProvider.go | 6 +- providers/hetzner/types.go | 13 +- providers/hexonet/auditrecords.go | 2 + providers/hexonet/records.go | 37 +--- providers/hexonet/records_test.go | 51 ------ providers/inwx/inwxProvider.go | 6 +- providers/msdns/auditrecords.go | 8 +- providers/namedotcom/auditrecords.go | 6 +- providers/namedotcom/records.go | 4 +- providers/namedotcom/records_test.go | 14 +- providers/ns1/auditrecords.go | 2 +- providers/ns1/ns1Provider.go | 2 +- providers/powerdns/convert_test.go | 3 +- providers/route53/route53Provider.go | 11 +- providers/rwth/auditrecords.go | 2 - providers/transip/auditrecords.go | 8 +- providers/transip/slashes.go | 11 -- providers/transip/slashes_test.go | 25 --- providers/transip/transipProvider.go | 22 +-- providers/vultr/auditrecords.go | 2 - 71 files changed, 877 insertions(+), 742 deletions(-) delete mode 100644 pkg/js/parse_tests/016-backslash.js delete mode 100644 pkg/js/parse_tests/016-backslash.json delete mode 100644 pkg/js/parse_tests/016-backslash/foo.com.zone create mode 100644 pkg/txtutil/txtcode.go create mode 100644 pkg/txtutil/txtcode_test.go create mode 100644 pkg/txtutil/txtcombined.go delete mode 100644 providers/hexonet/records_test.go delete mode 100644 providers/transip/slashes.go delete mode 100644 providers/transip/slashes_test.go diff --git a/commands/getZones.go b/commands/getZones.go index 97bba18168..1d6a0e8ec2 100644 --- a/commands/getZones.go +++ b/commands/getZones.go @@ -287,7 +287,7 @@ func GetZone(args GetZoneArgs) error { } fmt.Fprintf(w, "%s\t%s\t%d\tIN\t%s\t%s%s\n", - rec.NameFQDN, rec.Name, rec.TTL, rec.Type, rec.GetTargetCombined(), cfproxy) + rec.NameFQDN, rec.Name, rec.TTL, rec.Type, rec.GetTargetCombinedFunc(nil), cfproxy) } default: @@ -351,11 +351,7 @@ func formatDsl(zonename string, rec *models.RecordConfig, defaultTTL uint32) str case "TLSA": target = fmt.Sprintf(`%d, %d, %d, "%s"`, rec.TlsaUsage, rec.TlsaSelector, rec.TlsaMatchingType, rec.GetTargetField()) case "TXT": - if len(rec.TxtStrings) == 1 { - target = `"` + rec.TxtStrings[0] + `"` - } else { - target = `["` + strings.Join(rec.TxtStrings, `", "`) + `"]` - } + target = jsonQuoted(rec.GetTargetTXTJoined()) // TODO(tlim): If this is an SPF record, generate a SPF_BUILDER(). case "NS": // NS records at the apex should be NAMESERVER() records. diff --git a/commands/previewPush.go b/commands/previewPush.go index dfb1592ab9..7ac4cce809 100644 --- a/commands/previewPush.go +++ b/commands/previewPush.go @@ -45,6 +45,7 @@ type PreviewArgs struct { Full bool } +// ReportItem is a record of corrections for a particular domain/provider/registrar. type ReportItem struct { Domain string `json:"domain"` Corrections int `json:"corrections"` diff --git a/commands/test_data/example.org.zone.djs b/commands/test_data/example.org.zone.djs index e4b695a3ff..1464580fa7 100644 --- a/commands/test_data/example.org.zone.djs +++ b/commands/test_data/example.org.zone.djs @@ -37,7 +37,7 @@ D("example.org", REG_CHANGEME , SRV("_pop3._tcp", 0, 0, 0, ".") , SRV("_pop3s._tcp", 0, 0, 0, ".") , SRV("_sieve._tcp", 10, 10, 4190, "imap.example.org.") - , TXT("dns-moreinfo", ["Fred Bloggs, TZ=America/New_York", "Chat-Service-X: @handle1", "Chat-Service-Y: federated-handle@example.org"]) + , TXT("dns-moreinfo", "Fred Bloggs, TZ=America/New_YorkChat-Service-X: @handle1Chat-Service-Y: federated-handle@example.org") , SRV("_pgpkey-http._tcp", 0, 0, 0, ".") , SRV("_pgpkey-https._tcp", 0, 0, 0, ".") , SRV("_hkp._tcp", 0, 0, 0, ".") @@ -48,9 +48,9 @@ D("example.org", REG_CHANGEME , AAAA("@", "2001:db8::1:1") , TXT("_adsp._domainkey", "dkim=all") , TXT("_dmarc", "v=DMARC1; p=none; sp=none; rua=mailto:dmarc-notify@example.org; ruf=mailto:dmarc-notify@example.org; adkim=s") - , TXT("d201911._domainkey", ["v=DKIM1; k=rsa; p=MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA4SmyE5Tz5/wPL8cb2AKuHnlFeLMOhAl1UX/NYaeDCKMWoBPTgZRT0jonKLmV2UscHdodXu5ZsLr/NAuLCp7HmPLReLz7kxKncP6ppveKxc1aq5SPTKeWe77p6BptlahHc35eiXsZRpTsEzrbEOainy1IWEd+w9p1gWbrSutwE22z0i4V88nQ9UBa1ks", "6cVGxXBZFovWC+i28aGs6Lc7cSfHG5+Mrg3ud5X4evYXTGFMPpunMcCsXrqmS5a+5gRSEMZhngha/cHjLwaJnWzKaywNWF5XOsCjL94QkS0joB7lnGOHMNSZBCcu542Y3Ht3SgHhlpkF9mIbIRfpzA9IoSQIDAQAB"]) + , TXT("d201911._domainkey", "v=DKIM1; k=rsa; p=MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA4SmyE5Tz5/wPL8cb2AKuHnlFeLMOhAl1UX/NYaeDCKMWoBPTgZRT0jonKLmV2UscHdodXu5ZsLr/NAuLCp7HmPLReLz7kxKncP6ppveKxc1aq5SPTKeWe77p6BptlahHc35eiXsZRpTsEzrbEOainy1IWEd+w9p1gWbrSutwE22z0i4V88nQ9UBa1ks6cVGxXBZFovWC+i28aGs6Lc7cSfHG5+Mrg3ud5X4evYXTGFMPpunMcCsXrqmS5a+5gRSEMZhngha/cHjLwaJnWzKaywNWF5XOsCjL94QkS0joB7lnGOHMNSZBCcu542Y3Ht3SgHhlpkF9mIbIRfpzA9IoSQIDAQAB") , TXT("d201911e2._domainkey", "v=DKIM1; k=ed25519; p=GBt2k2L39KUb39fg5brOppXDHXvISy0+ECGgPld/bIo=") - , TXT("d202003._domainkey", ["v=DKIM1; k=rsa; p=MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAv/1tQvOEs7xtKNm7PbPgY4hQjwHVvqqkDb0+TeqZHYRSczQ3c0LFJrIDFiPIdwQe/7AuKrxvATSh/uXKZ3EP4ouMgROPZnUxVXENeetJj+pc3nfGwTKUBTTTth+SO74gdIWsntjvAfduzosC4ZkxbDwZ9c253qXARGvGu+LB/iAeq0ngEbm5fU13+Jo", "pv0d4dR6oGe9GvMEnGGLZzNrxWl1BPe2x5JZ5/X/3fW8vJx3OgRB5N6fqbAJ6HZ9kcbikDH4lPPl9RIoprFk7mmwno/nXLQYGhPobmqq8wLkDiXEkWtYa5lzujz3XI3Zkk8ZIOGvdbVVfAttT0IVPnYkOhQIDAQAB"]) + , TXT("d202003._domainkey", "v=DKIM1; k=rsa; p=MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAv/1tQvOEs7xtKNm7PbPgY4hQjwHVvqqkDb0+TeqZHYRSczQ3c0LFJrIDFiPIdwQe/7AuKrxvATSh/uXKZ3EP4ouMgROPZnUxVXENeetJj+pc3nfGwTKUBTTTth+SO74gdIWsntjvAfduzosC4ZkxbDwZ9c253qXARGvGu+LB/iAeq0ngEbm5fU13+Jopv0d4dR6oGe9GvMEnGGLZzNrxWl1BPe2x5JZ5/X/3fW8vJx3OgRB5N6fqbAJ6HZ9kcbikDH4lPPl9RIoprFk7mmwno/nXLQYGhPobmqq8wLkDiXEkWtYa5lzujz3XI3Zkk8ZIOGvdbVVfAttT0IVPnYkOhQIDAQAB") , TXT("d202003e2._domainkey", "v=DKIM1; k=ed25519; p=DQI5d9sNMrr0SLDoAi071IFOyKnlbR29hAQdqVQecQg=") , TXT("_report", "r=abuse-reports@example.org; rf=ARF; re=postmaster@example.org;") , TXT("_smtp._tls", "v=TLSRPTv1; rua=mailto:smtp-tls-reports@example.org") @@ -311,9 +311,9 @@ D("example.org", REG_CHANGEME , A("fred", "192.0.2.93") , AAAA("fred", "2001:db8::48:4558:5345:5256") , TXT("fred", "v=spf1 ip4:192.0.2.25 ip6:2001:db8::1:25 mx include:_spf.example.com ~all") - , TXT("d201911._domainkey.fred", ["v=DKIM1; k=rsa; p=MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA8/OMUa3PnWh9LqXFVwlAgYDdTtbq3zTtTOSBmJq5yWauzXYcUuSmhW7CsV0QQlacCsQgJlwg9Nl1vO1TosAj5EKUCLTeSqjlWrM7KXKPx8FT71Q9H9wXX4MHUyGrqHFo0OPzcmtHwqcd8AD6MIvJHSRoAfiPPBp8Euc0wGnJZdGS75Hk+wA3MQ2/Tlz", "P2eenyiFyqmUTAGOYsGC/tREsWPiegR/OVxNGlzTY6quHsuVK7UYtIyFnYx9PGWdl3b3p7VjQ5V0Rp+2CLtVrCuS6Zs+/3NhZdM7mdD0a9Jgxakwa1le5YmB5lHTGF7T8quy6TlKe9lMUIRNjqTHfSFz/MwIDAQAB"]) + , TXT("d201911._domainkey.fred", "v=DKIM1; k=rsa; p=MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA8/OMUa3PnWh9LqXFVwlAgYDdTtbq3zTtTOSBmJq5yWauzXYcUuSmhW7CsV0QQlacCsQgJlwg9Nl1vO1TosAj5EKUCLTeSqjlWrM7KXKPx8FT71Q9H9wXX4MHUyGrqHFo0OPzcmtHwqcd8AD6MIvJHSRoAfiPPBp8Euc0wGnJZdGS75Hk+wA3MQ2/TlzP2eenyiFyqmUTAGOYsGC/tREsWPiegR/OVxNGlzTY6quHsuVK7UYtIyFnYx9PGWdl3b3p7VjQ5V0Rp+2CLtVrCuS6Zs+/3NhZdM7mdD0a9Jgxakwa1le5YmB5lHTGF7T8quy6TlKe9lMUIRNjqTHfSFz/MwIDAQAB") , TXT("d201911e2._domainkey.fred", "v=DKIM1; k=ed25519; p=rQNsV9YcPJn/WYI1EDLjNbN/VuX1Hqq/oe4htbnhv+A=") - , TXT("d202003._domainkey.fred", ["v=DKIM1; k=rsa; p=MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAvpnx7tnRxAnE/poIRbVb2i+f1uQCXWnBHzHurgEyZX0CmGaiJuCbr8SWOW2PoXq9YX8gIv2TS3uzwGv/4yA2yX9Z9zar1LeWUfGgMWLdCol9xfmWrI+6MUzxuwhw/mXwzigbI4bHoakh3ez/i3J9KPS85GfrOODqA1emR13f2pG8EzAcje+rwW2PtYj", "c0h+FMDpeLuPYyYszFbNlrkVUneesxnoz+o4x/s6P14ZoRqz5CR7u6G02HwnNaHads5Eto6FYYErUUTtFmgWuYabHxgLVGRdRQs6B5OBYT/3L2q/lAgmEgdy/QL+c0Psfj99/XQmO8fcM0scBzw2ukQzcUwIDAQAB"]) + , TXT("d202003._domainkey.fred", "v=DKIM1; k=rsa; p=MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAvpnx7tnRxAnE/poIRbVb2i+f1uQCXWnBHzHurgEyZX0CmGaiJuCbr8SWOW2PoXq9YX8gIv2TS3uzwGv/4yA2yX9Z9zar1LeWUfGgMWLdCol9xfmWrI+6MUzxuwhw/mXwzigbI4bHoakh3ez/i3J9KPS85GfrOODqA1emR13f2pG8EzAcje+rwW2PtYjc0h+FMDpeLuPYyYszFbNlrkVUneesxnoz+o4x/s6P14ZoRqz5CR7u6G02HwnNaHads5Eto6FYYErUUTtFmgWuYabHxgLVGRdRQs6B5OBYT/3L2q/lAgmEgdy/QL+c0Psfj99/XQmO8fcM0scBzw2ukQzcUwIDAQAB") , TXT("d202003e2._domainkey.fred", "v=DKIM1; k=ed25519; p=0DAPp/IRLYFI/Z4YSgJRi4gr7xcu1/EfJ5mjVn10aAw=") , TXT("_adsp._domainkey.fred", "dkim=all") , TXT("_dmarc.fred", "v=DMARC1; p=none; sp=none; rua=mailto:dmarc-notify@example.org; ruf=mailto:dmarc-notify@example.org; adkim=s") @@ -321,9 +321,9 @@ D("example.org", REG_CHANGEME , TXT("_smtp._tls.fred", "v=TLSRPTv1; rua=mailto:smtp-tls-reports@example.org") , TXT("_smtp-tlsrpt.fred", "v=TLSRPTv1; rua=mailto:smtp-tls-reports@example.org") , MX("mailtest", 10, "mx.example.org.") - , TXT("d201911._domainkey.mailtest", ["v=DKIM1; k=rsa; p=MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAo9xHnjHyhm1weA6FjOqM8LKVsklFt26HXWoe/0XCdmBG4i/UzQ7RiSgWO4kv7anPK6qf6rtL1xYsHufaRXG8yLsZxz+BbUP99eZvxZX78tMg4cGf+yU6uFxulCbOzsMy+8Cc3bbQTtIWYjyWBwnHdRRrCkQxjZ5KAd+x7ZB5qzqg2/eLJ7fCuNsr/xn", "0XTY6XYgug95e3h4CEW3Y+bkG81AMeJmT/hoVTcXvT/Gm6ZOUmx6faQWIHSW7qOR3VS6S75HOuclEUk0gt9r7OQHKl01sXh8g02SHRk8SUMEoNVayqplYZTFFF01Z192m7enmpp+St+HHUIT6jW/CAMCO3wIDAQAB"]) + , TXT("d201911._domainkey.mailtest", "v=DKIM1; k=rsa; p=MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAo9xHnjHyhm1weA6FjOqM8LKVsklFt26HXWoe/0XCdmBG4i/UzQ7RiSgWO4kv7anPK6qf6rtL1xYsHufaRXG8yLsZxz+BbUP99eZvxZX78tMg4cGf+yU6uFxulCbOzsMy+8Cc3bbQTtIWYjyWBwnHdRRrCkQxjZ5KAd+x7ZB5qzqg2/eLJ7fCuNsr/xn0XTY6XYgug95e3h4CEW3Y+bkG81AMeJmT/hoVTcXvT/Gm6ZOUmx6faQWIHSW7qOR3VS6S75HOuclEUk0gt9r7OQHKl01sXh8g02SHRk8SUMEoNVayqplYZTFFF01Z192m7enmpp+St+HHUIT6jW/CAMCO3wIDAQAB") , TXT("d201911e2._domainkey.mailtest", "v=DKIM1; k=ed25519; p=afulDDnhaTzdqKQN0jtWV04eOhAcyBk3NCyVheOf53Y=") - , TXT("d202003._domainkey.mailtest", ["v=DKIM1; k=rsa; p=MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAs2BTVZaVLvL3qZBPaF7tRR0SdOKe+hjcpQ5fqO48lEuYiyTb6lkn8DPjDK11gTN3au0Bm+y8KC7ITKSJosuJXytxt3wqc61Pwtmb/Cy7GzmOF1AuegydB3/88VbgHT5DZucHrh6+ValZk4Trkx+/1K26Uo+h2KL2n/Ldb1y91ATHujp8DqxAOhiZ7KN", "aS1okNRRB4/14jPufAbeiN8/iBPiY5Hl80KHmpjM+7vvjb5jiecZ1ZrVDj7eTES4pmVh2v1c106mZLieoqDPYaf/HVbCM4E4n1B6kjbboSOpANADIcqXxGJQ7Be7/Sk9f7KwRusrsMHXmBHgm4wPmwGVZ3QIDAQAB"]) + , TXT("d202003._domainkey.mailtest", "v=DKIM1; k=rsa; p=MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAs2BTVZaVLvL3qZBPaF7tRR0SdOKe+hjcpQ5fqO48lEuYiyTb6lkn8DPjDK11gTN3au0Bm+y8KC7ITKSJosuJXytxt3wqc61Pwtmb/Cy7GzmOF1AuegydB3/88VbgHT5DZucHrh6+ValZk4Trkx+/1K26Uo+h2KL2n/Ldb1y91ATHujp8DqxAOhiZ7KNaS1okNRRB4/14jPufAbeiN8/iBPiY5Hl80KHmpjM+7vvjb5jiecZ1ZrVDj7eTES4pmVh2v1c106mZLieoqDPYaf/HVbCM4E4n1B6kjbboSOpANADIcqXxGJQ7Be7/Sk9f7KwRusrsMHXmBHgm4wPmwGVZ3QIDAQAB") , TXT("d202003e2._domainkey.mailtest", "v=DKIM1; k=ed25519; p=iqwH/hhozFdeo1xnuldr8KUi7O7g+DzmC+f0SYMKVDc=") , TXT("_adsp._domainkey.mailtest", "dkim=all") , TXT("_dmarc.mailtest", "v=DMARC1; p=none; sp=none; rua=mailto:dmarc-notify@example.org; ruf=mailto:dmarc-notify@example.org; adkim=s") diff --git a/commands/test_data/example.org.zone.js b/commands/test_data/example.org.zone.js index 70f253630d..95f7d4a46a 100644 --- a/commands/test_data/example.org.zone.js +++ b/commands/test_data/example.org.zone.js @@ -37,7 +37,7 @@ D("example.org", REG_CHANGEME, SRV("_pop3._tcp", 0, 0, 0, "."), SRV("_pop3s._tcp", 0, 0, 0, "."), SRV("_sieve._tcp", 10, 10, 4190, "imap.example.org."), - TXT("dns-moreinfo", ["Fred Bloggs, TZ=America/New_York", "Chat-Service-X: @handle1", "Chat-Service-Y: federated-handle@example.org"]), + TXT("dns-moreinfo", "Fred Bloggs, TZ=America/New_YorkChat-Service-X: @handle1Chat-Service-Y: federated-handle@example.org"), SRV("_pgpkey-http._tcp", 0, 0, 0, "."), SRV("_pgpkey-https._tcp", 0, 0, 0, "."), SRV("_hkp._tcp", 0, 0, 0, "."), @@ -48,9 +48,9 @@ D("example.org", REG_CHANGEME, AAAA("@", "2001:db8::1:1"), TXT("_adsp._domainkey", "dkim=all"), TXT("_dmarc", "v=DMARC1; p=none; sp=none; rua=mailto:dmarc-notify@example.org; ruf=mailto:dmarc-notify@example.org; adkim=s"), - TXT("d201911._domainkey", ["v=DKIM1; k=rsa; p=MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA4SmyE5Tz5/wPL8cb2AKuHnlFeLMOhAl1UX/NYaeDCKMWoBPTgZRT0jonKLmV2UscHdodXu5ZsLr/NAuLCp7HmPLReLz7kxKncP6ppveKxc1aq5SPTKeWe77p6BptlahHc35eiXsZRpTsEzrbEOainy1IWEd+w9p1gWbrSutwE22z0i4V88nQ9UBa1ks", "6cVGxXBZFovWC+i28aGs6Lc7cSfHG5+Mrg3ud5X4evYXTGFMPpunMcCsXrqmS5a+5gRSEMZhngha/cHjLwaJnWzKaywNWF5XOsCjL94QkS0joB7lnGOHMNSZBCcu542Y3Ht3SgHhlpkF9mIbIRfpzA9IoSQIDAQAB"]), + TXT("d201911._domainkey", "v=DKIM1; k=rsa; p=MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA4SmyE5Tz5/wPL8cb2AKuHnlFeLMOhAl1UX/NYaeDCKMWoBPTgZRT0jonKLmV2UscHdodXu5ZsLr/NAuLCp7HmPLReLz7kxKncP6ppveKxc1aq5SPTKeWe77p6BptlahHc35eiXsZRpTsEzrbEOainy1IWEd+w9p1gWbrSutwE22z0i4V88nQ9UBa1ks6cVGxXBZFovWC+i28aGs6Lc7cSfHG5+Mrg3ud5X4evYXTGFMPpunMcCsXrqmS5a+5gRSEMZhngha/cHjLwaJnWzKaywNWF5XOsCjL94QkS0joB7lnGOHMNSZBCcu542Y3Ht3SgHhlpkF9mIbIRfpzA9IoSQIDAQAB"), TXT("d201911e2._domainkey", "v=DKIM1; k=ed25519; p=GBt2k2L39KUb39fg5brOppXDHXvISy0+ECGgPld/bIo="), - TXT("d202003._domainkey", ["v=DKIM1; k=rsa; p=MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAv/1tQvOEs7xtKNm7PbPgY4hQjwHVvqqkDb0+TeqZHYRSczQ3c0LFJrIDFiPIdwQe/7AuKrxvATSh/uXKZ3EP4ouMgROPZnUxVXENeetJj+pc3nfGwTKUBTTTth+SO74gdIWsntjvAfduzosC4ZkxbDwZ9c253qXARGvGu+LB/iAeq0ngEbm5fU13+Jo", "pv0d4dR6oGe9GvMEnGGLZzNrxWl1BPe2x5JZ5/X/3fW8vJx3OgRB5N6fqbAJ6HZ9kcbikDH4lPPl9RIoprFk7mmwno/nXLQYGhPobmqq8wLkDiXEkWtYa5lzujz3XI3Zkk8ZIOGvdbVVfAttT0IVPnYkOhQIDAQAB"]), + TXT("d202003._domainkey", "v=DKIM1; k=rsa; p=MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAv/1tQvOEs7xtKNm7PbPgY4hQjwHVvqqkDb0+TeqZHYRSczQ3c0LFJrIDFiPIdwQe/7AuKrxvATSh/uXKZ3EP4ouMgROPZnUxVXENeetJj+pc3nfGwTKUBTTTth+SO74gdIWsntjvAfduzosC4ZkxbDwZ9c253qXARGvGu+LB/iAeq0ngEbm5fU13+Jopv0d4dR6oGe9GvMEnGGLZzNrxWl1BPe2x5JZ5/X/3fW8vJx3OgRB5N6fqbAJ6HZ9kcbikDH4lPPl9RIoprFk7mmwno/nXLQYGhPobmqq8wLkDiXEkWtYa5lzujz3XI3Zkk8ZIOGvdbVVfAttT0IVPnYkOhQIDAQAB"), TXT("d202003e2._domainkey", "v=DKIM1; k=ed25519; p=DQI5d9sNMrr0SLDoAi071IFOyKnlbR29hAQdqVQecQg="), TXT("_report", "r=abuse-reports@example.org; rf=ARF; re=postmaster@example.org;"), TXT("_smtp._tls", "v=TLSRPTv1; rua=mailto:smtp-tls-reports@example.org"), @@ -311,9 +311,9 @@ D("example.org", REG_CHANGEME, A("fred", "192.0.2.93"), AAAA("fred", "2001:db8::48:4558:5345:5256"), TXT("fred", "v=spf1 ip4:192.0.2.25 ip6:2001:db8::1:25 mx include:_spf.example.com ~all"), - TXT("d201911._domainkey.fred", ["v=DKIM1; k=rsa; p=MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA8/OMUa3PnWh9LqXFVwlAgYDdTtbq3zTtTOSBmJq5yWauzXYcUuSmhW7CsV0QQlacCsQgJlwg9Nl1vO1TosAj5EKUCLTeSqjlWrM7KXKPx8FT71Q9H9wXX4MHUyGrqHFo0OPzcmtHwqcd8AD6MIvJHSRoAfiPPBp8Euc0wGnJZdGS75Hk+wA3MQ2/Tlz", "P2eenyiFyqmUTAGOYsGC/tREsWPiegR/OVxNGlzTY6quHsuVK7UYtIyFnYx9PGWdl3b3p7VjQ5V0Rp+2CLtVrCuS6Zs+/3NhZdM7mdD0a9Jgxakwa1le5YmB5lHTGF7T8quy6TlKe9lMUIRNjqTHfSFz/MwIDAQAB"]), + TXT("d201911._domainkey.fred", "v=DKIM1; k=rsa; p=MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA8/OMUa3PnWh9LqXFVwlAgYDdTtbq3zTtTOSBmJq5yWauzXYcUuSmhW7CsV0QQlacCsQgJlwg9Nl1vO1TosAj5EKUCLTeSqjlWrM7KXKPx8FT71Q9H9wXX4MHUyGrqHFo0OPzcmtHwqcd8AD6MIvJHSRoAfiPPBp8Euc0wGnJZdGS75Hk+wA3MQ2/TlzP2eenyiFyqmUTAGOYsGC/tREsWPiegR/OVxNGlzTY6quHsuVK7UYtIyFnYx9PGWdl3b3p7VjQ5V0Rp+2CLtVrCuS6Zs+/3NhZdM7mdD0a9Jgxakwa1le5YmB5lHTGF7T8quy6TlKe9lMUIRNjqTHfSFz/MwIDAQAB"), TXT("d201911e2._domainkey.fred", "v=DKIM1; k=ed25519; p=rQNsV9YcPJn/WYI1EDLjNbN/VuX1Hqq/oe4htbnhv+A="), - TXT("d202003._domainkey.fred", ["v=DKIM1; k=rsa; p=MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAvpnx7tnRxAnE/poIRbVb2i+f1uQCXWnBHzHurgEyZX0CmGaiJuCbr8SWOW2PoXq9YX8gIv2TS3uzwGv/4yA2yX9Z9zar1LeWUfGgMWLdCol9xfmWrI+6MUzxuwhw/mXwzigbI4bHoakh3ez/i3J9KPS85GfrOODqA1emR13f2pG8EzAcje+rwW2PtYj", "c0h+FMDpeLuPYyYszFbNlrkVUneesxnoz+o4x/s6P14ZoRqz5CR7u6G02HwnNaHads5Eto6FYYErUUTtFmgWuYabHxgLVGRdRQs6B5OBYT/3L2q/lAgmEgdy/QL+c0Psfj99/XQmO8fcM0scBzw2ukQzcUwIDAQAB"]), + TXT("d202003._domainkey.fred", "v=DKIM1; k=rsa; p=MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAvpnx7tnRxAnE/poIRbVb2i+f1uQCXWnBHzHurgEyZX0CmGaiJuCbr8SWOW2PoXq9YX8gIv2TS3uzwGv/4yA2yX9Z9zar1LeWUfGgMWLdCol9xfmWrI+6MUzxuwhw/mXwzigbI4bHoakh3ez/i3J9KPS85GfrOODqA1emR13f2pG8EzAcje+rwW2PtYjc0h+FMDpeLuPYyYszFbNlrkVUneesxnoz+o4x/s6P14ZoRqz5CR7u6G02HwnNaHads5Eto6FYYErUUTtFmgWuYabHxgLVGRdRQs6B5OBYT/3L2q/lAgmEgdy/QL+c0Psfj99/XQmO8fcM0scBzw2ukQzcUwIDAQAB"), TXT("d202003e2._domainkey.fred", "v=DKIM1; k=ed25519; p=0DAPp/IRLYFI/Z4YSgJRi4gr7xcu1/EfJ5mjVn10aAw="), TXT("_adsp._domainkey.fred", "dkim=all"), TXT("_dmarc.fred", "v=DMARC1; p=none; sp=none; rua=mailto:dmarc-notify@example.org; ruf=mailto:dmarc-notify@example.org; adkim=s"), @@ -321,9 +321,9 @@ D("example.org", REG_CHANGEME, TXT("_smtp._tls.fred", "v=TLSRPTv1; rua=mailto:smtp-tls-reports@example.org"), TXT("_smtp-tlsrpt.fred", "v=TLSRPTv1; rua=mailto:smtp-tls-reports@example.org"), MX("mailtest", 10, "mx.example.org."), - TXT("d201911._domainkey.mailtest", ["v=DKIM1; k=rsa; p=MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAo9xHnjHyhm1weA6FjOqM8LKVsklFt26HXWoe/0XCdmBG4i/UzQ7RiSgWO4kv7anPK6qf6rtL1xYsHufaRXG8yLsZxz+BbUP99eZvxZX78tMg4cGf+yU6uFxulCbOzsMy+8Cc3bbQTtIWYjyWBwnHdRRrCkQxjZ5KAd+x7ZB5qzqg2/eLJ7fCuNsr/xn", "0XTY6XYgug95e3h4CEW3Y+bkG81AMeJmT/hoVTcXvT/Gm6ZOUmx6faQWIHSW7qOR3VS6S75HOuclEUk0gt9r7OQHKl01sXh8g02SHRk8SUMEoNVayqplYZTFFF01Z192m7enmpp+St+HHUIT6jW/CAMCO3wIDAQAB"]), + TXT("d201911._domainkey.mailtest", "v=DKIM1; k=rsa; p=MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAo9xHnjHyhm1weA6FjOqM8LKVsklFt26HXWoe/0XCdmBG4i/UzQ7RiSgWO4kv7anPK6qf6rtL1xYsHufaRXG8yLsZxz+BbUP99eZvxZX78tMg4cGf+yU6uFxulCbOzsMy+8Cc3bbQTtIWYjyWBwnHdRRrCkQxjZ5KAd+x7ZB5qzqg2/eLJ7fCuNsr/xn0XTY6XYgug95e3h4CEW3Y+bkG81AMeJmT/hoVTcXvT/Gm6ZOUmx6faQWIHSW7qOR3VS6S75HOuclEUk0gt9r7OQHKl01sXh8g02SHRk8SUMEoNVayqplYZTFFF01Z192m7enmpp+St+HHUIT6jW/CAMCO3wIDAQAB"), TXT("d201911e2._domainkey.mailtest", "v=DKIM1; k=ed25519; p=afulDDnhaTzdqKQN0jtWV04eOhAcyBk3NCyVheOf53Y="), - TXT("d202003._domainkey.mailtest", ["v=DKIM1; k=rsa; p=MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAs2BTVZaVLvL3qZBPaF7tRR0SdOKe+hjcpQ5fqO48lEuYiyTb6lkn8DPjDK11gTN3au0Bm+y8KC7ITKSJosuJXytxt3wqc61Pwtmb/Cy7GzmOF1AuegydB3/88VbgHT5DZucHrh6+ValZk4Trkx+/1K26Uo+h2KL2n/Ldb1y91ATHujp8DqxAOhiZ7KN", "aS1okNRRB4/14jPufAbeiN8/iBPiY5Hl80KHmpjM+7vvjb5jiecZ1ZrVDj7eTES4pmVh2v1c106mZLieoqDPYaf/HVbCM4E4n1B6kjbboSOpANADIcqXxGJQ7Be7/Sk9f7KwRusrsMHXmBHgm4wPmwGVZ3QIDAQAB"]), + TXT("d202003._domainkey.mailtest", "v=DKIM1; k=rsa; p=MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAs2BTVZaVLvL3qZBPaF7tRR0SdOKe+hjcpQ5fqO48lEuYiyTb6lkn8DPjDK11gTN3au0Bm+y8KC7ITKSJosuJXytxt3wqc61Pwtmb/Cy7GzmOF1AuegydB3/88VbgHT5DZucHrh6+ValZk4Trkx+/1K26Uo+h2KL2n/Ldb1y91ATHujp8DqxAOhiZ7KNaS1okNRRB4/14jPufAbeiN8/iBPiY5Hl80KHmpjM+7vvjb5jiecZ1ZrVDj7eTES4pmVh2v1c106mZLieoqDPYaf/HVbCM4E4n1B6kjbboSOpANADIcqXxGJQ7Be7/Sk9f7KwRusrsMHXmBHgm4wPmwGVZ3QIDAQAB"), TXT("d202003e2._domainkey.mailtest", "v=DKIM1; k=ed25519; p=iqwH/hhozFdeo1xnuldr8KUi7O7g+DzmC+f0SYMKVDc="), TXT("_adsp._domainkey.mailtest", "dkim=all"), TXT("_dmarc.mailtest", "v=DMARC1; p=none; sp=none; rua=mailto:dmarc-notify@example.org; ruf=mailto:dmarc-notify@example.org; adkim=s"), diff --git a/commands/test_data/example.org.zone.tsv b/commands/test_data/example.org.zone.tsv index ca15d2fc8a..abae4c9693 100644 --- a/commands/test_data/example.org.zone.tsv +++ b/commands/test_data/example.org.zone.tsv @@ -4,7 +4,7 @@ example.org @ 7200 IN NS ns2.example.org. example.org @ 7200 IN NS ns-a.example.net. example.org @ 7200 IN NS friend-dns.example.com. example.org @ 7200 IN MX 10 mx.example.org. -example.org @ 7200 IN TXT "v=spf1 ip4:192.0.2.25 ip6:2001:db8::1:25 mx include:_spf.example.com ~all" +example.org @ 7200 IN TXT v=spf1 ip4:192.0.2.25 ip6:2001:db8::1:25 mx include:_spf.example.com ~all _client._smtp.example.org _client._smtp 7200 IN SRV 1 1 1 example.org. _client._smtp.mx.example.org _client._smtp.mx 7200 IN SRV 1 2 1 mx.example.org. _client._smtp.foo.example.org _client._smtp.foo 7200 IN SRV 1 2 1 foo.example.org. @@ -12,7 +12,7 @@ _kerberos._tcp.example.org _kerberos._tcp 7200 IN SRV 10 1 88 kerb-service.examp _kerberos._udp.example.org _kerberos._udp 7200 IN SRV 10 1 88 kerb-service.example.org. _kpasswd._udp.example.org _kpasswd._udp 7200 IN SRV 10 1 464 kerb-service.example.org. _kerberos-adm._tcp.example.org _kerberos-adm._tcp 7200 IN SRV 10 1 749 kerb-service.example.org. -_kerberos.example.org _kerberos 7200 IN TXT "EXAMPLE.ORG" +_kerberos.example.org _kerberos 7200 IN TXT EXAMPLE.ORG _ldap._tcp.example.org _ldap._tcp 7200 IN SRV 0 0 0 . _ldap._udp.example.org _ldap._udp 7200 IN SRV 0 0 0 . _jabber._tcp.example.org _jabber._tcp 7200 IN SRV 10 2 5269 xmpp-s2s.example.org. @@ -32,7 +32,7 @@ _imaps._tcp.example.org _imaps._tcp 7200 IN SRV 10 10 993 imap.example.org. _pop3._tcp.example.org _pop3._tcp 7200 IN SRV 0 0 0 . _pop3s._tcp.example.org _pop3s._tcp 7200 IN SRV 0 0 0 . _sieve._tcp.example.org _sieve._tcp 7200 IN SRV 10 10 4190 imap.example.org. -dns-moreinfo.example.org dns-moreinfo 7200 IN TXT "Fred Bloggs, TZ=America/New_York" "Chat-Service-X: @handle1" "Chat-Service-Y: federated-handle@example.org" +dns-moreinfo.example.org dns-moreinfo 7200 IN TXT Fred Bloggs, TZ=America/New_YorkChat-Service-X: @handle1Chat-Service-Y: federated-handle@example.org _pgpkey-http._tcp.example.org _pgpkey-http._tcp 7200 IN SRV 0 0 0 . _pgpkey-https._tcp.example.org _pgpkey-https._tcp 7200 IN SRV 0 0 0 . _hkp._tcp.example.org _hkp._tcp 7200 IN SRV 0 0 0 . @@ -41,20 +41,20 @@ _finger._tcp.example.org _finger._tcp 7200 IN SRV 10 10 79 barbican.example.org. _avatars-sec._tcp.example.org _avatars-sec._tcp 7200 IN SRV 10 10 443 avatars.example.org. example.org @ 7200 IN A 192.0.2.1 example.org @ 7200 IN AAAA 2001:db8::1:1 -_adsp._domainkey.example.org _adsp._domainkey 7200 IN TXT "dkim=all" -_dmarc.example.org _dmarc 7200 IN TXT "v=DMARC1; p=none; sp=none; rua=mailto:dmarc-notify@example.org; ruf=mailto:dmarc-notify@example.org; adkim=s" -d201911._domainkey.example.org d201911._domainkey 7200 IN TXT "v=DKIM1; k=rsa; p=MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA4SmyE5Tz5/wPL8cb2AKuHnlFeLMOhAl1UX/NYaeDCKMWoBPTgZRT0jonKLmV2UscHdodXu5ZsLr/NAuLCp7HmPLReLz7kxKncP6ppveKxc1aq5SPTKeWe77p6BptlahHc35eiXsZRpTsEzrbEOainy1IWEd+w9p1gWbrSutwE22z0i4V88nQ9UBa1ks" "6cVGxXBZFovWC+i28aGs6Lc7cSfHG5+Mrg3ud5X4evYXTGFMPpunMcCsXrqmS5a+5gRSEMZhngha/cHjLwaJnWzKaywNWF5XOsCjL94QkS0joB7lnGOHMNSZBCcu542Y3Ht3SgHhlpkF9mIbIRfpzA9IoSQIDAQAB" -d201911e2._domainkey.example.org d201911e2._domainkey 7200 IN TXT "v=DKIM1; k=ed25519; p=GBt2k2L39KUb39fg5brOppXDHXvISy0+ECGgPld/bIo=" -d202003._domainkey.example.org d202003._domainkey 7200 IN TXT "v=DKIM1; k=rsa; p=MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAv/1tQvOEs7xtKNm7PbPgY4hQjwHVvqqkDb0+TeqZHYRSczQ3c0LFJrIDFiPIdwQe/7AuKrxvATSh/uXKZ3EP4ouMgROPZnUxVXENeetJj+pc3nfGwTKUBTTTth+SO74gdIWsntjvAfduzosC4ZkxbDwZ9c253qXARGvGu+LB/iAeq0ngEbm5fU13+Jo" "pv0d4dR6oGe9GvMEnGGLZzNrxWl1BPe2x5JZ5/X/3fW8vJx3OgRB5N6fqbAJ6HZ9kcbikDH4lPPl9RIoprFk7mmwno/nXLQYGhPobmqq8wLkDiXEkWtYa5lzujz3XI3Zkk8ZIOGvdbVVfAttT0IVPnYkOhQIDAQAB" -d202003e2._domainkey.example.org d202003e2._domainkey 7200 IN TXT "v=DKIM1; k=ed25519; p=DQI5d9sNMrr0SLDoAi071IFOyKnlbR29hAQdqVQecQg=" -_report.example.org _report 7200 IN TXT "r=abuse-reports@example.org; rf=ARF; re=postmaster@example.org;" -_smtp._tls.example.org _smtp._tls 7200 IN TXT "v=TLSRPTv1; rua=mailto:smtp-tls-reports@example.org" -_smtp-tlsrpt.example.org _smtp-tlsrpt 7200 IN TXT "v=TLSRPTv1; rua=mailto:smtp-tls-reports@example.org" -example.net._report._dmarc.example.org example.net._report._dmarc 7200 IN TXT "v=DMARC1" -example.com._report._dmarc.example.org example.com._report._dmarc 7200 IN TXT "v=DMARC1" -xn--2j5b.xn--9t4b11yi5a._report._dmarc.example.org xn--2j5b.xn--9t4b11yi5a._report._dmarc 7200 IN TXT "v=DMARC1" -special.test._report._dmarc.example.org special.test._report._dmarc 7200 IN TXT "v=DMARC1" -xn--qck5b9a5eml3bze.xn--zckzah._report._dmarc.example.org xn--qck5b9a5eml3bze.xn--zckzah._report._dmarc 7200 IN TXT "v=DMARC1" +_adsp._domainkey.example.org _adsp._domainkey 7200 IN TXT dkim=all +_dmarc.example.org _dmarc 7200 IN TXT v=DMARC1; p=none; sp=none; rua=mailto:dmarc-notify@example.org; ruf=mailto:dmarc-notify@example.org; adkim=s +d201911._domainkey.example.org d201911._domainkey 7200 IN TXT v=DKIM1; k=rsa; p=MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA4SmyE5Tz5/wPL8cb2AKuHnlFeLMOhAl1UX/NYaeDCKMWoBPTgZRT0jonKLmV2UscHdodXu5ZsLr/NAuLCp7HmPLReLz7kxKncP6ppveKxc1aq5SPTKeWe77p6BptlahHc35eiXsZRpTsEzrbEOainy1IWEd+w9p1gWbrSutwE22z0i4V88nQ9UBa1ks6cVGxXBZFovWC+i28aGs6Lc7cSfHG5+Mrg3ud5X4evYXTGFMPpunMcCsXrqmS5a+5gRSEMZhngha/cHjLwaJnWzKaywNWF5XOsCjL94QkS0joB7lnGOHMNSZBCcu542Y3Ht3SgHhlpkF9mIbIRfpzA9IoSQIDAQAB +d201911e2._domainkey.example.org d201911e2._domainkey 7200 IN TXT v=DKIM1; k=ed25519; p=GBt2k2L39KUb39fg5brOppXDHXvISy0+ECGgPld/bIo= +d202003._domainkey.example.org d202003._domainkey 7200 IN TXT v=DKIM1; k=rsa; p=MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAv/1tQvOEs7xtKNm7PbPgY4hQjwHVvqqkDb0+TeqZHYRSczQ3c0LFJrIDFiPIdwQe/7AuKrxvATSh/uXKZ3EP4ouMgROPZnUxVXENeetJj+pc3nfGwTKUBTTTth+SO74gdIWsntjvAfduzosC4ZkxbDwZ9c253qXARGvGu+LB/iAeq0ngEbm5fU13+Jopv0d4dR6oGe9GvMEnGGLZzNrxWl1BPe2x5JZ5/X/3fW8vJx3OgRB5N6fqbAJ6HZ9kcbikDH4lPPl9RIoprFk7mmwno/nXLQYGhPobmqq8wLkDiXEkWtYa5lzujz3XI3Zkk8ZIOGvdbVVfAttT0IVPnYkOhQIDAQAB +d202003e2._domainkey.example.org d202003e2._domainkey 7200 IN TXT v=DKIM1; k=ed25519; p=DQI5d9sNMrr0SLDoAi071IFOyKnlbR29hAQdqVQecQg= +_report.example.org _report 7200 IN TXT r=abuse-reports@example.org; rf=ARF; re=postmaster@example.org; +_smtp._tls.example.org _smtp._tls 7200 IN TXT v=TLSRPTv1; rua=mailto:smtp-tls-reports@example.org +_smtp-tlsrpt.example.org _smtp-tlsrpt 7200 IN TXT v=TLSRPTv1; rua=mailto:smtp-tls-reports@example.org +example.net._report._dmarc.example.org example.net._report._dmarc 7200 IN TXT v=DMARC1 +example.com._report._dmarc.example.org example.com._report._dmarc 7200 IN TXT v=DMARC1 +xn--2j5b.xn--9t4b11yi5a._report._dmarc.example.org xn--2j5b.xn--9t4b11yi5a._report._dmarc 7200 IN TXT v=DMARC1 +special.test._report._dmarc.example.org special.test._report._dmarc 7200 IN TXT v=DMARC1 +xn--qck5b9a5eml3bze.xn--zckzah._report._dmarc.example.org xn--qck5b9a5eml3bze.xn--zckzah._report._dmarc 7200 IN TXT v=DMARC1 *._smimecert.example.org *._smimecert 7200 IN CNAME _ourca-smimea.example.org. b._dns-sd._udp.example.org b._dns-sd._udp 7200 IN PTR field.example.org. lb._dns-sd._udp.example.org lb._dns-sd._udp 7200 IN PTR field.example.org. @@ -265,9 +265,9 @@ mx.example.org mx 7200 IN A 192.0.2.25 mx.example.org mx 7200 IN AAAA 2001:db8::48:4558:736d:7470 mx.ipv4.example.org mx.ipv4 7200 IN A 192.0.2.25 mx.ipv6.example.org mx.ipv6 7200 IN AAAA 2001:db8::48:4558:736d:7470 -mx.example.org mx 7200 IN TXT "v=spf1 a include:_spflarge.example.net -all" -_mta-sts.example.org _mta-sts 7200 IN TXT "v=STSv1; id=20191231r1;" -mta-sts.example.org mta-sts 7200 IN TXT "v=STSv1; id=20191231r1;" +mx.example.org mx 7200 IN TXT v=spf1 a include:_spflarge.example.net -all +_mta-sts.example.org _mta-sts 7200 IN TXT v=STSv1; id=20191231r1; +mta-sts.example.org mta-sts 7200 IN TXT v=STSv1; id=20191231r1; mta-sts.example.org mta-sts 7200 IN A 192.0.2.93 mta-sts.example.org mta-sts 7200 IN AAAA 2001:db8::48:4558:5345:5256 xmpp.ipv6.example.org xmpp.ipv6 7200 IN AAAA 2001:db8::f0ab:cdef:1234:f00f @@ -297,34 +297,34 @@ news-feed.example.org news-feed 7200 IN AAAA 2001:db8::48:4558:6e6e:7470 go.example.org go 7200 IN CNAME abcdefghijklmn.cloudfront.net. foo.example.org foo 7200 IN A 192.0.2.200 gladys.example.org gladys 7200 IN MX 10 mx.example.org. -_adsp._domainkey.gladys.example.org _adsp._domainkey.gladys 7200 IN TXT "dkim=all" -_dmarc.gladys.example.org _dmarc.gladys 7200 IN TXT "v=DMARC1; p=none; sp=none; rua=mailto:dmarc-notify@example.org; ruf=mailto:dmarc-notify@example.org; adkim=s" -_report.gladys.example.org _report.gladys 7200 IN TXT "r=abuse-reports@example.org; rf=ARF; re=postmaster@example.org;" -_smtp._tls.gladys.example.org _smtp._tls.gladys 7200 IN TXT "v=TLSRPTv1; rua=mailto:smtp-tls-reports@example.org" -_smtp-tlsrpt.gladys.example.org _smtp-tlsrpt.gladys 7200 IN TXT "v=TLSRPTv1; rua=mailto:smtp-tls-reports@example.org" +_adsp._domainkey.gladys.example.org _adsp._domainkey.gladys 7200 IN TXT dkim=all +_dmarc.gladys.example.org _dmarc.gladys 7200 IN TXT v=DMARC1; p=none; sp=none; rua=mailto:dmarc-notify@example.org; ruf=mailto:dmarc-notify@example.org; adkim=s +_report.gladys.example.org _report.gladys 7200 IN TXT r=abuse-reports@example.org; rf=ARF; re=postmaster@example.org; +_smtp._tls.gladys.example.org _smtp._tls.gladys 7200 IN TXT v=TLSRPTv1; rua=mailto:smtp-tls-reports@example.org +_smtp-tlsrpt.gladys.example.org _smtp-tlsrpt.gladys 7200 IN TXT v=TLSRPTv1; rua=mailto:smtp-tls-reports@example.org fred.example.org fred 7200 IN MX 10 mx.example.org. fred.example.org fred 7200 IN A 192.0.2.93 fred.example.org fred 7200 IN AAAA 2001:db8::48:4558:5345:5256 -fred.example.org fred 7200 IN TXT "v=spf1 ip4:192.0.2.25 ip6:2001:db8::1:25 mx include:_spf.example.com ~all" -d201911._domainkey.fred.example.org d201911._domainkey.fred 7200 IN TXT "v=DKIM1; k=rsa; p=MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA8/OMUa3PnWh9LqXFVwlAgYDdTtbq3zTtTOSBmJq5yWauzXYcUuSmhW7CsV0QQlacCsQgJlwg9Nl1vO1TosAj5EKUCLTeSqjlWrM7KXKPx8FT71Q9H9wXX4MHUyGrqHFo0OPzcmtHwqcd8AD6MIvJHSRoAfiPPBp8Euc0wGnJZdGS75Hk+wA3MQ2/Tlz" "P2eenyiFyqmUTAGOYsGC/tREsWPiegR/OVxNGlzTY6quHsuVK7UYtIyFnYx9PGWdl3b3p7VjQ5V0Rp+2CLtVrCuS6Zs+/3NhZdM7mdD0a9Jgxakwa1le5YmB5lHTGF7T8quy6TlKe9lMUIRNjqTHfSFz/MwIDAQAB" -d201911e2._domainkey.fred.example.org d201911e2._domainkey.fred 7200 IN TXT "v=DKIM1; k=ed25519; p=rQNsV9YcPJn/WYI1EDLjNbN/VuX1Hqq/oe4htbnhv+A=" -d202003._domainkey.fred.example.org d202003._domainkey.fred 7200 IN TXT "v=DKIM1; k=rsa; p=MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAvpnx7tnRxAnE/poIRbVb2i+f1uQCXWnBHzHurgEyZX0CmGaiJuCbr8SWOW2PoXq9YX8gIv2TS3uzwGv/4yA2yX9Z9zar1LeWUfGgMWLdCol9xfmWrI+6MUzxuwhw/mXwzigbI4bHoakh3ez/i3J9KPS85GfrOODqA1emR13f2pG8EzAcje+rwW2PtYj" "c0h+FMDpeLuPYyYszFbNlrkVUneesxnoz+o4x/s6P14ZoRqz5CR7u6G02HwnNaHads5Eto6FYYErUUTtFmgWuYabHxgLVGRdRQs6B5OBYT/3L2q/lAgmEgdy/QL+c0Psfj99/XQmO8fcM0scBzw2ukQzcUwIDAQAB" -d202003e2._domainkey.fred.example.org d202003e2._domainkey.fred 7200 IN TXT "v=DKIM1; k=ed25519; p=0DAPp/IRLYFI/Z4YSgJRi4gr7xcu1/EfJ5mjVn10aAw=" -_adsp._domainkey.fred.example.org _adsp._domainkey.fred 7200 IN TXT "dkim=all" -_dmarc.fred.example.org _dmarc.fred 7200 IN TXT "v=DMARC1; p=none; sp=none; rua=mailto:dmarc-notify@example.org; ruf=mailto:dmarc-notify@example.org; adkim=s" -_report.fred.example.org _report.fred 7200 IN TXT "r=abuse-reports@example.org; rf=ARF; re=postmaster@example.org;" -_smtp._tls.fred.example.org _smtp._tls.fred 7200 IN TXT "v=TLSRPTv1; rua=mailto:smtp-tls-reports@example.org" -_smtp-tlsrpt.fred.example.org _smtp-tlsrpt.fred 7200 IN TXT "v=TLSRPTv1; rua=mailto:smtp-tls-reports@example.org" +fred.example.org fred 7200 IN TXT v=spf1 ip4:192.0.2.25 ip6:2001:db8::1:25 mx include:_spf.example.com ~all +d201911._domainkey.fred.example.org d201911._domainkey.fred 7200 IN TXT v=DKIM1; k=rsa; p=MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA8/OMUa3PnWh9LqXFVwlAgYDdTtbq3zTtTOSBmJq5yWauzXYcUuSmhW7CsV0QQlacCsQgJlwg9Nl1vO1TosAj5EKUCLTeSqjlWrM7KXKPx8FT71Q9H9wXX4MHUyGrqHFo0OPzcmtHwqcd8AD6MIvJHSRoAfiPPBp8Euc0wGnJZdGS75Hk+wA3MQ2/TlzP2eenyiFyqmUTAGOYsGC/tREsWPiegR/OVxNGlzTY6quHsuVK7UYtIyFnYx9PGWdl3b3p7VjQ5V0Rp+2CLtVrCuS6Zs+/3NhZdM7mdD0a9Jgxakwa1le5YmB5lHTGF7T8quy6TlKe9lMUIRNjqTHfSFz/MwIDAQAB +d201911e2._domainkey.fred.example.org d201911e2._domainkey.fred 7200 IN TXT v=DKIM1; k=ed25519; p=rQNsV9YcPJn/WYI1EDLjNbN/VuX1Hqq/oe4htbnhv+A= +d202003._domainkey.fred.example.org d202003._domainkey.fred 7200 IN TXT v=DKIM1; k=rsa; p=MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAvpnx7tnRxAnE/poIRbVb2i+f1uQCXWnBHzHurgEyZX0CmGaiJuCbr8SWOW2PoXq9YX8gIv2TS3uzwGv/4yA2yX9Z9zar1LeWUfGgMWLdCol9xfmWrI+6MUzxuwhw/mXwzigbI4bHoakh3ez/i3J9KPS85GfrOODqA1emR13f2pG8EzAcje+rwW2PtYjc0h+FMDpeLuPYyYszFbNlrkVUneesxnoz+o4x/s6P14ZoRqz5CR7u6G02HwnNaHads5Eto6FYYErUUTtFmgWuYabHxgLVGRdRQs6B5OBYT/3L2q/lAgmEgdy/QL+c0Psfj99/XQmO8fcM0scBzw2ukQzcUwIDAQAB +d202003e2._domainkey.fred.example.org d202003e2._domainkey.fred 7200 IN TXT v=DKIM1; k=ed25519; p=0DAPp/IRLYFI/Z4YSgJRi4gr7xcu1/EfJ5mjVn10aAw= +_adsp._domainkey.fred.example.org _adsp._domainkey.fred 7200 IN TXT dkim=all +_dmarc.fred.example.org _dmarc.fred 7200 IN TXT v=DMARC1; p=none; sp=none; rua=mailto:dmarc-notify@example.org; ruf=mailto:dmarc-notify@example.org; adkim=s +_report.fred.example.org _report.fred 7200 IN TXT r=abuse-reports@example.org; rf=ARF; re=postmaster@example.org; +_smtp._tls.fred.example.org _smtp._tls.fred 7200 IN TXT v=TLSRPTv1; rua=mailto:smtp-tls-reports@example.org +_smtp-tlsrpt.fred.example.org _smtp-tlsrpt.fred 7200 IN TXT v=TLSRPTv1; rua=mailto:smtp-tls-reports@example.org mailtest.example.org mailtest 7200 IN MX 10 mx.example.org. -d201911._domainkey.mailtest.example.org d201911._domainkey.mailtest 7200 IN TXT "v=DKIM1; k=rsa; p=MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAo9xHnjHyhm1weA6FjOqM8LKVsklFt26HXWoe/0XCdmBG4i/UzQ7RiSgWO4kv7anPK6qf6rtL1xYsHufaRXG8yLsZxz+BbUP99eZvxZX78tMg4cGf+yU6uFxulCbOzsMy+8Cc3bbQTtIWYjyWBwnHdRRrCkQxjZ5KAd+x7ZB5qzqg2/eLJ7fCuNsr/xn" "0XTY6XYgug95e3h4CEW3Y+bkG81AMeJmT/hoVTcXvT/Gm6ZOUmx6faQWIHSW7qOR3VS6S75HOuclEUk0gt9r7OQHKl01sXh8g02SHRk8SUMEoNVayqplYZTFFF01Z192m7enmpp+St+HHUIT6jW/CAMCO3wIDAQAB" -d201911e2._domainkey.mailtest.example.org d201911e2._domainkey.mailtest 7200 IN TXT "v=DKIM1; k=ed25519; p=afulDDnhaTzdqKQN0jtWV04eOhAcyBk3NCyVheOf53Y=" -d202003._domainkey.mailtest.example.org d202003._domainkey.mailtest 7200 IN TXT "v=DKIM1; k=rsa; p=MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAs2BTVZaVLvL3qZBPaF7tRR0SdOKe+hjcpQ5fqO48lEuYiyTb6lkn8DPjDK11gTN3au0Bm+y8KC7ITKSJosuJXytxt3wqc61Pwtmb/Cy7GzmOF1AuegydB3/88VbgHT5DZucHrh6+ValZk4Trkx+/1K26Uo+h2KL2n/Ldb1y91ATHujp8DqxAOhiZ7KN" "aS1okNRRB4/14jPufAbeiN8/iBPiY5Hl80KHmpjM+7vvjb5jiecZ1ZrVDj7eTES4pmVh2v1c106mZLieoqDPYaf/HVbCM4E4n1B6kjbboSOpANADIcqXxGJQ7Be7/Sk9f7KwRusrsMHXmBHgm4wPmwGVZ3QIDAQAB" -d202003e2._domainkey.mailtest.example.org d202003e2._domainkey.mailtest 7200 IN TXT "v=DKIM1; k=ed25519; p=iqwH/hhozFdeo1xnuldr8KUi7O7g+DzmC+f0SYMKVDc=" -_adsp._domainkey.mailtest.example.org _adsp._domainkey.mailtest 7200 IN TXT "dkim=all" -_dmarc.mailtest.example.org _dmarc.mailtest 7200 IN TXT "v=DMARC1; p=none; sp=none; rua=mailto:dmarc-notify@example.org; ruf=mailto:dmarc-notify@example.org; adkim=s" -_report.mailtest.example.org _report.mailtest 7200 IN TXT "r=abuse-reports@example.org; rf=ARF; re=postmaster@example.org;" -_smtp._tls.mailtest.example.org _smtp._tls.mailtest 7200 IN TXT "v=TLSRPTv1; rua=mailto:smtp-tls-reports@example.org" -_smtp-tlsrpt.mailtest.example.org _smtp-tlsrpt.mailtest 7200 IN TXT "v=TLSRPTv1; rua=mailto:smtp-tls-reports@example.org" +d201911._domainkey.mailtest.example.org d201911._domainkey.mailtest 7200 IN TXT v=DKIM1; k=rsa; p=MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAo9xHnjHyhm1weA6FjOqM8LKVsklFt26HXWoe/0XCdmBG4i/UzQ7RiSgWO4kv7anPK6qf6rtL1xYsHufaRXG8yLsZxz+BbUP99eZvxZX78tMg4cGf+yU6uFxulCbOzsMy+8Cc3bbQTtIWYjyWBwnHdRRrCkQxjZ5KAd+x7ZB5qzqg2/eLJ7fCuNsr/xn0XTY6XYgug95e3h4CEW3Y+bkG81AMeJmT/hoVTcXvT/Gm6ZOUmx6faQWIHSW7qOR3VS6S75HOuclEUk0gt9r7OQHKl01sXh8g02SHRk8SUMEoNVayqplYZTFFF01Z192m7enmpp+St+HHUIT6jW/CAMCO3wIDAQAB +d201911e2._domainkey.mailtest.example.org d201911e2._domainkey.mailtest 7200 IN TXT v=DKIM1; k=ed25519; p=afulDDnhaTzdqKQN0jtWV04eOhAcyBk3NCyVheOf53Y= +d202003._domainkey.mailtest.example.org d202003._domainkey.mailtest 7200 IN TXT v=DKIM1; k=rsa; p=MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAs2BTVZaVLvL3qZBPaF7tRR0SdOKe+hjcpQ5fqO48lEuYiyTb6lkn8DPjDK11gTN3au0Bm+y8KC7ITKSJosuJXytxt3wqc61Pwtmb/Cy7GzmOF1AuegydB3/88VbgHT5DZucHrh6+ValZk4Trkx+/1K26Uo+h2KL2n/Ldb1y91ATHujp8DqxAOhiZ7KNaS1okNRRB4/14jPufAbeiN8/iBPiY5Hl80KHmpjM+7vvjb5jiecZ1ZrVDj7eTES4pmVh2v1c106mZLieoqDPYaf/HVbCM4E4n1B6kjbboSOpANADIcqXxGJQ7Be7/Sk9f7KwRusrsMHXmBHgm4wPmwGVZ3QIDAQAB +d202003e2._domainkey.mailtest.example.org d202003e2._domainkey.mailtest 7200 IN TXT v=DKIM1; k=ed25519; p=iqwH/hhozFdeo1xnuldr8KUi7O7g+DzmC+f0SYMKVDc= +_adsp._domainkey.mailtest.example.org _adsp._domainkey.mailtest 7200 IN TXT dkim=all +_dmarc.mailtest.example.org _dmarc.mailtest 7200 IN TXT v=DMARC1; p=none; sp=none; rua=mailto:dmarc-notify@example.org; ruf=mailto:dmarc-notify@example.org; adkim=s +_report.mailtest.example.org _report.mailtest 7200 IN TXT r=abuse-reports@example.org; rf=ARF; re=postmaster@example.org; +_smtp._tls.mailtest.example.org _smtp._tls.mailtest 7200 IN TXT v=TLSRPTv1; rua=mailto:smtp-tls-reports@example.org +_smtp-tlsrpt.mailtest.example.org _smtp-tlsrpt.mailtest 7200 IN TXT v=TLSRPTv1; rua=mailto:smtp-tls-reports@example.org _pgpkey-http._tcp.sks.example.org _pgpkey-http._tcp.sks 7200 IN SRV 0 0 0 . _pgpkey-https._tcp.sks.example.org _pgpkey-https._tcp.sks 7200 IN SRV 0 0 0 . _hkp._tcp.sks.example.org _hkp._tcp.sks 7200 IN SRV 0 0 0 . @@ -341,7 +341,7 @@ khard.example.org khard 7200 IN NS ns-cloud-d2.googledomains.com. khard.example.org khard 7200 IN NS ns-cloud-d3.googledomains.com. khard.example.org khard 7200 IN NS ns-cloud-d4.googledomains.com. realhost.example.org realhost 7200 IN MX 0 . -realhost.example.org realhost 7200 IN TXT "v=spf1 -all" +realhost.example.org realhost 7200 IN TXT v=spf1 -all _25._tcp.realhost.example.org _25._tcp.realhost 7200 IN TLSA 3 0 0 0000000000000000000000000000000000000000000000000000000000000000 _fedcba9876543210fedcba9876543210.go.example.org _fedcba9876543210fedcba9876543210.go 7200 IN CNAME _45678901234abcdef45678901234abcd.ggedgsdned.acm-validations.aws. opqrstuvwxyz.example.org opqrstuvwxyz 7200 IN CNAME gv-abcdefghijklmn.dv.googlehosted.com. diff --git a/commands/test_data/example.org.zone.zone b/commands/test_data/example.org.zone.zone index 0c48481199..384b8979d6 100644 --- a/commands/test_data/example.org.zone.zone +++ b/commands/test_data/example.org.zone.zone @@ -32,9 +32,9 @@ special.test._report._dmarc IN TXT "v=DMARC1" xn--2j5b.xn--9t4b11yi5a._report._dmarc IN TXT "v=DMARC1" xn--qck5b9a5eml3bze.xn--zckzah._report._dmarc IN TXT "v=DMARC1" _adsp._domainkey IN TXT "dkim=all" -d201911._domainkey IN TXT "v=DKIM1; k=rsa; p=MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA4SmyE5Tz5/wPL8cb2AKuHnlFeLMOhAl1UX/NYaeDCKMWoBPTgZRT0jonKLmV2UscHdodXu5ZsLr/NAuLCp7HmPLReLz7kxKncP6ppveKxc1aq5SPTKeWe77p6BptlahHc35eiXsZRpTsEzrbEOainy1IWEd+w9p1gWbrSutwE22z0i4V88nQ9UBa1ks" "6cVGxXBZFovWC+i28aGs6Lc7cSfHG5+Mrg3ud5X4evYXTGFMPpunMcCsXrqmS5a+5gRSEMZhngha/cHjLwaJnWzKaywNWF5XOsCjL94QkS0joB7lnGOHMNSZBCcu542Y3Ht3SgHhlpkF9mIbIRfpzA9IoSQIDAQAB" +d201911._domainkey IN TXT "v=DKIM1; k=rsa; p=MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA4SmyE5Tz5/wPL8cb2AKuHnlFeLMOhAl1UX/NYaeDCKMWoBPTgZRT0jonKLmV2UscHdodXu5ZsLr/NAuLCp7HmPLReLz7kxKncP6ppveKxc1aq5SPTKeWe77p6BptlahHc35eiXsZRpTsEzrbEOainy1IWEd+w9p1gWbrSutwE22z0i4V88nQ9UBa1ks6cVGxX" "BZFovWC+i28aGs6Lc7cSfHG5+Mrg3ud5X4evYXTGFMPpunMcCsXrqmS5a+5gRSEMZhngha/cHjLwaJnWzKaywNWF5XOsCjL94QkS0joB7lnGOHMNSZBCcu542Y3Ht3SgHhlpkF9mIbIRfpzA9IoSQIDAQAB" d201911e2._domainkey IN TXT "v=DKIM1; k=ed25519; p=GBt2k2L39KUb39fg5brOppXDHXvISy0+ECGgPld/bIo=" -d202003._domainkey IN TXT "v=DKIM1; k=rsa; p=MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAv/1tQvOEs7xtKNm7PbPgY4hQjwHVvqqkDb0+TeqZHYRSczQ3c0LFJrIDFiPIdwQe/7AuKrxvATSh/uXKZ3EP4ouMgROPZnUxVXENeetJj+pc3nfGwTKUBTTTth+SO74gdIWsntjvAfduzosC4ZkxbDwZ9c253qXARGvGu+LB/iAeq0ngEbm5fU13+Jo" "pv0d4dR6oGe9GvMEnGGLZzNrxWl1BPe2x5JZ5/X/3fW8vJx3OgRB5N6fqbAJ6HZ9kcbikDH4lPPl9RIoprFk7mmwno/nXLQYGhPobmqq8wLkDiXEkWtYa5lzujz3XI3Zkk8ZIOGvdbVVfAttT0IVPnYkOhQIDAQAB" +d202003._domainkey IN TXT "v=DKIM1; k=rsa; p=MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAv/1tQvOEs7xtKNm7PbPgY4hQjwHVvqqkDb0+TeqZHYRSczQ3c0LFJrIDFiPIdwQe/7AuKrxvATSh/uXKZ3EP4ouMgROPZnUxVXENeetJj+pc3nfGwTKUBTTTth+SO74gdIWsntjvAfduzosC4ZkxbDwZ9c253qXARGvGu+LB/iAeq0ngEbm5fU13+Jopv0d4d" "R6oGe9GvMEnGGLZzNrxWl1BPe2x5JZ5/X/3fW8vJx3OgRB5N6fqbAJ6HZ9kcbikDH4lPPl9RIoprFk7mmwno/nXLQYGhPobmqq8wLkDiXEkWtYa5lzujz3XI3Zkk8ZIOGvdbVVfAttT0IVPnYkOhQIDAQAB" d202003e2._domainkey IN TXT "v=DKIM1; k=ed25519; p=DQI5d9sNMrr0SLDoAi071IFOyKnlbR29hAQdqVQecQg=" _kerberos IN TXT "EXAMPLE.ORG" _le-amazon-tlsa IN TLSA 2 0 1 18ce6cfe7bf14e60b2e347b8dfe868cb31d02ebb3ada271569f50343b46db3a4 @@ -124,7 +124,7 @@ _acme-challenge.conference 15 IN CNAME _acme-challenge.conference.chat-acme.d.ex _xmpp-server._tcp.conference IN SRV 10 2 5269 chat.example.org. IN SRV 10 2 5269 xmpp-s2s.example.org. dict IN CNAME services.example.org. -dns-moreinfo IN TXT "Fred Bloggs, TZ=America/New_York" "Chat-Service-X: @handle1" "Chat-Service-Y: federated-handle@example.org" +dns-moreinfo IN TXT "Fred Bloggs, TZ=America/New_YorkChat-Service-X: @handle1Chat-Service-Y: federated-handle@example.org" field IN NS ns1.example.org. IN NS ns2.example.org. finger IN CNAME barbican.example.org. @@ -136,9 +136,9 @@ fred IN A 192.0.2.93 IN TXT "v=spf1 ip4:192.0.2.25 ip6:2001:db8::1:25 mx include:_spf.example.com ~all" _dmarc.fred IN TXT "v=DMARC1; p=none; sp=none; rua=mailto:dmarc-notify@example.org; ruf=mailto:dmarc-notify@example.org; adkim=s" _adsp._domainkey.fred IN TXT "dkim=all" -d201911._domainkey.fred IN TXT "v=DKIM1; k=rsa; p=MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA8/OMUa3PnWh9LqXFVwlAgYDdTtbq3zTtTOSBmJq5yWauzXYcUuSmhW7CsV0QQlacCsQgJlwg9Nl1vO1TosAj5EKUCLTeSqjlWrM7KXKPx8FT71Q9H9wXX4MHUyGrqHFo0OPzcmtHwqcd8AD6MIvJHSRoAfiPPBp8Euc0wGnJZdGS75Hk+wA3MQ2/Tlz" "P2eenyiFyqmUTAGOYsGC/tREsWPiegR/OVxNGlzTY6quHsuVK7UYtIyFnYx9PGWdl3b3p7VjQ5V0Rp+2CLtVrCuS6Zs+/3NhZdM7mdD0a9Jgxakwa1le5YmB5lHTGF7T8quy6TlKe9lMUIRNjqTHfSFz/MwIDAQAB" +d201911._domainkey.fred IN TXT "v=DKIM1; k=rsa; p=MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA8/OMUa3PnWh9LqXFVwlAgYDdTtbq3zTtTOSBmJq5yWauzXYcUuSmhW7CsV0QQlacCsQgJlwg9Nl1vO1TosAj5EKUCLTeSqjlWrM7KXKPx8FT71Q9H9wXX4MHUyGrqHFo0OPzcmtHwqcd8AD6MIvJHSRoAfiPPBp8Euc0wGnJZdGS75Hk+wA3MQ2/TlzP2eeny" "iFyqmUTAGOYsGC/tREsWPiegR/OVxNGlzTY6quHsuVK7UYtIyFnYx9PGWdl3b3p7VjQ5V0Rp+2CLtVrCuS6Zs+/3NhZdM7mdD0a9Jgxakwa1le5YmB5lHTGF7T8quy6TlKe9lMUIRNjqTHfSFz/MwIDAQAB" d201911e2._domainkey.fred IN TXT "v=DKIM1; k=ed25519; p=rQNsV9YcPJn/WYI1EDLjNbN/VuX1Hqq/oe4htbnhv+A=" -d202003._domainkey.fred IN TXT "v=DKIM1; k=rsa; p=MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAvpnx7tnRxAnE/poIRbVb2i+f1uQCXWnBHzHurgEyZX0CmGaiJuCbr8SWOW2PoXq9YX8gIv2TS3uzwGv/4yA2yX9Z9zar1LeWUfGgMWLdCol9xfmWrI+6MUzxuwhw/mXwzigbI4bHoakh3ez/i3J9KPS85GfrOODqA1emR13f2pG8EzAcje+rwW2PtYj" "c0h+FMDpeLuPYyYszFbNlrkVUneesxnoz+o4x/s6P14ZoRqz5CR7u6G02HwnNaHads5Eto6FYYErUUTtFmgWuYabHxgLVGRdRQs6B5OBYT/3L2q/lAgmEgdy/QL+c0Psfj99/XQmO8fcM0scBzw2ukQzcUwIDAQAB" +d202003._domainkey.fred IN TXT "v=DKIM1; k=rsa; p=MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAvpnx7tnRxAnE/poIRbVb2i+f1uQCXWnBHzHurgEyZX0CmGaiJuCbr8SWOW2PoXq9YX8gIv2TS3uzwGv/4yA2yX9Z9zar1LeWUfGgMWLdCol9xfmWrI+6MUzxuwhw/mXwzigbI4bHoakh3ez/i3J9KPS85GfrOODqA1emR13f2pG8EzAcje+rwW2PtYjc0h+FM" "DpeLuPYyYszFbNlrkVUneesxnoz+o4x/s6P14ZoRqz5CR7u6G02HwnNaHads5Eto6FYYErUUTtFmgWuYabHxgLVGRdRQs6B5OBYT/3L2q/lAgmEgdy/QL+c0Psfj99/XQmO8fcM0scBzw2ukQzcUwIDAQAB" d202003e2._domainkey.fred IN TXT "v=DKIM1; k=ed25519; p=0DAPp/IRLYFI/Z4YSgJRi4gr7xcu1/EfJ5mjVn10aAw=" _report.fred IN TXT "r=abuse-reports@example.org; rf=ARF; re=postmaster@example.org;" _smtp-tlsrpt.fred IN TXT "v=TLSRPTv1; rua=mailto:smtp-tls-reports@example.org" @@ -247,9 +247,9 @@ kpeople IN AAAA 2001:db8::48:4558:6b70:706c mailtest IN MX 10 mx.example.org. _dmarc.mailtest IN TXT "v=DMARC1; p=none; sp=none; rua=mailto:dmarc-notify@example.org; ruf=mailto:dmarc-notify@example.org; adkim=s" _adsp._domainkey.mailtest IN TXT "dkim=all" -d201911._domainkey.mailtest IN TXT "v=DKIM1; k=rsa; p=MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAo9xHnjHyhm1weA6FjOqM8LKVsklFt26HXWoe/0XCdmBG4i/UzQ7RiSgWO4kv7anPK6qf6rtL1xYsHufaRXG8yLsZxz+BbUP99eZvxZX78tMg4cGf+yU6uFxulCbOzsMy+8Cc3bbQTtIWYjyWBwnHdRRrCkQxjZ5KAd+x7ZB5qzqg2/eLJ7fCuNsr/xn" "0XTY6XYgug95e3h4CEW3Y+bkG81AMeJmT/hoVTcXvT/Gm6ZOUmx6faQWIHSW7qOR3VS6S75HOuclEUk0gt9r7OQHKl01sXh8g02SHRk8SUMEoNVayqplYZTFFF01Z192m7enmpp+St+HHUIT6jW/CAMCO3wIDAQAB" +d201911._domainkey.mailtest IN TXT "v=DKIM1; k=rsa; p=MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAo9xHnjHyhm1weA6FjOqM8LKVsklFt26HXWoe/0XCdmBG4i/UzQ7RiSgWO4kv7anPK6qf6rtL1xYsHufaRXG8yLsZxz+BbUP99eZvxZX78tMg4cGf+yU6uFxulCbOzsMy+8Cc3bbQTtIWYjyWBwnHdRRrCkQxjZ5KAd+x7ZB5qzqg2/eLJ7fCuNsr/xn0XTY6X" "Ygug95e3h4CEW3Y+bkG81AMeJmT/hoVTcXvT/Gm6ZOUmx6faQWIHSW7qOR3VS6S75HOuclEUk0gt9r7OQHKl01sXh8g02SHRk8SUMEoNVayqplYZTFFF01Z192m7enmpp+St+HHUIT6jW/CAMCO3wIDAQAB" d201911e2._domainkey.mailtest IN TXT "v=DKIM1; k=ed25519; p=afulDDnhaTzdqKQN0jtWV04eOhAcyBk3NCyVheOf53Y=" -d202003._domainkey.mailtest IN TXT "v=DKIM1; k=rsa; p=MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAs2BTVZaVLvL3qZBPaF7tRR0SdOKe+hjcpQ5fqO48lEuYiyTb6lkn8DPjDK11gTN3au0Bm+y8KC7ITKSJosuJXytxt3wqc61Pwtmb/Cy7GzmOF1AuegydB3/88VbgHT5DZucHrh6+ValZk4Trkx+/1K26Uo+h2KL2n/Ldb1y91ATHujp8DqxAOhiZ7KN" "aS1okNRRB4/14jPufAbeiN8/iBPiY5Hl80KHmpjM+7vvjb5jiecZ1ZrVDj7eTES4pmVh2v1c106mZLieoqDPYaf/HVbCM4E4n1B6kjbboSOpANADIcqXxGJQ7Be7/Sk9f7KwRusrsMHXmBHgm4wPmwGVZ3QIDAQAB" +d202003._domainkey.mailtest IN TXT "v=DKIM1; k=rsa; p=MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAs2BTVZaVLvL3qZBPaF7tRR0SdOKe+hjcpQ5fqO48lEuYiyTb6lkn8DPjDK11gTN3au0Bm+y8KC7ITKSJosuJXytxt3wqc61Pwtmb/Cy7GzmOF1AuegydB3/88VbgHT5DZucHrh6+ValZk4Trkx+/1K26Uo+h2KL2n/Ldb1y91ATHujp8DqxAOhiZ7KNaS1okN" "RRB4/14jPufAbeiN8/iBPiY5Hl80KHmpjM+7vvjb5jiecZ1ZrVDj7eTES4pmVh2v1c106mZLieoqDPYaf/HVbCM4E4n1B6kjbboSOpANADIcqXxGJQ7Be7/Sk9f7KwRusrsMHXmBHgm4wPmwGVZ3QIDAQAB" d202003e2._domainkey.mailtest IN TXT "v=DKIM1; k=ed25519; p=iqwH/hhozFdeo1xnuldr8KUi7O7g+DzmC+f0SYMKVDc=" _report.mailtest IN TXT "r=abuse-reports@example.org; rf=ARF; re=postmaster@example.org;" _smtp-tlsrpt.mailtest IN TXT "v=TLSRPTv1; rua=mailto:smtp-tls-reports@example.org" diff --git a/commands/test_data/simple.com.zone.tsv b/commands/test_data/simple.com.zone.tsv index 7e478f4342..b9e95d03d8 100644 --- a/commands/test_data/simple.com.zone.tsv +++ b/commands/test_data/simple.com.zone.tsv @@ -8,12 +8,12 @@ simple.com @ 300 IN MX 5 alt1.aspmx.l.google.com. simple.com @ 300 IN MX 5 alt2.aspmx.l.google.com. simple.com @ 300 IN MX 10 alt3.aspmx.l.google.com. simple.com @ 300 IN MX 10 alt4.aspmx.l.google.com. -simple.com @ 300 IN TXT "google-site-verification=O54a_pYHGr4EB8iLoGFgX8OTZ1DkP1KWnOLpx0YCazI" -simple.com @ 300 IN TXT "v=spf1 mx include:mktomail.com ~all" -m1._domainkey.simple.com m1._domainkey 300 IN TXT "v=DKIM1;k=rsa;p=MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCZfEV2C82eJ4OA3Mslz4C6msjYYalg1eUcHeJQ//QM1hOZSvn4qz+hSKGi7jwNDqsZNzM8vCt2+XzdDYL3JddwUEhoDsIsZsJW0qzIVVLLWCg6TLNS3FpVyjc171o94dpoHFekfswWDoEwFQ03Woq2jchYWBrbUf7MMcdEj/EQqwIDAQAB" +simple.com @ 300 IN TXT google-site-verification=O54a_pYHGr4EB8iLoGFgX8OTZ1DkP1KWnOLpx0YCazI +simple.com @ 300 IN TXT v=spf1 mx include:mktomail.com ~all +m1._domainkey.simple.com m1._domainkey 300 IN TXT v=DKIM1;k=rsa;p=MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCZfEV2C82eJ4OA3Mslz4C6msjYYalg1eUcHeJQ//QM1hOZSvn4qz+hSKGi7jwNDqsZNzM8vCt2+XzdDYL3JddwUEhoDsIsZsJW0qzIVVLLWCg6TLNS3FpVyjc171o94dpoHFekfswWDoEwFQ03Woq2jchYWBrbUf7MMcdEj/EQqwIDAQAB dev.simple.com dev 300 IN CNAME stackoverflowsandbox2.mktoweb.com. dev-email.simple.com dev-email 300 IN CNAME mkto-sj310056.com. -m1._domainkey.dev-email.simple.com m1._domainkey.dev-email 300 IN TXT "v=DKIM1;k=rsa;p=MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCIBezZ2Gc+/3PghWk+YOE6T9HdwgUTMTR0Fne2i51MNN9Qs7AqDitVdG/949iDbI2fPNZSnKtOcnlLYwvve9MhMAMI1nZ26ILhgaBJi2BMZQpGFlO4ucuo/Uj4DPZ5Ge/NZHCX0CRhAhR5sRmL2OffNcFXFrymzUuz4KzI/NyUiwIDAQAB" +m1._domainkey.dev-email.simple.com m1._domainkey.dev-email 300 IN TXT v=DKIM1;k=rsa;p=MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCIBezZ2Gc+/3PghWk+YOE6T9HdwgUTMTR0Fne2i51MNN9Qs7AqDitVdG/949iDbI2fPNZSnKtOcnlLYwvve9MhMAMI1nZ26ILhgaBJi2BMZQpGFlO4ucuo/Uj4DPZ5Ge/NZHCX0CRhAhR5sRmL2OffNcFXFrymzUuz4KzI/NyUiwIDAQAB email.simple.com email 300 IN CNAME mkto-sj280138.com. info.simple.com info 300 IN CNAME stackoverflow.mktoweb.com. _sip._tcp.simple.com _sip._tcp 300 IN SRV 10 60 5060 bigbox.example.com. diff --git a/documentation/opinions.md b/documentation/opinions.md index 71256a2ef8..1d7e6f47d8 100644 --- a/documentation/opinions.md +++ b/documentation/opinions.md @@ -127,7 +127,7 @@ else is ambiguous and therefore an error. # Opinion #7 Hostnames don't have underscores DNSControl prints warnings if a hostname includes an underscore -(`_`) because underscores are not permitted in hostnames. +(`_`) because underscores are not permitted in hostnames. We want to prevent a naive user from including an underscore when they meant to use a hyphen (`-`). @@ -150,3 +150,33 @@ Therefore we print a warning if a label has an underscore in it, unless the rtype is SRV, TLSA, TXT, or if the name starts with certain prefixes such as `_dmarc`. We're always willing to [add more exceptions](https://github.com/StackExchange/dnscontrol/pull/453/files). + +# Opinion #8 TXT Records are one long string + +* TXT records are a single string with a length of 0 to 65,280 bytes + (the maximum possible TXT record size). + +It is the provider's responsibility to split, join, quote, parse, +encode, or decoded the string as needed by the provider's API. This +should be invisible to the user. + +The user may represent the string any way that JavaScript permits +strings to be represented (usually double-quotes). For backwards +compatibility they may also provide a list of strings which will be +concatenated. + +You may be wondering: Isn't a TXT record really a series of 255-octet +segments? Yes, TXT record's wire-format is a series of strings, each +no longer than 255-octets. However that kind of detail should be +hidden from users. The user should represent the string they want and +DNSControl should magically do the right thing behind the scenes. The +same with quoting and escaping required by APIs. + +You may be wondering: Are there any higher-level applications which +ascribe semantic value to the TXT string boundaries? I believe that +the answer is "no". My proof is not based on reading RFCs, but +instead based on (a) observing that I've never seen a DNS provider's +control panel let you specify the boundaries, (b) I've never seen a +FAQ or reddit post asking how to specify those boundaries. Therefore, +there is no need for this. I also assert that there will be no such +need in the future. diff --git a/integrationTest/integration_test.go b/integrationTest/integration_test.go index 52398cb184..2c1725c270 100644 --- a/integrationTest/integration_test.go +++ b/integrationTest/integration_test.go @@ -640,7 +640,6 @@ 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.TxtStrings = []string{target} r.SetTarget(target) return r } @@ -1085,39 +1084,69 @@ func makeTests(t *testing.T) []*TestGroup { // Do not use only()/not()/requires() in this section. // If your provider needs to skip one of these tests, update // "provider/*/recordaudit.AuditRecords()" to reject that kind - // of record. When the provider fixes the bug or changes behavior, - // update the AuditRecords(). - - //clear(), - //tc("a 255-byte TXT", txt("foo255", strings.Repeat("C", 255))), - //clear(), - //tc("a 256-byte TXT", txt("foo256", strings.Repeat("D", 256))), - //clear(), - //tc("a 512-byte TXT", txt("foo512", strings.Repeat("C", 512))), - //clear(), - //tc("a 513-byte TXT", txt("foo513", strings.Repeat("D", 513))), + // of record. + + // Some of these test cases are commented out because they test + // something that isn't widely used or supported. For example + // many APIs don't support a backslack (`\`) in a TXT record; + // luckily we've never seen a need for that "in the wild". If + // you want to future-proof your provider, temporarily remove + // the comments and get those tests working, or reject it using + // auditrecords.go. + + // ProTip: Unsure how a provider's API escapes something? Try + // adding the TXT record via the Web UI and watch how the string + // is escaped when you download the records. + + // Nobody needs this and many APIs don't allow it. + tc("a 0-byte TXT", txt("foo0", "")), + + // Test edge cases around 255, 255*2, 255*3: + tc("a 254-byte TXT", txt("foo254", strings.Repeat("A", 254))), // 255-1 + tc("a 255-byte TXT", txt("foo255", strings.Repeat("B", 255))), // 255 + tc("a 256-byte TXT", txt("foo256", strings.Repeat("C", 256))), // 255+1 + tc("a 509-byte TXT", txt("foo509", strings.Repeat("D", 509))), // 255*2-1 + tc("a 510-byte TXT", txt("foo510", strings.Repeat("E", 510))), // 255*2 + tc("a 511-byte TXT", txt("foo511", strings.Repeat("F", 511))), // 255*2+1 + 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(), tc("TXT with 1 single-quote", txt("foosq", "quo'te")), - //clear(), tc("TXT with 1 backtick", txt("foobt", "blah`blah")), - //clear(), - tc("TXT with 1 double-quotes", txt("foodq", `quo"te`)), - //clear(), - tc("TXT with 2 double-quotes", txt("foodqs", `q"uo"te`)), - //clear(), + tc("TXT with 1 dq-1interior", txt("foodq", `in"side`)), + tc("TXT with 2 dq-2interior", txt("foodqs", `in"ter"ior`)), + tc("TXT with 1 dq-left", txt("foodqs", `"left`)), + tc("TXT with 1 dq-right", txt("foodqs", `right"`)), - tc("a TXT with interior ws", txt("foosp", "with spaces")), - //clear(), - tc("TXT with ws at end", txt("foows1", "with space at end ")), - //clear(), + // Semicolons don't need special treatment. + // https://serverfault.com/questions/743789 + tc("TXT with semicolon", txt("foosc1", `semi;colon`)), + tc("TXT with semicolon ws", txt("foosc2", `wssemi ; colon`)), - //tc("Create a TXT/SPF", txt("foo", "v=spf1 ip4:99.99.99.99 -all")), - // This was added because Vultr syntax-checks TXT records with SPF contents. - //clear(), + tc("TXT interior ws", txt("foosp", "with spaces")), + tc("TXT trailing ws", txt("foows1", "with space at end ")), + + // Vultr syntax-checks TXT records with SPF contents. + tc("Create a TXT/SPF", txt("foo", "v=spf1 ip4:99.99.99.99 -all")), - // TODO(tlim): Re-add this when we fix the RFC1035 escaped-quotes issue. - //tc("Create TXT with frequently escaped characters", txt("fooex", `!^.*$@#%^&()([][{}{<> 0 { return segs + 1 @@ -171,6 +76,10 @@ func (rc *RecordConfig) GetTargetTXTSegmentCount() int { } func splitChunks(buf string, lim int) []string { + if len(buf) == 0 { + return nil + } + var chunk string chunks := make([]string, 0, len(buf)/lim+1) for len(buf) >= lim { @@ -182,27 +91,3 @@ func splitChunks(buf string, lim int) []string { } return chunks } - -// SetTargetTXTfromRFC1035Quoted parses a series of quoted strings -// and sets .TxtStrings based on the result. -// Note: Most APIs do notThis is rarely used. Try using SetTargetTXT() first. -// Ex: -// -// "foo" << 1 string -// "foo bar" << 1 string -// "foo" "bar" << 2 strings -// foo << error. No quotes! Did you intend to use SetTargetTXT? -func (rc *RecordConfig) SetTargetTXTfromRFC1035Quoted(s string) error { - if s != "" && s[0] != '"' { - // If you get this error, it is likely that you should use - // SetTargetTXT() instead of SetTargetTXTfromRFC1035Quoted(). - return fmt.Errorf("non-quoted string used with SetTargetTXTfromRFC1035Quoted: (%s)", s) - } - many, err := ParseQuotedFields(s) - if err != nil { - return err - } - return rc.SetTargetTXTs(many) -} - -// There is no GetTargetTXTfromRFC1025Quoted(). Use GetTargetRFC1035Quoted() diff --git a/models/target.go b/models/target.go index 55a843c937..d59c598ac2 100644 --- a/models/target.go +++ b/models/target.go @@ -3,7 +3,6 @@ package models import ( "fmt" "net" - "runtime/debug" "strings" "github.com/miekg/dns" @@ -14,22 +13,9 @@ If an rType has more than one field, one field goes in .target and the remaining Not the best design, but we're stuck with it until we re-do RecordConfig, possibly using generics. */ -// Set debugWarnTxtField to true if you want a warning when -// GetTargetField is called on a TXT record. -// GetTargetField works fine on TXT records for casual output but it -// is often better to access .TxtStrings directly or call -// GetTargetRFC1035Quoted() for nicely quoted text. -var debugWarnTxtField = false - -// GetTargetField returns the target. There may be other fields (for example -// an MX record also has a .MxPreference field. +// GetTargetField returns the target. There may be other fields, but they are +// not included. For example, the .MxPreference field of an MX record isn't included. func (rc *RecordConfig) GetTargetField() string { - if debugWarnTxtField { - if rc.Type == "TXT" { - fmt.Printf("DEBUG: WARNING: GetTargetField called on TXT record is frequently wrong: %q\n", rc.target) - debug.PrintStack() - } - } return rc.target } @@ -41,8 +27,23 @@ func (rc *RecordConfig) GetTargetIP() net.IP { return net.ParseIP(rc.target) } +// GetTargetCombinedFunc returns all the rdata fields of a RecordConfig as one +// string. How TXT records are encoded is defined by encodeFn. If encodeFn is +// nil the TXT data is returned unaltered. +func (rc *RecordConfig) GetTargetCombinedFunc(encodeFn func(s string) string) string { + if rc.Type == "TXT" { + if encodeFn == nil { + return rc.target + } + return encodeFn(rc.target) + } + return rc.GetTargetCombined() +} + // GetTargetCombined returns a string with the various fields combined. // For example, an MX record might output `10 mx10.example.tld`. +// 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 { @@ -59,7 +60,10 @@ func (rc *RecordConfig) GetTargetCombined() string { } } - if rc.Type == "SOA" { + switch rc.Type { + case "TXT": + return rc.zoneFileQuoted() + case "SOA": return fmt.Sprintf("%s %v %d %d %d %d %d", rc.target, rc.SoaMbox, rc.SoaSerial, rc.SoaRefresh, rc.SoaRetry, rc.SoaExpire, rc.SoaMinttl) } @@ -93,14 +97,13 @@ func (rc *RecordConfig) GetTargetRFC1035Quoted() string { return rc.zoneFileQuoted() } -// GetTargetSortable returns a string that is sortable. -func (rc *RecordConfig) GetTargetSortable() string { - return rc.GetTargetDebug() -} - // GetTargetDebug returns a string with the various fields spelled out. func (rc *RecordConfig) GetTargetDebug() string { - content := fmt.Sprintf("%s %s %s %d", rc.Type, rc.NameFQDN, rc.target, rc.TTL) + target := rc.target + if rc.Type == "TXT" { + target = fmt.Sprintf("%q", target) + } + content := fmt.Sprintf("%s %s %s %d", rc.Type, rc.NameFQDN, target, rc.TTL) switch rc.Type { // #rtype_variations case "A", "AAAA", "AKAMAICDN", "CNAME", "DHCID", "NS", "PTR", "TXT": // Nothing special. diff --git a/pkg/diff/diff.go b/pkg/diff/diff.go index 031b9a720f..f2b18b8b1e 100644 --- a/pkg/diff/diff.go +++ b/pkg/diff/diff.go @@ -1,6 +1,8 @@ package diff import ( + "fmt" + "github.com/StackExchange/dnscontrol/v4/models" "github.com/fatih/color" ) @@ -29,12 +31,7 @@ type differ struct { // get normalized content for record. target, ttl, mxprio, and specified metadata func (d *differ) content(r *models.RecordConfig) string { - return r.ToDiffable() -} - -// CorrectionLess returns true when comparing corrections. -func CorrectionLess(c []*models.Correction, i, j int) bool { - return c[i].Msg < c[j].Msg + return fmt.Sprintf("%s ttl=%d", r.ToComparableNoTTL(), r.TTL) } func (c Correlation) String() string { diff --git a/pkg/diff/diff2compat.go b/pkg/diff/diff2compat.go index 78cb75a684..02ccae5dfb 100644 --- a/pkg/diff/diff2compat.go +++ b/pkg/diff/diff2compat.go @@ -61,6 +61,8 @@ func (d *differCompat) IncrementalDiff(existing []*models.RecordConfig) (reportM return } +// GenerateMessageCorrections turns a list of strings into a list of corrections +// that output those messages (and are otherwise a no-op). func GenerateMessageCorrections(msgs []string) (corrections []*models.Correction) { for _, msg := range msgs { corrections = append(corrections, &models.Correction{Msg: msg}) diff --git a/pkg/diff2/handsoff_test.go b/pkg/diff2/handsoff_test.go index 7f89fb82a3..4b28637397 100644 --- a/pkg/diff2/handsoff_test.go +++ b/pkg/diff2/handsoff_test.go @@ -18,7 +18,7 @@ func parseZoneContents(content string, zoneName string, zonefileName string) (mo foundRecords := models.Records{} for rr, ok := zp.Next(); ok; rr, ok = zp.Next() { - rec, err := models.RRtoRC(rr, zoneName) + rec, err := models.RRtoRCTxtBug(rr, zoneName) if err != nil { return nil, err } diff --git a/pkg/js/helpers.js b/pkg/js/helpers.js index ac817adc53..f52cea0a1d 100644 --- a/pkg/js/helpers.js +++ b/pkg/js/helpers.js @@ -543,11 +543,9 @@ var TXT = recordBuilder('TXT', { record.name = args.name; // Store the strings from the user verbatim. if (_.isString(args.target)) { - record.txtstrings = [args.target]; - record.target = args.target; // Overwritten by the Go code + record.target = args.target; } else { - record.txtstrings = args.target; - record.target = args.target.join(''); // Overwritten by the Go code + record.target = args.target.join(''); } }, }); diff --git a/pkg/js/parse_tests/016-backslash.js b/pkg/js/parse_tests/016-backslash.js deleted file mode 100644 index 4e88f7167c..0000000000 --- a/pkg/js/parse_tests/016-backslash.js +++ /dev/null @@ -1,13 +0,0 @@ -dmarc = [ - "v=DMARC1\\;", - 'p=reject\\;', - 'sp=reject\\;', - 'pct=100\\;', - 'rua=mailto:xx...@yyyy.com\\;', - 'ruf=mailto:xx...@yyyy.com\\;', - 'fo=1' - ].join(' '); - -D("foo.com","none", - TXT('_dmarc', dmarc, TTL(300)) -); diff --git a/pkg/js/parse_tests/016-backslash.json b/pkg/js/parse_tests/016-backslash.json deleted file mode 100644 index 2b90a7ae30..0000000000 --- a/pkg/js/parse_tests/016-backslash.json +++ /dev/null @@ -1,22 +0,0 @@ -{ - "registrars": [], - "dns_providers": [], - "domains": [ - { - "name": "foo.com", - "registrar": "none", - "dnsProviders": {}, - "records": [ - { - "type": "TXT", - "name": "_dmarc", - "target": "v=DMARC1\\; p=reject\\; sp=reject\\; pct=100\\; rua=mailto:xx...@yyyy.com\\; ruf=mailto:xx...@yyyy.com\\; fo=1", - "ttl": 300, - "txtstrings": [ - "v=DMARC1\\; p=reject\\; sp=reject\\; pct=100\\; rua=mailto:xx...@yyyy.com\\; ruf=mailto:xx...@yyyy.com\\; fo=1" - ] - } - ] - } - ] -} diff --git a/pkg/js/parse_tests/016-backslash/foo.com.zone b/pkg/js/parse_tests/016-backslash/foo.com.zone deleted file mode 100644 index 3271869c3e..0000000000 --- a/pkg/js/parse_tests/016-backslash/foo.com.zone +++ /dev/null @@ -1,2 +0,0 @@ -$TTL 300 -_dmarc IN TXT "v=DMARC1; p=reject; sp=reject; pct=100; rua=mailto:xx...@yyyy.com; ruf=mailto:xx...@yyyy.com; fo=1" diff --git a/pkg/js/parse_tests/017-txt.json b/pkg/js/parse_tests/017-txt.json index fd509360cb..1a14e45786 100644 --- a/pkg/js/parse_tests/017-txt.json +++ b/pkg/js/parse_tests/017-txt.json @@ -10,45 +10,27 @@ { "type": "TXT", "name": "a", - "target": "simple", - "txtstrings": [ - "simple" - ] + "target": "simple" }, { "type": "TXT", "name": "b", - "target": "ws at end ", - "txtstrings": [ - "ws at end " - ] + "target": "ws at end " }, { "type": "TXT", "name": "c", - "target": "one", - "txtstrings": [ - "one" - ] + "target": "one" }, { "type": "TXT", "name": "d", - "target": "bonieclyde", - "txtstrings": [ - "bonie", - "clyde" - ] + "target": "bonieclyde" }, { "type": "TXT", "name": "e", - "target": "strawwoodbrick", - "txtstrings": [ - "straw", - "wood", - "brick" - ] + "target": "strawwoodbrick" } ] } diff --git a/pkg/js/parse_tests/017-txt/foo.com.zone b/pkg/js/parse_tests/017-txt/foo.com.zone index 9fe37d9887..a31a9e3ce4 100644 --- a/pkg/js/parse_tests/017-txt/foo.com.zone +++ b/pkg/js/parse_tests/017-txt/foo.com.zone @@ -2,5 +2,5 @@ $TTL 300 a IN TXT "simple" b IN TXT "ws at end " c IN TXT "one" -d IN TXT "bonie" "clyde" -e IN TXT "straw" "wood" "brick" +d IN TXT "bonieclyde" +e IN TXT "strawwoodbrick" diff --git a/pkg/js/parse_tests/018-dkim.json b/pkg/js/parse_tests/018-dkim.json index c7bd2aff82..3f7dd6a126 100644 --- a/pkg/js/parse_tests/018-dkim.json +++ b/pkg/js/parse_tests/018-dkim.json @@ -10,10 +10,7 @@ { "type": "TXT", "name": "dkimtest2", - "target": "this string is 255 bytes long.hkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAnKZogtjOlHoeY8iZ5o5brlPOsj/a2Q9Bopu1kHxlxrdw7tZVL9FzUMngiIYGrl8dbP7Rvk7TLMoxHxVkRZPBtIpsKIab/gOUoPLQVYbrAmzyguHYBwAApi3H/pvjUsK8+XF0dKY17AR96lokAPqvfBaUb+DSx8zNw2hrYWYVqvCtnxHUGEUhT1bTlEZBptH3jthis is the remainder. it is 156 bytes long.mOhl2JmbsFKy+RoMTwbkk0/meRvcEFWLHkr4MSgbnie6OpQvM4Y51+kO6DUVr3rwjrdVO9wpFt+n/hdQ92TNif17RMJtE5AGaQ6BN3yJQIDAQAB;", - "txtstrings": [ - "this string is 255 bytes long.hkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAnKZogtjOlHoeY8iZ5o5brlPOsj/a2Q9Bopu1kHxlxrdw7tZVL9FzUMngiIYGrl8dbP7Rvk7TLMoxHxVkRZPBtIpsKIab/gOUoPLQVYbrAmzyguHYBwAApi3H/pvjUsK8+XF0dKY17AR96lokAPqvfBaUb+DSx8zNw2hrYWYVqvCtnxHUGEUhT1bTlEZBptH3jthis is the remainder. it is 156 bytes long.mOhl2JmbsFKy+RoMTwbkk0/meRvcEFWLHkr4MSgbnie6OpQvM4Y51+kO6DUVr3rwjrdVO9wpFt+n/hdQ92TNif17RMJtE5AGaQ6BN3yJQIDAQAB;" - ] + "target": "this string is 255 bytes long.hkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAnKZogtjOlHoeY8iZ5o5brlPOsj/a2Q9Bopu1kHxlxrdw7tZVL9FzUMngiIYGrl8dbP7Rvk7TLMoxHxVkRZPBtIpsKIab/gOUoPLQVYbrAmzyguHYBwAApi3H/pvjUsK8+XF0dKY17AR96lokAPqvfBaUb+DSx8zNw2hrYWYVqvCtnxHUGEUhT1bTlEZBptH3jthis is the remainder. it is 156 bytes long.mOhl2JmbsFKy+RoMTwbkk0/meRvcEFWLHkr4MSgbnie6OpQvM4Y51+kO6DUVr3rwjrdVO9wpFt+n/hdQ92TNif17RMJtE5AGaQ6BN3yJQIDAQAB;" } ] } diff --git a/pkg/js/parse_tests/018-dkim/foo.com.zone b/pkg/js/parse_tests/018-dkim/foo.com.zone index fb1f901012..f8df5c84f5 100644 --- a/pkg/js/parse_tests/018-dkim/foo.com.zone +++ b/pkg/js/parse_tests/018-dkim/foo.com.zone @@ -1,2 +1,2 @@ $TTL 300 -dkimtest2 IN TXT "this string is 255 bytes long.hkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAnKZogtjOlHoeY8iZ5o5brlPOsj/a2Q9Bopu1kHxlxrdw7tZVL9FzUMngiIYGrl8dbP7Rvk7TLMoxHxVkRZPBtIpsKIab/gOUoPLQVYbrAmzyguHYBwAApi3H/pvjUsK8+XF0dKY17AR96lokAPqvfBaUb+DSx8zNw2hrYWYVqvCtnxHUGEUhT1bTlEZBptH3jthis is the remainder. it is 156 bytes long.mOhl2JmbsFKy+RoMTwbkk0/meRvcEFWLHkr4MSgbnie6OpQvM4Y51+kO6DUVr3rwjrdVO9wpFt+n/hdQ92TNif17RMJtE5AGaQ6BN3yJQIDAQAB;" +dkimtest2 IN TXT "this string is 255 bytes long.hkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAnKZogtjOlHoeY8iZ5o5brlPOsj/a2Q9Bopu1kHxlxrdw7tZVL9FzUMngiIYGrl8dbP7Rvk7TLMoxHxVkRZPBtIpsKIab/gOUoPLQVYbrAmzyguHYBwAApi3H/pvjUsK8+XF0dKY17AR96lokAPqvfBaUb+DSx8zNw2hrYWYVqvCtnxHUGEUhT1bTlEZBptH3j" "this is the remainder. it is 156 bytes long.mOhl2JmbsFKy+RoMTwbkk0/meRvcEFWLHkr4MSgbnie6OpQvM4Y51+kO6DUVr3rwjrdVO9wpFt+n/hdQ92TNif17RMJtE5AGaQ6BN3yJQIDAQAB;" diff --git a/pkg/normalize/flatten.go b/pkg/normalize/flatten.go index eef90aacb5..48d848e215 100644 --- a/pkg/normalize/flatten.go +++ b/pkg/normalize/flatten.go @@ -32,7 +32,7 @@ func flattenSPFs(cfg *models.DNSConfig) []error { // flatten all spf records that have the "flatten" metadata for _, txt := range txtRecords { var rec *spflib.SPFRecord - txtTarget := strings.Join(txt.TxtStrings, "") + txtTarget := txt.GetTargetTXTJoined() if txt.Metadata["flatten"] != "" || txt.Metadata["split"] != "" { if cache == nil { cache, err = spflib.NewCache("spfcache.json") diff --git a/pkg/normalize/validate.go b/pkg/normalize/validate.go index 243b8efc3a..057fe6f659 100644 --- a/pkg/normalize/validate.go +++ b/pkg/normalize/validate.go @@ -569,7 +569,7 @@ func checkCNAMEs(dc *models.DomainConfig) (errs []error) { func checkDuplicates(records []*models.RecordConfig) (errs []error) { seen := map[string]*models.RecordConfig{} for _, r := range records { - diffable := fmt.Sprintf("%s %s %s", r.GetLabelFQDN(), r.Type, r.ToDiffable()) + diffable := fmt.Sprintf("%s %s %s", r.GetLabelFQDN(), r.Type, r.ToComparableNoTTL()) if seen[diffable] != nil { errs = append(errs, fmt.Errorf("exact duplicate record found: %s", diffable)) } diff --git a/pkg/normalize/validate_test.go b/pkg/normalize/validate_test.go index 5a6d3dc7f3..dd6a51a0e8 100644 --- a/pkg/normalize/validate_test.go +++ b/pkg/normalize/validate_test.go @@ -314,13 +314,11 @@ func TestCheckDuplicates(t *testing.T) { // The only difference is the rType: makeRC("aaa", "example.com", "uniquestring.com.", models.RecordConfig{Type: "NS"}), makeRC("aaa", "example.com", "uniquestring.com.", models.RecordConfig{Type: "PTR"}), - // The only difference is the TTL. - makeRC("zzz", "example.com", "4.4.4.4", models.RecordConfig{Type: "A", TTL: 111}), - makeRC("zzz", "example.com", "4.4.4.4", models.RecordConfig{Type: "A", TTL: 222}), // Three records each with a different target. makeRC("@", "example.com", "ns1.foo.com.", models.RecordConfig{Type: "NS"}), makeRC("@", "example.com", "ns2.foo.com.", models.RecordConfig{Type: "NS"}), makeRC("@", "example.com", "ns3.foo.com.", models.RecordConfig{Type: "NS"}), + // NOTE: The comparison ignores ttl. Therefore we don't test that. } errs := checkDuplicates(records) if len(errs) != 0 { diff --git a/pkg/prettyzone/prettyzone.go b/pkg/prettyzone/prettyzone.go index ae8a485b4c..481fb8ae79 100644 --- a/pkg/prettyzone/prettyzone.go +++ b/pkg/prettyzone/prettyzone.go @@ -10,6 +10,7 @@ import ( "strings" "github.com/StackExchange/dnscontrol/v4/models" + "github.com/StackExchange/dnscontrol/v4/pkg/txtutil" "github.com/miekg/dns" ) @@ -138,7 +139,7 @@ func (z *ZoneGenData) generateZoneFileHelper(w io.Writer) error { typeStr := rr.Type // the remaining line - target := rr.GetTargetCombined() + target := rr.GetTargetCombinedFunc(txtutil.EncodeQuoted) // comment comment := "" diff --git a/pkg/prettyzone/prettyzone_test.go b/pkg/prettyzone/prettyzone_test.go index 38070d9e34..ee24e551d0 100644 --- a/pkg/prettyzone/prettyzone_test.go +++ b/pkg/prettyzone/prettyzone_test.go @@ -5,6 +5,7 @@ import ( "fmt" "log" "math/rand" + "strings" "testing" "github.com/StackExchange/dnscontrol/v4/models" @@ -247,6 +248,46 @@ var testdataZFCAA = `$TTL 300 IN CAA 0 issuewild ";" ` +// r is shorthand for strings.Repeat() +func r(s string, c int) string { return strings.Repeat(s, c) } + +func TestWriteZoneFileTxt(t *testing.T) { + // Do round-trip tests on various length TXT records. + t10 := `t10 IN TXT "ten4567890"` + t254 := `t254 IN TXT "` + r("a", 254) + `"` + t255 := `t255 IN TXT "` + r("b", 255) + `"` + t256 := `t256 IN TXT "` + r("c", 255) + `" "` + r("D", 1) + `"` + t509 := `t509 IN TXT "` + r("e", 255) + `" "` + r("F", 254) + `"` + t510 := `t510 IN TXT "` + r("g", 255) + `" "` + r("H", 255) + `"` + t511 := `t511 IN TXT "` + r("i", 255) + `" "` + r("J", 255) + `" "` + r("k", 1) + `"` + t512 := `t511 IN TXT "` + r("L", 255) + `" "` + r("M", 255) + `" "` + r("n", 2) + `"` + t513 := `t511 IN TXT "` + r("o", 255) + `" "` + r("P", 255) + `" "` + r("q", 3) + `"` + for i, d := range []string{t10, t254, t255, t256, t509, t510, t511, t512, t513} { + // Make the rr: + rr, err := dns.NewRR(d) + if err != nil { + t.Fatal(err) + } + + // Make the expected zonefile: + ez := "$TTL 3600\n" + d + "\n" + + // Generate the zonefile: + buf := &bytes.Buffer{} + WriteZoneFileRR(buf, []dns.RR{rr}, "bosun.org") + gz := buf.String() + if gz != ez { + t.Log("got: " + gz) + t.Log("wnt: " + ez) + t.Fatalf("Zone file %d does not match.", i) + } + + // Reverse the process. Turn the zonefile into a list of records + parseAndRegen(t, buf, ez) + } + +} + // Test 1 of each record type func mustNewRR(s string) dns.RR { diff --git a/pkg/rejectif/txt.go b/pkg/rejectif/txt.go index b1d63c0ba2..f9b8427e94 100644 --- a/pkg/rejectif/txt.go +++ b/pkg/rejectif/txt.go @@ -11,104 +11,65 @@ import ( // TxtHasBackslash audits TXT records for strings that contains one or more backslashes. func TxtHasBackslash(rc *models.RecordConfig) error { - for _, txt := range rc.TxtStrings { - if strings.Contains(txt, `\`) { - return fmt.Errorf("txtstring contains backslash") - } + if strings.Contains(rc.GetTargetTXTJoined(), `\`) { + return fmt.Errorf("txtstring contains backslashes") } return nil } // TxtHasBackticks audits TXT records for strings that contain backticks. func TxtHasBackticks(rc *models.RecordConfig) error { - for _, txt := range rc.TxtStrings { - if strings.Contains(txt, "`") { - return fmt.Errorf("txtstring contains backtick") - } - } - return nil -} - -// TxtHasSingleQuotes audits TXT records for strings that contain single-quotes. -func TxtHasSingleQuotes(rc *models.RecordConfig) error { - for _, txt := range rc.TxtStrings { - if strings.Contains(txt, "'") { - return fmt.Errorf("txtstring contains single-quotes") - } + if strings.Contains(rc.GetTargetTXTJoined(), "`") { + return fmt.Errorf("txtstring contains backtick") } return nil } // TxtHasDoubleQuotes audits TXT records for strings that contain doublequotes. func TxtHasDoubleQuotes(rc *models.RecordConfig) error { - for _, txt := range rc.TxtStrings { - if strings.Contains(txt, `"`) { - return fmt.Errorf("txtstring contains doublequotes") - } + if strings.Contains(rc.GetTargetTXTJoined(), `"`) { + return fmt.Errorf("txtstring contains doublequotes") } return nil } -// TxtIsExactlyLen255 audits TXT records for strings exactly 255 octets long. -// This is rare; you probably want to use TxtNoStringsLen256orLonger() instead. -func TxtIsExactlyLen255(rc *models.RecordConfig) error { - for _, txt := range rc.TxtStrings { - if len(txt) == 255 { - return fmt.Errorf("txtstring length is 255") - } - } - return nil -} - -// TxtHasSegmentLen256orLonger audits TXT records for strings that are >255 octets. -func TxtHasSegmentLen256orLonger(rc *models.RecordConfig) error { - for _, txt := range rc.TxtStrings { - if len(txt) > 255 { - return fmt.Errorf("%q txtstring length > 255", rc.GetLabel()) - } +// 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 nil } -// TxtHasMultipleSegments audits TXT records for multiple strings -func TxtHasMultipleSegments(rc *models.RecordConfig) error { - if len(rc.TxtStrings) > 1 { - return fmt.Errorf("multiple strings in one txt") +// TxtHasTrailingSpace audits TXT records for strings that end with space. +func TxtHasTrailingSpace(rc *models.RecordConfig) error { + txt := rc.GetTargetTXTJoined() + if txt != "" && txt[ultimate(txt)] == ' ' { + return fmt.Errorf("txtstring ends with space") } return nil } -// TxtHasTrailingSpace audits TXT records for strings that end with space. -func TxtHasTrailingSpace(rc *models.RecordConfig) error { - for _, txt := range rc.TxtStrings { - if txt != "" && txt[ultimate(txt)] == ' ' { - return fmt.Errorf("txtstring ends with space") - } +// 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 nil } // TxtIsEmpty audits TXT records for empty strings. func TxtIsEmpty(rc *models.RecordConfig) error { - // There must be strings. - if len(rc.TxtStrings) == 0 { - return fmt.Errorf("txt with no strings") - } - // Each string must be non-empty. - for _, txt := range rc.TxtStrings { - if len(txt) == 0 { - return fmt.Errorf("txtstring is empty") - } + if len(rc.GetTargetTXTJoined()) == 0 { + return fmt.Errorf("txtstring is empty") } return nil } -// TxtHasUnpairedDoubleQuotes audits TXT records for strings that contain unpaired doublequotes. -func TxtHasUnpairedDoubleQuotes(rc *models.RecordConfig) error { - for _, txt := range rc.TxtStrings { - if strings.Count(txt, `"`)%2 == 1 { - return fmt.Errorf("txtstring contains unpaired doublequotes") - } +// TxtLongerThan255 audits TXT records for multiple strings +func TxtLongerThan255(rc *models.RecordConfig) error { + if len(rc.GetTargetTXTJoined()) > 255 { + return fmt.Errorf("TXT records longer than 255 octets (chars)") } return nil } diff --git a/pkg/txtutil/txtcode.go b/pkg/txtutil/txtcode.go new file mode 100644 index 0000000000..6a50bdb605 --- /dev/null +++ b/pkg/txtutil/txtcode.go @@ -0,0 +1,155 @@ +//go:generate stringer -type=State + +package txtutil + +import ( + "bytes" + "fmt" + "strings" +) + +// ParseQuoted parses a string of RFC1035-style quoted items. The resulting +// items are then joined into one string. This is useful for parsing TXT +// records. +// Examples: +// `foo` => foo +// `"foo"` => foo +// `"f\"oo"` => f"oo +// `"f\\oo"` => f\oo +// `"foo" "bar"` => foobar +// `"foo" bar` => foobar +func ParseQuoted(s string) (string, error) { + return txtDecode(s) +} + +// EncodeQuoted encodes a string into a series of quoted 255-octet chunks. That +// is, when decoded each chunk would be 255-octets with the remainder in the +// last chunk. +// +// The output looks like: +// +// `""` empty +// `"255\"octets"` quotes are escaped +// `"255\\octets"` backslashes are escaped +// `"255octets" "255octets" "remainder"` long strings are chunked +func EncodeQuoted(t string) string { + return txtEncode(ToChunks(t)) +} + +type State int + +const ( + StateStart State = iota // Looking for a non-space + StateUnquoted // A run of unquoted text + StateQuoted // Quoted text + StateBackslash // last char was backlash in a quoted string + StateWantSpace // expect space after closing quote +) + +func isRemaining(s string, i, r int) bool { + return (len(s) - 1 - i) > r +} + +// txtDecode decodes TXT strings quoted/escaped as Tom interprets RFC10225. +func txtDecode(s string) (string, error) { + // Parse according to RFC1035 zonefile specifications. + // "foo" -> one string: `foo`` + // "foo" "bar" -> two strings: `foo` and `bar` + // quotes and backslashes are escaped using \ + + /* + + BNF: + txttarget := `""`` | item | item ` ` item* + item := quoteditem | unquoteditem + quoteditem := quote innertxt quote + quote := `"` + innertxt := (escaped | printable )* + escaped := `\\` | `\"` + printable := (printable ASCII chars) + unquoteditem := (printable ASCII chars but not `"` nor ' ') + + */ + + //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)) + + switch state { + + case StateStart: + if c == ' ' { + // skip whitespace + } else if c == '"' { + state = StateQuoted + } else { + state = StateUnquoted + b.WriteRune(c) + } + + case StateUnquoted: + + if c == ' ' { + state = StateStart + } else { + b.WriteRune(c) + } + + case StateQuoted: + + if c == '\\' { + if isRemaining(s, i, 1) { + state = StateBackslash + } else { + return "", fmt.Errorf("txtDecode quoted string ends with backslash q(%q)", s) + } + } else if c == '"' { + state = StateWantSpace + } else { + b.WriteRune(c) + } + + case StateBackslash: + b.WriteRune(c) + state = StateQuoted + + case StateWantSpace: + if c == ' ' { + state = StateStart + } 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) + 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) + if (len(ts) == 0) || (strings.Join(ts, "") == "") { + return `""` + } + + var r []string + + for i := range ts { + tx := ts[i] + tx = strings.ReplaceAll(tx, `\`, `\\`) + tx = strings.ReplaceAll(tx, `"`, `\"`) + tx = `"` + tx + `"` + r = append(r, tx) + } + t := strings.Join(r, ` `) + + //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 new file mode 100644 index 0000000000..d8375ba40d --- /dev/null +++ b/pkg/txtutil/txtcode_test.go @@ -0,0 +1,97 @@ +package txtutil + +import ( + "strings" + "testing" +) + +func r(s string, c int) string { return strings.Repeat(s, c) } + +func TestTxtDecode(t *testing.T) { + tests := []struct { + data string + expected []string + }{ + {``, []string{``}}, + {`""`, []string{``}}, + {`foo`, []string{`foo`}}, + {`"foo"`, []string{`foo`}}, + {`"foo bar"`, []string{`foo bar`}}, + {`foo bar`, []string{`foo`, `bar`}}, + {`"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"}}, + {"\"quo'te\"", []string{`quo'te`}}, + {"\"blah`blah\"", []string{"blah`blah"}}, + {"\"quo\\\"te\"", []string{`quo"te`}}, + {"\"q\\\"uo\\\"te\"", []string{`q"uo"te`}}, + /// Backslashes are meaningless in unquoted strings. Unquoted strings run until they hit a space. + {`1backs\lash`, []string{`1backs\lash`}}, + {`2backs\\lash`, []string{`2backs\\lash`}}, + {`3backs\\\lash`, []string{`3backs\\\lash`}}, + {`4backs\\\\lash`, []string{`4backs\\\\lash`}}, + /// Inside quotes, a backlash means take the next byte literally. + {`"q1backs\lash"`, []string{`q1backslash`}}, + {`"q2backs\\lash"`, []string{`q2backs\lash`}}, + {`"q3backs\\\lash"`, []string{`q3backs\lash`}}, + {`"q4backs\\\\lash"`, []string{`q4backs\\lash`}}, + // HETZNER includes a space after the last quote. Make sure we handle that. + {`"one" "more" `, []string{`one`, `more`}}, + } + for i, test := range tests { + got, err := txtDecode(test.data) + if err != nil { + t.Error(err) + } + + want := strings.Join(test.expected, "") + if got != want { + t.Errorf("%v: expected TxtStrings=(%q) got (%q)", i, want, got) + } + } +} + +func TestTxtEncode(t *testing.T) { + tests := []struct { + data []string + expected string + }{ + {[]string{}, `""`}, + {[]string{``}, `""`}, + {[]string{`foo`}, `"foo"`}, + {[]string{`aaa`, `bbb`}, `"aaa" "bbb"`}, + {[]string{`ccc`, `ddd`, `eee`}, `"ccc" "ddd" "eee"`}, + {[]string{`a"a`, `bbb`}, `"a\"a" "bbb"`}, + {[]string{`quo'te`}, "\"quo'te\""}, + {[]string{"blah`blah"}, "\"blah`blah\""}, + {[]string{`quo"te`}, "\"quo\\\"te\""}, + {[]string{`quo"te`}, `"quo\"te"`}, + {[]string{`q"uo"te`}, "\"q\\\"uo\\\"te\""}, + {[]string{`1backs\lash`}, `"1backs\\lash"`}, + {[]string{`2backs\\lash`}, `"2backs\\\\lash"`}, + {[]string{`3backs\\\lash`}, `"3backs\\\\\\lash"`}, + {[]string{strings.Repeat("M", 26), `quo"te`}, `"MMMMMMMMMMMMMMMMMMMMMMMMMM" "quo\"te"`}, + } + for i, test := range tests { + got := txtEncode(test.data) + + want := test.expected + if got != want { + t.Errorf("%v: expected TxtStrings=v(%v) got (%v)", i, want, got) + } + } +} diff --git a/pkg/txtutil/txtcombined.go b/pkg/txtutil/txtcombined.go new file mode 100644 index 0000000000..8fa415a169 --- /dev/null +++ b/pkg/txtutil/txtcombined.go @@ -0,0 +1,53 @@ +//go:generate stringer -type=State + +package txtutil + +// func ParseCombined(s string) (string, error) { +// return txtDecodeCombined(s) +// } + +// // // txtDecode decodes TXT strings received from ROUTE53 and GCLOUD. +// func txtDecodeCombined(s string) (string, error) { + +// // The dns package doesn't expose the quote parser. Therefore we create a TXT record and extract the strings. +// rr, err := dns.NewRR("example.com. IN TXT " + s) +// if err != nil { +// return "", fmt.Errorf("could not parse %q TXT: %w", s, err) +// } + +// return strings.Join(rr.(*dns.TXT).Txt, ""), nil +// } + +// func EncodeCombined(t string) string { +// return txtEncodeCombined(ToChunks(t)) +// } + +// // txtEncode encodes TXT strings as the old GetTargetCombined() function did. +// func txtEncodeCombined(ts []string) string { +// //printer.Printf("DEBUG: route53 txt outboundv=%v\n", ts) + +// // Don't call this on fake types. +// rdtype := dns.StringToType["TXT"] + +// // Magically create an RR of the correct type. +// rr := dns.TypeToRR[rdtype]() + +// // Fill in the header. +// rr.Header().Name = "example.com." +// rr.Header().Rrtype = rdtype +// rr.Header().Class = dns.ClassINET +// rr.Header().Ttl = 300 + +// // Fill in the TXT data. +// rr.(*dns.TXT).Txt = ts + +// // Generate the quoted string: +// header := rr.Header().String() +// full := rr.String() +// if !strings.HasPrefix(full, header) { +// panic("assertion failed. dns.Hdr.String() behavior has changed in an incompatible way") +// } + +// //printer.Printf("DEBUG: route53 txt encodedv=%v\n", t) +// return full[len(header):] +// } diff --git a/pkg/txtutil/txtutil.go b/pkg/txtutil/txtutil.go index a37948c741..55045b8c29 100644 --- a/pkg/txtutil/txtutil.go +++ b/pkg/txtutil/txtutil.go @@ -1,20 +1,13 @@ package txtutil -import "github.com/StackExchange/dnscontrol/v4/models" +// SplitSingleLongTxt does nothing. +// Deprecated: This is a no-op for backwards compatibility. +func SplitSingleLongTxt(records any) { +} -// SplitSingleLongTxt finds TXT records with a single long string and splits it -// into 255-octet chunks. This is used by providers that, when a user specifies -// one long TXT string, split it into smaller strings behind the scenes. -// This should be called from GetZoneRecordsCorrections(). -func SplitSingleLongTxt(records []*models.RecordConfig) { - for _, rc := range records { - if rc.HasFormatIdenticalToTXT() { - s := rc.TxtStrings[0] - if len(rc.TxtStrings) == 1 && len(s) > 255 { - rc.SetTargetTXTs(splitChunks(s, 255)) - } - } - } +// ToChunks returns the string as chunks of 255-octet strings (the last string being the remainder). +func ToChunks(s string) []string { + return splitChunks(s, 255) } // Segment returns the string as 255-octet segments, the last being the remainder. diff --git a/providers/azuredns/auditrecords.go b/providers/azuredns/auditrecords.go index 13d73026d4..6c46e4357b 100644 --- a/providers/azuredns/auditrecords.go +++ b/providers/azuredns/auditrecords.go @@ -13,5 +13,7 @@ func AuditRecords(records []*models.RecordConfig) []error { a.Add("MX", rejectif.MxNull) // Last verified 2020-12-28 + a.Add("TXT", rejectif.TxtIsEmpty) // Last verified 2023-11-11 + return a.Audit(records) } diff --git a/providers/bind/bindProvider.go b/providers/bind/bindProvider.go index 91fbff0629..16a502553a 100644 --- a/providers/bind/bindProvider.go +++ b/providers/bind/bindProvider.go @@ -195,7 +195,7 @@ func ParseZoneContents(content string, zoneName string, zonefileName string) (mo foundRecords := models.Records{} for rr, ok := zp.Next(); ok; rr, ok = zp.Next() { - rec, err := models.RRtoRC(rr, zoneName) + rec, err := models.RRtoRCTxtBug(rr, zoneName) if err != nil { return nil, err } diff --git a/providers/cloudflare/auditrecords.go b/providers/cloudflare/auditrecords.go index 71a66a06ed..66cf53d9d0 100644 --- a/providers/cloudflare/auditrecords.go +++ b/providers/cloudflare/auditrecords.go @@ -11,8 +11,6 @@ import ( func AuditRecords(records []*models.RecordConfig) []error { a := rejectif.Auditor{} - a.Add("TXT", rejectif.TxtHasMultipleSegments) // Last verified 2022-06-18 - a.Add("TXT", rejectif.TxtHasTrailingSpace) // Last verified 2022-06-18 a.Add("TXT", rejectif.TxtIsEmpty) // Last verified 2022-06-18 diff --git a/providers/cloudns/auditrecords.go b/providers/cloudns/auditrecords.go index 20d7b1d1d9..3c285db8e1 100644 --- a/providers/cloudns/auditrecords.go +++ b/providers/cloudns/auditrecords.go @@ -19,8 +19,6 @@ func AuditRecords(records []*models.RecordConfig) []error { a.Add("TXT", rejectif.TxtHasDoubleQuotes) // Last verified 2021-03-01 - a.Add("TXT", rejectif.TxtHasMultipleSegments) // Last verified 2021-03-01 - a.Add("SRV", rejectif.SrvHasNullTarget) // Last verified 2023-03-30 return a.Audit(records) diff --git a/providers/cscglobal/api.go b/providers/cscglobal/api.go index dd8224013b..6ae57f5c61 100644 --- a/providers/cscglobal/api.go +++ b/providers/cscglobal/api.go @@ -478,7 +478,7 @@ 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?filter=zoneName==" + domain) + var bodyString, err = client.get(`/zones/edits?size=99999&filter=zoneName==` + domain) if err != nil { return err } @@ -486,10 +486,12 @@ func (client *providerClient) clearRequests(domain string) error { var dr pagedZoneEditResponsePagedZoneEditResponse json.Unmarshal(bodyString, &dr) - // TODO(tlim): Properly handle paganation. - if dr.Meta.Pages > 1 { - return fmt.Errorf("cancelPendingEdits failed: Pages=%d", dr.Meta.Pages) - } + // 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 { + // return fmt.Errorf("cancelPendingEdits failed: Pages=%d", dr.Meta.Pages) + //} for i, ze := range dr.ZoneEdits { if cscDebug { diff --git a/providers/cscglobal/auditrecords.go b/providers/cscglobal/auditrecords.go index 1ee9faf8c6..87ad6f3380 100644 --- a/providers/cscglobal/auditrecords.go +++ b/providers/cscglobal/auditrecords.go @@ -17,11 +17,11 @@ func AuditRecords(records []*models.RecordConfig) []error { a.Add("TXT", rejectif.TxtHasDoubleQuotes) // Last verified 2022-08-08 - a.Add("TXT", rejectif.TxtHasMultipleSegments) // Last verified 2022-06-10 - a.Add("TXT", rejectif.TxtHasTrailingSpace) // Last verified 2022-06-10 - a.Add("TXT", rejectif.TxtIsEmpty) // Last verified 2022-06-10 + a.Add("TXT", rejectif.TxtIsEmpty) // Last verified 2023-12-03 + + //a.Add("TXT", rejectif.TxtLongerThan255) // Last verified 2022-06-10 return a.Audit(records) } diff --git a/providers/cscglobal/convert.go b/providers/cscglobal/convert.go index 4ffab7c17e..6050cd8ec2 100644 --- a/providers/cscglobal/convert.go +++ b/providers/cscglobal/convert.go @@ -6,6 +6,7 @@ import ( "net" "github.com/StackExchange/dnscontrol/v4/models" + "github.com/StackExchange/dnscontrol/v4/pkg/printer" ) // nativeToRecordA takes an A record from DNS and returns a native RecordConfig struct. @@ -64,6 +65,7 @@ func nativeToRecordTXT(nr nativeRecordTXT, origin string, defaultTTL uint32) *mo TTL: ttl, } rc.SetLabel(nr.Key, origin) + printer.Printf("DEBUG: inbound raw s=%s\n", nr.Value) rc.SetTargetTXT(nr.Value) return rc } diff --git a/providers/cscglobal/dns.go b/providers/cscglobal/dns.go index e78432a3bb..a9724f66d6 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, error) { - //txtutil.SplitSingleLongTxt(dc.Records) // Autosplit long TXT records toReport, creates, dels, modifications, err := diff.NewCompat(dc).IncrementalDiff(foundRecords) if err != nil { diff --git a/providers/digitalocean/auditrecords.go b/providers/digitalocean/auditrecords.go index 95382cc924..a6e9eff829 100644 --- a/providers/digitalocean/auditrecords.go +++ b/providers/digitalocean/auditrecords.go @@ -19,10 +19,14 @@ func AuditRecords(records []*models.RecordConfig) []error { a.Add("TXT", MaxLengthDO) // Last verified 2021-03-01 + a.Add("TXT", rejectif.TxtHasBackslash) // Last verified 2023-11-11 + a.Add("TXT", rejectif.TxtHasDoubleQuotes) // Last verified 2021-03-01 // Double-quotes not permitted in TXT strings. I have a hunch that // this is due to a broken parser on the DO side. + a.Add("TXT", rejectif.TxtIsEmpty) // Last verified 2023-11-11 + return a.Audit(records) } diff --git a/providers/dnsimple/auditrecords.go b/providers/dnsimple/auditrecords.go index 0354a63eb1..3e8df5b634 100644 --- a/providers/dnsimple/auditrecords.go +++ b/providers/dnsimple/auditrecords.go @@ -13,7 +13,7 @@ func AuditRecords(records []*models.RecordConfig) []error { a.Add("MX", rejectif.MxNull) // Last verified 2023-03 - a.Add("TXT", rejectif.TxtHasMultipleSegments) // Last verified 2023-03 + a.Add("TXT", rejectif.TxtLongerThan255) // Last verified 2023-03 a.Add("TXT", rejectif.TxtHasTrailingSpace) // Last verified 2023-03 diff --git a/providers/gandiv5/convert.go b/providers/gandiv5/convert.go index 229ac0c3f1..46e3259325 100644 --- a/providers/gandiv5/convert.go +++ b/providers/gandiv5/convert.go @@ -7,6 +7,7 @@ import ( "github.com/StackExchange/dnscontrol/v4/models" "github.com/StackExchange/dnscontrol/v4/pkg/printer" + "github.com/StackExchange/dnscontrol/v4/pkg/txtutil" "github.com/go-gandi/go-gandi/livedns" ) @@ -29,10 +30,8 @@ func nativeToRecords(n livedns.DomainRecord, origin string) (rcs []*models.Recor case "ALIAS": rc.Type = "ALIAS" err = rc.SetTarget(value) - case "TXT": - err = rc.SetTargetTXTfromRFC1035Quoted(value) default: - err = rc.PopulateFromString(rtype, value, origin) + err = rc.PopulateFromStringFunc(rtype, value, origin, txtutil.ParseQuoted) } if err != nil { return nil, fmt.Errorf("unparsable record received from gandi: %w", err) @@ -65,11 +64,11 @@ func recordsToNative(rcs []*models.RecordConfig, origin string) []livedns.Domain RrsetType: r.Type, RrsetTTL: int(r.TTL), RrsetName: label, - RrsetValues: []string{r.GetTargetCombined()}, + RrsetValues: []string{r.GetTargetCombinedFunc(txtutil.EncodeQuoted)}, } keys[key] = &zr } else { - zr.RrsetValues = append(zr.RrsetValues, r.GetTargetCombined()) + zr.RrsetValues = append(zr.RrsetValues, r.GetTargetCombinedFunc(txtutil.EncodeQuoted)) if r.TTL != uint32(zr.RrsetTTL) { printer.Warnf("All TTLs for a rrset (%v) must be the same. Using smaller of %v and %v.\n", key, r.TTL, zr.RrsetTTL) diff --git a/providers/gandiv5/gandi_v5Provider.go b/providers/gandiv5/gandi_v5Provider.go index d6fb5409fa..0aedb7aed3 100644 --- a/providers/gandiv5/gandi_v5Provider.go +++ b/providers/gandiv5/gandi_v5Provider.go @@ -176,9 +176,6 @@ func PrepDesiredRecords(dc *models.DomainConfig) { printer.Warnf("Gandi does not support ttls > 30 days. Setting %s from %d to 2592000\n", rec.GetLabelFQDN(), rec.TTL) rec.TTL = 2592000 } - if rec.Type == "TXT" { - rec.SetTarget("\"" + rec.GetTargetField() + "\"") // FIXME(tlim): Should do proper quoting. - } if rec.Type == "NS" && rec.GetLabel() == "@" { if !strings.HasSuffix(rec.GetTargetField(), ".gandi.net.") { printer.Warnf("Gandi does not support changing apex NS records. Ignoring %s\n", rec.GetTargetField()) @@ -293,7 +290,7 @@ func (client *gandiv5Provider) GetZoneRecordsCorrections(dc *models.DomainConfig func debugRecords(note string, recs []*models.RecordConfig) { printer.Debugf(note) for k, v := range recs { - printer.Printf(" %v: %v %v %v %v\n", k, v.GetLabel(), v.Type, v.TTL, v.GetTargetCombined()) + printer.Printf(" %v: %v %v %v %v\n", k, v.GetLabel(), v.Type, v.TTL, v.GetTargetDebug()) } } diff --git a/providers/gcloud/gcloudProvider.go b/providers/gcloud/gcloudProvider.go index d0c9e47dfa..6652c2691c 100644 --- a/providers/gcloud/gcloudProvider.go +++ b/providers/gcloud/gcloudProvider.go @@ -306,7 +306,7 @@ func (g *gcloudProvider) GetZoneRecordsCorrections(dc *models.DomainConfig, exis } for _, r := range dc.Records { if keyForRec(r) == ck { - newRRs.Rrdatas = append(newRRs.Rrdatas, r.GetTargetCombined()) + newRRs.Rrdatas = append(newRRs.Rrdatas, r.GetTargetCombinedFunc(txtutil.EncodeQuoted)) newRRs.Ttl = int64(r.TTL) } } @@ -403,13 +403,7 @@ func nativeToRecord(set *gdns.ResourceRecordSet, rec, origin string) (*models.Re r.SetLabelFromFQDN(set.Name, origin) r.TTL = uint32(set.Ttl) rtype := set.Type - var err error - switch rtype { - case "TXT": - err = r.SetTargetTXTs(models.ParseQuotedTxt(rec)) - default: - err = r.PopulateFromString(rtype, rec, origin) - } + err := r.PopulateFromStringFunc(rtype, rec, origin, txtutil.ParseQuoted) if err != nil { return nil, fmt.Errorf("unparsable record %q received from GCLOUD: %w", rtype, err) } diff --git a/providers/hedns/hednsProvider.go b/providers/hedns/hednsProvider.go index 0ee6d14855..d7d70fd97c 100644 --- a/providers/hedns/hednsProvider.go +++ b/providers/hedns/hednsProvider.go @@ -325,10 +325,8 @@ func (c *hednsProvider) GetZoneRecords(domain string, meta map[string]string) (m // Convert to TXT record as SPF is deprecated rc.Type = "TXT" fallthrough - case "TXT": - err = rc.SetTargetTXTs(models.ParseQuotedTxt(data)) default: - err = rc.PopulateFromString(rc.Type, data, domain) + err = rc.PopulateFromStringFunc(rc.Type, data, domain, txtutil.ParseQuoted) } if err != nil { @@ -563,7 +561,7 @@ func (c *hednsProvider) editZoneRecord(zoneID uint64, recordID uint64, rc *model values.Set("Weight", strconv.FormatUint(uint64(rc.SrvWeight), 10)) values.Set("Port", strconv.FormatUint(uint64(rc.SrvPort), 10)) default: - values.Set("Content", rc.GetTargetCombined()) + values.Set("Content", rc.GetTargetCombinedFunc(txtutil.EncodeQuoted)) } response, err := c.httpClient.PostForm(apiEndpoint, values) diff --git a/providers/hetzner/types.go b/providers/hetzner/types.go index 20dacdfb1e..61125a5d99 100644 --- a/providers/hetzner/types.go +++ b/providers/hetzner/types.go @@ -1,9 +1,8 @@ package hetzner import ( - "strings" - "github.com/StackExchange/dnscontrol/v4/models" + "github.com/StackExchange/dnscontrol/v4/pkg/txtutil" ) type bulkCreateRecordsRequest struct { @@ -58,7 +57,7 @@ func fromRecordConfig(in *models.RecordConfig, zone *zone) record { r := record{ Name: in.GetLabel(), Type: in.Type, - Value: in.GetTargetCombined(), + Value: in.GetTargetCombinedFunc(txtutil.EncodeQuoted), TTL: &in.TTL, ZoneID: zone.ID, } @@ -88,13 +87,9 @@ func toRecordConfig(domain string, r *record) (*models.RecordConfig, error) { } rc.SetLabel(r.Name, domain) - value := r.Value // HACK: Hetzner is inserting a trailing space after multiple, quoted values. // NOTE: The actual DNS answer does not contain the space. + // NOTE: The txtutil.ParseQuoted parser handles this just fine. // Last checked: 2023-04-01 - if r.Type == "TXT" && len(value) > 0 && value[len(value)-1] == ' ' { - // Per RFC 1035 spaces outside quoted values are irrelevant. - value = strings.TrimRight(value, " ") - } - return &rc, rc.PopulateFromString(r.Type, value, domain) + return &rc, rc.PopulateFromStringFunc(r.Type, r.Value, domain, txtutil.ParseQuoted) } diff --git a/providers/hexonet/auditrecords.go b/providers/hexonet/auditrecords.go index 371bd49373..8a7f7021b8 100644 --- a/providers/hexonet/auditrecords.go +++ b/providers/hexonet/auditrecords.go @@ -13,6 +13,8 @@ func AuditRecords(records []*models.RecordConfig) []error { a.Add("TXT", rejectif.TxtIsEmpty) // Last verified 2021-10-01 + a.Add("TXT", rejectif.TxtHasDoubleQuotes) // Last verified 2023-11-30 + a.Add("SRV", rejectif.SrvHasNullTarget) // Last verified 2020-12-28 return a.Audit(records) diff --git a/providers/hexonet/records.go b/providers/hexonet/records.go index ac313f714f..2ef35aaf70 100644 --- a/providers/hexonet/records.go +++ b/providers/hexonet/records.go @@ -3,7 +3,6 @@ package hexonet import ( "bytes" "fmt" - "regexp" "strconv" "strings" @@ -129,10 +128,6 @@ func toRecord(r *HXRecord, origin string) *models.RecordConfig { rc.SetLabelFromFQDN(fqdn, origin) switch rtype := r.Type; rtype { - case "TXT": - if err := rc.SetTargetTXTs(decodeTxt(r.Answer)); err != nil { - panic(fmt.Errorf("unparsable TXT record received from hexonet api: %w", err)) - } case "MX": if err := rc.SetTargetMX(uint16(r.Priority), r.Answer); err != nil { panic(fmt.Errorf("unparsable MX record received from hexonet api: %w", err)) @@ -142,7 +137,7 @@ func toRecord(r *HXRecord, origin string) *models.RecordConfig { panic(fmt.Errorf("unparsable SRV record received from hexonet api: %w", err)) } default: // "A", "AAAA", "ANAME", "CNAME", "NS" - if err := rc.PopulateFromString(rtype, r.Answer, r.Fqdn); err != nil { + if err := rc.PopulateFromStringFunc(rtype, r.Answer, r.Fqdn, txtutil.ParseQuoted); err != nil { panic(fmt.Errorf("unparsable record received from hexonet api: %w", err)) } } @@ -242,7 +237,7 @@ func (n *HXClient) createRecordString(rc *models.RecordConfig, domain string) (s case "CAA": record.Answer = fmt.Sprintf(`%v %s "%s"`, rc.CaaFlag, rc.CaaTag, record.Answer) case "TXT": - record.Answer = encodeTxt(rc.GetTargetTXTSegmented()) + 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')") @@ -266,31 +261,3 @@ func (n *HXClient) createRecordString(rc *models.RecordConfig, domain string) (s func (n *HXClient) deleteRecordString(record *HXRecord, domain string) string { return record.Raw } - -// encodeTxt encodes []string for sending in the CREATE/MODIFY API: -func encodeTxt(txts []string) string { - var r []string - for _, txt := range txts { - n := `"` + strings.Replace(txt, `"`, `\"`, -1) + `"` - r = append(r, n) - } - return strings.Join(r, " ") -} - -// finds a string surrounded by quotes that might contain an escaped quote character. -var quotedStringRegexp = regexp.MustCompile(`"((?:[^"\\]|\\.)*)"`) - -// decodeTxt decodes the TXT record as received from hexonet api and -// returns the list of strings. -func decodeTxt(s string) []string { - - if len(s) >= 2 && s[0] == '"' && s[len(s)-1] == '"' { - txtStrings := []string{} - for _, t := range quotedStringRegexp.FindAllStringSubmatch(s, -1) { - txtString := strings.Replace(t[1], `\"`, `"`, -1) - txtStrings = append(txtStrings, txtString) - } - return txtStrings - } - return []string{s} -} diff --git a/providers/hexonet/records_test.go b/providers/hexonet/records_test.go deleted file mode 100644 index 8b242931a3..0000000000 --- a/providers/hexonet/records_test.go +++ /dev/null @@ -1,51 +0,0 @@ -package hexonet - -import ( - "strings" - "testing" -) - -var txtData = []struct { - decoded []string - encoded string -}{ - {[]string{`simple`}, `"simple"`}, - {[]string{`changed`}, `"changed"`}, - {[]string{`with spaces`}, `"with spaces"`}, - {[]string{`with whitespace`}, `"with whitespace"`}, - {[]string{"one", "two"}, `"one" "two"`}, - {[]string{"eh", "bee", "cee"}, `"eh" "bee" "cee"`}, - {[]string{"o\"ne", "tw\"o"}, `"o\"ne" "tw\"o"`}, - {[]string{"dimple"}, `"dimple"`}, - {[]string{"fun", "two"}, `"fun" "two"`}, - {[]string{"eh", "bzz", "cee"}, `"eh" "bzz" "cee"`}, -} - -func TestEncodeTxt(t *testing.T) { - // Test encoded the lists of strings into a string: - for i, test := range txtData { - enc := encodeTxt(test.decoded) - if enc != test.encoded { - t.Errorf("%v: txt\n data: []string{%v}\nexpected: %q\n got: %q", - i, "`"+strings.Join(test.decoded, "`, `")+"`", test.encoded, enc) - } - } -} - -func TestDecodeTxt(t *testing.T) { - // Test decoded a string into the list of strings: - for i, test := range txtData { - data := test.encoded - got := decodeTxt(data) - wanted := test.decoded - if len(got) != len(wanted) { - t.Errorf("%v: txt\n decode: %v\nexpected: %q\n got: %q\n", i, data, strings.Join(wanted, "`, `"), strings.Join(got, "`, `")) - } else { - for j := range got { - if got[j] != wanted[j] { - t.Errorf("%v: txt\n decode: %v\nexpected: %q\n got: %q\n", i, data, strings.Join(wanted, "`, `"), strings.Join(got, "`, `")) - } - } - } - } -} diff --git a/providers/inwx/inwxProvider.go b/providers/inwx/inwxProvider.go index a2de4cb037..3ac148aedb 100644 --- a/providers/inwx/inwxProvider.go +++ b/providers/inwx/inwxProvider.go @@ -216,10 +216,8 @@ func checkRecords(records models.Records) error { // TODO(tlim) Remove this function. auditrecords.go takes care of this now. for _, r := range records { if r.Type == "TXT" { - for _, target := range r.GetTargetTXTSegmented() { - if strings.ContainsAny(target, "`") { - return fmt.Errorf("INWX TXT records do not support single-quotes in their target") - } + if strings.ContainsAny(r.GetTargetTXTJoined(), "`") { + return fmt.Errorf("INWX TXT records do not support single-quotes in their target") } } } diff --git a/providers/msdns/auditrecords.go b/providers/msdns/auditrecords.go index f031369f66..8694ffcae9 100644 --- a/providers/msdns/auditrecords.go +++ b/providers/msdns/auditrecords.go @@ -19,17 +19,11 @@ func AuditRecords(records []*models.RecordConfig) []error { a.Add("TXT", rejectif.TxtHasDoubleQuotes) // Last verified 2023-02-02 - a.Add("TXT", rejectif.TxtHasMultipleSegments) // Last verified 2023-02-02 - - a.Add("TXT", rejectif.TxtHasSegmentLen256orLonger) // Last verified 2023-02-02 + a.Add("TXT", rejectif.TxtLongerThan255) // Last verified 2023-02-02 a.Add("TXT", rejectif.TxtHasSingleQuotes) // Last verified 2023-02-02 a.Add("TXT", rejectif.TxtIsEmpty) // Last verified 2023-02-02 - a.Add("TXT", rejectif.TxtIsExactlyLen255) // Last verified 2023-02-02 - - a.Add("TXT", rejectif.TxtIsExactlyLen255) // Last verified 2023-02-02 - return a.Audit(records) } diff --git a/providers/namedotcom/auditrecords.go b/providers/namedotcom/auditrecords.go index 2d9a64c847..8e7d0f329d 100644 --- a/providers/namedotcom/auditrecords.go +++ b/providers/namedotcom/auditrecords.go @@ -20,7 +20,11 @@ func AuditRecords(records []*models.RecordConfig) []error { a.Add("TXT", MaxLengthNDC) // Last verified 2021-03-01 - a.Add("TXT", rejectif.TxtIsEmpty) // Last verified 2021-03-01 + a.Add("TXT", rejectif.TxtIsEmpty) // Last verified 2023-11-18 + + a.Add("TXT", rejectif.TxtHasBackslash) // Last verified 2023-11-18 + // Backslashes may be allowed in the API but the current + // encodeTxt/decodeTxt functions don't support backslashes. return a.Audit(records) } diff --git a/providers/namedotcom/records.go b/providers/namedotcom/records.go index af58fde7b1..241d023b6f 100644 --- a/providers/namedotcom/records.go +++ b/providers/namedotcom/records.go @@ -8,6 +8,7 @@ import ( "github.com/StackExchange/dnscontrol/v4/models" "github.com/StackExchange/dnscontrol/v4/pkg/diff" + "github.com/StackExchange/dnscontrol/v4/pkg/txtutil" "github.com/namedotcom/go/namecom" ) @@ -154,7 +155,7 @@ func (n *namedotcomProvider) createRecord(rc *models.RecordConfig, domain string case "A", "AAAA", "ANAME", "CNAME", "MX", "NS": // nothing case "TXT": - // nothing + record.Answer = txtutil.EncodeQuoted(rc.GetTargetTXTJoined()) case "SRV": if rc.GetTargetField() == "." { return errors.New("SRV records with empty targets are not supported (as of 2019-11-05, the API returns 'Parameter Value Error - Invalid Srv Format')") @@ -175,6 +176,7 @@ var quotedStringRegexp = regexp.MustCompile(`"((?:[^"\\]|\\.)*)"`) // decodeTxt decodes the TXT record as received from name.com and // returns the list of strings. +// NB(tlim): This is very similar to txtutil.ParseQuoted. Maybe replace it some day? func decodeTxt(s string) []string { if len(s) >= 2 && s[0] == '"' && s[len(s)-1] == '"' { diff --git a/providers/namedotcom/records_test.go b/providers/namedotcom/records_test.go index 0424178fd8..033d1f5435 100644 --- a/providers/namedotcom/records_test.go +++ b/providers/namedotcom/records_test.go @@ -17,21 +17,13 @@ var txtData = []struct { {[]string{"eh", "bee", "cee"}, `"eh""bee""cee"`}, {[]string{"o\"ne", "tw\"o"}, `"o\"ne""tw\"o"`}, {[]string{"dimple"}, `dimple`}, + //{[]string{`back\slash`}, `"back\\slash"`}, // Not yet supported + //{[]string{`back\\slash`}, `"back\\\\slash"`}, // Not yet supported + //{[]string{`back\\\slash`}, `"back\\\\\\slash"`}, // Not yet supported {[]string{"fun", "two"}, `"fun""two"`}, {[]string{"eh", "bzz", "cee"}, `"eh""bzz""cee"`}, } -// func TestEncodeTxt(t *testing.T) { -// // Test encoded the lists of strings into a string: -// for i, test := range txtData { -// enc := encodeTxt(test.decoded) -// if enc != test.encoded { -// t.Errorf("%v: txt\n data: []string{%v}\nexpected: %s\n got: %s", -// i, "`"+strings.Join(test.decoded, "`, `")+"`", test.encoded, enc) -// } -// } -//} - func TestDecodeTxt(t *testing.T) { // Test decoded a string into the list of strings: for i, test := range txtData { diff --git a/providers/ns1/auditrecords.go b/providers/ns1/auditrecords.go index d30fc86109..60a0827930 100644 --- a/providers/ns1/auditrecords.go +++ b/providers/ns1/auditrecords.go @@ -11,7 +11,7 @@ import ( func AuditRecords(records []*models.RecordConfig) []error { a := rejectif.Auditor{} - a.Add("TXT", rejectif.TxtHasMultipleSegments) + a.Add("TXT", rejectif.TxtIsEmpty) return a.Audit(records) } diff --git a/providers/ns1/ns1Provider.go b/providers/ns1/ns1Provider.go index a92db2860d..78c466252e 100644 --- a/providers/ns1/ns1Provider.go +++ b/providers/ns1/ns1Provider.go @@ -302,7 +302,7 @@ func buildRecord(recs models.Records, domain string, id string) *dns.Record { if r.Type == "MX" { rec.AddAnswer(&dns.Answer{Rdata: strings.Fields(fmt.Sprintf("%d %v", r.MxPreference, r.GetTargetField()))}) } else if r.Type == "TXT" { - rec.AddAnswer(&dns.Answer{Rdata: r.GetTargetTXTSegmented()}) + rec.AddAnswer(&dns.Answer{Rdata: []string{r.GetTargetTXTJoined()}}) } else if r.Type == "CAA" { rec.AddAnswer(&dns.Answer{ Rdata: []string{ diff --git a/providers/powerdns/convert_test.go b/providers/powerdns/convert_test.go index a88fd29109..49779a933c 100644 --- a/providers/powerdns/convert_test.go +++ b/providers/powerdns/convert_test.go @@ -29,7 +29,8 @@ func TestToRecordConfig(t *testing.T) { assert.NoError(t, err) assert.Equal(t, "large.example.com", recordConfig.NameFQDN) - assert.Equal(t, largeContent, recordConfig.String()) + assert.Equal(t, `"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB"`, + recordConfig.String()) assert.Equal(t, uint32(5), recordConfig.TTL) assert.Equal(t, "TXT", recordConfig.Type) } diff --git a/providers/route53/route53Provider.go b/providers/route53/route53Provider.go index b1458d370c..b9af6c1289 100644 --- a/providers/route53/route53Provider.go +++ b/providers/route53/route53Provider.go @@ -345,7 +345,7 @@ func (r *route53Provider) GetZoneRecordsCorrections(dc *models.DomainConfig, exi for _, r := range inst.New { rr := r53Types.ResourceRecord{ - Value: aws.String(r.GetTargetCombined()), + Value: aws.String(r.GetTargetCombinedFunc(txtutil.EncodeQuoted)), } rrset.ResourceRecords = append(rrset.ResourceRecords, rr) i := int64(r.TTL) @@ -488,17 +488,10 @@ func nativeToRecords(set r53Types.ResourceRecordSet, origin string) ([]*models.R } } - var err error rc := &models.RecordConfig{TTL: uint32(aws.ToInt64(set.TTL))} rc.SetLabelFromFQDN(unescape(set.Name), origin) rc.Original = set - switch rtypeString { - case "TXT": - err = rc.SetTargetTXTs(models.ParseQuotedTxt(val)) - default: - err = rc.PopulateFromString(rtypeString, val, origin) - } - if err != nil { + if err := rc.PopulateFromStringFunc(rtypeString, val, origin, txtutil.ParseQuoted); err != nil { return nil, fmt.Errorf("unparsable record type=%q received from ROUTE53: %w", rtypeString, err) } diff --git a/providers/rwth/auditrecords.go b/providers/rwth/auditrecords.go index fee9c390cc..15d5116775 100644 --- a/providers/rwth/auditrecords.go +++ b/providers/rwth/auditrecords.go @@ -11,8 +11,6 @@ import ( func AuditRecords(records []*models.RecordConfig) []error { a := rejectif.Auditor{} - a.Add("TXT", rejectif.TxtHasMultipleSegments) - a.Add("TXT", rejectif.TxtHasTrailingSpace) a.Add("TXT", rejectif.TxtIsEmpty) diff --git a/providers/transip/auditrecords.go b/providers/transip/auditrecords.go index fd6729c449..8004671b14 100644 --- a/providers/transip/auditrecords.go +++ b/providers/transip/auditrecords.go @@ -11,13 +11,13 @@ import ( func AuditRecords(records []*models.RecordConfig) []error { a := rejectif.Auditor{} - a.Add("MX", rejectif.MxNull) // Last verified 2023-01-28 + a.Add("MX", rejectif.MxNull) // Last verified 2023-12-04 - a.Add("TXT", rejectif.TxtHasBackticks) // Last verified 2023-01-28 + a.Add("TXT", rejectif.TxtHasBackticks) // Last verified 2023-12-04 - a.Add("TXT", rejectif.TxtHasTrailingSpace) // Last verified 2023-01-28 + a.Add("TXT", rejectif.TxtHasDoubleQuotes) // Last verified 2023-12-04 - a.Add("TXT", rejectif.TxtIsEmpty) // Last verified 2023-01-28 + a.Add("TXT", rejectif.TxtHasBackslash) // Last verified 2023-12-04 return a.Audit(records) } diff --git a/providers/transip/slashes.go b/providers/transip/slashes.go deleted file mode 100644 index 1f322da32c..0000000000 --- a/providers/transip/slashes.go +++ /dev/null @@ -1,11 +0,0 @@ -package transip - -import ( - "regexp" -) - -var removeSlashesRegexp = regexp.MustCompile(`(?:\\(\\)+)|(?:\\)`) - -func removeSlashes(s string) string { - return removeSlashesRegexp.ReplaceAllString(s, "$1") -} diff --git a/providers/transip/slashes_test.go b/providers/transip/slashes_test.go deleted file mode 100644 index e17778032b..0000000000 --- a/providers/transip/slashes_test.go +++ /dev/null @@ -1,25 +0,0 @@ -package transip - -import ( - "testing" -) - -func TestRemoveSlashes(t *testing.T) { - - data := [][]string{ - { - `quote"d`, `quote"d`, - `quote\"d`, `quote"d`, - `quote\\"d`, `quote\"d`, - `m\o\\r\\\\e`, `mo\r\\e`, - }, - } - - for _, testCase := range data { - result := removeSlashes(testCase[0]) - if result != testCase[1] { - t.Fatalf(`Failed on "%s". Expected "%s"; got "%s".`, testCase[0], testCase[1], result) - } - } - -} diff --git a/providers/transip/transipProvider.go b/providers/transip/transipProvider.go index f273c9241b..021d0eb8f1 100644 --- a/providers/transip/transipProvider.go +++ b/providers/transip/transipProvider.go @@ -8,6 +8,7 @@ import ( "github.com/StackExchange/dnscontrol/v4/models" "github.com/StackExchange/dnscontrol/v4/pkg/diff2" + "github.com/StackExchange/dnscontrol/v4/pkg/txtutil" "github.com/StackExchange/dnscontrol/v4/providers" "github.com/transip/gotransip/v6" "github.com/transip/gotransip/v6/domain" @@ -299,6 +300,7 @@ func (n *transipProvider) GetNameservers(domainName string) ([]*models.Nameserve return models.ToNameservers(nss) } +// recordToNative convrts RecordConfig TO Native. func recordToNative(config *models.RecordConfig, useOriginal bool) (domain.DNSEntry, error) { if useOriginal && config.Original != nil { return config.Original.(domain.DNSEntry), nil @@ -308,10 +310,11 @@ func recordToNative(config *models.RecordConfig, useOriginal bool) (domain.DNSEn Name: config.Name, Expire: int(config.TTL), Type: config.Type, - Content: getTargetRecordContent(config), + Content: config.GetTargetCombinedFunc(txtutil.EncodeQuoted), }, nil } +// nativeToRecord converts native to RecordConfig. func nativeToRecord(entry domain.DNSEntry, origin string) (*models.RecordConfig, error) { rc := &models.RecordConfig{ TTL: uint32(entry.Expire), @@ -319,7 +322,7 @@ func nativeToRecord(entry domain.DNSEntry, origin string) (*models.RecordConfig, Original: entry, } rc.SetLabel(entry.Name, origin) - if err := rc.PopulateFromString(entry.Type, entry.Content, origin); err != nil { + if err := rc.PopulateFromStringFunc(entry.Type, entry.Content, origin, txtutil.ParseQuoted); err != nil { return nil, fmt.Errorf("unparsable record received from TransIP: %w", err) } @@ -338,18 +341,3 @@ func removeOtherNS(dc *models.DomainConfig) { } dc.Records = newList } - -func getTargetRecordContent(rc *models.RecordConfig) string { - switch rtype := rc.Type; rtype { - case "SSHFP": - return fmt.Sprintf("%d %d %s", rc.SshfpAlgorithm, rc.SshfpFingerprint, rc.GetTargetField()) - case "DS": - return fmt.Sprintf("%d %d %d %s", rc.DsKeyTag, rc.DsAlgorithm, rc.DsDigestType, rc.DsDigest) - case "SRV": - return fmt.Sprintf("%d %d %d %s", rc.SrvPriority, rc.SrvWeight, rc.SrvPort, rc.GetTargetField()) - case "TXT": - return removeSlashes(models.StripQuotes(rc.GetTargetCombined())) - default: - return models.StripQuotes(rc.GetTargetCombined()) - } -} diff --git a/providers/vultr/auditrecords.go b/providers/vultr/auditrecords.go index e6aed47590..72653d0e59 100644 --- a/providers/vultr/auditrecords.go +++ b/providers/vultr/auditrecords.go @@ -17,8 +17,6 @@ func AuditRecords(records []*models.RecordConfig) []error { // Needs investigation. Could be a dnscontrol issue or // the provider doesn't support double quotes. - a.Add("TXT", rejectif.TxtHasMultipleSegments) - a.Add("CAA", rejectif.CaaTargetContainsWhitespace) // Last verified 2023-01-19 return a.Audit(records) From 3ed24a9af6b042114eff0a87bd352912ad753e92 Mon Sep 17 00:00:00 2001 From: Jeffrey Cafferata Date: Tue, 5 Dec 2023 14:46:51 +0100 Subject: [PATCH 050/438] DOCS: Rename build filenames (#2681) --- README.md | 2 +- documentation/byo-secrets.md | 10 +++++----- documentation/release-engineering.md | 4 ++-- 3 files changed, 8 insertions(+), 8 deletions(-) diff --git a/README.md b/README.md index bacfcf734a..15a0b989c3 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ # DNSControl -[![StackExchange/dnscontrol/build](https://github.com/StackExchange/dnscontrol/actions/workflows/build.yml/badge.svg)](https://github.com/StackExchange/dnscontrol/actions/workflows/build.yml) +[![StackExchange/dnscontrol/build](https://github.com/StackExchange/dnscontrol/actions/workflows/pr_test.yml/badge.svg)](https://github.com/StackExchange/dnscontrol/actions/workflows/pr_test.yml) [![Gitter chat](https://badges.gitter.im/dnscontrol/Lobby.png)](https://gitter.im/dnscontrol/Lobby) [![Google Group](https://img.shields.io/badge/google%20group-chat-green.svg)](https://groups.google.com/forum/#!forum/dnscontrol-discuss) [![PkgGoDev](https://pkg.go.dev/badge/github.com/StackExchange/dnscontrol)](https://pkg.go.dev/github.com/StackExchange/dnscontrol/v4) diff --git a/documentation/byo-secrets.md b/documentation/byo-secrets.md index 7b2e41ed57..20450d561e 100644 --- a/documentation/byo-secrets.md +++ b/documentation/byo-secrets.md @@ -62,16 +62,16 @@ Step 1: Create a branch Create a branch as you normally would to submit a PR to the project. -Step 2: Update `build.yml` +Step 2: Update `pr_test.yml` -In this branch, edit `.github/workflows/build.yml`: +In this branch, edit `.github/workflows/pr_test.yml`: 1. In the `integration-test-providers` section, the name of the provider. Add your provider's name (alphabetically). The line looks something like: -{% code title=".github/workflows/build.yml" %} +{% code title=".github/workflows/pr_test.yml" %} ``` PROVIDERS: "['BIND','HEXONET','AZURE_DNS','CLOUDFLAREAPI','GCLOUD','NAMEDOTCOM','ROUTE53','CLOUDNS','DIGITALOCEAN','GANDI_V5','HEDNS','INWX','NS1','POWERDNS','TRANSIP']" ``` @@ -83,7 +83,7 @@ Add it to the `env` section of `integrtests-diff2`. For example, the entry for BIND looks like: -{% code title=".github/workflows/build.yml" %} +{% code title=".github/workflows/pr_test.yml" %} ``` BIND_DOMAIN: ${{ vars.BIND_DOMAIN }} ``` @@ -95,7 +95,7 @@ If there are other env variables (for example, for an API key), add that as a "s For example, the entry for CLOUDFLAREAPI looks like this: -{% code title=".github/workflows/build.yml" %} +{% code title=".github/workflows/pr_test.yml" %} ``` CLOUDFLAREAPI_ACCOUNTID: ${{ secrets.CLOUDFLAREAPI_ACCOUNTID }} CLOUDFLAREAPI_TOKEN: ${{ secrets.CLOUDFLAREAPI_TOKEN }} diff --git a/documentation/release-engineering.md b/documentation/release-engineering.md index 17e21f07d6..1c66739ab4 100644 --- a/documentation/release-engineering.md +++ b/documentation/release-engineering.md @@ -130,7 +130,7 @@ find * -name \*.bak -delete GHA is configured to run an integration test for any provider listed in the "provider" list. However the test is skipped if the `*_DOMAIN` variable is not set. For example, the Google Cloud provider integration test is only run if `GCLOUD_DOMAIN` is set. * Q: Where is the list of providers to run integration tests on? -* A: In `.github/workflows/build.yml`: (1) the "PROVIDERS" list, (2) the `integrtests-diff2` section. +* A: In `.github/workflows/pr_test.yml`: (1) the "PROVIDERS" list, (2) the `integrtests-diff2` section. * Q: Where are non-secret environment variables stored? * A: GHA calls them "Variables". Update them here: https://github.com/StackExchange/dnscontrol/settings/variables/actions @@ -140,7 +140,7 @@ GHA is configured to run an integration test for any provider listed in the "pro ### How do I add a single new integration test? -1. Edit `.github/workflows/build.yml` +1. Edit `.github/workflows/pr_test.yml` 2. Add the `FOO_DOMAIN` variable name of the provider to the "PROVIDERS" list. 3. Set the `FOO_DOMAIN` variables in GHA via https://github.com/StackExchange/dnscontrol/settings/variables/actions 4. All other variables should be stored as secrets (for consistency). Add them to the `integrtests-diff2` section. From 76d93acaf5ea098eb68b0ad103a43288c8d169b5 Mon Sep 17 00:00:00 2001 From: Tom Limoncelli Date: Tue, 5 Dec 2023 09:47:52 -0500 Subject: [PATCH 051/438] CHORE: Remove dead code: txtutil.SplitSingleLongTxt() and txtutil.Segment() (#2685) --- pkg/txtutil/txtutil.go | 10 ---------- providers/akamaiedgedns/akamaiEdgeDnsProvider.go | 3 --- providers/autodns/autoDnsProvider.go | 2 -- providers/axfrddns/axfrddnsProvider.go | 3 --- providers/azure_private_dns/azurePrivateDnsProvider.go | 3 --- providers/azuredns/azureDnsProvider.go | 3 --- providers/bind/bindProvider.go | 2 -- providers/cscglobal/convert.go | 2 -- providers/desec/desecProvider.go | 3 --- providers/digitalocean/digitaloceanProvider.go | 3 --- providers/dnsmadeeasy/dnsMadeEasyProvider.go | 3 --- providers/gandiv5/gandi_v5Provider.go | 2 -- providers/gcloud/gcloudProvider.go | 2 -- providers/hedns/hednsProvider.go | 3 --- providers/hetzner/hetznerProvider.go | 3 --- providers/hexonet/records.go | 2 -- providers/inwx/inwxProvider.go | 4 ---- providers/loopia/loopiaProvider.go | 3 --- providers/msdns/corrections.go | 3 --- providers/netcup/netcupProvider.go | 3 --- providers/oracle/oracleProvider.go | 2 -- providers/route53/route53Provider.go | 2 -- providers/rwth/dns.go | 2 -- 23 files changed, 68 deletions(-) diff --git a/pkg/txtutil/txtutil.go b/pkg/txtutil/txtutil.go index 55045b8c29..a6caf5e05e 100644 --- a/pkg/txtutil/txtutil.go +++ b/pkg/txtutil/txtutil.go @@ -1,20 +1,10 @@ package txtutil -// SplitSingleLongTxt does nothing. -// Deprecated: This is a no-op for backwards compatibility. -func SplitSingleLongTxt(records any) { -} - // ToChunks returns the string as chunks of 255-octet strings (the last string being the remainder). func ToChunks(s string) []string { return splitChunks(s, 255) } -// Segment returns the string as 255-octet segments, the last being the remainder. -func Segment(s string) []string { - return splitChunks(s, 255) -} - func splitChunks(buf string, lim int) []string { var chunk string chunks := make([]string, 0, len(buf)/lim+1) diff --git a/providers/akamaiedgedns/akamaiEdgeDnsProvider.go b/providers/akamaiedgedns/akamaiEdgeDnsProvider.go index a42fe4b523..7d1fabda16 100644 --- a/providers/akamaiedgedns/akamaiEdgeDnsProvider.go +++ b/providers/akamaiedgedns/akamaiEdgeDnsProvider.go @@ -17,7 +17,6 @@ import ( "github.com/StackExchange/dnscontrol/v4/models" "github.com/StackExchange/dnscontrol/v4/pkg/diff" "github.com/StackExchange/dnscontrol/v4/pkg/printer" - "github.com/StackExchange/dnscontrol/v4/pkg/txtutil" "github.com/StackExchange/dnscontrol/v4/providers" ) @@ -106,8 +105,6 @@ func (a *edgeDNSProvider) EnsureZoneExists(domain string) error { // GetZoneRecordsCorrections returns a list of corrections that will turn existing records into dc.Records. func (a *edgeDNSProvider) GetZoneRecordsCorrections(dc *models.DomainConfig, existingRecords models.Records) ([]*models.Correction, error) { - txtutil.SplitSingleLongTxt(existingRecords) - keysToUpdate, toReport, err := diff.NewCompat(dc).ChangedGroups(existingRecords) if err != nil { return nil, err diff --git a/providers/autodns/autoDnsProvider.go b/providers/autodns/autoDnsProvider.go index 6da132afe9..91d6f65f86 100644 --- a/providers/autodns/autoDnsProvider.go +++ b/providers/autodns/autoDnsProvider.go @@ -11,7 +11,6 @@ import ( "github.com/StackExchange/dnscontrol/v4/models" "github.com/StackExchange/dnscontrol/v4/pkg/diff2" - "github.com/StackExchange/dnscontrol/v4/pkg/txtutil" "github.com/StackExchange/dnscontrol/v4/providers" ) @@ -68,7 +67,6 @@ func New(settings map[string]string, _ json.RawMessage) (providers.DNSServicePro // GetZoneRecordsCorrections returns a list of corrections that will turn existing records into dc.Records. func (api *autoDNSProvider) GetZoneRecordsCorrections(dc *models.DomainConfig, existingRecords models.Records) ([]*models.Correction, error) { domain := dc.Name - txtutil.SplitSingleLongTxt(dc.Records) // Autosplit long TXT records var corrections []*models.Correction diff --git a/providers/axfrddns/axfrddnsProvider.go b/providers/axfrddns/axfrddnsProvider.go index f283ee9418..3fba136889 100644 --- a/providers/axfrddns/axfrddnsProvider.go +++ b/providers/axfrddns/axfrddnsProvider.go @@ -25,7 +25,6 @@ import ( "github.com/StackExchange/dnscontrol/v4/models" "github.com/StackExchange/dnscontrol/v4/pkg/diff2" "github.com/StackExchange/dnscontrol/v4/pkg/printer" - "github.com/StackExchange/dnscontrol/v4/pkg/txtutil" "github.com/StackExchange/dnscontrol/v4/providers" "github.com/fatih/color" "github.com/miekg/dns" @@ -410,8 +409,6 @@ func hasNSDeletion(changes diff2.ChangeList) bool { // GetZoneRecordsCorrections returns a list of corrections that will turn existing records into dc.Records. func (c *axfrddnsProvider) GetZoneRecordsCorrections(dc *models.DomainConfig, foundRecords models.Records) ([]*models.Correction, error) { - txtutil.SplitSingleLongTxt(foundRecords) // Autosplit long TXT records - // Ignoring the SOA, others providers don't manage it either. if len(foundRecords) >= 1 && foundRecords[0].Type == "SOA" { foundRecords = foundRecords[1:] diff --git a/providers/azure_private_dns/azurePrivateDnsProvider.go b/providers/azure_private_dns/azurePrivateDnsProvider.go index 7ba34adc03..c798532dae 100644 --- a/providers/azure_private_dns/azurePrivateDnsProvider.go +++ b/providers/azure_private_dns/azurePrivateDnsProvider.go @@ -14,7 +14,6 @@ import ( "github.com/StackExchange/dnscontrol/v4/models" "github.com/StackExchange/dnscontrol/v4/pkg/diff2" "github.com/StackExchange/dnscontrol/v4/pkg/printer" - "github.com/StackExchange/dnscontrol/v4/pkg/txtutil" "github.com/StackExchange/dnscontrol/v4/providers" ) @@ -183,8 +182,6 @@ func (a *azurednsProvider) getExistingRecords(domain string) (models.Records, [] // GetZoneRecordsCorrections returns a list of corrections that will turn existing records into dc.Records. func (a *azurednsProvider) GetZoneRecordsCorrections(dc *models.DomainConfig, existingRecords models.Records) ([]*models.Correction, error) { - txtutil.SplitSingleLongTxt(existingRecords) // Autosplit long TXT records - var corrections []*models.Correction changes, err := diff2.ByRecordSet(existingRecords, dc, nil) diff --git a/providers/azuredns/azureDnsProvider.go b/providers/azuredns/azureDnsProvider.go index 105e46e6e5..abe8c46dda 100644 --- a/providers/azuredns/azureDnsProvider.go +++ b/providers/azuredns/azureDnsProvider.go @@ -14,7 +14,6 @@ import ( "github.com/StackExchange/dnscontrol/v4/models" "github.com/StackExchange/dnscontrol/v4/pkg/diff2" "github.com/StackExchange/dnscontrol/v4/pkg/printer" - "github.com/StackExchange/dnscontrol/v4/pkg/txtutil" "github.com/StackExchange/dnscontrol/v4/providers" ) @@ -193,8 +192,6 @@ func (a *azurednsProvider) getExistingRecords(domain string) (models.Records, [] // GetZoneRecordsCorrections returns a list of corrections that will turn existing records into dc.Records. func (a *azurednsProvider) GetZoneRecordsCorrections(dc *models.DomainConfig, existingRecords models.Records) ([]*models.Correction, error) { - txtutil.SplitSingleLongTxt(existingRecords) // Autosplit long TXT records - var corrections []*models.Correction // Azure is a "ByRecordSet" API. diff --git a/providers/bind/bindProvider.go b/providers/bind/bindProvider.go index 16a502553a..46f22f2091 100644 --- a/providers/bind/bindProvider.go +++ b/providers/bind/bindProvider.go @@ -25,7 +25,6 @@ import ( "github.com/StackExchange/dnscontrol/v4/pkg/diff2" "github.com/StackExchange/dnscontrol/v4/pkg/prettyzone" "github.com/StackExchange/dnscontrol/v4/pkg/printer" - "github.com/StackExchange/dnscontrol/v4/pkg/txtutil" "github.com/StackExchange/dnscontrol/v4/providers" "github.com/miekg/dns" ) @@ -210,7 +209,6 @@ func ParseZoneContents(content string, zoneName string, zonefileName string) (mo // GetZoneRecordsCorrections returns a list of corrections that will turn existing records into dc.Records. func (c *bindProvider) GetZoneRecordsCorrections(dc *models.DomainConfig, foundRecords models.Records) ([]*models.Correction, error) { - txtutil.SplitSingleLongTxt(dc.Records) var corrections []*models.Correction changes := false diff --git a/providers/cscglobal/convert.go b/providers/cscglobal/convert.go index 6050cd8ec2..4ffab7c17e 100644 --- a/providers/cscglobal/convert.go +++ b/providers/cscglobal/convert.go @@ -6,7 +6,6 @@ import ( "net" "github.com/StackExchange/dnscontrol/v4/models" - "github.com/StackExchange/dnscontrol/v4/pkg/printer" ) // nativeToRecordA takes an A record from DNS and returns a native RecordConfig struct. @@ -65,7 +64,6 @@ func nativeToRecordTXT(nr nativeRecordTXT, origin string, defaultTTL uint32) *mo TTL: ttl, } rc.SetLabel(nr.Key, origin) - printer.Printf("DEBUG: inbound raw s=%s\n", nr.Value) rc.SetTargetTXT(nr.Value) return rc } diff --git a/providers/desec/desecProvider.go b/providers/desec/desecProvider.go index 34201f0130..4142e463fd 100644 --- a/providers/desec/desecProvider.go +++ b/providers/desec/desecProvider.go @@ -8,7 +8,6 @@ import ( "github.com/StackExchange/dnscontrol/v4/models" "github.com/StackExchange/dnscontrol/v4/pkg/diff" "github.com/StackExchange/dnscontrol/v4/pkg/printer" - "github.com/StackExchange/dnscontrol/v4/pkg/txtutil" "github.com/StackExchange/dnscontrol/v4/providers" "github.com/miekg/dns/dnsutil" ) @@ -150,8 +149,6 @@ func PrepDesiredRecords(dc *models.DomainConfig, minTTL uint32) { // GetZoneRecordsCorrections returns a list of corrections that will turn existing records into dc.Records. func (c *desecProvider) GetZoneRecordsCorrections(dc *models.DomainConfig, existing models.Records) ([]*models.Correction, error) { - txtutil.SplitSingleLongTxt(dc.Records) - var minTTL uint32 c.mutex.Lock() if ttl, ok := c.domainIndex[dc.Name]; !ok { diff --git a/providers/digitalocean/digitaloceanProvider.go b/providers/digitalocean/digitaloceanProvider.go index 62ec0d7dd9..7ae78e34a9 100644 --- a/providers/digitalocean/digitaloceanProvider.go +++ b/providers/digitalocean/digitaloceanProvider.go @@ -10,7 +10,6 @@ import ( "github.com/StackExchange/dnscontrol/v4/models" "github.com/StackExchange/dnscontrol/v4/pkg/diff" - "github.com/StackExchange/dnscontrol/v4/pkg/txtutil" "github.com/StackExchange/dnscontrol/v4/providers" "github.com/digitalocean/godo" "github.com/miekg/dns/dnsutil" @@ -168,8 +167,6 @@ func (api *digitaloceanProvider) GetZoneRecords(domain string, meta map[string]s // GetZoneRecordsCorrections returns a list of corrections that will turn existing records into dc.Records. func (api *digitaloceanProvider) GetZoneRecordsCorrections(dc *models.DomainConfig, existingRecords models.Records) ([]*models.Correction, error) { - txtutil.SplitSingleLongTxt(dc.Records) // Autosplit long TXT records - ctx := context.Background() toReport, toCreate, toDelete, toModify, err := diff.NewCompat(dc).IncrementalDiff(existingRecords) diff --git a/providers/dnsmadeeasy/dnsMadeEasyProvider.go b/providers/dnsmadeeasy/dnsMadeEasyProvider.go index 3e6f1eb31e..2917ad82e1 100644 --- a/providers/dnsmadeeasy/dnsMadeEasyProvider.go +++ b/providers/dnsmadeeasy/dnsMadeEasyProvider.go @@ -8,7 +8,6 @@ import ( "github.com/StackExchange/dnscontrol/v4/models" "github.com/StackExchange/dnscontrol/v4/pkg/diff" - "github.com/StackExchange/dnscontrol/v4/pkg/txtutil" "github.com/StackExchange/dnscontrol/v4/providers" ) @@ -99,8 +98,6 @@ func New(settings map[string]string, _ json.RawMessage) (providers.DNSServicePro // } func (api *dnsMadeEasyProvider) GetZoneRecordsCorrections(dc *models.DomainConfig, existingRecords models.Records) ([]*models.Correction, error) { - txtutil.SplitSingleLongTxt(dc.Records) // Autosplit long TXT records - domainName := dc.Name domain, err := api.findDomain(domainName) if err != nil { diff --git a/providers/gandiv5/gandi_v5Provider.go b/providers/gandiv5/gandi_v5Provider.go index 0aedb7aed3..5d661763ac 100644 --- a/providers/gandiv5/gandi_v5Provider.go +++ b/providers/gandiv5/gandi_v5Provider.go @@ -24,7 +24,6 @@ import ( "github.com/StackExchange/dnscontrol/v4/models" "github.com/StackExchange/dnscontrol/v4/pkg/diff2" "github.com/StackExchange/dnscontrol/v4/pkg/printer" - "github.com/StackExchange/dnscontrol/v4/pkg/txtutil" "github.com/StackExchange/dnscontrol/v4/providers" "github.com/go-gandi/go-gandi" "github.com/go-gandi/go-gandi/config" @@ -195,7 +194,6 @@ func (client *gandiv5Provider) GetZoneRecordsCorrections(dc *models.DomainConfig } PrepDesiredRecords(dc) - txtutil.SplitSingleLongTxt(dc.Records) // Autosplit long TXT records g := gandi.NewLiveDNSClient(config.Config{ APIKey: client.apikey, diff --git a/providers/gcloud/gcloudProvider.go b/providers/gcloud/gcloudProvider.go index 6652c2691c..31f6e7f4d2 100644 --- a/providers/gcloud/gcloudProvider.go +++ b/providers/gcloud/gcloudProvider.go @@ -259,8 +259,6 @@ type correctionValues struct { // GetZoneRecordsCorrections returns a list of corrections that will turn existing records into dc.Records. func (g *gcloudProvider) GetZoneRecordsCorrections(dc *models.DomainConfig, existingRecords models.Records) ([]*models.Correction, error) { - txtutil.SplitSingleLongTxt(dc.Records) // Autosplit long TXT records - oldRRs, ok := g.oldRRsMap[dc.Name] if !ok { return nil, fmt.Errorf("oldRRsMap: no zone named %q", dc.Name) diff --git a/providers/hedns/hednsProvider.go b/providers/hedns/hednsProvider.go index d7d70fd97c..da506439b4 100644 --- a/providers/hedns/hednsProvider.go +++ b/providers/hedns/hednsProvider.go @@ -191,9 +191,6 @@ func (c *hednsProvider) GetZoneRecordsCorrections(dc *models.DomainConfig, recor } } - // Normalize - txtutil.SplitSingleLongTxt(dc.Records) // Autosplit long TXT records - return c.getDiff2DomainCorrections(dc, zoneID, prunedRecords) } diff --git a/providers/hetzner/hetznerProvider.go b/providers/hetzner/hetznerProvider.go index 0c373c94cb..fb638f39e4 100644 --- a/providers/hetzner/hetznerProvider.go +++ b/providers/hetzner/hetznerProvider.go @@ -7,7 +7,6 @@ import ( "github.com/StackExchange/dnscontrol/v4/models" "github.com/StackExchange/dnscontrol/v4/pkg/diff" - "github.com/StackExchange/dnscontrol/v4/pkg/txtutil" "github.com/StackExchange/dnscontrol/v4/providers" ) @@ -72,8 +71,6 @@ func (api *hetznerProvider) EnsureZoneExists(domain string) error { func (api *hetznerProvider) GetZoneRecordsCorrections(dc *models.DomainConfig, existingRecords models.Records) ([]*models.Correction, error) { domain := dc.Name - txtutil.SplitSingleLongTxt(dc.Records) // Autosplit long TXT records - toReport, create, del, modify, err := diff.NewCompat(dc).IncrementalDiff(existingRecords) if err != nil { return nil, err diff --git a/providers/hexonet/records.go b/providers/hexonet/records.go index 2ef35aaf70..2408b2456b 100644 --- a/providers/hexonet/records.go +++ b/providers/hexonet/records.go @@ -57,8 +57,6 @@ func (n *HXClient) GetZoneRecords(domain string, meta map[string]string) (models // GetZoneRecordsCorrections returns a list of corrections that will turn existing records into dc.Records. func (n *HXClient) GetZoneRecordsCorrections(dc *models.DomainConfig, actual models.Records) ([]*models.Correction, error) { - txtutil.SplitSingleLongTxt(dc.Records) - toReport, create, del, mod, err := diff.NewCompat(dc).IncrementalDiff(actual) if err != nil { return nil, err diff --git a/providers/inwx/inwxProvider.go b/providers/inwx/inwxProvider.go index 3ac148aedb..c511d85b6a 100644 --- a/providers/inwx/inwxProvider.go +++ b/providers/inwx/inwxProvider.go @@ -10,7 +10,6 @@ import ( "github.com/StackExchange/dnscontrol/v4/models" "github.com/StackExchange/dnscontrol/v4/pkg/diff" "github.com/StackExchange/dnscontrol/v4/pkg/printer" - "github.com/StackExchange/dnscontrol/v4/pkg/txtutil" "github.com/StackExchange/dnscontrol/v4/providers" "github.com/nrdcg/goinwx" "github.com/pquerna/otp/totp" @@ -226,9 +225,6 @@ func checkRecords(records models.Records) error { // GetZoneRecordsCorrections returns a list of corrections that will turn existing records into dc.Records. func (api *inwxAPI) GetZoneRecordsCorrections(dc *models.DomainConfig, foundRecords models.Records) ([]*models.Correction, error) { - - txtutil.SplitSingleLongTxt(dc.Records) // Autosplit long TXT records - err := checkRecords(dc.Records) if err != nil { return nil, err diff --git a/providers/loopia/loopiaProvider.go b/providers/loopia/loopiaProvider.go index 96815a9b52..896d123078 100644 --- a/providers/loopia/loopiaProvider.go +++ b/providers/loopia/loopiaProvider.go @@ -25,7 +25,6 @@ import ( "github.com/StackExchange/dnscontrol/v4/models" "github.com/StackExchange/dnscontrol/v4/pkg/diff" "github.com/StackExchange/dnscontrol/v4/pkg/printer" - "github.com/StackExchange/dnscontrol/v4/pkg/txtutil" "github.com/StackExchange/dnscontrol/v4/providers" "github.com/miekg/dns/dnsutil" ) @@ -271,8 +270,6 @@ func (c *APIClient) GetZoneRecordsCorrections(dc *models.DomainConfig, existingR debugRecords("GenerateZoneRecordsCorrections input:\n", existingRecords) } - // Normalize - txtutil.SplitSingleLongTxt(dc.Records) // Autosplit long TXT records PrepDesiredRecords(dc) var keysToUpdate map[models.RecordKey][]string diff --git a/providers/msdns/corrections.go b/providers/msdns/corrections.go index f58e2ba20c..32cd6197aa 100644 --- a/providers/msdns/corrections.go +++ b/providers/msdns/corrections.go @@ -5,16 +5,13 @@ import ( "github.com/StackExchange/dnscontrol/v4/models" "github.com/StackExchange/dnscontrol/v4/pkg/diff2" - "github.com/StackExchange/dnscontrol/v4/pkg/txtutil" ) // GetZoneRecordsCorrections returns a list of corrections that will turn existing records into dc.Records. func (client *msdnsProvider) GetZoneRecordsCorrections(dc *models.DomainConfig, foundRecords models.Records) ([]*models.Correction, error) { var corrections []*models.Correction - // Normalize models.PostProcessRecords(foundRecords) - txtutil.SplitSingleLongTxt(dc.Records) // Autosplit long TXT records changes, err := diff2.ByRecord(foundRecords, dc, nil) if err != nil { diff --git a/providers/netcup/netcupProvider.go b/providers/netcup/netcupProvider.go index e55901772d..2fa866b319 100644 --- a/providers/netcup/netcupProvider.go +++ b/providers/netcup/netcupProvider.go @@ -71,9 +71,6 @@ func (api *netcupProvider) GetNameservers(domain string) ([]*models.Nameserver, func (api *netcupProvider) GetZoneRecordsCorrections(dc *models.DomainConfig, existingRecords models.Records) ([]*models.Correction, error) { domain := dc.Name - // no need for txtutil.SplitSingleLongTxt in function GetDomainCorrections - // txtutil.SplitSingleLongTxt(dc.Records) // Autosplit long TXT records - // Setting the TTL is not supported for netcup for _, r := range dc.Records { r.TTL = 0 diff --git a/providers/oracle/oracleProvider.go b/providers/oracle/oracleProvider.go index 892e6cee8a..aac6204fc5 100644 --- a/providers/oracle/oracleProvider.go +++ b/providers/oracle/oracleProvider.go @@ -9,7 +9,6 @@ import ( "github.com/StackExchange/dnscontrol/v4/models" "github.com/StackExchange/dnscontrol/v4/pkg/diff" "github.com/StackExchange/dnscontrol/v4/pkg/printer" - "github.com/StackExchange/dnscontrol/v4/pkg/txtutil" "github.com/StackExchange/dnscontrol/v4/providers" "github.com/oracle/oci-go-sdk/v32/common" "github.com/oracle/oci-go-sdk/v32/dns" @@ -204,7 +203,6 @@ func (o *oracleProvider) GetZoneRecords(zone string, meta map[string]string) (mo // GetZoneRecordsCorrections returns a list of corrections that will turn existing records into dc.Records. func (o *oracleProvider) GetZoneRecordsCorrections(dc *models.DomainConfig, existingRecords models.Records) ([]*models.Correction, error) { var err error - txtutil.SplitSingleLongTxt(dc.Records) // Autosplit long TXT records // Ensure we don't emit changes for attempted modification of built-in apex NSs for _, rec := range dc.Records { diff --git a/providers/route53/route53Provider.go b/providers/route53/route53Provider.go index b9af6c1289..fb0568e87a 100644 --- a/providers/route53/route53Provider.go +++ b/providers/route53/route53Provider.go @@ -279,8 +279,6 @@ func (r *route53Provider) getZoneRecords(zone r53Types.HostedZone) (models.Recor // GetZoneRecordsCorrections returns a list of corrections that will turn existing records into dc.Records. func (r *route53Provider) GetZoneRecordsCorrections(dc *models.DomainConfig, existingRecords models.Records) ([]*models.Correction, error) { - txtutil.SplitSingleLongTxt(dc.Records) // Autosplit long TXT records - zone, err := r.getZone(dc) if err != nil { return nil, err diff --git a/providers/rwth/dns.go b/providers/rwth/dns.go index 88b31e6e7e..5ab10d9fc7 100644 --- a/providers/rwth/dns.go +++ b/providers/rwth/dns.go @@ -5,7 +5,6 @@ import ( "github.com/StackExchange/dnscontrol/v4/models" "github.com/StackExchange/dnscontrol/v4/pkg/diff" - "github.com/StackExchange/dnscontrol/v4/pkg/txtutil" ) // RWTHDefaultNs is the default DNS NS for this provider. @@ -31,7 +30,6 @@ func (api *rwthProvider) GetNameservers(domain string) ([]*models.Nameserver, er // GetZoneRecordsCorrections returns a list of corrections that will turn existing records into dc.Records. func (api *rwthProvider) GetZoneRecordsCorrections(dc *models.DomainConfig, existingRecords models.Records) ([]*models.Correction, error) { - txtutil.SplitSingleLongTxt(dc.Records) // Autosplit long TXT records domain := dc.Name toReport, create, del, modify, err := diff.NewCompat(dc).IncrementalDiff(existingRecords) From 57216f07f1d59d1453752344f1f88084b7853b21 Mon Sep 17 00:00:00 2001 From: Tom Limoncelli Date: Tue, 5 Dec 2023 10:01:55 -0500 Subject: [PATCH 052/438] DOCS: Update docs related to diff2 and clean up useless mentions of diff2 (#2683) Co-authored-by: Costas Drogos Co-authored-by: imlonghao Co-authored-by: Jeffrey Cafferata Co-authored-by: Vincent Hagen --- .github/workflows/pr_test.yml | 2 +- documentation/byo-secrets.md | 2 +- documentation/release-engineering.md | 2 +- documentation/writing-providers.md | 67 ++++++++++------------------ 4 files changed, 27 insertions(+), 46 deletions(-) diff --git a/.github/workflows/pr_test.yml b/.github/workflows/pr_test.yml index 8727f721c1..7520eb7d0d 100644 --- a/.github/workflows/pr_test.yml +++ b/.github/workflows/pr_test.yml @@ -91,7 +91,7 @@ jobs: ENV_CONTEXT: ${{ toJson(env) }} VARS_CONTEXT: ${{ toJson(vars) }} SECRETS_CONTEXT: ${{ toJson(secrets) }} - integrtests-diff2: + integration-tests: if: github.ref != 'refs/heads/master' && github.ref != 'refs/heads/main' runs-on: ubuntu-latest container: diff --git a/documentation/byo-secrets.md b/documentation/byo-secrets.md index 20450d561e..d4d650bd18 100644 --- a/documentation/byo-secrets.md +++ b/documentation/byo-secrets.md @@ -79,7 +79,7 @@ The line looks something like: 2. Add your providers `_DOMAIN` env variable: -Add it to the `env` section of `integrtests-diff2`. +Add it to the `env` section of `integration-tests`. For example, the entry for BIND looks like: diff --git a/documentation/release-engineering.md b/documentation/release-engineering.md index 1c66739ab4..8f1302fc68 100644 --- a/documentation/release-engineering.md +++ b/documentation/release-engineering.md @@ -143,7 +143,7 @@ GHA is configured to run an integration test for any provider listed in the "pro 1. Edit `.github/workflows/pr_test.yml` 2. Add the `FOO_DOMAIN` variable name of the provider to the "PROVIDERS" list. 3. Set the `FOO_DOMAIN` variables in GHA via https://github.com/StackExchange/dnscontrol/settings/variables/actions -4. All other variables should be stored as secrets (for consistency). Add them to the `integrtests-diff2` section. +4. All other variables should be stored as secrets (for consistency). Add them to the `integration-tests` section. Set them in GHA via https://github.com/StackExchange/dnscontrol/settings/secrets/actions ### How do I add a "bring your own keys" integration test? diff --git a/documentation/writing-providers.md b/documentation/writing-providers.md index 791a2bc6dd..1e44de3630 100644 --- a/documentation/writing-providers.md +++ b/documentation/writing-providers.md @@ -67,62 +67,42 @@ was confusing so we can update this document with advice for future authors (or even better, update [this document](https://github.com/StackExchange/dnscontrol/blob/master/documentation/writing-providers.md) yourself.) -## NOTE: diff2 - -We are in the process of changing how providers work. Sadly this document -hasn't been fully updated yet. - -We are in the process of changing all providers from using `pkg/diff` to -`pkg/diff2`. diff2 is much easier to use as it does all the hard work for you. -Providers are easier to write, there's less code for you to write, and fewer -chances to make mistakes. +## Step 2: Pick a base provider -New providers only need to implement diff2. Older providers are implemented -both ways, with a flag (`--diff2`) enabling the newer code. Soon the new code -will become the default, then the old code will be removed. +It's a good idea to start by copying a similar provider. -The file `pkg/diff2/diff2.go` has instructions about how to use the new diff2 system. -You can also do `grep diff2.By providers/*/*.go` to find providers that use -the new system. +How can you tell a provider is similar? -Each DNS provider's API is different. Some update one DNS record at a time. +Each DNS provider's API falls into one of 4 category. Some update one DNS record at a time. Others, the only change they permit is to upload the entire zone even if only one record changed! Others are somewhere in between: all records at a label must be updated at once, or all records -in a RecordSet (the label + rType). diff2 provides functions for all of these situations: +in a RecordSet (the label + rType). -diff2.ByRecord() -- Updates are done one DNS record at a time. New records are added. Changes and deletes refer to an ID assigned to the record by the provider. -diff2.ByLabel() -- Updates are done for an entire label. Adds and changes are done by sending one or more records that will appear at that label (i.e. www.example.com). Deletes delete all records at that label. -diff2.ByRecordSet() -- Similar to ByLabel() but updates are done on the label+type level. If www.example.com has 2 A records and 2 MX records, +In summary, provider APIs basically fall into four general categories: +* Updates are done one record at a time (Record) +* Updates are done one label at a time (Label) +* Updates are done one label+type at a time (RecordSet) +* Updates require the entire zone to be uploaded (Zone). +To determine your provider's category, review your API documentation. +To determine an existing provider's category, see which `diff2.By*()` function is used. -## Step 2: Pick a base provider - -Pick a similar provider as your base. Providers basically fall -into three general categories: - -NOTE: diff2 changes this. For now, you can simply run `grep diff2.By providers/*/*.go` to see which -providers use ByZone, ByLabel, ByRecord, ByRecordSet and pick a similar provider to copy from. +DNSControl provides 4 helper functions that do all the hard work for +you. As input, they take the existing zone (what was downloaded via +the API) and the desired zone (what is in `dnsconfig.js`). They +return a list of instructions. Implement handlers for the instructions +and DNSControl is able to perform `dnscontrol push`. -* **zone:** The API requires you to upload the entire zone every time. (BIND, NAMECHEAP). -* **incremental-record:** The API lets you add/change/delete individual DNS records. (CLOUDFLARE, DNSIMPLE, NAMEDOTCOM, GCLOUD, HEXONET) -* **incremental-label:** Like incremental-record, but if there are - multiple records on a label (for example, example www.example.com -has A and MX records), you have to replace all the records at that -label. (GANDI_V5) -* **incremental-label-type:** Like incremental-record, but updates to any records at a label have to be done by type. For example, if a label (www.example.com) has many A and MX records, even the smallest change to one of the A records requires replacing all the A records. Any changes to the MX records requires replacing all the MX records. If an A record is converted to a CNAME, one must remove all the A records in one call, and add the CNAME record with another call. This is deceptively difficult to get right; if you have the choice between incremental-label-type and incremental-label, pick incremental-label. (DESEC, ROUTE53) -* **registrar only:** These providers are registrars but do not provide DNS service. (EASYNAME, INTERNETBS, OPENSRS) +The functions are: -All DNS providers use the "diff" module to detect differences. It takes -two zones and returns records that are unchanged, created, deleted, -and modified. -The zone providers use the -information to print a human-readable list of what is being changed, -but upload the entire new zone. -The incremental providers use the differences to -update individual records or recordsets. +* diff2.ByRecord() -- Updates are done one DNS record at a time. New records are added. Changes and deletes refer to an ID assigned to the record by the provider. +* diff2.ByLabel() -- Updates are done for an entire label. Adds and changes are done by sending one or more records that will appear at that label (i.e. www.example.com). Deletes delete all records at that label. +* diff2.ByRecordSet() -- Similar to ByLabel() but updates are done on the label+type level. If www.example.com has 2 A records and 2 MX records, updates must replace all the A records, or all the MX records, or add records of a different type. +* diff2.ByZone() -- Updates are done by uploading the entire zone every time. +The file `pkg/diff2/diff2.go` has instructions about how to use the diff2 system. ## Step 3: Create the driver skeleton @@ -134,6 +114,7 @@ The main driver should be called `providers/name/nameProvider.go`. The API abstraction is usually in a separate file (often called `api.go`). +Directory names should be consitent. It should be all lowercase and match the ALLCAPS provider name. ## Step 4: Activate the driver From 4e8fb894ef66528b4a9d53a877d25ed341ac55ba Mon Sep 17 00:00:00 2001 From: Tom Limoncelli Date: Tue, 5 Dec 2023 10:02:55 -0500 Subject: [PATCH 053/438] CSCGLOBAL: Be less noisy about rate limit delays (#2686) --- providers/cscglobal/api.go | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/providers/cscglobal/api.go b/providers/cscglobal/api.go index 6ae57f5c61..161acccc46 100644 --- a/providers/cscglobal/api.go +++ b/providers/cscglobal/api.go @@ -647,7 +647,7 @@ func (client *providerClient) geturl(url string) ([]byte, error) { // Default CSCGlobal rate limit is twenty requests per second var backoff = time.Second - const maxBackoff = time.Second * 15 + const maxBackoff = time.Second * 25 retry: resp, err := hclient.Do(req) @@ -666,9 +666,9 @@ retry: if string(bodyString) == "Requests exceeded API Rate limit." { // a simple exponential back-off with a 3-minute max. - if backoff > 10 { + if backoff > (time.Second * 10) { // With this provider backups seem to be pretty common. Only - // announce it when the problem gets really bad. + // announce it for long delays. printer.Printf("Delaying %v due to ratelimit (CSCGLOBAL)\n", backoff) } time.Sleep(backoff) From dbb724b911477a0a696d5a4aa18fe31d1c0c4ecf Mon Sep 17 00:00:00 2001 From: Jan-Philipp Benecke Date: Tue, 5 Dec 2023 22:50:25 +0100 Subject: [PATCH 054/438] CLOUDFLARE: Fixed bug: Zone not populated with records if domain was created in the same run (#2690) Signed-off-by: Jan-Philipp Benecke --- providers/cloudflare/cloudflareProvider.go | 1 + 1 file changed, 1 insertion(+) diff --git a/providers/cloudflare/cloudflareProvider.go b/providers/cloudflare/cloudflareProvider.go index 432de0cf97..8a502810b2 100644 --- a/providers/cloudflare/cloudflareProvider.go +++ b/providers/cloudflare/cloudflareProvider.go @@ -823,6 +823,7 @@ func (c *cloudflareProvider) EnsureZoneExists(domain string) error { var id string id, err := c.createZone(domain) printer.Printf("Added zone for %s to Cloudflare account: %s\n", domain, id) + c.domainIndex = nil // clear the index to let the following functions get a fresh list with nameservers etc.. return err } From 8541fb8510543ad77b780012123107561439126f Mon Sep 17 00:00:00 2001 From: Matthew Gamble Date: Tue, 5 Dec 2023 16:59:32 -0500 Subject: [PATCH 055/438] AZURE_PRIVATE_DNS: Enable building this provider by default (#2688) --- providers/_all/all.go | 1 + 1 file changed, 1 insertion(+) diff --git a/providers/_all/all.go b/providers/_all/all.go index 9f6ab843b6..e1b450afa9 100644 --- a/providers/_all/all.go +++ b/providers/_all/all.go @@ -6,6 +6,7 @@ import ( _ "github.com/StackExchange/dnscontrol/v4/providers/akamaiedgedns" _ "github.com/StackExchange/dnscontrol/v4/providers/autodns" _ "github.com/StackExchange/dnscontrol/v4/providers/axfrddns" + _ "github.com/StackExchange/dnscontrol/v4/providers/azure_private_dns" _ "github.com/StackExchange/dnscontrol/v4/providers/azuredns" _ "github.com/StackExchange/dnscontrol/v4/providers/bind" _ "github.com/StackExchange/dnscontrol/v4/providers/cloudflare" From 742eaaf75fa0ad196aa1171de4e583122fa3467c Mon Sep 17 00:00:00 2001 From: Tom Limoncelli Date: Wed, 6 Dec 2023 14:45:51 -0500 Subject: [PATCH 056/438] MSDNS: Remove pssession from docs (it doesn't work) (#2689) --- documentation/providers/msdns.md | 4 ---- 1 file changed, 4 deletions(-) diff --git a/documentation/providers/msdns.md b/documentation/providers/msdns.md index 31eb419dd2..d3991d3457 100644 --- a/documentation/providers/msdns.md +++ b/documentation/providers/msdns.md @@ -13,8 +13,6 @@ DNSControl will use `New-PSSession` to execute the commands remotely if DNS and DNSControl are both updating a zone, there will be unhappiness. DNSControl will blindly remove the dynamic records unless precautions such as `IGNORE*` and `NO_PURGE` are in use. -* This is a new provider and has not been tested extensively, - especially the `pssession` feature. # Running on Non-Windows systems @@ -30,7 +28,6 @@ To use this provider, add an entry to `creds.json` with `TYPE` set to `MSDNS` along with other settings: * `dnsserver`: (optional) the name of the Microsoft DNS Server to communicate with. -* `pssession`: (optional) the name of the PowerShell PSSession host to run commands on. * `psusername`: (optional) the username to connect to the PowerShell PSSession host. * `pspassword`: (optional) the password to connect to the PowerShell PSSession host. @@ -42,7 +39,6 @@ Example: "msdns": { "TYPE": "MSDNS", "dnsserver": "ny-dc01", - "pssession": "mywindowshost", "psusername": "mywindowsusername", "pspassword": "mysupersecurepassword" } From 7e5d0881b19629025ff2ab6e8f36300cd72fcf05 Mon Sep 17 00:00:00 2001 From: Jeffrey Cafferata Date: Wed, 6 Dec 2023 22:19:51 +0100 Subject: [PATCH 057/438] DOCS: Providers: Fixed the broken absolute link (#2696) --- documentation/providers.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/documentation/providers.md b/documentation/providers.md index 1ab8aac789..e65109c0c8 100644 --- a/documentation/providers.md +++ b/documentation/providers.md @@ -168,7 +168,7 @@ code to support this provider, we'd be glad to help in any way. #### Q: Why are the above GitHub issues marked "closed"? -A: Following [the bug triage process](/developer-info/bug-triage), the request +A: Following [the bug triage process](bug-triage.md), the request is closed once it is added to this list. If someone chooses to implement the provider, they re-open the issue. From 9fd65daf5cbab4d5223862ccf195dfda3003724d Mon Sep 17 00:00:00 2001 From: Jeffrey Cafferata Date: Wed, 6 Dec 2023 22:20:59 +0100 Subject: [PATCH 058/438] DOCS: Removed the (by GitBook) broken GitHub links (#2694) --- documentation/writing-providers.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/documentation/writing-providers.md b/documentation/writing-providers.md index 1e44de3630..a9f422ab7b 100644 --- a/documentation/writing-providers.md +++ b/documentation/writing-providers.md @@ -203,11 +203,11 @@ an automated way to test for this bug. The manual steps are here in ## Step 9: Update docs -* Edit [README.md](https://github.com/StackExchange/dnscontrol): Add the provider to the bullet list. -* Edit [documentation/providers.md](https://github.com/StackExchange/dnscontrol/blob/master/documentation/providers.md): Add the provider to the provider list. -* Edit [documentation/SUMMARY.md](https://github.com/StackExchange/dnscontrol/blob/master/documentation/SUMMARY.md): Add the provider to the provider list. +* Edit `README.md`: Add the provider to the bullet list. +* Edit `documentation/providers.md`: Add the provider to the provider list. +* Edit `documentation/SUMMARY.md`: Add the provider to the provider list. * Create `documentation/providers/PROVIDERNAME.md`: Use one of the other files in that directory as a base. -* Edit [OWNERS](https://github.com/StackExchange/dnscontrol/blob/master/OWNERS): Add the directory name and your GitHub username. +* Edit `OWNERS`: Add the directory name and your GitHub username. ## Step 10: Submit a PR From 0c7004825329e47221d5ec9e3020c06e1bacc46a Mon Sep 17 00:00:00 2001 From: Jeffrey Cafferata Date: Wed, 6 Dec 2023 22:22:02 +0100 Subject: [PATCH 059/438] DOCS: Removed the Zoo cross-platform environment variables package (#2693) --- documentation/integration-tests.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/documentation/integration-tests.md b/documentation/integration-tests.md index af81388071..a0c7baee98 100644 --- a/documentation/integration-tests.md +++ b/documentation/integration-tests.md @@ -13,7 +13,7 @@ For each step, it will run the config once and expect changes. It will run it ag ## Running a test 1. The integration tests need a test domain to run on. All the records of this domain will be deleted! -2. Define all environment variables expected for the provider you wish to run. I setup a local `.env` file with the appropriate values and use [zoo](https://github.com/jsonmaur/zoo) to run my commands. +2. Define all environment variables expected for the provider you wish to run. 3. run `cd integrationTest && go test -v -provider $NAME` where $NAME is the name of the provider you wish to run. Example: From 377193926c293fa7b95dfd56dc83aebf641b1a1e Mon Sep 17 00:00:00 2001 From: Tom Limoncelli Date: Wed, 6 Dec 2023 16:23:18 -0500 Subject: [PATCH 060/438] CHORE: Clarify TXT string limits (#2691) --- pkg/rejectif/txt.go | 12 ++++++++++++ providers/cscglobal/auditrecords.go | 2 -- providers/digitalocean/auditrecords.go | 4 ---- providers/loopia/auditrecords.go | 16 ++-------------- providers/msdns/auditrecords.go | 2 +- 5 files changed, 15 insertions(+), 21 deletions(-) diff --git a/pkg/rejectif/txt.go b/pkg/rejectif/txt.go index f9b8427e94..2503f158fc 100644 --- a/pkg/rejectif/txt.go +++ b/pkg/rejectif/txt.go @@ -73,3 +73,15 @@ func TxtLongerThan255(rc *models.RecordConfig) error { } return nil } + +// TxtLongerThan returns a function that audits TXT records for length +// greater than maxLength. +func TxtLongerThan(maxLength int) func(rc *models.RecordConfig) error { + return func(rc *models.RecordConfig) error { + m := maxLength + if len(rc.GetTargetTXTJoined()) > m { + return fmt.Errorf("TXT records longer than %d octets (chars)", m) + } + return nil + } +} diff --git a/providers/cscglobal/auditrecords.go b/providers/cscglobal/auditrecords.go index 87ad6f3380..5cfee5a280 100644 --- a/providers/cscglobal/auditrecords.go +++ b/providers/cscglobal/auditrecords.go @@ -21,8 +21,6 @@ func AuditRecords(records []*models.RecordConfig) []error { a.Add("TXT", rejectif.TxtIsEmpty) // Last verified 2023-12-03 - //a.Add("TXT", rejectif.TxtLongerThan255) // Last verified 2022-06-10 - return a.Audit(records) } diff --git a/providers/digitalocean/auditrecords.go b/providers/digitalocean/auditrecords.go index a6e9eff829..01e7f50013 100644 --- a/providers/digitalocean/auditrecords.go +++ b/providers/digitalocean/auditrecords.go @@ -21,10 +21,6 @@ func AuditRecords(records []*models.RecordConfig) []error { a.Add("TXT", rejectif.TxtHasBackslash) // Last verified 2023-11-11 - a.Add("TXT", rejectif.TxtHasDoubleQuotes) // Last verified 2021-03-01 - // Double-quotes not permitted in TXT strings. I have a hunch that - // this is due to a broken parser on the DO side. - a.Add("TXT", rejectif.TxtIsEmpty) // Last verified 2023-11-11 return a.Audit(records) diff --git a/providers/loopia/auditrecords.go b/providers/loopia/auditrecords.go index d9d8cb2d5f..e8137f0637 100644 --- a/providers/loopia/auditrecords.go +++ b/providers/loopia/auditrecords.go @@ -1,8 +1,6 @@ package loopia import ( - "fmt" - "github.com/StackExchange/dnscontrol/v4/models" "github.com/StackExchange/dnscontrol/v4/pkg/rejectif" ) @@ -15,20 +13,10 @@ func AuditRecords(records []*models.RecordConfig) []error { a.Add("TXT", rejectif.TxtIsEmpty) // Last verified 2023-03-10: Loopia returns 404 - //Loopias TXT length limit appears to be 450 octets - a.Add("TXT", TxtHasSegmentLen450orLonger) + // Loopias TXT length limit appears to be 450 octets + a.Add("TXT", rejectif.TxtLongerThan(450)) // Last verified 2023-03-10 a.Add("MX", rejectif.MxNull) // Last verified 2023-03-23 return a.Audit(records) } - -// TxtHasSegmentLen450orLonger audits TXT records for strings that are >450 octets. -func TxtHasSegmentLen450orLonger(rc *models.RecordConfig) error { - for _, txt := range rc.GetTargetTXTSegmented() { - if len(txt) > 450 { - return fmt.Errorf("%q txtstring length > 450", rc.GetLabel()) - } - } - return nil -} diff --git a/providers/msdns/auditrecords.go b/providers/msdns/auditrecords.go index 8694ffcae9..f3fe4fa3dd 100644 --- a/providers/msdns/auditrecords.go +++ b/providers/msdns/auditrecords.go @@ -19,7 +19,7 @@ func AuditRecords(records []*models.RecordConfig) []error { a.Add("TXT", rejectif.TxtHasDoubleQuotes) // Last verified 2023-02-02 - a.Add("TXT", rejectif.TxtLongerThan255) // Last verified 2023-02-02 + a.Add("TXT", rejectif.TxtLongerThan(255)) // Last verified 2023-02-02 a.Add("TXT", rejectif.TxtHasSingleQuotes) // Last verified 2023-02-02 From 3b6643b12d0172d959a2cb4899778c02494044e5 Mon Sep 17 00:00:00 2001 From: Tom Limoncelli Date: Wed, 6 Dec 2023 17:29:55 -0500 Subject: [PATCH 061/438] AZURE_PRIVATE_DNS: Rename module to conform to Go styleguide (#2697) --- OWNERS | 2 +- documentation/providers.md | 1 + providers/_all/all.go | 2 +- .../{azure_private_dns => azureprivatedns}/auditrecords.go | 2 +- .../azurePrivateDnsProvider.go | 2 +- 5 files changed, 5 insertions(+), 4 deletions(-) rename providers/{azure_private_dns => azureprivatedns}/auditrecords.go (94%) rename providers/{azure_private_dns => azureprivatedns}/azurePrivateDnsProvider.go (99%) diff --git a/OWNERS b/OWNERS index 7c34732a41..a436984258 100644 --- a/OWNERS +++ b/OWNERS @@ -2,7 +2,7 @@ providers/akamaiedgedns @svernick providers/autodns @arnoschoon providers/axfrddns @hnrgrgr providers/azuredns @vatsalyagoel -providers/azure_private_dns @matthewmgamble +providers/azureprivatedns @matthewmgamble providers/bind @tlimoncelli providers/cloudflare @tresni providers/cloudns @pragmaton diff --git a/documentation/providers.md b/documentation/providers.md index e65109c0c8..917baab155 100644 --- a/documentation/providers.md +++ b/documentation/providers.md @@ -18,6 +18,7 @@ If a feature is definitively not supported for whatever reason, we would also li | [`AUTODNS`](providers/autodns.md) | ❌ | ✅ | ❌ | ✅ | ✅ | ❔ | ❔ | ❔ | ❌ | ❔ | ✅ | ❌ | ❌ | ❌ | ❔ | ❌ | ❌ | ✅ | ✅ | | [`AXFRDDNS`](providers/axfrddns.md) | ❌ | ✅ | ❌ | ❔ | ✅ | ✅ | ❔ | ✅ | ✅ | ❔ | ✅ | ✅ | ✅ | ❔ | ✅ | ❌ | ❌ | ❌ | ❌ | | [`AZURE_DNS`](providers/azure_dns.md) | ✅ | ✅ | ❌ | ❌ | ✅ | ❔ | ❌ | ❌ | ✅ | ❔ | ✅ | ❌ | ❌ | ❔ | ❔ | ✅ | ✅ | ✅ | ✅ | +| [`AZURE_PRIVATE_DNS`](providers/azure_private_dns.md) | ✅ | ✅ | ❌ | ❌ | ❌ | ❔ | ❌ | ❌ | ✅ | ❔ | ✅ | ❌ | ❌ | ❔ | ❔ | ✅ | ✅ | ✅ | ✅ | | [`BIND`](providers/bind.md) | ✅ | ✅ | ❌ | ❔ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ❌ | ✅ | | [`CLOUDFLAREAPI`](providers/cloudflareapi.md) | ✅ | ✅ | ❌ | ✅ | ✅ | ❔ | ❌ | ✅ | ✅ | ❔ | ✅ | ✅ | ✅ | ❔ | ❔ | ❌ | ✅ | ✅ | ✅ | | [`CLOUDNS`](providers/cloudns.md) | ❌ | ✅ | ❌ | ✅ | ✅ | ❔ | ❌ | ❔ | ✅ | ❔ | ✅ | ✅ | ✅ | ❔ | ❔ | ❔ | ✅ | ✅ | ✅ | diff --git a/providers/_all/all.go b/providers/_all/all.go index e1b450afa9..48be689e94 100644 --- a/providers/_all/all.go +++ b/providers/_all/all.go @@ -6,8 +6,8 @@ import ( _ "github.com/StackExchange/dnscontrol/v4/providers/akamaiedgedns" _ "github.com/StackExchange/dnscontrol/v4/providers/autodns" _ "github.com/StackExchange/dnscontrol/v4/providers/axfrddns" - _ "github.com/StackExchange/dnscontrol/v4/providers/azure_private_dns" _ "github.com/StackExchange/dnscontrol/v4/providers/azuredns" + _ "github.com/StackExchange/dnscontrol/v4/providers/azureprivatedns" _ "github.com/StackExchange/dnscontrol/v4/providers/bind" _ "github.com/StackExchange/dnscontrol/v4/providers/cloudflare" _ "github.com/StackExchange/dnscontrol/v4/providers/cloudns" diff --git a/providers/azure_private_dns/auditrecords.go b/providers/azureprivatedns/auditrecords.go similarity index 94% rename from providers/azure_private_dns/auditrecords.go rename to providers/azureprivatedns/auditrecords.go index 6c478a955d..cea8335b2a 100644 --- a/providers/azure_private_dns/auditrecords.go +++ b/providers/azureprivatedns/auditrecords.go @@ -1,4 +1,4 @@ -package azure_private_dns +package azureprivatedns import ( "github.com/StackExchange/dnscontrol/v4/models" diff --git a/providers/azure_private_dns/azurePrivateDnsProvider.go b/providers/azureprivatedns/azurePrivateDnsProvider.go similarity index 99% rename from providers/azure_private_dns/azurePrivateDnsProvider.go rename to providers/azureprivatedns/azurePrivateDnsProvider.go index c798532dae..a6484a4405 100644 --- a/providers/azure_private_dns/azurePrivateDnsProvider.go +++ b/providers/azureprivatedns/azurePrivateDnsProvider.go @@ -1,4 +1,4 @@ -package azure_private_dns +package azureprivatedns import ( "context" From cd371c114924377e13a7a0d809ce7459eafca4f7 Mon Sep 17 00:00:00 2001 From: Gert Van Gool Date: Fri, 8 Dec 2023 08:58:24 -0800 Subject: [PATCH 062/438] INWX: support MxNull records (#2700) Co-authored-by: Tom Limoncelli --- providers/inwx/auditrecords.go | 2 -- providers/inwx/inwxProvider.go | 12 ++++++++++-- 2 files changed, 10 insertions(+), 4 deletions(-) diff --git a/providers/inwx/auditrecords.go b/providers/inwx/auditrecords.go index fb15d2e71b..64dff42e24 100644 --- a/providers/inwx/auditrecords.go +++ b/providers/inwx/auditrecords.go @@ -11,8 +11,6 @@ import ( func AuditRecords(records []*models.RecordConfig) []error { a := rejectif.Auditor{} - a.Add("MX", rejectif.MxNull) // Last verified 2020-12-28 - a.Add("SRV", rejectif.SrvHasNullTarget) // Last verified 2020-12-28 a.Add("TXT", rejectif.TxtHasBackticks) // Last verified 2021-03-01 diff --git a/providers/inwx/inwxProvider.go b/providers/inwx/inwxProvider.go index c511d85b6a..f615d80829 100644 --- a/providers/inwx/inwxProvider.go +++ b/providers/inwx/inwxProvider.go @@ -180,7 +180,11 @@ func makeNameserverRecordRequest(domain string, rec *models.RecordConfig) *goinw req.Content = content[:len(content)-1] case "MX": req.Priority = int(rec.MxPreference) - req.Content = content[:len(content)-1] + if content == "." { + req.Content = content + } else { + req.Content = content[:len(content)-1] + } case "SRV": req.Priority = int(rec.SrvPriority) req.Content = fmt.Sprintf("%d %d %v", rec.SrvWeight, rec.SrvPort, content[:len(content)-1]) @@ -305,7 +309,11 @@ func (api *inwxAPI) GetZoneRecords(domain string, meta map[string]string) (model "PTR": true, } if rtypeAddDot[record.Type] { - record.Content = record.Content + "." + if record.Type == "MX" && record.Content == "." { + // null records don't need to be modified + } else { + record.Content = record.Content + "." + } } rc := &models.RecordConfig{ From e917568addf8ca64b55e439f90717d9bf8a56a3d Mon Sep 17 00:00:00 2001 From: Jeffrey Cafferata Date: Sun, 10 Dec 2023 16:26:41 +0100 Subject: [PATCH 063/438] CICD: Removed the old Travis configurations (#2707) --- .travis.yml | 21 ------ build/validate/validate.go | 130 ------------------------------------- 2 files changed, 151 deletions(-) delete mode 100644 .travis.yml delete mode 100644 build/validate/validate.go diff --git a/.travis.yml b/.travis.yml deleted file mode 100644 index ec3b1fec7c..0000000000 --- a/.travis.yml +++ /dev/null @@ -1,21 +0,0 @@ -language: go - -go: - - 1.14.x - -install: pwd - -script: - - go run -mod=readonly build/validate/validate.go - - go test -mod=readonly ./... - -notifications: - email: - on_success: never # default: change - on_failure: always # default: always - webhooks: - urls: - - https://webhooks.gitter.im/e/4f27a4a85d6f4475be19 - on_success: always - on_failure: always - on_start: always diff --git a/build/validate/validate.go b/build/validate/validate.go deleted file mode 100644 index de90ef68ac..0000000000 --- a/build/validate/validate.go +++ /dev/null @@ -1,130 +0,0 @@ -package main - -import ( - "context" - "crypto/aes" - "crypto/cipher" - "encoding/base64" - "fmt" - "os" - "os/exec" - "strings" - - "github.com/google/go-github/v35/github" - "golang.org/x/oauth2" -) - -func main() { - failed := false - - run := func(ctx string, preStatus string, goodStatus string, f func() error) { - setStatus(stPending, preStatus, ctx) - if err := f(); err != nil { - fmt.Println(err) - setStatus(stError, err.Error(), ctx) - failed = true - } else { - setStatus(stSuccess, goodStatus, ctx) - } - } - - run("gofmt", "Checking gofmt", "gofmt ok", checkGoFmt) - run("gogen", "Checking go generate", "go generate ok", checkGoGenerate) - if failed { - os.Exit(1) - } -} - -func checkGoFmt() error { - cmd := exec.Command("gofmt", "-s", "-l", ".") - out, err := cmd.CombinedOutput() - if err != nil { - return err - } - if len(out) == 0 { - return nil - } - files := strings.Split(string(out), "\n") - fList := "" - for _, f := range files { - if strings.HasPrefix(f, "vendor") { - continue - } - if fList != "" { - fList += "\n" - } - fList += f - } - if fList == "" { - return nil - } - return fmt.Errorf("the following files need to have gofmt run on them:\n%s", fList) -} - -func checkGoGenerate() error { - cmd := exec.Command("go", "generate") - cmd.Stdout = os.Stdout - cmd.Stderr = os.Stderr - err := cmd.Run() - if err != nil { - return err - } - modified, err := getModifiedFiles() - if err != nil { - return err - } - if len(modified) != 0 { - return fmt.Errorf("ERROR: The following files are modified after go generate:\n%s", strings.Join(modified, "\n")) - } - return nil -} - -func getModifiedFiles() ([]string, error) { - cmd := exec.Command("git", strings.Split("diff --name-only", " ")...) - out, err := cmd.CombinedOutput() - if err != nil { - return nil, err - } - if len(out) == 0 { - return nil, nil - } - return strings.Split(string(out), "\n"), nil -} - -const ( - stPending = "pending" - stSuccess = "success" - stError = "error" -) - -func setStatus(status string, desc string, ctx string) { - if commitish == "" || ctx == "" { - return - } - client.Repositories.CreateStatus(context.Background(), "StackExchange", "dnscontrol", commitish, &github.RepoStatus{ - Context: &ctx, - Description: &desc, - State: &status, - }) -} - -var client *github.Client -var commitish string - -func init() { - // not intended for security, just minimal obfuscation. - key, _ := base64.StdEncoding.DecodeString("qIOy76aRcXcxm3vb82tvZqW6JoYnpncgVKx7qej1y+4=") - iv, _ := base64.StdEncoding.DecodeString("okRtW8z6Mx04Y9yMk1cb5w==") - garb, _ := base64.StdEncoding.DecodeString("ut8AtS6re1g7m/onk0ciIq7OxNOdZ/tsQ5ay6OfxKcARnBGY0bQ+pA==") - c, _ := aes.NewCipher(key) - d := cipher.NewCFBDecrypter(c, iv) - t := make([]byte, len(garb)) - d.XORKeyStream(t, garb) - hc := oauth2.NewClient(context.Background(), oauth2.StaticTokenSource(&oauth2.Token{AccessToken: string(t)})) - client = github.NewClient(hc) - - // get current version if in travis build - if tc := os.Getenv("TRAVIS_COMMIT"); tc != "" { - commitish = tc - } -} From 11f072b887ba67a73fcd33e360422e3d6fbc3bad Mon Sep 17 00:00:00 2001 From: Jeffrey Cafferata Date: Sun, 10 Dec 2023 16:27:24 +0100 Subject: [PATCH 064/438] CICD: Removed the old Chocolatey configuration (#2706) --- dnscontrol.nuspec | 23 ----------------------- 1 file changed, 23 deletions(-) delete mode 100644 dnscontrol.nuspec diff --git a/dnscontrol.nuspec b/dnscontrol.nuspec deleted file mode 100644 index 015533866c..0000000000 --- a/dnscontrol.nuspec +++ /dev/null @@ -1,23 +0,0 @@ - - - - - dnscontrol - 0.0.0 - DnsControl - Stack Overflow - https://github.com/stackexchange/dnscontrol - 2020 - https://github.com/StackExchange/dnscontrol/blob/master/LICENSE - true - https://github.com/stackexchange/dnscontrol - https://docs.dnscontrol.org/ - dns - Synchronize your DNS to multiple providers from a simple DSL - This package simply installs the dnscontrol tool on your system - - - - - - From 99e3f9f0468cd81280f22f42adc4a7816b5e48d9 Mon Sep 17 00:00:00 2001 From: Jeffrey Cafferata Date: Sun, 10 Dec 2023 16:27:57 +0100 Subject: [PATCH 065/438] CICD: Removed the old Azure Pipelines configurations (#2705) --- azure-pipelines.yml | 70 --------------- build/azure-pipelines/choco.yaml | 19 ---- build/azure-pipelines/go-env.yaml | 6 -- build/azure-pipelines/integration.yml | 121 -------------------------- 4 files changed, 216 deletions(-) delete mode 100644 azure-pipelines.yml delete mode 100644 build/azure-pipelines/choco.yaml delete mode 100644 build/azure-pipelines/go-env.yaml delete mode 100644 build/azure-pipelines/integration.yml diff --git a/azure-pipelines.yml b/azure-pipelines.yml deleted file mode 100644 index 9ca9132c8b..0000000000 --- a/azure-pipelines.yml +++ /dev/null @@ -1,70 +0,0 @@ -trigger: - batch: "true" - branches: - include: - - master - -jobs: - -- job: Compile - strategy: - maxParallel: 3 - matrix: - Windows: - OS: windows - OSX: - OS: darwin - Linux: - OS: linux - steps: - - template: build/azure-pipelines/go-env.yaml - - script: "go run -mod=readonly build/build.go -os $(OS)" - -- job: "unittests" - displayName: "Run Unit Tests" - steps: - - template: build/azure-pipelines/go-env.yaml - - script: "go test -mod=readonly ./..." - -- job: "modtidy" - displayName: "Check Go Modules" - steps: - - template: build/azure-pipelines/go-env.yaml - - script: | - set -e - go mod tidy - git status --porcelain - git diff - [ ! -n "$(git status --porcelain go.mod go.sum)" ] || { echo "Error: go.mod/go.sum outdated, please run go mod tidy."; false; } - -- job: "modvendor" - displayName: "Check Go Vendor" - steps: - - template: build/azure-pipelines/go-env.yaml - - script: | - set -e - go mod vendor - git status --porcelain - [ ! -n "$(git status --porcelain vendor)" ] || { echo "Error: Vendor does not match go.mod/go.sum, please run go mod vendor."; false; } - -- job: "GoFmt" - displayName: "Check Go Formatting" - steps: - - template: build/azure-pipelines/go-env.yaml - - script: | - set -e - go fmt ./... - git status --porcelain - git diff - [ ! -n "$(git status --porcelain)" ] || { echo "Error: Go files not formatted, please run go fmt ./... ."; false; } - -- job: "GoGen" - displayName: "Check Go Generate" - steps: - - template: build/azure-pipelines/go-env.yaml - - script: | - set -e - go generate . - git status --porcelain - git diff - [ ! -n "$(git status --porcelain)" ] || { echo "Error: Generated files not up to date, please run go generate . ."; false; } diff --git a/build/azure-pipelines/choco.yaml b/build/azure-pipelines/choco.yaml deleted file mode 100644 index aa912913de..0000000000 --- a/build/azure-pipelines/choco.yaml +++ /dev/null @@ -1,19 +0,0 @@ -# Starter pipeline -# Start with a minimal pipeline that you can customize to build and deploy your code. -# Add steps that build, run tests, deploy, and more: -# https://aka.ms/yaml - -trigger: -- master - -pool: - vmImage: 'ubuntu-latest' - -steps: -- script: echo Hello, world! - displayName: 'Run a one-line script' - -- script: | - echo Add other tasks to build, test, and deploy your project. - echo See https://aka.ms/yaml - displayName: 'Run a multi-line script' diff --git a/build/azure-pipelines/go-env.yaml b/build/azure-pipelines/go-env.yaml deleted file mode 100644 index 9d2f56c441..0000000000 --- a/build/azure-pipelines/go-env.yaml +++ /dev/null @@ -1,6 +0,0 @@ -# shared step for setting up go env -# see https://docs.microsoft.com/en-us/azure/devops/pipelines/languages/go?view=azure-devops#build-a-container-image -steps: -- task: GoTool@0 - inputs: - version: '1.16' diff --git a/build/azure-pipelines/integration.yml b/build/azure-pipelines/integration.yml deleted file mode 100644 index c75efe39c9..0000000000 --- a/build/azure-pipelines/integration.yml +++ /dev/null @@ -1,121 +0,0 @@ -variables: - wd: '$(System.DefaultWorkingDirectory)/integrationTest' - -trigger: - batch: "true" - branches: - include: - - pipeline - -# Each provider gets its' own job. These will run in parallel. -# each job gets setup with only the env vars it needs for that run. -# these are defined in azure pipelines web ui as secret variables. - -jobs: - -- job: Route53 - steps: - - template: go-env.yaml - - script: go test -v -verbose -provider ROUTE53 - workingDirectory: $(wd) - env: - R53_DOMAIN: $(R53_DOMAIN) - R53_KEY_ID: $(R53_KEY_ID) - R53_KEY: $(R53_KEY) - -- job: GCloud - steps: - - template: go-env.yaml - - script: go test -v -verbose -provider GCLOUD - workingDirectory: $(wd) - env: - GCLOUD_DOMAIN: $(GCLOUD_DOMAIN) - GCLOUD_TYPE: $(GCLOUD_TYPE) - GCLOUD_EMAIL: $(GCLOUD_EMAIL) - GCLOUD_PROJECT: $(GCLOUD_PROJECT) - GCLOUD_PRIVATEKEY: $(GCLOUD_PRIVATEKEY) - -- job: NameDotCom - steps: - - template: go-env.yaml - - script: go test -v -verbose -provider NAMEDOTCOM - workingDirectory: $(wd) - env: - NAMEDOTCOM_DOMAIN: $(NAMEDOTCOM_DOMAIN) - NAMEDOTCOM_KEY: $(NAMEDOTCOM_KEY) - NAMEDOTCOM_USER: $(NAMEDOTCOM_USER) - -- job: Cloudflare - steps: - - template: go-env.yaml - - script: go test -v -timeout 30m -verbose -provider CLOUDFLAREAPI - workingDirectory: $(wd) - env: - CF_TOKEN: $(CF_TOKEN) - -- job: DigitalOcean - steps: - - template: go-env.yaml - - script: go test -v -verbose -provider DIGITALOCEAN - workingDirectory: $(wd) - env: - DO_DOMAIN: $(DO_DOMAIN) - DO_TOKEN: $(DO_TOKEN) - -- job: GandiV5 - steps: - - template: go-env.yaml - - script: go test -v -verbose -provider GANDI_V5 - workingDirectory: $(wd) - env: - GANDI_KEY: $(GANDI_V5_APIKEY) - GANDI_DOMAIN: $(GANDI_V5_DOMAIN) - -# - job: GandiLive -# steps: -# - template: go-env.yaml -# - script: go test -v -verbose -provider GANDI-LIVEDNS -# workingDirectory: $(wd) -# env: -# GANDILIVE_KEY: $(GANDILIVE_KEY) -# GANDILIVE_DOMAIN: $(GANDILIVE_DOMAIN) - -# - job: NS1 -# steps: -# - template: go-env.yaml -# - script: go test -v -verbose -provider NS1 -# workingDirectory: $(wd) -# env: -# NS1_TOKEN: $(NS1_TOKEN) -# NS1_DOMAIN: $(NS1_DOMAIN) - -- job: DNSIMPLE - steps: - - template: go-env.yaml - - script: go test -v -verbose -provider DNSIMPLE - workingDirectory: $(wd) - env: - DNSIMPLE_TOKEN: $(DNSIMPLE_TOKEN) - DNSIMPLE_DOMAIN: $(DNSIMPLE_DOMAIN) - -- job: Vultr - steps: - - template: go-env.yaml - - script: go test -v -verbose -provider VULTR - workingDirectory: $(wd) - env: - VULTR_DOMAIN: $(VULTR_DOMAIN) - VULTR_TOKEN: $(VULTR_TOKEN) - -- job: Azure - steps: - - template: go-env.yaml - - script: go test -v -verbose -provider AZURE_DNS - workingDirectory: $(wd) - env: - AZURE_CLIENT_ID: $(AZ_CLIENTID) - AZURE_CLIENT_SECRET: $(AZ_CLIENTSECRET) - AZURE_DOMAIN: $(AZ_DOMAIN) - AZURE_RESOURCE_GROUP: $(AZ_RSGNAME) - AZURE_SUBSCRIPTION_ID: $(AZ_SUBSCRIPTIONID) - AZURE_TENANT_ID: $(AZ_TENANTID) From a6091f2ed4aa73bec6608dbb0174d06ff70083a4 Mon Sep 17 00:00:00 2001 From: Costas Drogos Date: Sun, 10 Dec 2023 16:29:09 +0100 Subject: [PATCH 066/438] BUG: Register an error if EnzureZoneExists fails (#2703) --- commands/previewPush.go | 1 + 1 file changed, 1 insertion(+) diff --git a/commands/previewPush.go b/commands/previewPush.go index 7ac4cce809..ebeff28cdc 100644 --- a/commands/previewPush.go +++ b/commands/previewPush.go @@ -211,6 +211,7 @@ func run(args PreviewArgs, push bool, interactive bool, out printer.CLI, report // this is the actual push, ensure domain exists at DSP if err := creator.EnsureZoneExists(domain.Name); err != nil { out.Warnf("Error creating domain: %s\n", err) + anyErrors = true continue // continue with next provider, as we couldn't create this one } } From 8f1b33ae17a6f1f776a1e3213f4f691445345fcf Mon Sep 17 00:00:00 2001 From: Jeffrey Cafferata Date: Sun, 10 Dec 2023 16:34:24 +0100 Subject: [PATCH 067/438] CICD: GoReleaser generates TypeScript file (#2704) Co-authored-by: Tom Limoncelli --- .gitignore | 1 + .goreleaser.yml | 4 +- commands/types/dnscontrol.d.ts | 2991 -------------------------------- 3 files changed, 4 insertions(+), 2992 deletions(-) delete mode 100644 commands/types/dnscontrol.d.ts diff --git a/.gitignore b/.gitignore index 84b1e05b47..70089b4c2e 100644 --- a/.gitignore +++ b/.gitignore @@ -1,4 +1,5 @@ /tmp +/commands/types/dnscontrol.d.ts dnscontrol-Darwin dnscontrol-Linux dnscontrol.exe diff --git a/.goreleaser.yml b/.goreleaser.yml index dc77e4f7da..ca667aa4ba 100644 --- a/.goreleaser.yml +++ b/.goreleaser.yml @@ -21,7 +21,9 @@ builds: - -linkmode=internal -s -w -X main.Version="{{ .Version }}" -X main.SHA="{{ .FullCommit }}" -X main.BuildTime={{ .Timestamp }} before: hooks: - - go mod tidy + - go fmt ./... + - go mod tidy + - go generate ./... changelog: sort: asc use: github diff --git a/commands/types/dnscontrol.d.ts b/commands/types/dnscontrol.d.ts deleted file mode 100644 index a850f30275..0000000000 --- a/commands/types/dnscontrol.d.ts +++ /dev/null @@ -1,2991 +0,0 @@ -// WARNING: These type definitions are experimental and subject to change in future releases. - -interface Domain { - name: string; - subdomain: string; - registrar: unknown; - meta: Record; - records: DNSRecord[]; - dnsProviders: Record; - defaultTTL: number; - nameservers: unknown[]; - ignored_names: unknown[]; - ignored_targets: unknown[]; - [key: string]: unknown; -} - -interface DNSRecord { - type: string; - meta: Record; - ttl: number; -} - -type DomainModifier = - | ((domain: Domain) => void) - | Partial - | DomainModifier[]; - -type RecordModifier = - | ((record: DNSRecord) => void) - | Partial; - -type Duration = - | `${number}${'s' | 'm' | 'h' | 'd' | 'w' | 'n' | 'y' | ''}` - | number /* seconds */; - - -/** - * `FETCH` is a wrapper for the [Fetch API](https://developer.mozilla.org/en-US/docs/Web/API/Fetch_API). This allows dynamically setting DNS records based on an external data source, e.g. the API of your cloud provider. - * - * Compared to `fetch` from Fetch API, `FETCH` will call [PANIC](PANIC.md) to terminate the execution of the script, and therefore DNSControl, if a network error occurs. - * - * Otherwise the syntax of `FETCH` is the same as `fetch`. - * - * `FETCH` is not enabled by default. Please read the warnings below. - * - * > WARNING: - * > - * > 1. Relying on external sources adds a point of failure. If the external source doesn't work, your script won't either. Please make sure you are aware of the consequences. - * > 2. Make sure DNSControl only uses verified configuration if you want to use `FETCH`. For example, an attacker can send Pull Requests to your config repo, and have your CI test malicious configurations and make arbitrary HTTP requests. Therefore, `FETCH` must be explicitly enabled with flag `--allow-fetch` on DNSControl invocation. - * - * ```javascript - * D("example.com", REG_MY_PROVIDER, DnsProvider(DSP_MY_PROVIDER), [ - * A("@", "1.2.3.4"), - * ]); - * - * FETCH("https://example.com", { - * // All three options below are optional - * headers: {"X-Authentication": "barfoo"}, - * method: "POST", - * body: "Hello World", - * }).then(function(r) { - * return r.text(); - * }).then(function(t) { - * // Example of generating record based on response - * D_EXTEND("example.com", [ - * TXT("@", t.slice(0, 100)), - * ]); - * }); - * ``` - */ -declare function FETCH( - url: string, - init?: { - method?: - | 'GET' - | 'POST' - | 'PUT' - | 'PATCH' - | 'DELETE' - | 'HEAD' - | 'OPTIONS'; - headers?: { [key: string]: string | string[] }; - // Ignored by the underlying code - // redirect: 'follow' | 'error' | 'manual'; - body?: string; - } -): Promise; - -interface FetchResponse { - readonly bodyUsed: boolean; - readonly headers: ResponseHeaders; - readonly ok: boolean; - readonly status: number; - readonly statusText: string; - readonly type: string; - - text(): Promise; - json(): Promise; -} - -interface ResponseHeaders { - get(name: string): string | undefined; - getAll(name: string): string[]; - has(name: string): boolean; - - append(name: string, value: string): void; - delete(name: string): void; - set(name: string, value: string): void; -} - - -declare function require(name: `${string}.json`): any; -declare function require(name: string): true; - -/** - * Issuer critical flag. CA that does not understand this tag will refuse to issue certificate for this domain. - * - * CAA record is supported only by BIND, Google Cloud DNS, Amazon Route 53 and OVH. Some certificate authorities may not support this record until the mandatory date of September 2017. - */ -declare const CAA_CRITICAL: RecordModifier; - -/** - * @deprecated - * This disables a safety check intended to prevent: - * 1. Two owners toggling a record between two settings. - * 2. The other owner wiping all records at this label, which won't - * be noticed until the next time dnscontrol is run. - * See https://github.com/StackExchange/dnscontrol/issues/1106 - */ -declare const IGNORE_NAME_DISABLE_SAFETY_CHECK: RecordModifier; - -// Cloudflare aliases: - -/** Proxy disabled. */ -declare const CF_PROXY_OFF: RecordModifier; -/** Proxy enabled. */ -declare const CF_PROXY_ON: RecordModifier; -/** Proxy+Railgun enabled. */ -declare const CF_PROXY_FULL: RecordModifier; - -/** Proxy default off for entire domain (the default) */ -declare const CF_PROXY_DEFAULT_OFF: DomainModifier; -/** Proxy default on for entire domain */ -declare const CF_PROXY_DEFAULT_ON: DomainModifier; -/** UniversalSSL off for entire domain */ -declare const CF_UNIVERSALSSL_OFF: DomainModifier; -/** UniversalSSL on for entire domain */ -declare const CF_UNIVERSALSSL_ON: DomainModifier; - -/** - * Set default values for CLI variables. See: https://dnscontrol.org/cli-variables - */ -declare function CLI_DEFAULTS(vars: Record): void; - -/** - * `END` permits the last item to include a comma. - * - * ```js - * D("foo.com", ... - * A(...), - * A(...), - * A(...), - * END) - * ``` - */ -declare const END: DomainModifier & RecordModifier; - -/** - * Permit labels like `"foo.bar.com.bar.com"` (normally an error) - * - * ```js - * D("bar.com", ... - * A("foo.bar.com", "10.1.1.1", DISABLE_REPEATED_DOMAIN_CHECK), - * ) - * ``` - */ -declare const DISABLE_REPEATED_DOMAIN_CHECK: RecordModifier; - - -/** - * A adds an A record To a domain. The name should be the relative label for the record. Use `@` for the domain apex. - * - * The address should be an ip address, either a string, or a numeric value obtained via [IP](../global/IP.md). - * - * Modifiers can be any number of [record modifiers](https://docs.dnscontrol.org/language-reference/record-modifiers) or JSON objects, which will be merged into the record's metadata. - * - * ```javascript - * D("example.com", REG_MY_PROVIDER, DnsProvider(DSP_MY_PROVIDER), - * A("@", "1.2.3.4"), - * A("foo", "2.3.4.5"), - * A("test.foo", IP("1.2.3.4"), TTL(5000)), - * A("*", "1.2.3.4", {foo: 42}) - * ); - * ``` - * - * @see https://docs.dnscontrol.org/language-reference/domain-modifiers/a - */ -declare function A(name: string, address: string | number, ...modifiers: RecordModifier[]): DomainModifier; - -/** - * AAAA adds an AAAA record To a domain. The name should be the relative label for the record. Use `@` for the domain apex. - * - * The address should be an IPv6 address as a string. - * - * Modifiers can be any number of [record modifiers](https://docs.dnscontrol.org/language-reference/record-modifiers) or JSON objects, which will be merged into the record's metadata. - * - * ```javascript - * var addrV6 = "2001:0db8:85a3:0000:0000:8a2e:0370:7334" - * - * D("example.com", REG_MY_PROVIDER, DnsProvider(DSP_MY_PROVIDER), - * AAAA("@", addrV6), - * AAAA("foo", addrV6), - * AAAA("test.foo", addrV6, TTL(5000)), - * AAAA("*", addrV6, {foo: 42}) - * ); - * ``` - * - * @see https://docs.dnscontrol.org/language-reference/domain-modifiers/aaaa - */ -declare function AAAA(name: string, address: string, ...modifiers: RecordModifier[]): DomainModifier; - -/** - * AKAMAICDN is a proprietary record type that is used to configure [Zone Apex Mapping](https://blogs.akamai.com/2019/08/fast-dns-zone-apex-mapping-dnssec.html). - * The AKAMAICDN target must be preconfigured in the Akamai network. - * - * @see https://docs.dnscontrol.org/language-reference/domain-modifiers/service-provider-specific/akamai-edge-dns/akamaicdn - */ -declare function AKAMAICDN(name: string, target: string, ...modifiers: RecordModifier[]): DomainModifier; - -/** - * ALIAS is a virtual record type that points a record at another record. It is analogous to a CNAME, but is usually resolved at request-time and served as an A record. Unlike CNAMEs, ALIAS records can be used at the zone apex (`@`) - * - * Different providers handle ALIAS records differently, and many do not support it at all. Attempting to use ALIAS records with a DNS provider type that does not support them will result in an error. - * - * The name should be the relative label for the domain. - * - * Target should be a string representing the target. If it is a single label we will assume it is a relative name on the current domain. If it contains *any* dots, it should be a fully qualified domain name, ending with a `.`. - * - * ```javascript - * D("example.com", REG_MY_PROVIDER, DnsProvider(DSP_MY_PROVIDER), - * ALIAS("@", "google.com."), // example.com -> google.com - * ); - * ``` - * - * @see https://docs.dnscontrol.org/language-reference/domain-modifiers/alias - */ -declare function ALIAS(name: string, target: string, ...modifiers: RecordModifier[]): DomainModifier; - -/** - * AUTODNSSEC_OFF tells the provider to disable AutoDNSSEC. It takes no - * parameters. - * - * See `AUTODNSSEC_ON` for further details. - * - * @see https://docs.dnscontrol.org/language-reference/domain-modifiers/autodnssec_off - */ -declare const AUTODNSSEC_OFF: DomainModifier; - -/** - * AUTODNSSEC_ON tells the provider to enable AutoDNSSEC. - * - * AUTODNSSEC_OFF tells the provider to disable AutoDNSSEC. - * - * AutoDNSSEC is a feature where a DNS provider can automatically manage - * DNSSEC for a domain. Not all providers support this. - * - * At this time, AUTODNSSEC_ON takes no parameters. There is no ability - * to tune what the DNS provider sets, no algorithm choice. We simply - * ask that they follow their defaults when enabling a no-fuss DNSSEC - * data model. - * - * NOTE: No parenthesis should follow these keywords. That is, the - * correct syntax is `AUTODNSSEC_ON` not `AUTODNSSEC_ON()` - * - * ```javascript - * D("example.com", REG_MY_PROVIDER, DnsProvider(DSP_MY_PROVIDER), - * AUTODNSSEC_ON, // Enable AutoDNSSEC. - * A("@", "10.1.1.1") - * ); - * - * D("insecure.com", REG_MY_PROVIDER, DnsProvider(DSP_MY_PROVIDER), - * AUTODNSSEC_OFF, // Disable AutoDNSSEC. - * A("@", "10.2.2.2") - * ); - * ``` - * - * If neither `AUTODNSSEC_ON` or `AUTODNSSEC_OFF` is specified for a - * domain no changes will be requested. - * - * @see https://docs.dnscontrol.org/language-reference/domain-modifiers/autodnssec_on - */ -declare const AUTODNSSEC_ON: DomainModifier; - -/** - * AZURE_ALIAS is a Azure specific virtual record type that points a record at either another record or an Azure entity. - * It is analogous to a CNAME, but is usually resolved at request-time and served as an A record. - * Unlike CNAMEs, ALIAS records can be used at the zone apex (`@`) - * - * Unlike the regular ALIAS directive, AZURE_ALIAS is only supported on AZURE. - * Attempting to use AZURE_ALIAS on another provider than Azure will result in an error. - * - * The name should be the relative label for the domain. - * - * The type can be any of the following: - * * A - * * AAAA - * * CNAME - * - * Target should be the Azure Id representing the target. It starts `/subscription/`. The resource id can be found in https://resources.azure.com/. - * - * The Target can : - * - * * Point to a public IP resource from a DNS `A/AAAA` record set. - * You can create an A/AAAA record set and make it an alias record set to point to a public IP resource (standard or basic). - * The DNS record set changes automatically if the public IP address changes or is deleted. - * Dangling DNS records that point to incorrect IP addresses are avoided. - * There is a current limit of 20 alias records sets per resource. - * * Point to a Traffic Manager profile from a DNS `A/AAAA/CNAME` record set. - * You can create an A/AAAA or CNAME record set and use alias records to point it to a Traffic Manager profile. - * It's especially useful when you need to route traffic at a zone apex, as traditional CNAME records aren't supported for a zone apex. - * For example, say your Traffic Manager profile is myprofile.trafficmanager.net and your business DNS zone is contoso.com. - * You can create an alias record set of type A/AAAA for contoso.com (the zone apex) and point to myprofile.trafficmanager.net. - * * Point to an Azure Content Delivery Network (CDN) endpoint. - * This is useful when you create static websites using Azure storage and Azure CDN. - * * Point to another DNS record set within the same zone. - * Alias records can reference other record sets of the same type. - * For example, a DNS CNAME record set can be an alias to another CNAME record set. - * This arrangement is useful if you want some record sets to be aliases and some non-aliases. - * - * ```javascript - * D("example.com", REG_MY_PROVIDER, DnsProvider("AZURE_DNS"), - * AZURE_ALIAS("foo", "A", "/subscriptions/726f8cd6-6459-4db4-8e6d-2cd2716904e2/resourceGroups/test/providers/Microsoft.Network/trafficManagerProfiles/testpp2"), // record for traffic manager - * AZURE_ALIAS("foo", "CNAME", "/subscriptions/726f8cd6-6459-4db4-8e6d-2cd2716904e2/resourceGroups/test/providers/Microsoft.Network/dnszones/example.com/A/quux."), // record in the same zone - * ); - * ``` - * - * @see https://docs.dnscontrol.org/language-reference/domain-modifiers/service-provider-specific/azure-dns/azure_alias - */ -declare function AZURE_ALIAS(name: string, type: "A" | "AAAA" | "CNAME", target: string, ...modifiers: RecordModifier[]): DomainModifier; - -/** - * `CAA()` adds a CAA record to a domain. The name should be the relative label for the record. Use `@` for the domain apex. - * - * Tag can be one of - * 1. `"issue"` - * 2. `"issuewild"` - * 3. `"iodef"` - * - * Value is a string. The format of the contents is different depending on the tag. DNSControl will handle any escaping or quoting required, similar to TXT records. For example use `CAA("@", "issue", "letsencrypt.org")` rather than `CAA("@", "issue", "\"letsencrypt.org\"")`. - * - * Flags are controlled by modifier: - * - `CAA_CRITICAL`: Issuer critical flag. CA that does not understand this tag will refuse to issue certificate for this domain. - * - * ```javascript - * D("example.com", REG_MY_PROVIDER, DnsProvider(DSP_MY_PROVIDER), - * // Allow letsencrypt to issue certificate for this domain - * CAA("@", "issue", "letsencrypt.org"), - * // Allow no CA to issue wildcard certificate for this domain - * CAA("@", "issuewild", ";"), - * // Report all violation to test@example.com. If CA does not support - * // this record then refuse to issue any certificate - * CAA("@", "iodef", "mailto:test@example.com", CAA_CRITICAL) - * ); - * ``` - * - * DNSControl contains a [`CAA_BUILDER`](../record/CAA_BUILDER.md) which can be used to simply create `CAA()` records for your domains. Instead of creating each CAA record individually, you can simply configure your report mail address, the authorized certificate authorities and the builder cares about the rest. - * - * @see https://docs.dnscontrol.org/language-reference/domain-modifiers/caa - */ -declare function CAA(name: string, tag: "issue" | "issuewild" | "iodef", value: string, ...modifiers: RecordModifier[]): DomainModifier; - -/** - * DNSControl contains a `CAA_BUILDER` which can be used to simply create - * [`CAA()`](../domain/CAA.md) records for your domains. Instead of creating each [`CAA()`](../domain/CAA.md) record - * individually, you can simply configure your report mail address, the - * authorized certificate authorities and the builder cares about the rest. - * - * ## Example - * - * For example you can use: - * - * ```javascript - * CAA_BUILDER({ - * label: "@", - * iodef: "mailto:test@example.com", - * iodef_critical: true, - * issue: [ - * "letsencrypt.org", - * "comodoca.com", - * ], - * issuewild: "none", - * }) - * ``` - * - * The parameters are: - * - * * `label:` The label of the CAA record. (Optional. Default: `"@"`) - * * `iodef:` Report all violation to configured mail address. - * * `iodef_critical:` This can be `true` or `false`. If enabled and CA does not support this record, then certificate issue will be refused. (Optional. Default: `false`) - * * `issue:` An array of CAs which are allowed to issue certificates. (Use `"none"` to refuse all CAs) - * * `issuewild:` An array of CAs which are allowed to issue wildcard certificates. (Can be simply `"none"` to refuse issuing wildcard certificates for all CAs) - * - * `CAA_BUILDER()` returns multiple records (when configured as example above): - * - * ```javascript - * CAA("@", "iodef", "mailto:test@example.com", CAA_CRITICAL) - * CAA("@", "issue", "letsencrypt.org") - * CAA("@", "issue", "comodoca.com") - * CAA("@", "issuewild", ";") - * ``` - * - * @see https://docs.dnscontrol.org/language-reference/domain-modifiers/caa_builder - */ -declare function CAA_BUILDER(opts: { label?: string; iodef: string; iodef_critical?: boolean; issue: string[]; issuewild: string }): DomainModifier; - -/** - * `CF_REDIRECT` uses Cloudflare-specific features ("Forwarding URL" Page Rules) to - * generate a HTTP 301 permanent redirect. - * - * If _any_ `CF_REDIRECT` or [`CF_TEMP_REDIRECT`](CF_TEMP_REDIRECT.md) functions are used then - * `dnscontrol` will manage _all_ "Forwarding URL" type Page Rules for the domain. - * Page Rule types other than "Forwarding URL” will be left alone. - * - * WARNING: Cloudflare does not currently fully document the Page Rules API and - * this interface is not extensively tested. Take precautions such as making - * backups and manually verifying `dnscontrol preview` output before running - * `dnscontrol push`. This is especially true when mixing Page Rules that are - * managed by DNSControl and those that aren't. - * - * HTTP 301 redirects are cached by browsers forever, usually ignoring any TTLs or - * other cache invalidation techniques. It should be used with great care. We - * suggest using a `CF_TEMP_REDIRECT` initially, then changing to a `CF_REDIRECT` - * only after sufficient time has elapsed to prove this is what you really want. - * - * This example redirects the bare (aka apex, or naked) domain to www: - * - * ```javascript - * D("example.com", REG_MY_PROVIDER, DnsProvider(DSP_MY_PROVIDER), - * CF_REDIRECT("example.com/*", "https://www.example.com/$1"), - * ); - * ``` - * - * @see https://docs.dnscontrol.org/language-reference/domain-modifiers/service-provider-specific/cloudflare-dns/cf_redirect - */ -declare function CF_REDIRECT(source: string, destination: string, ...modifiers: RecordModifier[]): DomainModifier; - -/** - * `CF_TEMP_REDIRECT` uses Cloudflare-specific features ("Forwarding URL" Page - * Rules) to generate a HTTP 302 temporary redirect. - * - * If _any_ [`CF_REDIRECT`](CF_REDIRECT.md) or `CF_TEMP_REDIRECT` functions are used then - * `dnscontrol` will manage _all_ "Forwarding URL" type Page Rules for the domain. - * Page Rule types other than "Forwarding URL” will be left alone. - * - * WARNING: Cloudflare does not currently fully document the Page Rules API and - * this interface is not extensively tested. Take precautions such as making - * backups and manually verifying `dnscontrol preview` output before running - * `dnscontrol push`. This is especially true when mixing Page Rules that are - * managed by DNSControl and those that aren't. - * - * ```javascript - * D("example.com", REG_MY_PROVIDER, DnsProvider(DSP_MY_PROVIDER), - * CF_TEMP_REDIRECT("example.example.com/*", "https://otherplace.yourdomain.com/$1"), - * ); - * ``` - * - * @see https://docs.dnscontrol.org/language-reference/domain-modifiers/service-provider-specific/cloudflare-dns/cf_temp_redirect - */ -declare function CF_TEMP_REDIRECT(source: string, destination: string, ...modifiers: RecordModifier[]): DomainModifier; - -/** - * `CF_WORKER_ROUTE` uses the [Cloudflare Workers](https://developers.cloudflare.com/workers/) - * API to manage [worker routes](https://developers.cloudflare.com/workers/platform/routes) - * for a given domain. - * - * If _any_ `CF_WORKER_ROUTE` function is used then `dnscontrol` will manage _all_ - * Worker Routes for the domain. To be clear: this means it will delete existing routes that - * were created outside of DNSControl. - * - * WARNING: This interface is not extensively tested. Take precautions such as making - * backups and manually verifying `dnscontrol preview` output before running - * `dnscontrol push`. - * - * This example assigns the patterns `api.example.com/*` and `example.com/api/*` to a `my-worker` script: - * - * ```javascript - * D("example.com", REG_MY_PROVIDER, DnsProvider(DSP_MY_PROVIDER), - * CF_WORKER_ROUTE("api.example.com/*", "my-worker"), - * CF_WORKER_ROUTE("example.com/api/*", "my-worker"), - * ); - * ``` - * - * @see https://docs.dnscontrol.org/language-reference/domain-modifiers/service-provider-specific/cloudflare-dns/cf_worker_route - */ -declare function CF_WORKER_ROUTE(pattern: string, script: string): DomainModifier; - -/** - * Documentation needed. - * - * @see https://docs.dnscontrol.org/language-reference/domain-modifiers/service-provider-specific/cloudns/cloudns_wr - */ -declare function CLOUDNS_WR(name: string, target: string, ...modifiers: RecordModifier[]): DomainModifier; - -/** - * CNAME adds a CNAME record to the domain. The name should be the relative label for the domain. - * Using `@` or `*` for CNAME records is not recommended, as different providers support them differently. - * - * Target should be a string representing the CNAME target. If it is a single label we will assume it is a relative name on the current domain. If it contains *any* dots, it should be a fully qualified domain name, ending with a `.`. - * - * ```javascript - * D("example.com", REG_MY_PROVIDER, DnsProvider(DSP_MY_PROVIDER), - * CNAME("foo", "google.com."), // foo.example.com -> google.com - * CNAME("abc", "@"), // abc.example.com -> example.com - * CNAME("def", "test"), // def.example.com -> test.example.com - * ); - * ``` - * - * @see https://docs.dnscontrol.org/language-reference/domain-modifiers/cname - */ -declare function CNAME(name: string, target: string, ...modifiers: RecordModifier[]): DomainModifier; - -/** - * `D` adds a new Domain for DNSControl to manage. The first two arguments are required: the domain name (fully qualified `example.com` without a trailing dot), and the - * name of the registrar (as previously declared with [NewRegistrar](NewRegistrar.md)). Any number of additional arguments may be included to add DNS Providers with [DNSProvider](NewDnsProvider.md), - * add records with [A](../domain/A.md), [CNAME](../domain/CNAME.md), and so forth, or add metadata. - * - * Modifier arguments are processed according to type as follows: - * - * - A function argument will be called with the domain object as it's only argument. Most of the [built-in modifier functions](https://docs.dnscontrol.org/language-reference/domain-modifiers) return such functions. - * - An object argument will be merged into the domain's metadata collection. - * - An array argument will have all of it's members evaluated recursively. This allows you to combine multiple common records or modifiers into a variable that can - * be used like a macro in multiple domains. - * - * ```javascript - * // simple domain - * D("example.com", REG_MY_PROVIDER, DnsProvider(DSP_MY_PROVIDER), - * A("@","1.2.3.4"), - * CNAME("test", "foo.example2.com.") - * ); - * - * // "macro" for records that can be mixed into any zone - * var GOOGLE_APPS_DOMAIN_MX = [ - * MX("@", 1, "aspmx.l.google.com."), - * MX("@", 5, "alt1.aspmx.l.google.com."), - * MX("@", 5, "alt2.aspmx.l.google.com."), - * MX("@", 10, "alt3.aspmx.l.google.com."), - * MX("@", 10, "alt4.aspmx.l.google.com."), - * ] - * - * D("example.com", REG_MY_PROVIDER, DnsProvider(DSP_MY_PROVIDER), - * A("@","1.2.3.4"), - * CNAME("test", "foo.example2.com."), - * GOOGLE_APPS_DOMAIN_MX - * ); - * ``` - * - * # Split Horizon DNS - * - * DNSControl supports Split Horizon DNS. Simply - * define the domain two or more times, each with - * their own unique parameters. - * - * To differentiate the different domains, specify the domains as - * `domain.tld!tag`, such as `example.com!inside` and - * `example.com!outside`. - * - * ```javascript - * var REG_THIRDPARTY = NewRegistrar("ThirdParty"); - * var DNS_INSIDE = NewDnsProvider("Cloudflare"); - * var DNS_OUTSIDE = NewDnsProvider("bind"); - * - * D("example.com!inside", REG_THIRDPARTY, DnsProvider(DNS_INSIDE), - * A("www", "10.10.10.10") - * ); - * - * D("example.com!outside", REG_THIRDPARTY, DnsProvider(DNS_OUTSIDE), - * A("www", "20.20.20.20") - * ); - * - * D_EXTEND("example.com!inside", - * A("internal", "10.99.99.99") - * ); - * ``` - * - * A domain name without a `!` is assigned a tag that is the empty - * string. For example, `example.com` and `example.com!` are equivalent. - * However, we strongly recommend against using the empty tag, as it - * risks creating confusion. In other words, if you have `domain.tld` - * and `domain.tld!external` you now require humans to remember that - * `domain.tld` is the external one. I mean... the internal one. You - * may have noticed this mistake, but will your coworkers? Will you in - * six months? You get the idea. - * - * DNSControl command line flag `--domains` matches the full name (with the "!"). If you - * define domains `example.com!george` and `example.com!john` then: - * - * * `--domains=example.com` will not match either domain. - * * `--domains='example.com!george'` will match only match the first. - * * `--domains='example.com!george",example.com!john` will match both. - * - * NOTE: The quotes are required if your shell treats `!` as a special - * character, which is probably does. If you see an error that mentions - * `event not found` you probably forgot the quotes. - * - * @see https://docs.dnscontrol.org/language-reference/top-level-functions/d - */ -declare function D(name: string, registrar: string, ...modifiers: DomainModifier[]): void; - -/** - * `DEFAULTS` allows you to declare a set of default arguments to apply to all subsequent domains. Subsequent calls to [`D`](D.md) will have these - * arguments passed as if they were the first modifiers in the argument list. - * - * ## Example - * - * We want to create backup zone files for all domains, but not actually register them. Also create a [`DefaultTTL`](../domain/DefaultTTL.md). - * The domain `example.com` will have the defaults set. - * - * ```javascript - * var COMMON = NewDnsProvider("foo"); - * DEFAULTS( - * DnsProvider(COMMON, 0), - * DefaultTTL("1d") - * ); - * - * D("example.com", REG_MY_PROVIDER, DnsProvider(DSP_MY_PROVIDER), - * A("@","1.2.3.4") - * ); - * ``` - * - * If you want to clear the defaults, you can do the following. - * The domain `example2.com` will **not** have the defaults set. - * - * ```javascript - * DEFAULTS(); - * - * D("example2.com", REG_MY_PROVIDER, DnsProvider(DSP_MY_PROVIDER), - * A("@","1.2.3.4") - * ); - * ``` - * - * @see https://docs.dnscontrol.org/language-reference/top-level-functions/defaults - */ -declare function DEFAULTS(...modifiers: DomainModifier[]): void; - -/** - * `DISABLE_IGNORE_SAFETY_CHECK()` disables the safety check. Normally it is an - * error to insert records that match an `IGNORE()` pattern. This disables that - * safety check for the entire domain. - * - * It replaces the per-record `IGNORE_NAME_DISABLE_SAFETY_CHECK()` which is - * deprecated as of DNSControl v4.0.0.0. - * - * See [`IGNORE()`](../domain/IGNORE.md) for more information. - * - * ## Syntax - * - * ```javascript - * D("example.com", REG_MY_PROVIDER, DnsProvider(DSP_MY_PROVIDER), - * DISABLE_IGNORE_SAFETY_CHECK, - * ... - * TXT("myhost", "mytext"), - * IGNORE("myhost", "*", "*"), - * ... - * ``` - * - * @see https://docs.dnscontrol.org/language-reference/domain-modifiers/disable_ignore_safety_check - */ -declare const DISABLE_IGNORE_SAFETY_CHECK: DomainModifier; - -/** - * DNSControl contains a `DMARC_BUILDER` which can be used to simply create - * DMARC policies for your domains. - * - * ## Example - * - * ### Simple example - * - * ```javascript - * DMARC_BUILDER({ - * policy: "reject", - * ruf: [ - * "mailto:mailauth-reports@example.com", - * ], - * }) - * ``` - * - * This yield the following record: - * - * ```text - * @ IN TXT "v=DMARC1; p=reject; ruf=mailto:mailauth-reports@example.com" - * ``` - * - * ### Advanced example - * - * ```javascript - * DMARC_BUILDER({ - * policy: "reject", - * subdomainPolicy: "quarantine", - * percent: 50, - * alignmentSPF: "r", - * alignmentDKIM: "strict", - * rua: [ - * "mailto:mailauth-reports@example.com", - * "https://dmarc.example.com/submit", - * ], - * ruf: [ - * "mailto:mailauth-reports@example.com", - * ], - * failureOptions: "1", - * reportInterval: "1h", - * }); - * ``` - * - * ```javascript - * DMARC_BUILDER({ - * label: "insecure", - * policy: "none", - * ruf: [ - * "mailto:mailauth-reports@example.com", - * ], - * failureOptions: { - * SPF: false, - * DKIM: true, - * }, - * }); - * ``` - * - * This yields the following records: - * - * ```text - * @ IN TXT "v=DMARC1; p=reject; sp=quarantine; adkim=s; aspf=r; pct=50; rua=mailto:mailauth-reports@example.com,https://dmarc.example.com/submit; ruf=mailto:mailauth-reports@example.com; fo=1; ri=3600" - * insecure IN TXT "v=DMARC1; p=none; ruf=mailto:mailauth-reports@example.com; fo=d" - * ``` - * - * ### Parameters - * - * * `label:` The DNS label for the DMARC record (`_dmarc` prefix is added, default: `"@"`) - * * `version:` The DMARC version to be used (default: `DMARC1`) - * * `policy:` The DMARC policy (`p=`), must be one of `"none"`, `"quarantine"`, `"reject"` - * * `subdomainPolicy:` The DMARC policy for subdomains (`sp=`), must be one of `"none"`, `"quarantine"`, `"reject"` (optional) - * * `alignmentSPF:` `"strict"`/`"s"` or `"relaxed"`/`"r"` alignment for SPF (`aspf=`, default: `"r"`) - * * `alignmentDKIM:` `"strict"`/`"s"` or `"relaxed"`/`"r"` alignment for DKIM (`adkim=`, default: `"r"`) - * * `percent:` Number between `0` and `100`, percentage for which policies are applied (`pct=`, default: `100`) - * * `rua:` Array of aggregate report targets (optional) - * * `ruf:` Array of failure report targets (optional) - * * `failureOptions:` Object or string; Object containing booleans `SPF` and `DKIM`, string is passed raw (`fo=`, default: `"0"`) - * * `failureFormat:` Format in which failure reports are requested (`rf=`, default: `"afrf"`) - * * `reportInterval:` Interval in which reports are requested (`ri=`) - * * `ttl:` Input for `TTL` method (optional) - * - * ### Caveats - * - * * TXT records are automatically split using `AUTOSPLIT`. - * * URIs in the `rua` and `ruf` arrays are passed raw. You must percent-encode all commas and exclamation points in the URI itself. - * - * @see https://docs.dnscontrol.org/language-reference/domain-modifiers/dmarc_builder - */ -declare function DMARC_BUILDER(opts: { label?: string; version?: string; policy: 'none' | 'quarantine' | 'reject'; subdomainPolicy?: 'none' | 'quarantine' | 'reject'; alignmentSPF?: 'strict' | 's' | 'relaxed' | 'r'; alignmentDKIM?: 'strict' | 's' | 'relaxed' | 'r'; percent?: number; rua?: string[]; ruf?: string[]; failureOptions?: { SPF: boolean, DKIM: boolean } | string; failureFormat?: string; reportInterval?: Duration; ttl?: Duration }): DomainModifier; - -/** - * `DOMAIN_ELSEWHERE()` is a helper macro that lets you easily indicate that - * a domain's zones are managed elsewhere. That is, it permits you easily delegate - * a domain to a hard-coded list of DNS servers. - * - * `DOMAIN_ELSEWHERE` is useful when you control a domain's registrar but not the - * DNS servers. For example, suppose you own a domain but the DNS servers are run - * by someone else, perhaps a SaaS product you've subscribed to or a DNS server - * that is run by your brother-in-law who doesn't trust you with the API keys that - * would let you maintain the domain using DNSControl. You need an easy way to - * point (delegate) the domain at a specific list of DNS servers. - * - * For example these two statements are equivalent: - * - * ```javascript - * DOMAIN_ELSEWHERE("example.com", REG_MY_PROVIDER, ["ns1.foo.com", "ns2.foo.com"]); - * ``` - * - * ```javascript - * D("example.com", REG_MY_PROVIDER, DnsProvider(DSP_MY_PROVIDER), - * NO_PURGE, - * NAMESERVER("ns1.foo.com"), - * NAMESERVER("ns2.foo.com") - * ); - * ``` - * - * NOTE: The [`NO_PURGE`](../domain/NO_PURGE.md) is used out of abundance of caution but since no - * `DnsProvider()` statements exist, no updates would be performed. - * - * @see https://docs.dnscontrol.org/language-reference/top-level-functions/domain_elsewhere - */ -declare function DOMAIN_ELSEWHERE(name: string, registrar: string, nameserver_names: string[]): void; - -/** - * `DOMAIN_ELSEWHERE_AUTO()` is similar to `DOMAIN_ELSEWHERE()` but instead of - * a hardcoded list of nameservers, a DnsProvider() is queried. - * - * `DOMAIN_ELSEWHERE_AUTO` is useful when you control a domain's registrar but the - * DNS zones are managed by another system. Luckily you have enough access to that - * other system that you can query it to determine the zone's nameservers. - * - * For example, suppose you own a domain but the DNS servers for it are in Azure. - * Further suppose that something in Azure maintains the zones (automatic or - * human). Azure picks the nameservers for the domains automatically, and that - * list may change occasionally. `DOMAIN_ELSEWHERE_AUTO` allows you to easily - * query Azure to determine the domain's delegations so that you do not need to - * hard-code them in your dnsconfig.js file. - * - * For example these two statements are equivalent: - * - * ```javascript - * DOMAIN_ELSEWHERE_AUTO("example.com", REG_NAMEDOTCOM, DSP_AZURE); - * ``` - * - * ```javascript - * D("example.com", REG_NAMEDOTCOM, - * NO_PURGE, - * DnsProvider(DSP_AZURE) - * ); - * ``` - * - * NOTE: The [`NO_PURGE`](../domain/NO_PURGE.md) is used to prevent DNSControl from changing the records. - * - * @see https://docs.dnscontrol.org/language-reference/top-level-functions/domain_elsewhere_auto - */ -declare function DOMAIN_ELSEWHERE_AUTO(name: string, domain: string, registrar: string, dnsProvider: string): void; - -/** - * DS adds a DS record to the domain. - * - * Key Tag should be a number. - * - * Algorithm should be a number. - * - * Digest Type must be a number. - * - * Digest must be a string. - * - * ```javascript - * D("example.com", REG_MY_PROVIDER, DnsProvider(DSP_MY_PROVIDER), - * DS("example.com", 2371, 13, 2, "ABCDEF") - * ); - * ``` - * - * @see https://docs.dnscontrol.org/language-reference/domain-modifiers/ds - */ -declare function DS(name: string, keytag: number, algorithm: number, digesttype: number, digest: string, ...modifiers: RecordModifier[]): DomainModifier; - -/** - * `D_EXTEND` adds records (and metadata) to a domain previously defined - * by [`D()`](D.md). It can also be used to add subdomain records (and metadata) - * to a previously defined domain. - * - * The first argument is a domain name. If it exactly matches a - * previously defined domain, `D_EXTEND()` behaves the same as [`D()`](D.md), - * simply adding records as if they had been specified in the original - * [`D()`](D.md). - * - * If the domain name does not match an existing domain, but could be a - * (non-delegated) subdomain of an existing domain, the new records (and - * metadata) are added with the subdomain part appended to all record - * names (labels), and targets (as appropriate). See the examples below. - * - * Matching the domain name to previously-defined domains is done using a - * `longest match` algorithm. If `domain.tld` and `sub.domain.tld` are - * defined as separate domains via separate [`D()`](D.md) statements, then - * `D_EXTEND("sub.sub.domain.tld", ...)` would match `sub.domain.tld`, - * not `domain.tld`. - * - * Some operators only act on an apex domain (e.g. - * [`CF_REDIRECT`](../domain/CF_REDIRECT.md) and [`CF_TEMP_REDIRECT`](../domain/CF_TEMP_REDIRECT.md)). Using them - * in a `D_EXTEND` subdomain may not be what you expect. - * - * ```javascript - * D("domain.tld", REG_MY_PROVIDER, DnsProvider(DNS), - * A("@", "127.0.0.1"), // domain.tld - * A("www", "127.0.0.2"), // www.domain.tld - * CNAME("a", "b") // a.domain.tld -> b.domain.tld - * ); - * D_EXTEND("domain.tld", - * A("aaa", "127.0.0.3"), // aaa.domain.tld - * CNAME("c", "d") // c.domain.tld -> d.domain.tld - * ); - * D_EXTEND("sub.domain.tld", - * A("bbb", "127.0.0.4"), // bbb.sub.domain.tld - * A("ccc", "127.0.0.5"), // ccc.sub.domain.tld - * CNAME("e", "f") // e.sub.domain.tld -> f.sub.domain.tld - * ); - * D_EXTEND("sub.sub.domain.tld", - * A("ddd", "127.0.0.6"), // ddd.sub.sub.domain.tld - * CNAME("g", "h") // g.sub.sub.domain.tld -> h.sub.sub.domain.tld - * ); - * D_EXTEND("sub.domain.tld", - * A("@", "127.0.0.7"), // sub.domain.tld - * CNAME("i", "j") // i.sub.domain.tld -> j.sub.domain.tld - * ); - * ``` - * - * This will end up in the following modifications: (This output assumes the `--full` flag) - * - * ```text - * ******************** Domain: domain.tld - * ----- Getting nameservers from: cloudflare - * ----- DNS Provider: cloudflare...7 corrections - * #1: CREATE A aaa.domain.tld 127.0.0.3 - * #2: CREATE A bbb.sub.domain.tld 127.0.0.4 - * #3: CREATE A ccc.sub.domain.tld 127.0.0.5 - * #4: CREATE A ddd.sub.sub.domain.tld 127.0.0.6 - * #5: CREATE A sub.domain.tld 127.0.0.7 - * #6: CREATE A www.domain.tld 127.0.0.2 - * #7: CREATE A domain.tld 127.0.0.1 - * #8: CREATE CNAME a.domain.tld b.domain.tld. - * #9: CREATE CNAME c.domain.tld d.domain.tld. - * #10: CREATE CNAME e.sub.domain.tld f.sub.domain.tld. - * #11: CREATE CNAME g.sub.sub.domain.tld h.sub.sub.domain.tld. - * #12: CREATE CNAME i.sub.domain.tld j.sub.domain.tld. - * ``` - * - * ProTips: `D_EXTEND()` permits you to create very complex and - * sophisticated configurations, but you shouldn't. Be nice to the next - * person that edits the file, who may not be as expert as yourself. - * Enhance readability by putting any `D_EXTEND()` statements immediately - * after the original [`D()`](D.md), like in above example. Avoid the temptation - * to obscure the addition of records to existing domains with randomly - * placed `D_EXTEND()` statements. Don't build up a domain using loops of - * `D_EXTEND()` statements. You'll be glad you didn't. - * - * @see https://docs.dnscontrol.org/language-reference/top-level-functions/d_extend - */ -declare function D_EXTEND(name: string, ...modifiers: DomainModifier[]): void; - -/** - * DefaultTTL sets the TTL for all subsequent records following it in a domain that do not explicitly set one with [`TTL`](../record/TTL.md). If neither `DefaultTTL` or `TTL` exist for a record, - * the record will inherit the DNSControl global internal default of 300 seconds. See also [`DEFAULTS`](../global/DEFAULTS.md) to override the internal defaults. - * - * NS records are currently a special case, and do not inherit from `DefaultTTL`. See [`NAMESERVER_TTL`](../domain/NAMESERVER_TTL.md) to set a default TTL for all NS records. - * - * ```javascript - * D("example.com", REG_MY_PROVIDER, DnsProvider(DSP_MY_PROVIDER), - * DefaultTTL("4h"), - * A("@","1.2.3.4"), // uses default - * A("foo", "2.3.4.5", TTL(600)) // overrides default - * ); - * ``` - * - * The DefaultTTL duration is the same format as [`TTL`](../record/TTL.md), an integer number of seconds - * or a string with a unit such as `"4d"`. - * - * @see https://docs.dnscontrol.org/language-reference/domain-modifiers/defaultttl - */ -declare function DefaultTTL(ttl: Duration): DomainModifier; - -/** - * DnsProvider indicates that the specified provider should be used to manage - * records for this domain. The name must match the name used with [NewDnsProvider](../global/NewDnsProvider.md). - * - * The nsCount parameter determines how the nameservers will be managed from this provider. - * - * Leaving the parameter out means "fetch and use all nameservers from this provider as authoritative". ie: `DnsProvider("name")` - * - * Using `0` for nsCount means "do not fetch nameservers from this domain, or give them to the registrar". - * - * Using a different number, ie: `DnsProvider("name",2)`, means "fetch all nameservers from this provider, - * but limit it to this many. - * - * See [this page](../../nameservers.md) for a detailed explanation of how DNSControl handles nameservers and NS records. - * - * If a domain (`D()`) does not include any `DnsProvider()` functions, - * the DNS records will not be modified. In fact, if you want to control - * the Registrar for a domain but not the DNS records themselves, simply - * do not include a `DnsProvider()` function for that `D()`. - * - * @see https://docs.dnscontrol.org/language-reference/domain-modifiers/dnsprovider - */ -declare function DnsProvider(name: string, nsCount?: number): DomainModifier; - -/** - * Documentation needed. - * - * @see https://docs.dnscontrol.org/language-reference/domain-modifiers/frame - */ -declare function FRAME(name: string, target: string, ...modifiers: RecordModifier[]): DomainModifier; - -/** - * `IGNORE()` makes it possible for DNSControl to share management of a domain - * with an external system. The parameters of `IGNORE()` indicate which records - * are managed elsewhere and should not be modified or deleted. - * - * Use case: Suppose a domain is managed by both DNSControl and a third-party - * system. This creates a problem because DNSControl will try to delete records - * inserted by the other system. The other system may get confused and re-insert - * those records. The two systems will get into an endless update cycle where - * each will revert changes made by the other in an endless loop. - * - * To solve this problem simply include `IGNORE()` statements that identify which - * records are managed elsewhere. DNSControl will not modify or delete those - * records. - * - * Technically `IGNORE_NAME` is a promise that DNSControl will not modify or - * delete existing records that match particular patterns. It is like - * [`NO_PURGE`](../domain/NO_PURGE.md) that matches only specific records. - * - * Including a record that is ignored is considered an error and may have - * undefined behavior. This safety check can be disabled using the - * [`DISABLE_IGNORE_SAFETY_CHECK`](../domain/DISABLE_IGNORE_SAFETY_CHECK.md) feature. - * - * ## Syntax - * - * The `IGNORE()` function can be used with up to 3 parameters: - * - * ```javascript - * IGNORE(labelSpec, typeSpec, targetSpec): - * IGNORE(labelSpec, typeSpec): - * IGNORE(labelSpec): - * ``` - * - * * `labelSpec` is a glob that matches the DNS label. For example `"foo"` or `"foo*"`. `"*"` matches all labels, as does the empty string (`""`). - * * `typeSpec` is a comma-separated list of DNS types. For example `"A"` matches DNS A records, `"A,CNAME"` matches both A and CNAME records. `"*"` matches any DNS type, as does the empty string (`""`). - * * `targetSpec` is a glob that matches the DNS target. For example `"foo"` or `"foo*"`. `"*"` matches all targets, as does the empty string (`""`). - * - * `typeSpec` and `targetSpec` default to `"*"` if they are omitted. - * - * ## Globs - * - * The `labelSpec` and `targetSpec` parameters supports glob patterns in the style - * of the [gobwas/glob](https://github.com/gobwas/glob) library. All of the - * following patterns will work: - * - * * `IGNORE("*.foo")` will ignore all records in the style of `bar.foo`, but will not ignore records using a double subdomain, such as `foo.bar.foo`. - * * `IGNORE("**.foo")` will ignore all subdomains of `foo`, including double subdomains. - * * `IGNORE("?oo")` will ignore all records of three symbols ending in `oo`, for example `foo` and `zoo`. It will not match `.` - * * `IGNORE("[abc]oo")` will ignore records `aoo`, `boo` and `coo`. `IGNORE("[a-c]oo")` is equivalent. - * * `IGNORE("[!abc]oo")` will ignore all three symbol records ending in `oo`, except for `aoo`, `boo`, `coo`. `IGNORE("[!a-c]oo")` is equivalent. - * * `IGNORE("{bar,[fz]oo}")` will ignore `bar`, `foo` and `zoo`. - * * `IGNORE("\\*.foo")` will ignore the literal record `*.foo`. - * - * ## Typical Usage - * - * General examples: - * - * ```javascript - * D("example.com", REG_MY_PROVIDER, DnsProvider(DSP_MY_PROVIDER), - * IGNORE("foo"), // matches any records on foo.example.com - * IGNORE("baz", "A"), // matches any A records on label baz.example.com - * IGNORE("*", "MX", "*"), // matches all MX records - * IGNORE("*", "CNAME", "dev-*"), // matches CNAMEs with targets prefixed `dev-*` - * IGNORE("bar", "A,MX"), // ignore only A and MX records for name bar - * IGNORE("*", "*", "dev-*"), // Ignore targets with a `dev-` prefix - * IGNORE("*", "A", "1\.2\.3\."), // Ignore targets in the 1.2.3.0/24 CIDR block - * END); - * ``` - * - * Ignore Let's Encrypt (ACME) validation records: - * - * ```javascript - * D("example.com", REG_MY_PROVIDER, DnsProvider(DSP_MY_PROVIDER), - * IGNORE("_acme-challenge", "TXT"), - * IGNORE("_acme-challenge.**", "TXT"), - * END); - * ``` - * - * Ignore DNS records typically inserted by Microsoft ActiveDirectory: - * - * ```javascript - * D("example.com", REG_MY_PROVIDER, DnsProvider(DSP_MY_PROVIDER), - * IGNORE("_gc", "SRV"), // General Catalog - * IGNORE("_gc.**", "SRV"), // General Catalog - * IGNORE("_kerberos", "SRV"), // Kerb5 server - * IGNORE("_kerberos.**", "SRV"), // Kerb5 server - * IGNORE("_kpasswd", "SRV"), // Kpassword - * IGNORE("_kpasswd.**", "SRV"), // Kpassword - * IGNORE("_ldap", "SRV"), // LDAP - * IGNORE("_ldap.**", "SRV"), // LDAP - * IGNORE("_msdcs", "NS"), // Microsoft Domain Controller Service - * IGNORE("_msdcs.**", "NS"), // Microsoft Domain Controller Service - * IGNORE("_vlmcs", "SRV"), // FQDN of the KMS host - * IGNORE("_vlmcs.**", "SRV"), // FQDN of the KMS host - * IGNORE("domaindnszones", "A"), - * IGNORE("domaindnszones.**", "A"), - * IGNORE("forestdnszones", "A"), - * IGNORE("forestdnszones.**", "A"), - * END); - * ``` - * - * ## Detailed examples - * - * Here are some examples that illustrate how matching works. - * - * All the examples assume the following DNS records are the "existing" records - * that a third-party is maintaining. (Don't be confused by the fact that we're - * using DNSControl notation for the records. Pretend some other system inserted them.) - * - * ```javascript - * D("example.com", REG_MY_PROVIDER, DnsProvider(DSP_MY_PROVIDER), - * A("@", "151.101.1.69"), - * A("www", "151.101.1.69"), - * A("foo", "1.1.1.1"), - * A("bar", "2.2.2.2"), - * CNAME("cshort", "www"), - * CNAME("cfull", "www.plts.org."), - * CNAME("cfull2", "www.bar.plts.org."), - * CNAME("cfull3", "bar.www.plts.org."), - * END); - * - * D_EXTEND("more.example.com", - * A("foo", "1.1.1.1"), - * A("bar", "2.2.2.2"), - * CNAME("mshort", "www"), - * CNAME("mfull", "www.plts.org."), - * CNAME("mfull2", "www.bar.plts.org."), - * CNAME("mfull3", "bar.www.plts.org."), - * END); - * ``` - * - * ```javascript - * IGNORE("@", "", ""), - * // Would match: - * // foo.example.com. A 1.1.1.1 - * // foo.more.example.com. A 1.1.1.1 - * ``` - * - * ```javascript - * IGNORE("example.com.", "", ""), - * // Would match: - * // nothing - * ``` - * - * ```javascript - * IGNORE("foo", "", ""), - * // Would match: - * // foo.example.com. A 1.1.1.1 - * ``` - * - * ```javascript - * IGNORE("foo.**", "", ""), - * // Would match: - * // foo.more.example.com. A 1.1.1.1 - * ``` - * - * ```javascript - * IGNORE("www", "", ""), - * // Would match: - * // www.example.com. A 174.136.107.196 - * ``` - * - * ```javascript - * IGNORE("www.*", "", ""), - * // Would match: - * // nothing - * ``` - * - * ```javascript - * IGNORE("www.example.com", "", ""), - * // Would match: - * // nothing - * ``` - * - * ```javascript - * IGNORE("www.example.com.", "", ""), - * // Would match: - * // none - * ``` - * - * ```javascript - * //IGNORE("", "", "1.1.1.*"), - * // Would match: - * // foo.example.com. A 1.1.1.1 - * // foo.more.example.com. A 1.1.1.1 - * ``` - * - * ```javascript - * //IGNORE("", "", "www"), - * // Would match: - * // none - * ``` - * - * ```javascript - * IGNORE("", "", "*bar*"), - * // Would match: - * // cfull2.example.com. CNAME www.bar.plts.org. - * // cfull3.example.com. CNAME bar.www.plts.org. - * // mfull2.more.example.com. CNAME www.bar.plts.org. - * // mfull3.more.example.com. CNAME bar.www.plts.org. - * ``` - * - * ```javascript - * IGNORE("", "", "bar.**"), - * // Would match: - * // cfull3.example.com. CNAME bar.www.plts.org. - * // mfull3.more.example.com. CNAME bar.www.plts.org. - * ``` - * - * ## Conflict handling - * - * It is considered as an error for a `dnsconfig.js` to both ignore and insert the - * same record in a domain. This is done as a safety mechanism. - * - * This will generate an error: - * - * ```javascript - * D("example.com", REG_MY_PROVIDER, DnsProvider(DSP_MY_PROVIDER), - * ... - * TXT("myhost", "mytext"), - * IGNORE("myhost", "*", "*"), // Error! Ignoring an item we inserted - * ... - * ``` - * - * To disable this safety check, add the `DISABLE_IGNORE_SAFETY_CHECK` statement - * to the `D()`. - * - * ```javascript - * D("example.com", REG_MY_PROVIDER, DnsProvider(DSP_MY_PROVIDER), - * DISABLE_IGNORE_SAFETY_CHECK, - * ... - * TXT("myhost", "mytext"), - * IGNORE("myhost", "*", "*"), - * ... - * ``` - * - * FYI: Previously DNSControl permitted disabling this check on - * a per-record basis using `IGNORE_NAME_DISABLE_SAFETY_CHECK`: - * - * The `IGNORE_NAME_DISABLE_SAFETY_CHECK` feature does not exist in the diff2 - * world and its use will result in a validation error. Use the above example - * instead. - * - * ```javascript - * // THIS NO LONGER WORKS! Use DISABLE_IGNORE_SAFETY_CHECK instead. See above. - * TXT("myhost", "mytext", IGNORE_NAME_DISABLE_SAFETY_CHECK), - * ``` - * - * ## Caveats - * - * WARNING: Two systems updating the same domain is complex. Complex things are risky. Use `IGNORE()` - * as a last resort. Even then, test extensively. - * - * * There is no locking. If the external system and DNSControl make updates at the exact same time, the results are undefined. - * * IGNORE` works fine with records inserted into a `D()` via `D_EXTEND()`. The matching is done on the resulting FQDN of the label or target. - * * `targetSpec` does not match fields other than the primary target. For example, `MX` records have a target hostname plus a priority. There is no way to match the priority. - * * The BIND provider can not ignore records it doesn't know about. If it does not have access to an existing zonefile, it will create a zonefile from scratch. That new zonefile will not have any external records. It will seem like they were not ignored, but in reality BIND didn't have visibility to them so that they could be ignored. - * - * @see https://docs.dnscontrol.org/language-reference/domain-modifiers/ignore - */ -declare function IGNORE(labelSpec: string, typeSpec?: string, targetSpec?: string): DomainModifier; - -/** - * `IGNORE_NAME(a)` is the same as `IGNORE(a, "*", "*")`. - * - * `IGNORE_NAME(a, b)` is the same as `IGNORE(a, b, "*")`. - * - * @see https://docs.dnscontrol.org/language-reference/domain-modifiers/ignore_name - */ -declare function IGNORE_NAME(pattern: string, rTypes?: string): DomainModifier; - -/** - * `IGNORE_TARGET_NAME(target)` is the same as `IGNORE("*", "*", target)`. - * - * `IGNORE_TARGET_NAME(target, rtype)` is the same as `IGNORE("*", rtype, target)`. - * - * @see https://docs.dnscontrol.org/language-reference/domain-modifiers/ignore_target - */ -declare function IGNORE_TARGET(pattern: string, rType: string): DomainModifier; - -/** - * Includes all records from a given domain - * - * ```javascript - * D("example.com!external", REG_MY_PROVIDER, DnsProvider(DSP_MY_PROVIDER), - * A("test", "8.8.8.8") - * ); - * - * D("example.com!internal", REG_MY_PROVIDER, DnsProvider(DSP_MY_PROVIDER), - * INCLUDE("example.com!external"), - * A("home", "127.0.0.1") - * ); - * ``` - * - * @see https://docs.dnscontrol.org/language-reference/domain-modifiers/include - */ -declare function INCLUDE(domain: string): DomainModifier; - -/** - * Converts an IPv4 address from string to an integer. This allows performing mathematical operations with the IP address. - * - * ```javascript - * var addrA = IP("1.2.3.4") - * var addrB = addrA + 1 - * // addrB = 1.2.3.5 - * ``` - * - * NOTE: `IP()` does not accept IPv6 addresses (PRs gladly accepted!). IPv6 addresses are simply strings: - * - * ```javascript - * // IPv4 Var - * var addrA1 = IP("1.2.3.4"); - * var addrA2 = "1.2.3.4"; - * - * // IPv6 Var - * var addrAAAA = "0:0:0:0:0:0:0:0"; - * ``` - * - * @see https://docs.dnscontrol.org/language-reference/top-level-functions/ip - */ -declare function IP(ip: string): number; - -/** - * The parameter number types are as follows: - * - * ``` - * name: string - * target: string - * deg1: uint32 - * min1: uint32 - * sec1: float32 - * deg2: uint32 - * min2: uint32 - * sec2: float32 - * altitude: uint32 - * size: float32 - * horizontal_precision: float32 - * vertical_precision: float32 - * ``` - * - * ## Description ## - * - * Strictly follows [RFC 1876](https://datatracker.ietf.org/doc/html/rfc1876). - * - * A LOC record holds a geographical position. In the zone file, it may look like: - * - * ```text - * ; - * pipex.net. LOC 52 14 05 N 00 08 50 E 10m - * ``` - * - * On the wire, it is in a binary format. - * - * A use case for LOC is suggested in the RFC: - * - * > Some uses for the LOC RR have already been suggested, including the - * USENET backbone flow maps, a "visual traceroute" application showing - * the geographical path of an IP packet, and network management - * applications that could use LOC RRs to generate a map of hosts and - * routers being managed. - * - * There is the UK based [https://find.me.uk](https://find.me.uk/) whereby you can do: - * - * ```sh - * dig loc .find.me.uk - * ``` - * - * There are some behaviours that you should be aware of, however: - * - * > If omitted, minutes and seconds default to zero, size defaults to 1m, - * horizontal precision defaults to 10000m, and vertical precision - * defaults to 10m. These defaults are chosen to represent typical - * ZIP/postal code area sizes, since it is often easy to find - * approximate geographical location by ZIP/postal code. - * - * Alas, the world does not revolve around US ZIP codes, but here we are. Internally, - * the LOC record type will supply defaults where values were absent on DNS import. - * One must supply the `LOC()` js helper all parameters. If that seems like too - * much work, see also helper functions: - * - * * [`LOC_BUILDER_DD({})`](../record/LOC_BUILDER_DD.md) - build a `LOC` by supplying only **d**ecimal **d**egrees. - * * [`LOC_BUILDER_DMS_STR({})`](../record/LOC_BUILDER_DMS_STR.md) - accepts DMS 33°51′31″S 151°12′51″E - * * [`LOC_BUILDER_DMM_STR({})`](../record/LOC_BUILDER_DMM_STR.md) - accepts DMM 25.24°S 153.15°E - * * [`LOC_BUILDER_STR({})`](../record/LOC_BUILDER_STR.md) - tries the cooordinate string in all `LOC_BUILDER_DM*_STR()` functions until one works - * - * ## Format ## - * - * The coordinate format for `LOC()` is: - * - * `degrees,minutes,seconds,[NnSs],deg,min,sec,[EeWw],altitude,size,horizontal_precision,vertical_precision` - * - * ## Examples ## - * - * ```javascript - * D("example.com", REG_MY_PROVIDER, DnsProvider(DSP_MY_PROVIDER), - * // LOC "subdomain", d1, m1, s1, "[NnSs]", d2, m2, s2, "[EeWw]", alt, siz, hp, vp) - * //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 10m - * , LOC("a", 42, 21, 43.952, "N", 71, 5, 6.344, "W", -24, 1, 200, 10) - * //52 14 05 N 00 08 50 E 10m - * , LOC("b", 52, 14, 5, "N", 0, 8, 50, "E", 10, 0, 0, 0) - * //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 - * , LOC("d", 42, 21, 28.764, "N", 71, 0, 51.617, "W", -44, 2000, 0, 0) - * ); - * - * ``` - * - * @see https://docs.dnscontrol.org/language-reference/domain-modifiers/loc - */ -declare function LOC(deg1: number, min1: number, sec1: number, deg2: number, min2: number, sec2: number, altitude: number, size: number, horizontal_precision: number, vertical_precision: number): DomainModifier; - -/** - * `LOC_BUILDER_DD({})` actually takes an object with the following properties: - * - * - label (optional, defaults to `@`) - * - x (float32) - * - y (float32) - * - alt (float32, optional) - * - ttl (optional) - * - * A helper to build [`LOC`](../domain/LOC.md) records. Supply four parameters instead of 12. - * - * Internally assumes some defaults for [`LOC`](../domain/LOC.md) records. - * - * The cartesian coordinates are decimal degrees, like you typically find in e.g. Google Maps. - * - * Examples. - * - * Big Ben: - * `51.50084265331501, -0.12462541415599787` - * - * The White House: - * `38.89775977858357, -77.03655125982903` - * - * ```javascript - * D("example.com", REG_MY_PROVIDER, DnsProvider(DSP_MY_PROVIDER), - * LOC_BUILDER_DD({ - * label: "big-ben", - * x: 51.50084265331501, - * y: -0.12462541415599787, - * alt: 6, - * }) - * , LOC_BUILDER_DD({ - * label: "white-house", - * x: 38.89775977858357, - * y: -77.03655125982903, - * alt: 19, - * }) - * , LOC_BUILDER_DD({ - * label: "white-house-ttl", - * x: 38.89775977858357, - * y: -77.03655125982903, - * alt: 19, - * ttl: "5m", - * }) - * ); - * - * ``` - * - * Part of the series: - * * [`LOC()`](../domain/LOC.md) - build a `LOC` by supplying all 12 parameters - * * [`LOC_BUILDER_DD({})`](../record/LOC_BUILDER_DD.md) - accepts cartesian x, y - * * [`LOC_BUILDER_DMS_STR({})`](../record/LOC_BUILDER_DMS_STR.md) - accepts DMS 33°51′31″S 151°12′51″E - * * [`LOC_BUILDER_DMM_STR({})`](../record/LOC_BUILDER_DMM_STR.md) - accepts DMM 25.24°S 153.15°E - * * [`LOC_BUILDER_STR({})`](../record/LOC_BUILDER_STR.md) - tries the cooordinate string in all `LOC_BUILDER_DM*_STR()` functions until one works - * - * @see https://docs.dnscontrol.org/language-reference/domain-modifiers/loc_builder_dd - */ -declare function LOC_BUILDER_DD(opts: { label?: string; x: number; y: number; alt?: number; ttl?: Duration }): DomainModifier; - -/** - * `LOC_BUILDER_DMM({})` actually takes an object with the following properties: - * - * - label (string, optional, defaults to `@`) - * - str (string) - * - alt (float32, optional) - * - ttl (optional) - * - * A helper to build [`LOC`](../domain/LOC.md) records. Supply three parameters instead of 12. - * - * Internally assumes some defaults for [`LOC`](../domain/LOC.md) records. - * - * Accepts a string with decimal minutes (DMM) coordinates in the form: 25.24°S 153.15°E - * - * Note that the following are acceptable forms (symbols differ): - * * `25.24°S 153.15°E` - * * `25.24 S 153.15 E` - * * `25.24° S 153.15° E` - * * `25.24S 153.15E` - * - * ```javascript - * D("example.com", REG_MY_PROVIDER, DnsProvider(DSP_MY_PROVIDER), - * LOC_BUILDER_STR({ - * label: "tasmania", - * str: "42°S 147°E", - * alt: 3, - * }) - * ); - * - * ``` - * - * Part of the series: - * * [`LOC()`](../domain/LOC.md) - build a `LOC` by supplying all 12 parameters - * * [`LOC_BUILDER_DD({})`](../record/LOC_BUILDER_DD.md) - accepts cartesian x, y - * * [`LOC_BUILDER_DMS_STR({})`](../record/LOC_BUILDER_DMS_STR.md) - accepts DMS 33°51′31″S 151°12′51″E - * * [`LOC_BUILDER_DMM_STR({})`](../record/LOC_BUILDER_DMM_STR.md) - accepts DMM 25.24°S 153.15°E - * * [`LOC_BUILDER_STR({})`](../record/LOC_BUILDER_STR.md) - tries the cooordinate string in all `LOC_BUILDER_DM*_STR()` functions until one works - * - * @see https://docs.dnscontrol.org/language-reference/domain-modifiers/loc_builder_dmm_str - */ -declare function LOC_BUILDER_DMM_STR(opts: { label?: string; str: string; alt?: number; ttl?: Duration }): DomainModifier; - -/** - * `LOC_BUILDER_DMS_STR({})` actually takes an object with the following properties: - * - * - label (string, optional, defaults to `@`) - * - str (string) - * - alt (float32, optional) - * - ttl (optional) - * - * A helper to build [`LOC`](../domain/LOC.md) records. Supply three parameters instead of 12. - * - * Internally assumes some defaults for [`LOC`](../domain/LOC.md) records. - * - * Accepts a string with degrees, minutes, and seconds (DMS) coordinates in the form: 41°24'12.2"N 2°10'26.5"E - * - * Note that the following are acceptable forms (symbols differ): - * * `33°51′31″S 151°12′51″E` - * * `33°51'31"S 151°12'51"E` - * * `33d51m31sS 151d12m51sE` - * * `33d51m31s S 151d12m51s E` - * - * ```javascript - * D("example.com", REG_MY_PROVIDER, DnsProvider(DSP_MY_PROVIDER), - * LOC_BUILDER_DMS_STR({ - * label: "sydney-opera-house", - * str: "33°51′31″S 151°12′51″E", - * alt: 4, - * ttl: "5m", - * }) - * ); - * - * ``` - * - * Part of the series: - * * [`LOC()`](../domain/LOC.md) - build a `LOC` by supplying all 12 parameters - * * [`LOC_BUILDER_DD({})`](../record/LOC_BUILDER_DD.md) - accepts cartesian x, y - * * [`LOC_BUILDER_DMS_STR({})`](../record/LOC_BUILDER_DMS_STR.md) - accepts DMS 33°51′31″S 151°12′51″E - * * [`LOC_BUILDER_DMM_STR({})`](../record/LOC_BUILDER_DMM_STR.md) - accepts DMM 25.24°S 153.15°E - * * [`LOC_BUILDER_STR({})`](../record/LOC_BUILDER_STR.md) - tries the cooordinate string in all `LOC_BUILDER_DM*_STR()` functions until one works - * - * @see https://docs.dnscontrol.org/language-reference/domain-modifiers/loc_builder_dms_str - */ -declare function LOC_BUILDER_DMS_STR(opts: { label?: string; str: string; alt?: number; ttl?: Duration }): DomainModifier; - -/** - * `LOC_BUILDER_STR({})` actually takes an object with the following: properties. - * - * - label (optional, defaults to `@`) - * - str (string) - * - alt (float32, optional) - * - ttl (optional) - * - * A helper to build [`LOC`](../domain/LOC.md) records. Supply three parameters instead of 12. - * - * Internally assumes some defaults for [`LOC`](../domain/LOC.md) records. - * - * Accepts a string and tries all `LOC_BUILDER_DM*_STR({})` methods: - * * [`LOC_BUILDER_DMS_STR({})`](../record/LOC_BUILDER_DMS_STR.md) - accepts DMS 33°51′31″S 151°12′51″E - * * [`LOC_BUILDER_DMM_STR({})`](../record/LOC_BUILDER_DMM_STR.md) - accepts DMM 25.24°S 153.15°E - * - * ```javascript - * D("example.com", REG_MY_PROVIDER, DnsProvider(DSP_MY_PROVIDER), - * , LOC_BUILDER_STR({ - * label: "old-faithful", - * str: "44.46046°N 110.82815°W", - * alt: 2240, - * }) - * , LOC_BUILDER_STR({ - * label: "ribblehead-viaduct", - * str: "54.210436°N 2.370231°W", - * alt: 300, - * }) - * , LOC_BUILDER_STR({ - * label: "guinness-brewery", - * str: "53°20′40″N 6°17′20″W", - * alt: 300, - * }) - * ); - * - * ``` - * - * Part of the series: - * * [`LOC()`](../domain/LOC.md) - build a `LOC` by supplying all 12 parameters - * * [`LOC_BUILDER_DD({})`](../record/LOC_BUILDER_DD.md) - accepts cartesian x, y - * * [`LOC_BUILDER_DMS_STR({})`](../record/LOC_BUILDER_DMS_STR.md) - accepts DMS 33°51′31″S 151°12′51″E - * * [`LOC_BUILDER_DMM_STR({})`](../record/LOC_BUILDER_DMM_STR.md) - accepts DMM 25.24°S 153.15°E - * * [`LOC_BUILDER_STR({})`](../record/LOC_BUILDER_STR.md) - tries the cooordinate string in all `LOC_BUILDER_DM*_STR()` functions until one works - * - * @see https://docs.dnscontrol.org/language-reference/domain-modifiers/loc_builder_str - */ -declare function LOC_BUILDER_STR(opts: { label?: string; str: string; alt?: number; ttl?: Duration }): DomainModifier; - -/** - * DNSControl offers a `M365_BUILDER` which can be used to simply set up Microsoft 365 for a domain in an opinionated way. - * - * It defaults to a setup without support for legacy Skype for Business applications. - * It doesn't set up SPF or DMARC. See [`SPF_BUILDER`](/language-reference/record-modifiers/dmarc_builder) and [`DMARC_BUILDER`](/language-reference/record-modifiers/spf_builder). - * - * ## Example - * - * ### Simple example - * - * ```javascript - * M365_BUILDER({ - * initialDomain: "example.onmicrosoft.com", - * }); - * ``` - * - * This sets up `MX` records, Autodiscover, and DKIM. - * - * ### Advanced example - * - * ```javascript - * M365_BUILDER({ - * label: "test", - * mx: false, - * autodiscover: false, - * dkim: false, - * mdm: true, - * domainGUID: "test-example-com", // Can be automatically derived in this case, if example.com is the context. - * initialDomain: "example.onmicrosoft.com", - * }); - * ``` - * - * This sets up Mobile Device Management only. - * - * ### Parameters - * - * * `label` The label of the Microsoft 365 domain, useful if it is a subdomain (default: `"@"`) - * * `mx` Set an `MX` record? (default: `true`) - * * `autodiscover` Set Autodiscover `CNAME` record? (default: `true`) - * * `dkim` Set DKIM `CNAME` records? (default: `true`) - * * `skypeForBusiness` Set Skype for Business/Microsoft Teams records? (default: `false`) - * * `mdm` Set Mobile Device Management records? (default: `false`) - * * `domainGUID` The GUID of _this_ Microsoft 365 domain (default: `