diff --git a/.github/workflows/codeql.yml b/.github/workflows/codeql.yml new file mode 100644 index 0000000000..fab2960a3b --- /dev/null +++ b/.github/workflows/codeql.yml @@ -0,0 +1,59 @@ +name: "CodeQL" + +# Advanced CodeQL setup. +# +# This replaces GitHub's "default setup" for CodeQL. The default setup runs the +# Go extractor's autobuild with whatever Go is pre-installed on the runner and +# with GOTOOLCHAIN=local, which forbids downloading a newer toolchain. When +# go.mod requires a Go version newer than the runner's (e.g. `go 1.27` while the +# runner only has 1.26.x), extraction fails with: +# +# go: go.mod requires go >= 1.27 (running go 1.26.x; GOTOOLCHAIN=local) +# +# Installing Go from go.mod before the extractor runs makes the required +# toolchain the "local" one, so autobuild succeeds. +# +# NOTE: An advanced workflow and the repository's "default setup" cannot both be +# active. Disable default setup under +# Settings -> Code security -> CodeQL analysis (switch Default -> Advanced). + +on: + push: + branches: [main, master, release_candidate_v5] + pull_request: + branches: [main, master, release_candidate_v5] + schedule: + - cron: "0 0 * * 1" + +concurrency: + group: codeql-${{ github.ref }} + cancel-in-progress: true + +jobs: + analyze: + name: Analyze (go) + runs-on: ubuntu-latest + permissions: + security-events: write + actions: read + contents: read + + steps: + - name: Checkout repository + uses: actions/checkout@v7 + + - name: Set up Go + uses: actions/setup-go@v7 + with: + go-version-file: go.mod + + - name: Initialize CodeQL + uses: github/codeql-action/init@v4 + with: + languages: go + build-mode: autobuild + + - name: Perform CodeQL Analysis + uses: github/codeql-action/analyze@v4 + with: + category: "/language:go" diff --git a/.github/workflows/pr_integration_tests.yml b/.github/workflows/pr_integration_tests.yml index 85c046e885..5d454f9b38 100644 --- a/.github/workflows/pr_integration_tests.yml +++ b/.github/workflows/pr_integration_tests.yml @@ -95,7 +95,7 @@ jobs: warm-gomod-cache: runs-on: ubuntu-latest container: - image: golang:1.26 + image: golang:1.27 needs: - integration-test-providers outputs: @@ -144,7 +144,7 @@ jobs: if: ${{ inputs.full || (github.ref != 'refs/heads/master' && github.ref != 'refs/heads/main') }} runs-on: ubuntu-latest container: - image: golang:1.26 + image: golang:1.27 needs: - integration-test-providers - warm-gomod-cache diff --git a/.linkspector.yml b/.linkspector.yml index 0b60d8d582..bd74388ecb 100644 --- a/.linkspector.yml +++ b/.linkspector.yml @@ -10,7 +10,6 @@ ignorePatterns: - pattern: '.*.md#$' - pattern: '^https://cloud.digitalocean.com/account/api/tokens' - pattern: '^https://cloud.digitalocean.com/settings/applications' - - pattern: '^https://dns.hetzner.com/settings/api-token' - pattern: '^https://github.com/DNSControl/dnscontrol/settings/.*$' - pattern: '^https://gitlab.com/cafferata/dnscontrol/-/pipelines/new.*$' - pattern: '^https://my.easyname.com/en/account/api' diff --git a/REFACTORING_PROJECTS.md b/REFACTORING_PROJECTS.md new file mode 100644 index 0000000000..285f1682ca --- /dev/null +++ b/REFACTORING_PROJECTS.md @@ -0,0 +1,46 @@ +# Refactoring + +Useful refactoring projects. Please feel free to pick up any of these. + + +## Code that can probably be deleted + +* RegisterCustomRecordType()/GetCustomRecordType() is no longer needed. Remove. + +* I don't think the metadata "orig_custom_type" is used any more. We store to it but don't use it. + +## Rewrites needed + +* PTR() "magic" should be reworked as a builder called PTR(). It will be much more +cleaner and more testable. Plus it will consolidate the code into one place instead +of being some in LabelFromDnsconfigjs() and other places. + +* PopulateNamesFromRaw() and MakeDomainNameVarieties() seem like a silly design. Maybe move them to pkg/nameutil, or maybe models (since that's where makeLabelNameUnicode() is) + +* All the LOC() builders should be in Go, not helpers.js. + +* There are multiple ways that code strips the trailing dot from a domain name. Benchmark a few and standardize on the fastest. In pkg/nameutil. Possibly have one that is extra fast but panics if there is no "." at the end. + +* pkg/normalize/validate.go has half of the Transform code, the other half is in pkg/transform. An easy thing would be to move the part of pkg/normalize/validate.go and validate_test.go into pkg/normalize/transform{,_test}.go. The more difficult thing would be to move all or most of the code to pkg/transform. + +* models/record.go FixPostion has an easy TODO. + +* models/t_txt.go has an some easy FIXMEs. + +## Bad decisions to reverse + +* Providers, not Registrars + DNS Service Providers. It should be possible to make a PROVIDER() function that returns +something that is both a Reg and a DSP. + +* mustbe.TargetHost() accepts "." as a special flag. This can probably be replaced by nrc.Flags{} + +* models.SetLabel() should be removed (it's only used in a few places) or enhanced to also create the .NameUnicode/.NameFQDNUnicode fields. Then de-duplicate the code that does this for NewRecordConfig(). + +* deSEC: BUG: It mutates RecordConfigs, which will create problems if the same zone is sent to multiple providers. + + +## Actual new features: + +* Handle "unknown types". dnsv2 has a way to managing unknown types. Investigate it and replace the half-written version (see rc.UnknownTypeName) + +* pkg/diff2/analyze.go: Smarter diffs. Diffs could just show which fields changed. For example, if just the preference of an MX record changes, show "old -> new" just for the priority. diff --git a/build/astypegen/astype_generate.go b/build/astypegen/astype_generate.go new file mode 100644 index 0000000000..9c3f571eac --- /dev/null +++ b/build/astypegen/astype_generate.go @@ -0,0 +1,65 @@ +package main + +// Command astype_generate generates models/record_astype.go. +// +// Generates an As$TYPE() method for every rtype. +// +// Run by `go generate ./models/` (see the //go:generate directive in rdata.go) +// and by bin/generate-all.sh. + +import ( + "bytes" + "fmt" + "log" + + dnsv2 "codeberg.org/miekg/dns" + "github.com/DNSControl/dnscontrol/v5/pkg/privatetypes" +) + +const outputFile = "record_astype.go" + +func main() { + var buf bytes.Buffer + + buf.WriteString("// Code generated by astype_generate.go; DO NOT EDIT.\n\n") + buf.WriteString("package models\n\n") + buf.WriteString("import (\n") + buf.WriteString("\tdnsrdatav2 \"codeberg.org/miekg/dns/rdata\"\n") + buf.WriteString("\tprivatetypesrdata \"github.com/DNSControl/dnscontrol/v5/pkg/privatetypes/rdata\"\n") + buf.WriteString(")\n\n") + + seen := map[string]bool{} + for _, name := range privatetypes.GetAllTypeNames() { + codepoint := dnsv2.StringToType[name] + + // Skip irrelevant rtypes. Make a struct of that type. + newFn, ok := dnsv2.TypeToRR[codepoint] + if !ok { + continue + } + rd := newFn().Data() + + // is this a dnsrdatav2. or privatetypes. namespace? + structName, pkgPath := StructName(rd) + pkg, ok := Namespace(pkgPath) + if structName == "" || !ok { + continue + } + + method := "As" + goIdent(name) + // Have we seen this before? + if seen[method] { + continue + } + seen[method] = true + + fmt.Fprintf(&buf, + "func (rc *RecordConfig) %s() %s.%s {\n\treturn rc.GetRDATA().(%s.%s)\n}\n\n", + method, pkg, structName, pkg, structName) + } + + if err := writeGoFile(outputFile, buf.Bytes()); err != nil { + log.Fatal(err) + } + fmt.Printf("astype_generate.go: wrote %s\n", outputFile) +} diff --git a/build/astypegen/astypeutil.go b/build/astypegen/astypeutil.go new file mode 100644 index 0000000000..eb621c4904 --- /dev/null +++ b/build/astypegen/astypeutil.go @@ -0,0 +1,61 @@ +package main + +import ( + "fmt" + "go/format" + "os" + "reflect" + "strings" +) + +// goIdent turns a DNS type name into a valid Go identifier by dropping any +// character that is not a letter or digit (e.g. "NSAP-PTR" -> "NSAPPTR", +// "CLOUDFLAREAPI_SINGLE_REDIRECT" -> "CLOUDFLAREAPISINGLEREDIRECT"). +func goIdent(name string) string { + return strings.Map(func(r rune) rune { + switch { + case r >= 'A' && r <= 'Z', r >= 'a' && r <= 'z', r >= '0' && r <= '9': + return r + default: + return -1 + } + }, name) +} + +// writeGoFile runs the generated source through gofmt (go/format) and writes it +// to path. +// Copied from pkg/privatetypes/types_generate.go. +func writeGoFile(path string, src []byte) error { + formatted, err := format.Source(src) + if err != nil { + _ = os.WriteFile(path, src, 0o644) + return fmt.Errorf("gofmt %s: %w", path, err) + } + return os.WriteFile(path, formatted, 0o644) +} + +// StructName returns the Go struct name and package import path of an RDATA value. +// It returns ("", "") for nil or a type with no name. +func StructName(rd any) (name, pkgPath string) { + rt := reflect.TypeOf(rd) + if rt == nil { + return "", "" + } + if rt.Kind() == reflect.Pointer { + rt = rt.Elem() + } + return rt.Name(), rt.PkgPath() +} + +// Namespace maps an RDATA struct's package import path. +// Possible return values are ("privatetypesrdata", true), ("dnsrdatav2", true), or ("", false). +func Namespace(pkgPath string) (alias string, ok bool) { + switch { + case strings.HasSuffix(pkgPath, "/pkg/privatetypes/rdata"): + return "privatetypesrdata", true + case pkgPath == "codeberg.org/miekg/dns/rdata": + return "dnsrdatav2", true + default: + return "", false + } +} diff --git a/build/astypegen/astypeutil_test.go b/build/astypegen/astypeutil_test.go new file mode 100644 index 0000000000..79ae06688b --- /dev/null +++ b/build/astypegen/astypeutil_test.go @@ -0,0 +1,54 @@ +package main_test + +import ( + "testing" + + gen "github.com/DNSControl/dnscontrol/v5/build/astypegen" +) + +type sampleRD struct{} + +func TestStructName(t *testing.T) { + // Value: name + this test package's path. + name, pkgPath := gen.StructName(sampleRD{}) + if name != "sampleRD" { + t.Errorf("StructName(value): name=%q, want %q", name, "sampleRD") + } + if pkgPath == "" { + t.Errorf("StructName(value): pkgPath is empty, want a non-empty package path") + } + + // Pointer is dereferenced to the same name/path. + pName, pPkg := gen.StructName(&sampleRD{}) + if pName != name || pPkg != pkgPath { + t.Errorf("StructName(pointer) = (%q,%q), want (%q,%q)", pName, pPkg, name, pkgPath) + } + + // nil yields empties (generator skips these). + if n, p := gen.StructName(nil); n != "" || p != "" { + t.Errorf("StructName(nil) = (%q,%q), want empty", n, p) + } +} + +func TestNamespace(t *testing.T) { + cases := []struct { + pkgPath string + wantAlias string + wantOK bool + }{ + {"codeberg.org/miekg/dns/rdata", "dnsrdatav2", true}, + {"github.com/DNSControl/dnscontrol/v5/pkg/privatetypes/rdata", "privatetypesrdata", true}, + // Version-independent: a future major version must still map correctly. + {"github.com/DNSControl/dnscontrol/v6/pkg/privatetypes/rdata", "privatetypesrdata", true}, + // Anything else is skipped. + {"codeberg.org/miekg/dns", "", false}, + {"some/other/package", "", false}, + {"", "", false}, + } + for _, c := range cases { + alias, ok := gen.Namespace(c.pkgPath) + if alias != c.wantAlias || ok != c.wantOK { + t.Errorf("Namespace(%q) = (%q, %v), want (%q, %v)", c.pkgPath, alias, ok, c.wantAlias, c.wantOK) + } + } +} diff --git a/build/build.go b/build/build.go index 9abdd1f45f..fa6aefffa3 100644 --- a/build/build.go +++ b/build/build.go @@ -7,15 +7,15 @@ import ( "os" "os/exec" - "github.com/DNSControl/dnscontrol/v4/pkg/version" + "github.com/DNSControl/dnscontrol/v5/pkg/version" ) var goos = flag.String("os", "", "OS to build (linux, windows, or darwin) Defaults to all.") func main() { flag.Parse() - flags := fmt.Sprintf(`-s -w -X "github.com/DNSControl/dnscontrol/v4/pkg/version.version=%s"`, version.Version()) - pkg := "github.com/DNSControl/dnscontrol/v4" + flags := fmt.Sprintf(`-s -w -X "github.com/DNSControl/dnscontrol/v5/pkg/version.version=%s"`, version.Version()) + pkg := "github.com/DNSControl/dnscontrol/v5" build := func(out, goos string) { log.Printf("Building %s", out) diff --git a/build/generate/featureMatrix.go b/build/generate/featureMatrix.go index 66666a5888..ae065f0792 100644 --- a/build/generate/featureMatrix.go +++ b/build/generate/featureMatrix.go @@ -7,9 +7,8 @@ import ( "sort" "strings" - "github.com/DNSControl/dnscontrol/v4/pkg/providers" - _ "github.com/DNSControl/dnscontrol/v4/pkg/providers/_all" - _ "github.com/DNSControl/dnscontrol/v4/pkg/rtype" + "github.com/DNSControl/dnscontrol/v5/pkg/providers" + _ "github.com/DNSControl/dnscontrol/v5/pkg/providers/_all" "github.com/fbiville/markdown-table-formatter/pkg/markdown" ) @@ -178,39 +177,39 @@ func matrixData() *FeatureMatrix { "DNSSEC", }, FeatureTables: [][]string{ - []string{ // provider type + { // provider type OfficialSupport, ProviderDNSProvider, ProviderRegistrar, }, - []string{ // provider API + { // provider API ProviderThreadSafe, DualHost, CreateDomains, // NoPurge, GetZones, }, - []string{ // DNS extensions + { // DNS extensions DomainModifierAlias, DomainModifierDname, DomainModifierLoc, DomainModifierPtr, DomainModifierSoa, }, - []string{ // service discovery + { // service discovery DomainModifierDhcid, DomainModifierNaptr, DomainModifierSrv, DomainModifierSvcb, }, - []string{ // security + { // security DomainModifierCaa, DomainModifierHTTPS, DomainModifierSMIMEA, DomainModifierSshfp, DomainModifierTlsa, }, - []string{ // dnssec + { // dnssec DomainModifierDnssec, DomainModifierDnskey, DomainModifierDs, diff --git a/build/generate/functionTypes.go b/build/generate/functionTypes.go index 9a24255675..d2abff3a36 100644 --- a/build/generate/functionTypes.go +++ b/build/generate/functionTypes.go @@ -149,7 +149,7 @@ func generateFunctionTypes() (string, error) { params := []Param{} for _, p := range paramNames { - // start with supplied type, fall back to defaultParamType + // start with supplied type, fall back to "unknown". paramType := suppliedParamTypes[p] if paramType == "" { println("WARNING:", fPath+":", "no type for parameter ", "'"+p+"'") diff --git a/build/generate/labelerFile.go b/build/generate/labelerFile.go index 199a1f7d3d..e1fa1c2de9 100644 --- a/build/generate/labelerFile.go +++ b/build/generate/labelerFile.go @@ -4,7 +4,7 @@ import ( "os" "strings" - "github.com/DNSControl/dnscontrol/v4/pkg/providers" + "github.com/DNSControl/dnscontrol/v5/pkg/providers" ) func generateLabelerFile() error { diff --git a/build/generate/ownersFile.go b/build/generate/ownersFile.go index c171b98ae6..2be6a0e498 100644 --- a/build/generate/ownersFile.go +++ b/build/generate/ownersFile.go @@ -5,7 +5,7 @@ import ( "sort" "strings" - "github.com/DNSControl/dnscontrol/v4/pkg/providers" + "github.com/DNSControl/dnscontrol/v5/pkg/providers" ) func generateOwnersFile() error { diff --git a/commands/cmdzonecache.go b/commands/cmdzonecache.go index b4ce95b073..0d5a86918c 100644 --- a/commands/cmdzonecache.go +++ b/commands/cmdzonecache.go @@ -1,6 +1,6 @@ package commands -import "github.com/DNSControl/dnscontrol/v4/pkg/providers" +import "github.com/DNSControl/dnscontrol/v5/pkg/providers" // FYI(tlim): This file was originally called zonecache.go. To remove any // confusion between it and pkg/zonecache, we've renamed it. We've also added diff --git a/commands/commands.go b/commands/commands.go index 3756bc314d..9a45f806e6 100644 --- a/commands/commands.go +++ b/commands/commands.go @@ -8,11 +8,11 @@ import ( "sort" "strings" - "github.com/DNSControl/dnscontrol/v4/models" - "github.com/DNSControl/dnscontrol/v4/pkg/diff2" - "github.com/DNSControl/dnscontrol/v4/pkg/js" - "github.com/DNSControl/dnscontrol/v4/pkg/printer" - "github.com/DNSControl/dnscontrol/v4/pkg/version" + "github.com/DNSControl/dnscontrol/v5/models" + "github.com/DNSControl/dnscontrol/v5/pkg/diff2" + "github.com/DNSControl/dnscontrol/v5/pkg/js" + "github.com/DNSControl/dnscontrol/v5/pkg/printer" + "github.com/DNSControl/dnscontrol/v5/pkg/version" "github.com/fatih/color" "github.com/urfave/cli/v3" ) @@ -26,6 +26,11 @@ const ( var commands = []*cli.Command{} +func commandNotFound(ctx context.Context, c *cli.Command, command string) { + fmt.Fprintf(c.Root().ErrWriter, "Unknown command: %s\n", command) + cli.OsExiter(1) +} + func cmd(cat string, c *cli.Command) bool { c.Category = cat commands = append(commands, c) @@ -54,6 +59,7 @@ func Run(v string) int { Usage: "DNSControl is a compiler and DSL for managing dns zones", Version: v, } + app.CommandNotFound = commandNotFound app.Flags = []cli.Flag{ &cli.BoolFlag{ Name: "debug", @@ -205,10 +211,8 @@ func preloadProviders(cfg *models.DNSConfig) (*models.DNSConfig, error) { return nil, fmt.Errorf("registrar named %s expected for %s, but never registered", d.RegistrarName, d.Name) } d.RegistrarInstance = &models.RegistrarInstance{ - ProviderBase: models.ProviderBase{ - Name: reg.Name, - ProviderType: reg.Type, - }, + Name: reg.Name, + ProviderType: reg.Type, } for pName, n := range d.DNSProviderNames { prov, ok := cfg.DNSProvidersByName[pName] @@ -216,10 +220,8 @@ func preloadProviders(cfg *models.DNSConfig) (*models.DNSConfig, error) { return nil, fmt.Errorf("DNS Provider named %s expected for %s, but never registered", pName, d.Name) } d.DNSProviderInstances = append(d.DNSProviderInstances, &models.DNSProviderInstance{ - ProviderBase: models.ProviderBase{ - Name: pName, - ProviderType: prov.Type, - }, + Name: pName, + ProviderType: prov.Type, NumberOfNameservers: n, }) } diff --git a/commands/createDomains.go b/commands/createDomains.go index f42b588010..50f1f2917b 100644 --- a/commands/createDomains.go +++ b/commands/createDomains.go @@ -4,8 +4,8 @@ import ( "context" "fmt" - "github.com/DNSControl/dnscontrol/v4/pkg/credsfile" - "github.com/DNSControl/dnscontrol/v4/pkg/providers" + "github.com/DNSControl/dnscontrol/v5/pkg/credsfile" + "github.com/DNSControl/dnscontrol/v5/pkg/providers" "github.com/urfave/cli/v3" ) diff --git a/commands/getZones.go b/commands/getZones.go index 7fc5d11fd4..8cb5513878 100644 --- a/commands/getZones.go +++ b/commands/getZones.go @@ -7,13 +7,10 @@ import ( "os" "strings" - "github.com/DNSControl/dnscontrol/v4/models" - "github.com/DNSControl/dnscontrol/v4/pkg/credsfile" - "github.com/DNSControl/dnscontrol/v4/pkg/domaintags" - "github.com/DNSControl/dnscontrol/v4/pkg/prettyzone" - "github.com/DNSControl/dnscontrol/v4/pkg/providers" - "github.com/DNSControl/dnscontrol/v4/pkg/rtypecontrol" - + "github.com/DNSControl/dnscontrol/v5/models" + "github.com/DNSControl/dnscontrol/v5/pkg/credsfile" + "github.com/DNSControl/dnscontrol/v5/pkg/prettyzone" + "github.com/DNSControl/dnscontrol/v5/pkg/providers" "github.com/urfave/cli/v3" ) @@ -86,6 +83,7 @@ var _ = cmd(catUtils, func() *cli.Command { // This takes one or two command-line args. // Starting in v3.16: Using it with 2 args will generate a warning. // Starting in v4.0: Using it with 2 args might be an error. + // After v5.0, it will be an error. (FIXME(tlim): Make it an error) if c.NArg() == 1 { arg0 = c.Args().Get(0) arg1 = "" @@ -207,20 +205,14 @@ func GetZone(args GetZoneArgs) error { // fetch all of the records zoneRecs := make([]models.Records, len(zones)) for i, zone := range zones { - ff := domaintags.MakeDomainNameVarieties(zone) - recs, err := provider.GetZoneRecords( - &models.DomainConfig{ - Name: ff.NameASCII, - Metadata: map[string]string{ - models.DomainUniqueName: ff.UniqueName, - models.DomainNameRaw: ff.NameRaw, - models.DomainNameUnicode: ff.NameUnicode, - }, - }) + dc, err := models.NewDomainConfig(zone) + if err != nil { + return fmt.Errorf("failed GetZone NewDC: %w", err) + } + recs, err := provider.GetZoneRecords(dc) if err != nil { return fmt.Errorf("failed GetZone gzr: %w", err) } - rtypecontrol.FixLegacyRecords(&recs) // Call this after GetZoneRecords() to fix providers that haven't been updated for RecordConfigV2. zoneRecs[i] = recs } @@ -338,6 +330,8 @@ func GetZone(args GetZoneArgs) error { case "tsv": for _, rec := range recs { providerMeta := "" + + // Cloudflare metadata if cp, ok := rec.Metadata["cloudflare_proxy"]; ok { if cp == "true" { providerMeta += ",cloudflare_proxy=true" @@ -354,6 +348,7 @@ func GetZone(args GetZoneArgs) error { if tags := rec.Metadata["cloudflare_tags"]; tags != "" { providerMeta += ",cloudflare_tags=" + tags } + // HEDNS metadata if dyn, ok := rec.Metadata["hedns_dynamic"]; ok && dyn == "on" { providerMeta += ",hedns_dynamic=on" @@ -361,6 +356,7 @@ func GetZone(args GetZoneArgs) error { providerMeta += ",hedns_ddns_key=" + key } } + if providerMeta != "" { providerMeta = "\t" + providerMeta[1:] // Remove leading comma, add tab } @@ -369,8 +365,15 @@ func GetZone(args GetZoneArgs) error { if rec.Type == "UNKNOWN" { ty = rec.UnknownTypeName } + + var content string + if rec.HasFormatIdenticalToTXT() { + content = rec.GetTargetTXTJoined() + } else { + content = rec.GetRDATA().String() + } fmt.Fprintf(w, "%s\t%s\t%d\tIN\t%s\t%s%s\n", - rec.NameFQDN, rec.Name, rec.TTL, ty, rec.GetTargetCombinedFunc(nil), providerMeta) + rec.NameFQDN, rec.Name, rec.TTL, ty, content, providerMeta) } default: @@ -391,7 +394,6 @@ func jsonQuoted(i string) string { } func formatDsl(rec *models.RecordConfig, defaultTTL uint32) string { - target := rec.GetTargetCombined() ttl := uint32(0) ttlop := "" @@ -461,58 +463,33 @@ func formatDsl(rec *models.RecordConfig, defaultTTL uint32) string { } } - switch rec.Type { // #rtype_variations + fj, _ := models.RDtoFieldsJS(rec.GetRDATA()) + + var target string + switch rec.Type { case "CAA": return makeCaa(rec, ttlop) - case "DS": - target = fmt.Sprintf(`%d, %d, %d, "%s"`, rec.DsKeyTag, rec.DsAlgorithm, rec.DsDigestType, rec.DsDigest) - case "DNSKEY": - target = fmt.Sprintf(`%d, %d, %d, "%s"`, rec.DnskeyFlags, rec.DnskeyProtocol, rec.DnskeyAlgorithm, rec.DnskeyPublicKey) - case "MX": - target = fmt.Sprintf(`%d, "%s"`, rec.MxPreference, rec.GetTargetField()) - case "NAPTR": - target = fmt.Sprintf(`%d, %d, %s, %s, %s, %s`, - rec.NaptrOrder, // 1 - rec.NaptrPreference, // 10 - jsonQuoted(rec.NaptrFlags), // U - jsonQuoted(rec.NaptrService), // E2U+sip - jsonQuoted(rec.NaptrRegexp), // regex - jsonQuoted(rec.GetTargetField()), // . - ) - case "SMIMEA": - target = fmt.Sprintf(`%d, %d, %d, "%s"`, rec.SmimeaUsage, rec.SmimeaSelector, rec.SmimeaMatchingType, rec.GetTargetField()) - case "SSHFP": - target = fmt.Sprintf(`%d, %d, "%s"`, rec.SshfpAlgorithm, rec.SshfpFingerprint, rec.GetTargetField()) case "SOA": - rec.Type = "//SOA" - target = fmt.Sprintf(`"%s", "%s", %d, %d, %d, %d`, rec.GetTargetField(), rec.SoaMbox, rec.SoaRefresh, rec.SoaRetry, rec.SoaExpire, rec.SoaMinttl) - case "SRV": - target = fmt.Sprintf(`%d, %d, %d, "%s"`, rec.SrvPriority, rec.SrvWeight, rec.SrvPort, rec.GetTargetField()) - case "SVCB", "HTTPS": - target = fmt.Sprintf(`%d, "%s", "%s"`, rec.SvcPriority, rec.GetTargetField(), rec.SvcParams) - case "TLSA": - target = fmt.Sprintf(`%d, %d, %d, "%s"`, rec.TlsaUsage, rec.TlsaSelector, rec.TlsaMatchingType, rec.GetTargetField()) + rec.Type = "//SOA" // Most providers don't need an SOA. Users can remove comments if they want it. + noserial := append(fj[:2], fj[3:]...) + target = strings.Join(noserial, ", ") + // f.Serial is not included in the SOA() function because DNSControl controls that field. case "TXT": target = jsonQuoted(rec.GetTargetTXTJoined()) // TODO(tlim): If this is an SPF record, generate a SPF_BUILDER(). case "LUA": - target = fmt.Sprintf("%q, %s", rec.LuaRType, jsonQuoted(rec.GetTargetTXTJoined())) + target = fmt.Sprintf("%q, %s", rec.AsLUA().LuaType, jsonQuoted(rec.GetTargetTXTJoined())) case "NS": // NS records at the apex should be NAMESERVER() records. // DnsControl uses the API to get this info. NAMESERVER() is just // to override that when needed. if rec.Name == "@" { - return fmt.Sprintf(`//NAMESERVER("%s")`, target) + return fmt.Sprintf(`//NAMESERVER("%s")`, rec.AsNS().Ns) } - target = `"` + target + `"` - case "MIKROTIK_FWD": - target = `"` + target + `"` - case "MIKROTIK_NXDOMAIN": - // NXDOMAIN has no target — emit only name + optional metadata + TTL - return fmt.Sprintf(`MIKROTIK_NXDOMAIN("%s"%s%s)`, rec.Name, mtmeta, ttlop) + target = `"` + rec.AsNS().Ns + `"` case "MIKROTIK_FORWARDER": // Forwarder: target is dns-servers, metadata has doh_servers/verify_doh_cert - target = `"` + target + `"` + target = `"` + rec.GetRDATA().String() + `"` if rec.Metadata != nil { var fwdParts []string if v := rec.Metadata["doh_servers"]; v != "" { @@ -530,18 +507,19 @@ func formatDsl(rec *models.RecordConfig, defaultTTL uint32) string { case "UNKNOWN": return makeUknown(rec, ttl) default: - target = `"` + target + `"` + target = strings.Join(fj, ", ") } return fmt.Sprintf(`%s("%s", %s%s%s%s%s%s%s%s)`, rec.Type, rec.Name, target, cfproxy, cfflatten, cfcomment, cftags, mtmeta, hednsDynamic, ttlop) } func makeCaa(rec *models.RecordConfig, ttlop string) string { + f := rec.AsCAA() var target string - if rec.CaaFlag == 128 { - target = fmt.Sprintf(`"%s", "%s", CAA_CRITICAL`, rec.CaaTag, rec.GetTargetField()) + if f.Flag == 128 { + target = fmt.Sprintf(`"%s", "%s", CAA_CRITICAL`, f.Tag, f.Value) } else { - target = fmt.Sprintf(`"%s", "%s"`, rec.CaaTag, rec.GetTargetField()) + target = fmt.Sprintf(`"%s", "%s"`, f.Tag, f.Value) } return fmt.Sprintf(`%s("%s", %s%s)`, rec.Type, rec.Name, target, ttlop) @@ -549,15 +527,16 @@ func makeCaa(rec *models.RecordConfig, ttlop string) string { } func makeR53alias(rec *models.RecordConfig, ttl uint32) string { + f := rec.AsR53ALIAS() items := []string{ `"` + rec.Name + `"`, - `"` + rec.R53Alias["type"] + `"`, - `"` + rec.GetTargetField() + `"`, + `"` + f.AliasType + `"`, + `"` + f.Target + `"`, } - if z, ok := rec.R53Alias["zone_id"]; ok { - items = append(items, `R53_ZONE("`+z+`")`) + if f.ZoneID != "" { + items = append(items, `R53_ZONE("`+f.ZoneID+`")`) } - if e, ok := rec.R53Alias["evaluate_target_health"]; ok && e == "true" { + if f.EvalTargetHealth == "true" { items = append(items, "R53_EVALUATE_TARGET_HEALTH(true)") } if ttl != 0 { @@ -567,5 +546,5 @@ func makeR53alias(rec *models.RecordConfig, ttl uint32) string { } func makeUknown(rc *models.RecordConfig, ttl uint32) string { - return fmt.Sprintf(`// %s("%s", TTL(%d))`, rc.UnknownTypeName, rc.GetTargetField(), ttl) + return fmt.Sprintf(`// %s("%s", TTL(%d))`, rc.UnknownTypeName, rc.GetRDATA().String(), ttl) } diff --git a/commands/gz_test.go b/commands/gz_test.go index 504a652acd..15d3a5ccb2 100644 --- a/commands/gz_test.go +++ b/commands/gz_test.go @@ -2,13 +2,11 @@ package commands import ( "fmt" - "log" "os" "testing" - _ "github.com/DNSControl/dnscontrol/v4/pkg/providers/_all" - _ "github.com/DNSControl/dnscontrol/v4/pkg/rtype" - "github.com/andreyvit/diff" + _ "github.com/DNSControl/dnscontrol/v5/pkg/providers/_all" + "github.com/google/go-cmp/cmp" ) func TestFormatTypes(t *testing.T) { @@ -35,9 +33,11 @@ func testFormat(t *testing.T, domain, format string) { outfile, err := os.CreateTemp(t.TempDir(), outputFiletmpl) if err != nil { - log.Fatal(fmt.Errorf("gz can't TempFile %q: %w", outputFiletmpl, err)) + t.Fatalf("gz can't TempFile %q: %v", outputFiletmpl, err) + } + if err := outfile.Close(); err != nil { + t.Fatalf("gz can't close TempFile %q: %v", outfile.Name(), err) } - defer os.Remove(outfile.Name()) // Convert test data to the experiment output. gzargs := GetZoneArgs{ @@ -46,33 +46,33 @@ func testFormat(t *testing.T, domain, format string) { OutputFile: outfile.Name(), CredName: "bind", ProviderName: "BIND", + CredsFile: "test_data/bind-creds.json", } - gzargs.CredsFile = "test_data/bind-creds.json" // Read the zonefile and convert err = GetZone(gzargs) if err != nil { - log.Fatal(fmt.Errorf("can't GetZone: %w", err)) + t.Fatalf("can't GetZone: %v", err) } // Read the actual result: got, err := os.ReadFile(outfile.Name()) if err != nil { - log.Fatal(fmt.Errorf("can't read actuals %q: %w", outfile.Name(), err)) + t.Fatalf("can't read actuals %q: %v", outfile.Name(), err) } // Read the expected result want, err := os.ReadFile(expectedFilename) if err != nil { - log.Fatal(fmt.Errorf("can't read expected %q: %w", expectedFilename, err)) + t.Fatalf("can't read expected %q: %v", expectedFilename, err) } - if w, g := string(want), string(got); w != g { + if diff := cmp.Diff(string(got), string(want)); diff != "" { // If the test fails, output a file showing "got" err = os.WriteFile(expectedFilename+".ACTUAL", got, 0o644) if err != nil { - log.Fatal(err) + t.Fatalf("can't write actual output: %v", err) } - t.Errorf("testFormat mismatch (-got +want):\n%s", diff.LineDiff(g, w)) + t.Errorf("testFormat mismatch (-got +want):\n%s", diff) } } diff --git a/commands/init.go b/commands/init.go index df31ecc0a9..b0fa1d8072 100644 --- a/commands/init.go +++ b/commands/init.go @@ -11,12 +11,10 @@ import ( "sort" "strings" - "github.com/DNSControl/dnscontrol/v4/models" - "github.com/DNSControl/dnscontrol/v4/pkg/credsfile" - "github.com/DNSControl/dnscontrol/v4/pkg/domaintags" - "github.com/DNSControl/dnscontrol/v4/pkg/prettyzone" - "github.com/DNSControl/dnscontrol/v4/pkg/providers" - "github.com/DNSControl/dnscontrol/v4/pkg/rtypecontrol" + "github.com/DNSControl/dnscontrol/v5/models" + "github.com/DNSControl/dnscontrol/v5/pkg/credsfile" + "github.com/DNSControl/dnscontrol/v5/pkg/prettyzone" + "github.com/DNSControl/dnscontrol/v5/pkg/providers" "github.com/urfave/cli/v3" ) @@ -309,20 +307,14 @@ func fetchZoneRecordsReal(entry InitCredsEntry, zone string) (models.Records, er if err != nil { return nil, err } - ff := domaintags.MakeDomainNameVarieties(zone) - recs, err := provider.GetZoneRecords( - &models.DomainConfig{ - Name: ff.NameASCII, - Metadata: map[string]string{ - models.DomainUniqueName: ff.UniqueName, - models.DomainNameRaw: ff.NameRaw, - models.DomainNameUnicode: ff.NameUnicode, - }, - }) + dc, err := models.NewDomainConfig(zone) + if err != nil { + return nil, fmt.Errorf("failed fetchZoneRecordsReal NewDC: %w", err) + } + recs, err := provider.GetZoneRecords(dc) if err != nil { return nil, err } - rtypecontrol.FixLegacyRecords(&recs) return recs, nil } diff --git a/commands/init_flow_test.go b/commands/init_flow_test.go index 82a9508836..f83db0cace 100644 --- a/commands/init_flow_test.go +++ b/commands/init_flow_test.go @@ -8,7 +8,8 @@ import ( "strings" "testing" - "github.com/DNSControl/dnscontrol/v4/models" + dnsv2 "codeberg.org/miekg/dns" + "github.com/DNSControl/dnscontrol/v5/models" ) // stubAsker drives the init flow from a pre recorded script for @@ -89,7 +90,37 @@ func stubFetchNoRecords(t *testing.T) { t.Cleanup(func() { fetchZoneRecordsFunc = origFetch }) } +// captureInitOutput keeps successful init-flow output from leaking into an +// unrelated test failure. If an init test fails, its captured output is logged. +func captureInitOutput(t *testing.T) { + t.Helper() + + output, err := os.CreateTemp(t.TempDir(), "init-output-*.txt") + if err != nil { + t.Fatalf("create init output capture: %v", err) + } + origStdout, origStderr := os.Stdout, os.Stderr + os.Stdout, os.Stderr = output, output + t.Cleanup(func() { + os.Stdout, os.Stderr = origStdout, origStderr + if err := output.Close(); err != nil { + t.Errorf("close init output capture: %v", err) + return + } + if !t.Failed() { + return + } + captured, err := os.ReadFile(output.Name()) + if err != nil { + t.Errorf("read init output capture: %v", err) + return + } + t.Logf("init output:\n%s", captured) + }) +} + func TestRunInit_VerifyDNSProviderCredsWithZones(t *testing.T) { + captureInitOutput(t) dir := t.TempDir() stub := &stubAsker{ @@ -152,6 +183,7 @@ func TestRunInit_VerifyDNSProviderCredsWithZones(t *testing.T) { } func TestRunInit_VerifyDNSProviderCredsRetry(t *testing.T) { + captureInitOutput(t) dir := t.TempDir() attempt := 0 @@ -209,6 +241,7 @@ func TestRunInit_VerifyDNSProviderCredsRetry(t *testing.T) { } func TestRunInit_VerifyDNSProviderCredsAbort(t *testing.T) { + captureInitOutput(t) dir := t.TempDir() stub := &stubAsker{ @@ -249,6 +282,7 @@ func TestRunInit_VerifyDNSProviderCredsAbort(t *testing.T) { // in providers (NONE registrar + BIND DNS). It asserts the generated // creds.json and dnsconfig.js parse cleanly. func TestRunInit_NoneBindFlow(t *testing.T) { + captureInitOutput(t) dir := t.TempDir() stub := &stubAsker{ @@ -318,6 +352,7 @@ func TestRunInit_NoneBindFlow(t *testing.T) { } func TestRunInit_ImportRecords(t *testing.T) { + captureInitOutput(t) dir := t.TempDir() stub := &stubAsker{ @@ -356,13 +391,11 @@ func TestRunInit_ImportRecords(t *testing.T) { origFetch := fetchZoneRecordsFunc fetchZoneRecordsFunc = func(_ InitCredsEntry, zone string) (models.Records, error) { - aRecord := &models.RecordConfig{Type: "A", Name: "www", TTL: 300} - aRecord.SetTarget("192.0.2.1") - mxRecord := &models.RecordConfig{Type: "MX", Name: "@", TTL: 300, MxPreference: 10} - mxRecord.SetTarget("mx.example.com.") - soaRecord := &models.RecordConfig{Type: "SOA", Name: "@"} - nsRecord := &models.RecordConfig{Type: "NS", Name: "@"} - nsRecord.SetTarget("ns1.example.com.") + dc := models.MustNewDomainConfig("example.com") + aRecord := dc.MustNewRecordConfig(dc.LabelFromShort("www"), 300, dnsv2.TypeA, "192.0.2.1") + mxRecord := dc.MustNewRecordConfig(dc.LabelFromShort("@"), 300, dnsv2.TypeMX, 10, "mx.example.com.") + soaRecord := dc.MustNewRecordConfig(dc.LabelFromShort("@"), 300, dnsv2.TypeSOA, "foo.example.com", "tal@example.com", 1, 2, 3, 4, 5) + nsRecord := dc.MustNewRecordConfig(dc.LabelFromShort("@"), 300, dnsv2.TypeNS, "ns.example.com.") return models.Records{aRecord, mxRecord, soaRecord, nsRecord}, nil } t.Cleanup(func() { fetchZoneRecordsFunc = origFetch }) @@ -398,6 +431,7 @@ func TestRunInit_ImportRecords(t *testing.T) { } func TestRunInit_ImportFallback(t *testing.T) { + captureInitOutput(t) dir := t.TempDir() stub := &stubAsker{ diff --git a/commands/init_prompt.go b/commands/init_prompt.go index bcdc0e4e1f..5a803f6d18 100644 --- a/commands/init_prompt.go +++ b/commands/init_prompt.go @@ -8,7 +8,7 @@ import ( "strings" "github.com/AlecAivazis/survey/v2" - "github.com/DNSControl/dnscontrol/v4/pkg/providers" + "github.com/DNSControl/dnscontrol/v5/pkg/providers" ) // Asker is the minimal set of interactive prompts used by `dnscontrol diff --git a/commands/init_render.go b/commands/init_render.go index 6d2bfdb7f0..09311003ca 100644 --- a/commands/init_render.go +++ b/commands/init_render.go @@ -7,7 +7,7 @@ import ( "maps" "strings" - "github.com/DNSControl/dnscontrol/v4/models" + "github.com/DNSControl/dnscontrol/v5/models" ) // InitCredsEntry represents a single provider entry ready to be written @@ -125,7 +125,7 @@ func renderDnsconfigJS(choice InitDnsconfigChoice) []byte { } // jsVarName builds a safe JavaScript variable name from a provider type. -// "CLOUDFLAREAPI" -> "CLOUDFLAREAPI", "HETZNER_V2" -> "HETZNER_V2". +// "CLOUDFLAREAPI" -> "DNS_CLOUDFLAREAPI", "HETZNER_V2" -> "REG_HETZNER_V2". func jsVarName(prefix, providerType string) string { clean := strings.Map(func(char rune) rune { switch { diff --git a/commands/ppreviewPush.go b/commands/ppreviewPush.go index 2df530dd84..badba54ed0 100644 --- a/commands/ppreviewPush.go +++ b/commands/ppreviewPush.go @@ -17,17 +17,18 @@ import ( "time" "unsafe" - "github.com/DNSControl/dnscontrol/v4/models" - "github.com/DNSControl/dnscontrol/v4/pkg/bindserial" - "github.com/DNSControl/dnscontrol/v4/pkg/credsfile" - "github.com/DNSControl/dnscontrol/v4/pkg/domaintags" - "github.com/DNSControl/dnscontrol/v4/pkg/nameservers" - "github.com/DNSControl/dnscontrol/v4/pkg/normalize" - "github.com/DNSControl/dnscontrol/v4/pkg/notifications" - "github.com/DNSControl/dnscontrol/v4/pkg/printer" - "github.com/DNSControl/dnscontrol/v4/pkg/providers" - "github.com/DNSControl/dnscontrol/v4/pkg/rfc4183" - "github.com/DNSControl/dnscontrol/v4/pkg/zonerecs" + "github.com/DNSControl/dnscontrol/v5/models" + "github.com/DNSControl/dnscontrol/v5/pkg/bindserial" + "github.com/DNSControl/dnscontrol/v5/pkg/credsfile" + "github.com/DNSControl/dnscontrol/v5/pkg/domaintags" + "github.com/DNSControl/dnscontrol/v5/pkg/nameservers" + "github.com/DNSControl/dnscontrol/v5/pkg/normalize" + "github.com/DNSControl/dnscontrol/v5/pkg/notifications" + "github.com/DNSControl/dnscontrol/v5/pkg/printer" + "github.com/DNSControl/dnscontrol/v5/pkg/providers" + "github.com/DNSControl/dnscontrol/v5/pkg/rfc4183" + "github.com/DNSControl/dnscontrol/v5/pkg/zonerecs" + "github.com/DNSControl/dnscontrol/v5/providers/ovh" "github.com/dustin/go-humanize" "github.com/nozzle/throttler" "github.com/urfave/cli/v3" @@ -142,6 +143,18 @@ func (args *PPreviewArgs) flags() []cli.Flag { return nil }, }) + flags = append(flags, &cli.BoolFlag{ + Name: "disable-list-zones", + Hidden: true, + Usage: `Pretend ListZones() is unimplemented (OVH only)`, + Action: func(ctx context.Context, c *cli.Command, noListZones bool) error { + // This was added because the integration test API key donated to + // the project doesn't have ListZones privs. If other providers + // this, we should make it a general thing. + ovh.NoListZone = noListZones + return nil + }, + }) flags = append(flags, &cli.Int64Flag{ Name: "bindserial", Destination: &bindserial.ForcedValue, @@ -434,7 +447,7 @@ func prun(args PPreviewArgs, push bool, interactive bool, out printer.CLI, repor // stats returns a JSON string with memory usage statistics. // These stats are unofficial and subject to change without notice. -// "average_mem_per_record" is misleading because it includes all memory overhead. +// "benchmark1" is misleading because it includes all memory overhead. func stats(cfg *models.DNSConfig) string { // https://www.datadoghq.com/blog/go-memory-metrics/ @@ -640,10 +653,12 @@ func skipProvider(name string, providers []*models.DNSProviderInstance) bool { }) } +// ansiEscapeRe matches terminal ANSI styling escape sequences. +var ansiEscapeRe = regexp.MustCompile(`\x1b\[[0-9;]*[a-zA-Z]`) + func parseCorrectionMsg(s string) []string { - // Regex to remove the terminal styled formatting - ansiRe := regexp.MustCompile(`\x1b\[[0-9;]*[a-zA-Z]`) - s = ansiRe.ReplaceAllString(s, "") + // Remove the terminal styled formatting. + s = ansiEscapeRe.ReplaceAllString(s, "") // Create a slice(array) of correction/actions/changes from Msg corrections := strings.Split(s, "\n") // Clean up the slice, precaution remove any empty entries. diff --git a/commands/ppreviewPush_test.go b/commands/ppreviewPush_test.go index cdc1cd7756..a1336de7a5 100644 --- a/commands/ppreviewPush_test.go +++ b/commands/ppreviewPush_test.go @@ -3,17 +3,16 @@ package commands import ( "testing" - "github.com/DNSControl/dnscontrol/v4/models" - "github.com/DNSControl/dnscontrol/v4/pkg/rtypecontrol" + "github.com/DNSControl/dnscontrol/v5/models" ) func Test_whichZonesToProcess(t *testing.T) { - dcNoTag := &models.DomainConfig{Name: "example.com"} - dcNoTag2 := &models.DomainConfig{Name: "example.net"} - dcTaggedEmpty := &models.DomainConfig{Name: "example.com!"} - dcTaggedGeorge := &models.DomainConfig{Name: "example.com!george"} - dcTaggedJohn := &models.DomainConfig{Name: "example.com!john"} + dcNoTag := models.MustNewDomainConfig("example.com") + dcNoTag2 := models.MustNewDomainConfig("example.net") + dcTaggedEmpty := models.MustNewDomainConfig("example.com!") + dcTaggedGeorge := models.MustNewDomainConfig("example.com!george") + dcTaggedJohn := models.MustNewDomainConfig("example.com!john") allDC := []*models.DomainConfig{ dcNoTag, @@ -26,7 +25,6 @@ func Test_whichZonesToProcess(t *testing.T) { // This is needed since we aren't calling js.ExecuteJavaScript(). for _, dc := range allDC { dc.PostProcess() - rtypecontrol.FixLegacyDC(dc) } type args struct { @@ -209,7 +207,7 @@ func Test_zoneWillBeCreated(t *testing.T) { for _, tc := range tests { t.Run(tc.name, func(t *testing.T) { - zone := &models.DomainConfig{Name: "example.com"} + zone := models.MustNewDomainConfig("example.com") zone.StorePopulateCorrections(provider, tc.corrections) if got := zoneWillBeCreated(zone, provider); got != tc.want { t.Errorf("zoneWillBeCreated() = %v, want %v", got, tc.want) @@ -242,7 +240,7 @@ func Test_reportZonePendingCreation(t *testing.T) { for _, tc := range tests { t.Run(tc.name, func(t *testing.T) { - zone := &models.DomainConfig{Name: "example.com"} + zone := models.MustNewDomainConfig("example.com") zone.StorePopulateCorrections(provider, tc.corrections) if got := reportZonePendingCreation(zone, provider, tc.push, tc.populateOnPreview); got != tc.want { t.Errorf("reportZonePendingCreation() = %v, want %v", got, tc.want) diff --git a/commands/previewPush.go b/commands/previewPush.go index 78568d5918..c62c03b3d4 100644 --- a/commands/previewPush.go +++ b/commands/previewPush.go @@ -5,9 +5,9 @@ import ( "os" "strings" - "github.com/DNSControl/dnscontrol/v4/models" - "github.com/DNSControl/dnscontrol/v4/pkg/notifications" - "github.com/DNSControl/dnscontrol/v4/pkg/providers" + "github.com/DNSControl/dnscontrol/v5/models" + "github.com/DNSControl/dnscontrol/v5/pkg/notifications" + "github.com/DNSControl/dnscontrol/v5/pkg/providers" ) // ReportItem is a record of corrections for a particular domain/provider/registrar. diff --git a/commands/printIR.go b/commands/printIR.go index 9f1e940a4a..1426318041 100644 --- a/commands/printIR.go +++ b/commands/printIR.go @@ -9,10 +9,10 @@ import ( "os" "strings" - "github.com/DNSControl/dnscontrol/v4/models" - "github.com/DNSControl/dnscontrol/v4/pkg/js" - "github.com/DNSControl/dnscontrol/v4/pkg/normalize" - "github.com/DNSControl/dnscontrol/v4/pkg/rfc4183" + "github.com/DNSControl/dnscontrol/v5/models" + "github.com/DNSControl/dnscontrol/v5/pkg/js" + "github.com/DNSControl/dnscontrol/v5/pkg/normalize" + "github.com/DNSControl/dnscontrol/v5/pkg/rfc4183" "github.com/urfave/cli/v3" ) diff --git a/commands/r53_test.go b/commands/r53_test.go deleted file mode 100644 index 11dcd22048..0000000000 --- a/commands/r53_test.go +++ /dev/null @@ -1,137 +0,0 @@ -package commands - -import ( - "testing" - - "github.com/DNSControl/dnscontrol/v4/models" - _ "github.com/DNSControl/dnscontrol/v4/pkg/providers/_all" - _ "github.com/DNSControl/dnscontrol/v4/pkg/rtype" -) - -func TestR53Test_1(t *testing.T) { - rec := models.RecordConfig{ - Type: "R53_ALIAS", - Name: "foo", - NameFQDN: "foo.domain.tld", - } - rec.MustSetTarget("bar") - rec.R53Alias = make(map[string]string) - rec.R53Alias["type"] = "A" - w := `R53_ALIAS("foo", "A", "bar")` - if g := makeR53alias(&rec, 0); g != w { - t.Errorf("makeR53alias failure: got `%s` want `%s`", g, w) - } -} - -func TestR53Test_1ttl(t *testing.T) { - rec := models.RecordConfig{ - Type: "R53_ALIAS", - Name: "foo", - NameFQDN: "foo.domain.tld", - } - rec.MustSetTarget("bar") - rec.R53Alias = make(map[string]string) - rec.R53Alias["type"] = "A" - w := `R53_ALIAS("foo", "A", "bar", TTL(321))` - if g := makeR53alias(&rec, 321); g != w { - t.Errorf("makeR53alias failure: got `%s` want `%s`", g, w) - } -} - -func TestR53Test_2(t *testing.T) { - rec := models.RecordConfig{ - Type: "R53_ALIAS", - Name: "foo", - NameFQDN: "foo.domain.tld", - } - rec.MustSetTarget("bar") - rec.R53Alias = make(map[string]string) - rec.R53Alias["type"] = "A" - rec.R53Alias["zone_id"] = "blarg" - w := `R53_ALIAS("foo", "A", "bar", R53_ZONE("blarg"))` - if g := makeR53alias(&rec, 0); g != w { - t.Errorf("makeR53alias failure: got `%s` want `%s`", g, w) - } -} - -func TestR53Test_2ttl(t *testing.T) { - rec := models.RecordConfig{ - Type: "R53_ALIAS", - Name: "foo", - NameFQDN: "foo.domain.tld", - } - rec.MustSetTarget("bar") - rec.R53Alias = make(map[string]string) - rec.R53Alias["type"] = "A" - rec.R53Alias["zone_id"] = "blarg" - w := `R53_ALIAS("foo", "A", "bar", R53_ZONE("blarg"), TTL(123))` - if g := makeR53alias(&rec, 123); g != w { - 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.MustSetTarget("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.MustSetTarget("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.MustSetTarget("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.MustSetTarget("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/test_data/example.org.zone.djs b/commands/test_data/example.org.zone.djs index 540942a331..11771de7e7 100644 --- a/commands/test_data/example.org.zone.djs +++ b/commands/test_data/example.org.zone.djs @@ -78,28 +78,28 @@ D("example.org", REG_CHANGEME , AAAA("megalomaniac", "2001:db8:ffef::254") , A("megalomaniac.ipv4", "198.51.100.254") , AAAA("megalomaniac.ipv6", "2001:db8:ffef::254") - , SSHFP("megalomaniac", 1, 2, "4e9ced94d3caf2ce915f85a63ce7279d5118a79ea03dac59cf4859b825d2f619") - , SSHFP("megalomaniac", 3, 2, "d3556a3db83ab9ccec39dc6693dd2f3e28b178c9bba61880924821c426cc61eb") - , SSHFP("megalomaniac", 4, 2, "c60c9d9d4728668f5f46986ff0c5b416c5e913862c4970cbfe211a6f44a111b4") - , SSHFP("megalomaniac.ipv4", 1, 2, "4e9ced94d3caf2ce915f85a63ce7279d5118a79ea03dac59cf4859b825d2f619") - , SSHFP("megalomaniac.ipv4", 3, 2, "d3556a3db83ab9ccec39dc6693dd2f3e28b178c9bba61880924821c426cc61eb") - , SSHFP("megalomaniac.ipv4", 4, 2, "c60c9d9d4728668f5f46986ff0c5b416c5e913862c4970cbfe211a6f44a111b4") - , SSHFP("megalomaniac.ipv6", 1, 2, "4e9ced94d3caf2ce915f85a63ce7279d5118a79ea03dac59cf4859b825d2f619") - , SSHFP("megalomaniac.ipv6", 3, 2, "d3556a3db83ab9ccec39dc6693dd2f3e28b178c9bba61880924821c426cc61eb") - , SSHFP("megalomaniac.ipv6", 4, 2, "c60c9d9d4728668f5f46986ff0c5b416c5e913862c4970cbfe211a6f44a111b4") + , SSHFP("megalomaniac", 1, 2, "4E9CED94D3CAF2CE915F85A63CE7279D5118A79EA03DAC59CF4859B825D2F619") + , SSHFP("megalomaniac", 3, 2, "D3556A3DB83AB9CCEC39DC6693DD2F3E28B178C9BBA61880924821C426CC61EB") + , SSHFP("megalomaniac", 4, 2, "C60C9D9D4728668F5F46986FF0C5B416C5E913862C4970CBFE211A6F44A111B4") + , SSHFP("megalomaniac.ipv4", 1, 2, "4E9CED94D3CAF2CE915F85A63CE7279D5118A79EA03DAC59CF4859B825D2F619") + , SSHFP("megalomaniac.ipv4", 3, 2, "D3556A3DB83AB9CCEC39DC6693DD2F3E28B178C9BBA61880924821C426CC61EB") + , SSHFP("megalomaniac.ipv4", 4, 2, "C60C9D9D4728668F5F46986FF0C5B416C5E913862C4970CBFE211A6F44A111B4") + , SSHFP("megalomaniac.ipv6", 1, 2, "4E9CED94D3CAF2CE915F85A63CE7279D5118A79EA03DAC59CF4859B825D2F619") + , SSHFP("megalomaniac.ipv6", 3, 2, "D3556A3DB83AB9CCEC39DC6693DD2F3E28B178C9BBA61880924821C426CC61EB") + , SSHFP("megalomaniac.ipv6", 4, 2, "C60C9D9D4728668F5F46986FF0C5B416C5E913862C4970CBFE211A6F44A111B4") , A("tower", "192.0.2.42") , AAAA("tower", "2001:db8::1:42") , A("tower.ipv4", "192.0.2.42") , AAAA("tower.ipv6", "2001:db8::1:42") - , SSHFP("tower", 1, 2, "0f211d236e94768911a294f38653c4af6fa935a5b06c975d8162f59142571451") - , SSHFP("tower", 3, 2, "88bf7b7401c11fa2e84871efb06cd73d8fc409154605b354db2dda0b82fe1160") - , SSHFP("tower", 4, 2, "6d30900be0faaae73568fc007a87b4d076cf9a351ecacc1106aef726c34ad61d") - , SSHFP("tower.ipv4", 1, 2, "0f211d236e94768911a294f38653c4af6fa935a5b06c975d8162f59142571451") - , SSHFP("tower.ipv4", 3, 2, "88bf7b7401c11fa2e84871efb06cd73d8fc409154605b354db2dda0b82fe1160") - , SSHFP("tower.ipv4", 4, 2, "6d30900be0faaae73568fc007a87b4d076cf9a351ecacc1106aef726c34ad61d") - , SSHFP("tower.ipv6", 1, 2, "0f211d236e94768911a294f38653c4af6fa935a5b06c975d8162f59142571451") - , SSHFP("tower.ipv6", 3, 2, "88bf7b7401c11fa2e84871efb06cd73d8fc409154605b354db2dda0b82fe1160") - , SSHFP("tower.ipv6", 4, 2, "6d30900be0faaae73568fc007a87b4d076cf9a351ecacc1106aef726c34ad61d") + , SSHFP("tower", 1, 2, "0F211D236E94768911A294F38653C4AF6FA935A5B06C975D8162F59142571451") + , SSHFP("tower", 3, 2, "88BF7B7401C11FA2E84871EFB06CD73D8FC409154605B354DB2DDA0B82FE1160") + , SSHFP("tower", 4, 2, "6D30900BE0FAAAE73568FC007A87B4D076CF9A351ECACC1106AEF726C34AD61D") + , SSHFP("tower.ipv4", 1, 2, "0F211D236E94768911A294F38653C4AF6FA935A5B06C975D8162F59142571451") + , SSHFP("tower.ipv4", 3, 2, "88BF7B7401C11FA2E84871EFB06CD73D8FC409154605B354DB2DDA0B82FE1160") + , SSHFP("tower.ipv4", 4, 2, "6D30900BE0FAAAE73568FC007A87B4D076CF9A351ECACC1106AEF726C34AD61D") + , SSHFP("tower.ipv6", 1, 2, "0F211D236E94768911A294F38653C4AF6FA935A5B06C975D8162F59142571451") + , SSHFP("tower.ipv6", 3, 2, "88BF7B7401C11FA2E84871EFB06CD73D8FC409154605B354DB2DDA0B82FE1160") + , SSHFP("tower.ipv6", 4, 2, "6D30900BE0FAAAE73568FC007A87B4D076CF9A351ECACC1106AEF726C34AD61D") , A("vcs", "192.0.2.228") , AAAA("vcs", "2001:db8::48:4558:4456:4353") , A("vcs.ipv4", "192.0.2.228") @@ -108,28 +108,28 @@ D("example.org", REG_CHANGEME , CNAME("git.ipv4", "vcs.ipv4.example.org.") , CNAME("git.ipv6", "vcs.ipv6.example.org.") , AAAA("svn", "2001:db8::48:4558:73:766e") - , SSHFP("vcs", 1, 2, "b518be390babdf43cb2d598aa6befa6ce6878546bf107b829d0cfc65253a97d4") - , SSHFP("vcs", 3, 2, "e92545dc0bf501f72333ddeb7a37afc2c5b408ce39a3ad95fbc66236f0077323") - , SSHFP("vcs", 4, 2, "02289441124a487095a6cda2e946c6a8ed9087faf3592ec4135536c3e615521c") - , SSHFP("vcs.ipv4", 1, 2, "b518be390babdf43cb2d598aa6befa6ce6878546bf107b829d0cfc65253a97d4") - , SSHFP("vcs.ipv4", 3, 2, "e92545dc0bf501f72333ddeb7a37afc2c5b408ce39a3ad95fbc66236f0077323") - , SSHFP("vcs.ipv4", 4, 2, "02289441124a487095a6cda2e946c6a8ed9087faf3592ec4135536c3e615521c") - , SSHFP("vcs.ipv6", 1, 2, "b518be390babdf43cb2d598aa6befa6ce6878546bf107b829d0cfc65253a97d4") - , SSHFP("vcs.ipv6", 3, 2, "e92545dc0bf501f72333ddeb7a37afc2c5b408ce39a3ad95fbc66236f0077323") - , SSHFP("vcs.ipv6", 4, 2, "02289441124a487095a6cda2e946c6a8ed9087faf3592ec4135536c3e615521c") + , SSHFP("vcs", 1, 2, "B518BE390BABDF43CB2D598AA6BEFA6CE6878546BF107B829D0CFC65253A97D4") + , SSHFP("vcs", 3, 2, "E92545DC0BF501F72333DDEB7A37AFC2C5B408CE39A3AD95FBC66236F0077323") + , SSHFP("vcs", 4, 2, "02289441124A487095A6CDA2E946C6A8ED9087FAF3592EC4135536C3E615521C") + , SSHFP("vcs.ipv4", 1, 2, "B518BE390BABDF43CB2D598AA6BEFA6CE6878546BF107B829D0CFC65253A97D4") + , SSHFP("vcs.ipv4", 3, 2, "E92545DC0BF501F72333DDEB7A37AFC2C5B408CE39A3AD95FBC66236F0077323") + , SSHFP("vcs.ipv4", 4, 2, "02289441124A487095A6CDA2E946C6A8ED9087FAF3592EC4135536C3E615521C") + , SSHFP("vcs.ipv6", 1, 2, "B518BE390BABDF43CB2D598AA6BEFA6CE6878546BF107B829D0CFC65253A97D4") + , SSHFP("vcs.ipv6", 3, 2, "E92545DC0BF501F72333DDEB7A37AFC2C5B408CE39A3AD95FBC66236F0077323") + , SSHFP("vcs.ipv6", 4, 2, "02289441124A487095A6CDA2E946C6A8ED9087FAF3592EC4135536C3E615521C") , A("nsauth", "192.0.2.53") , AAAA("nsauth", "2001:db8::53:1") , A("nsauth.ipv4", "192.0.2.53") , AAAA("nsauth.ipv6", "2001:db8::53:1") - , SSHFP("nsauth", 1, 2, "895804ae022fff643b2677563cb850607c5bb564d9919896c521098c8abc40f2") - , SSHFP("nsauth", 3, 2, "28a65470badae611375747e1a803211c41e3d71e97741fa92ccbdf7b01f34e42") - , SSHFP("nsauth", 4, 2, "6e10445c0649c03fa83e18b1873e5b89b3a20893ecb48d01e7cedb3dd563ecf0") - , SSHFP("nsauth.ipv4", 1, 2, "895804ae022fff643b2677563cb850607c5bb564d9919896c521098c8abc40f2") - , SSHFP("nsauth.ipv4", 3, 2, "28a65470badae611375747e1a803211c41e3d71e97741fa92ccbdf7b01f34e42") - , SSHFP("nsauth.ipv4", 4, 2, "6e10445c0649c03fa83e18b1873e5b89b3a20893ecb48d01e7cedb3dd563ecf0") - , SSHFP("nsauth.ipv6", 1, 2, "895804ae022fff643b2677563cb850607c5bb564d9919896c521098c8abc40f2") - , SSHFP("nsauth.ipv6", 3, 2, "28a65470badae611375747e1a803211c41e3d71e97741fa92ccbdf7b01f34e42") - , SSHFP("nsauth.ipv6", 4, 2, "6e10445c0649c03fa83e18b1873e5b89b3a20893ecb48d01e7cedb3dd563ecf0") + , SSHFP("nsauth", 1, 2, "895804AE022FFF643B2677563CB850607C5BB564D9919896C521098C8ABC40F2") + , SSHFP("nsauth", 3, 2, "28A65470BADAE611375747E1A803211C41E3D71E97741FA92CCBDF7B01F34E42") + , SSHFP("nsauth", 4, 2, "6E10445C0649C03FA83E18B1873E5B89B3A20893ECB48D01E7CEDB3DD563ECF0") + , SSHFP("nsauth.ipv4", 1, 2, "895804AE022FFF643B2677563CB850607C5BB564D9919896C521098C8ABC40F2") + , SSHFP("nsauth.ipv4", 3, 2, "28A65470BADAE611375747E1A803211C41E3D71E97741FA92CCBDF7B01F34E42") + , SSHFP("nsauth.ipv4", 4, 2, "6E10445C0649C03FA83E18B1873E5B89B3A20893ECB48D01E7CEDB3DD563ECF0") + , SSHFP("nsauth.ipv6", 1, 2, "895804AE022FFF643B2677563CB850607C5BB564D9919896C521098C8ABC40F2") + , SSHFP("nsauth.ipv6", 3, 2, "28A65470BADAE611375747E1A803211C41E3D71E97741FA92CCBDF7B01F34E42") + , SSHFP("nsauth.ipv6", 4, 2, "6E10445C0649C03FA83E18B1873E5B89B3A20893ECB48D01E7CEDB3DD563ECF0") , A("ns1", "192.0.2.53") , AAAA("ns1", "2001:db8::53:1") , A("ns2", "203.0.113.53") @@ -140,15 +140,15 @@ D("example.org", REG_CHANGEME , A("hermes.ipv4", "192.0.2.25") , AAAA("hermes.ipv6", "2001:db8::48:4558:736d:7470") , AAAA("hermes.ipv6", "2001:db8::48:4558:696d:6170") - , SSHFP("hermes", 1, 2, "4472ff5bd0528cd49216af4503ba6a1c48f121d0292a31d6af193e5000af4966") - , SSHFP("hermes", 3, 2, "eaba20c1565676a5229184ccfcf82d0ee408f91757a67d9fa51a0b6f3db4a33b") - , SSHFP("hermes", 4, 2, "a9d89920e599d04363c8b35a4ce66c1ed257ea1d16981f060b6aed080bbb7a7c") - , SSHFP("hermes.ipv4", 1, 2, "4472ff5bd0528cd49216af4503ba6a1c48f121d0292a31d6af193e5000af4966") - , SSHFP("hermes.ipv4", 3, 2, "eaba20c1565676a5229184ccfcf82d0ee408f91757a67d9fa51a0b6f3db4a33b") - , SSHFP("hermes.ipv4", 4, 2, "a9d89920e599d04363c8b35a4ce66c1ed257ea1d16981f060b6aed080bbb7a7c") - , SSHFP("hermes.ipv6", 1, 2, "4472ff5bd0528cd49216af4503ba6a1c48f121d0292a31d6af193e5000af4966") - , SSHFP("hermes.ipv6", 3, 2, "eaba20c1565676a5229184ccfcf82d0ee408f91757a67d9fa51a0b6f3db4a33b") - , SSHFP("hermes.ipv6", 4, 2, "a9d89920e599d04363c8b35a4ce66c1ed257ea1d16981f060b6aed080bbb7a7c") + , SSHFP("hermes", 1, 2, "4472FF5BD0528CD49216AF4503BA6A1C48F121D0292A31D6AF193E5000AF4966") + , SSHFP("hermes", 3, 2, "EABA20C1565676A5229184CCFCF82D0EE408F91757A67D9FA51A0B6F3DB4A33B") + , SSHFP("hermes", 4, 2, "A9D89920E599D04363C8B35A4CE66C1ED257EA1D16981F060B6AED080BBB7A7C") + , SSHFP("hermes.ipv4", 1, 2, "4472FF5BD0528CD49216AF4503BA6A1C48F121D0292A31D6AF193E5000AF4966") + , SSHFP("hermes.ipv4", 3, 2, "EABA20C1565676A5229184CCFCF82D0EE408F91757A67D9FA51A0B6F3DB4A33B") + , SSHFP("hermes.ipv4", 4, 2, "A9D89920E599D04363C8B35A4CE66C1ED257EA1D16981F060B6AED080BBB7A7C") + , SSHFP("hermes.ipv6", 1, 2, "4472FF5BD0528CD49216AF4503BA6A1C48F121D0292A31D6AF193E5000AF4966") + , SSHFP("hermes.ipv6", 3, 2, "EABA20C1565676A5229184CCFCF82D0EE408F91757A67D9FA51A0B6F3DB4A33B") + , SSHFP("hermes.ipv6", 4, 2, "A9D89920E599D04363C8B35A4CE66C1ED257EA1D16981F060B6AED080BBB7A7C") , A("kerb-service", "192.0.2.88") , AAAA("kerb-service", "2001:db8::48:4558:6b65:7262") , A("security", "192.0.2.92") @@ -175,51 +175,51 @@ D("example.org", REG_CHANGEME , CNAME("www.ipv4", "services.ipv4.example.org.") , CNAME("www.ipv6", "services.ipv6.example.org.") , CAA("@", "issue", "example.net") - , CAA("@", "issue", "letsencrypt.org\; accounturi=https://acme-v01.api.letsencrypt.org/acme/reg/1234567") - , CAA("@", "issue", "letsencrypt.org\; accounturi=https://acme-staging-v02.api.letsencrypt.org/acme/acct/23456789") - , CAA("@", "issue", "letsencrypt.org\; accounturi=https://acme-v02.api.letsencrypt.org/acme/acct/76543210") + , CAA("@", "issue", "letsencrypt.org; accounturi=https://acme-v01.api.letsencrypt.org/acme/reg/1234567") + , CAA("@", "issue", "letsencrypt.org; accounturi=https://acme-staging-v02.api.letsencrypt.org/acme/acct/23456789") + , CAA("@", "issue", "letsencrypt.org; accounturi=https://acme-v02.api.letsencrypt.org/acme/acct/76543210") , CAA("@", "issuewild", ";") , CAA("@", "iodef", "mailto:security@example.org") - , TLSA("_ourcaca4-tlsa", 2, 0, 1, "ea99063a0a3bda9727032cf82da238698b90ba729300703d3956943635f96488") - , TLSA("_ourcaca5-tlsa", 2, 0, 1, "11f058f61f97b8adc66ef4801f918c71b10e5c1e3d39afde10408b3026647ef1") - , TLSA("_cacert-c3-tlsa", 2, 0, 1, "4edde9e55ca453b388887caa25d5c5c5bccf2891d73b87495808293d5fac83c8") - , TLSA("_letsencrypt-tlsa", 2, 1, 1, "60b87575447dcba2a36b7d11ac09fb24a9db406fee12d2cc90180517616e8a18") - , TLSA("_letsencrypt-tlsa", 2, 1, 1, "b111dd8a1c2091a89bd4fd60c57f0716cce50feeff8137cdbee0326e02cf362b") - , TLSA("_amazon-tlsa", 2, 0, 1, "8ecde6884f3d87b1125ba31ac3fcb13d7016de7f57cc904fe1cb97c6ae98196e") - , TLSA("_amazon-tlsa", 2, 0, 1, "1ba5b2aa8c65401a82960118f80bec4f62304d83cec4713a19c39c011ea46db4") - , TLSA("_amazon-tlsa", 2, 0, 1, "18ce6cfe7bf14e60b2e347b8dfe868cb31d02ebb3ada271569f50343b46db3a4") - , TLSA("_amazon-tlsa", 2, 0, 1, "e35d28419ed02025cfa69038cd623962458da5c695fbdea3c22b0bfb25897092") - , TLSA("_ourca-tlsa", 2, 0, 1, "ea99063a0a3bda9727032cf82da238698b90ba729300703d3956943635f96488") - , TLSA("_ourca-tlsa", 2, 0, 1, "11f058f61f97b8adc66ef4801f918c71b10e5c1e3d39afde10408b3026647ef1") - , TLSA("_ourca-cacert-tlsa", 2, 0, 1, "ea99063a0a3bda9727032cf82da238698b90ba729300703d3956943635f96488") - , TLSA("_ourca-cacert-tlsa", 2, 0, 1, "11f058f61f97b8adc66ef4801f918c71b10e5c1e3d39afde10408b3026647ef1") - , TLSA("_ourca-cacert-tlsa", 2, 0, 1, "4edde9e55ca453b388887caa25d5c5c5bccf2891d73b87495808293d5fac83c8") - , TLSA("_ourca-le-tlsa", 2, 0, 1, "ea99063a0a3bda9727032cf82da238698b90ba729300703d3956943635f96488") - , TLSA("_ourca-le-tlsa", 2, 0, 1, "11f058f61f97b8adc66ef4801f918c71b10e5c1e3d39afde10408b3026647ef1") - , TLSA("_ourca-le-tlsa", 2, 1, 1, "60b87575447dcba2a36b7d11ac09fb24a9db406fee12d2cc90180517616e8a18") - , TLSA("_ourca-le-tlsa", 2, 1, 1, "b111dd8a1c2091a89bd4fd60c57f0716cce50feeff8137cdbee0326e02cf362b") - , TLSA("_ourca-cacert-le-tlsa", 2, 0, 1, "ea99063a0a3bda9727032cf82da238698b90ba729300703d3956943635f96488") - , TLSA("_ourca-cacert-le-tlsa", 2, 0, 1, "11f058f61f97b8adc66ef4801f918c71b10e5c1e3d39afde10408b3026647ef1") - , TLSA("_ourca-cacert-le-tlsa", 2, 0, 1, "4edde9e55ca453b388887caa25d5c5c5bccf2891d73b87495808293d5fac83c8") - , TLSA("_ourca-cacert-le-tlsa", 2, 1, 1, "60b87575447dcba2a36b7d11ac09fb24a9db406fee12d2cc90180517616e8a18") - , TLSA("_ourca-cacert-le-tlsa", 2, 1, 1, "b111dd8a1c2091a89bd4fd60c57f0716cce50feeff8137cdbee0326e02cf362b") - , TLSA("_cacert-le-tlsa", 2, 0, 1, "4edde9e55ca453b388887caa25d5c5c5bccf2891d73b87495808293d5fac83c8") - , TLSA("_cacert-le-tlsa", 2, 1, 1, "60b87575447dcba2a36b7d11ac09fb24a9db406fee12d2cc90180517616e8a18") - , TLSA("_cacert-le-tlsa", 2, 1, 1, "b111dd8a1c2091a89bd4fd60c57f0716cce50feeff8137cdbee0326e02cf362b") - , TLSA("_le-amazon-tlsa", 2, 1, 1, "60b87575447dcba2a36b7d11ac09fb24a9db406fee12d2cc90180517616e8a18") - , TLSA("_le-amazon-tlsa", 2, 1, 1, "b111dd8a1c2091a89bd4fd60c57f0716cce50feeff8137cdbee0326e02cf362b") - , TLSA("_le-amazon-tlsa", 2, 0, 1, "8ecde6884f3d87b1125ba31ac3fcb13d7016de7f57cc904fe1cb97c6ae98196e") - , TLSA("_le-amazon-tlsa", 2, 0, 1, "1ba5b2aa8c65401a82960118f80bec4f62304d83cec4713a19c39c011ea46db4") - , TLSA("_le-amazon-tlsa", 2, 0, 1, "18ce6cfe7bf14e60b2e347b8dfe868cb31d02ebb3ada271569f50343b46db3a4") - , TLSA("_le-amazon-tlsa", 2, 0, 1, "e35d28419ed02025cfa69038cd623962458da5c695fbdea3c22b0bfb25897092") - , TLSA("_ourca-le-amazon-tlsa", 2, 0, 1, "ea99063a0a3bda9727032cf82da238698b90ba729300703d3956943635f96488") - , TLSA("_ourca-le-amazon-tlsa", 2, 0, 1, "11f058f61f97b8adc66ef4801f918c71b10e5c1e3d39afde10408b3026647ef1") - , TLSA("_ourca-le-amazon-tlsa", 2, 1, 1, "60b87575447dcba2a36b7d11ac09fb24a9db406fee12d2cc90180517616e8a18") - , TLSA("_ourca-le-amazon-tlsa", 2, 1, 1, "b111dd8a1c2091a89bd4fd60c57f0716cce50feeff8137cdbee0326e02cf362b") - , TLSA("_ourca-le-amazon-tlsa", 2, 0, 1, "8ecde6884f3d87b1125ba31ac3fcb13d7016de7f57cc904fe1cb97c6ae98196e") - , TLSA("_ourca-le-amazon-tlsa", 2, 0, 1, "1ba5b2aa8c65401a82960118f80bec4f62304d83cec4713a19c39c011ea46db4") - , TLSA("_ourca-le-amazon-tlsa", 2, 0, 1, "18ce6cfe7bf14e60b2e347b8dfe868cb31d02ebb3ada271569f50343b46db3a4") - , TLSA("_ourca-le-amazon-tlsa", 2, 0, 1, "e35d28419ed02025cfa69038cd623962458da5c695fbdea3c22b0bfb25897092") + , TLSA("_ourcaca4-tlsa", 2, 0, 1, "EA99063A0A3BDA9727032CF82DA238698B90BA729300703D3956943635F96488") + , TLSA("_ourcaca5-tlsa", 2, 0, 1, "11F058F61F97B8ADC66EF4801F918C71B10E5C1E3D39AFDE10408B3026647EF1") + , TLSA("_cacert-c3-tlsa", 2, 0, 1, "4EDDE9E55CA453B388887CAA25D5C5C5BCCF2891D73B87495808293D5FAC83C8") + , TLSA("_letsencrypt-tlsa", 2, 1, 1, "60B87575447DCBA2A36B7D11AC09FB24A9DB406FEE12D2CC90180517616E8A18") + , TLSA("_letsencrypt-tlsa", 2, 1, 1, "B111DD8A1C2091A89BD4FD60C57F0716CCE50FEEFF8137CDBEE0326E02CF362B") + , TLSA("_amazon-tlsa", 2, 0, 1, "8ECDE6884F3D87B1125BA31AC3FCB13D7016DE7F57CC904FE1CB97C6AE98196E") + , TLSA("_amazon-tlsa", 2, 0, 1, "1BA5B2AA8C65401A82960118F80BEC4F62304D83CEC4713A19C39C011EA46DB4") + , TLSA("_amazon-tlsa", 2, 0, 1, "18CE6CFE7BF14E60B2E347B8DFE868CB31D02EBB3ADA271569F50343B46DB3A4") + , TLSA("_amazon-tlsa", 2, 0, 1, "E35D28419ED02025CFA69038CD623962458DA5C695FBDEA3C22B0BFB25897092") + , TLSA("_ourca-tlsa", 2, 0, 1, "EA99063A0A3BDA9727032CF82DA238698B90BA729300703D3956943635F96488") + , TLSA("_ourca-tlsa", 2, 0, 1, "11F058F61F97B8ADC66EF4801F918C71B10E5C1E3D39AFDE10408B3026647EF1") + , TLSA("_ourca-cacert-tlsa", 2, 0, 1, "EA99063A0A3BDA9727032CF82DA238698B90BA729300703D3956943635F96488") + , TLSA("_ourca-cacert-tlsa", 2, 0, 1, "11F058F61F97B8ADC66EF4801F918C71B10E5C1E3D39AFDE10408B3026647EF1") + , TLSA("_ourca-cacert-tlsa", 2, 0, 1, "4EDDE9E55CA453B388887CAA25D5C5C5BCCF2891D73B87495808293D5FAC83C8") + , TLSA("_ourca-le-tlsa", 2, 0, 1, "EA99063A0A3BDA9727032CF82DA238698B90BA729300703D3956943635F96488") + , TLSA("_ourca-le-tlsa", 2, 0, 1, "11F058F61F97B8ADC66EF4801F918C71B10E5C1E3D39AFDE10408B3026647EF1") + , TLSA("_ourca-le-tlsa", 2, 1, 1, "60B87575447DCBA2A36B7D11AC09FB24A9DB406FEE12D2CC90180517616E8A18") + , TLSA("_ourca-le-tlsa", 2, 1, 1, "B111DD8A1C2091A89BD4FD60C57F0716CCE50FEEFF8137CDBEE0326E02CF362B") + , TLSA("_ourca-cacert-le-tlsa", 2, 0, 1, "EA99063A0A3BDA9727032CF82DA238698B90BA729300703D3956943635F96488") + , TLSA("_ourca-cacert-le-tlsa", 2, 0, 1, "11F058F61F97B8ADC66EF4801F918C71B10E5C1E3D39AFDE10408B3026647EF1") + , TLSA("_ourca-cacert-le-tlsa", 2, 0, 1, "4EDDE9E55CA453B388887CAA25D5C5C5BCCF2891D73B87495808293D5FAC83C8") + , TLSA("_ourca-cacert-le-tlsa", 2, 1, 1, "60B87575447DCBA2A36B7D11AC09FB24A9DB406FEE12D2CC90180517616E8A18") + , TLSA("_ourca-cacert-le-tlsa", 2, 1, 1, "B111DD8A1C2091A89BD4FD60C57F0716CCE50FEEFF8137CDBEE0326E02CF362B") + , TLSA("_cacert-le-tlsa", 2, 0, 1, "4EDDE9E55CA453B388887CAA25D5C5C5BCCF2891D73B87495808293D5FAC83C8") + , TLSA("_cacert-le-tlsa", 2, 1, 1, "60B87575447DCBA2A36B7D11AC09FB24A9DB406FEE12D2CC90180517616E8A18") + , TLSA("_cacert-le-tlsa", 2, 1, 1, "B111DD8A1C2091A89BD4FD60C57F0716CCE50FEEFF8137CDBEE0326E02CF362B") + , TLSA("_le-amazon-tlsa", 2, 1, 1, "60B87575447DCBA2A36B7D11AC09FB24A9DB406FEE12D2CC90180517616E8A18") + , TLSA("_le-amazon-tlsa", 2, 1, 1, "B111DD8A1C2091A89BD4FD60C57F0716CCE50FEEFF8137CDBEE0326E02CF362B") + , TLSA("_le-amazon-tlsa", 2, 0, 1, "8ECDE6884F3D87B1125BA31AC3FCB13D7016DE7F57CC904FE1CB97C6AE98196E") + , TLSA("_le-amazon-tlsa", 2, 0, 1, "1BA5B2AA8C65401A82960118F80BEC4F62304D83CEC4713A19C39C011EA46DB4") + , TLSA("_le-amazon-tlsa", 2, 0, 1, "18CE6CFE7BF14E60B2E347B8DFE868CB31D02EBB3ADA271569F50343B46DB3A4") + , TLSA("_le-amazon-tlsa", 2, 0, 1, "E35D28419ED02025CFA69038CD623962458DA5C695FBDEA3C22B0BFB25897092") + , TLSA("_ourca-le-amazon-tlsa", 2, 0, 1, "EA99063A0A3BDA9727032CF82DA238698B90BA729300703D3956943635F96488") + , TLSA("_ourca-le-amazon-tlsa", 2, 0, 1, "11F058F61F97B8ADC66EF4801F918C71B10E5C1E3D39AFDE10408B3026647EF1") + , TLSA("_ourca-le-amazon-tlsa", 2, 1, 1, "60B87575447DCBA2A36B7D11AC09FB24A9DB406FEE12D2CC90180517616E8A18") + , TLSA("_ourca-le-amazon-tlsa", 2, 1, 1, "B111DD8A1C2091A89BD4FD60C57F0716CCE50FEEFF8137CDBEE0326E02CF362B") + , TLSA("_ourca-le-amazon-tlsa", 2, 0, 1, "8ECDE6884F3D87B1125BA31AC3FCB13D7016DE7F57CC904FE1CB97C6AE98196E") + , TLSA("_ourca-le-amazon-tlsa", 2, 0, 1, "1BA5B2AA8C65401A82960118F80BEC4F62304D83CEC4713A19C39C011EA46DB4") + , TLSA("_ourca-le-amazon-tlsa", 2, 0, 1, "18CE6CFE7BF14E60B2E347B8DFE868CB31D02EBB3ADA271569F50343B46DB3A4") + , TLSA("_ourca-le-amazon-tlsa", 2, 0, 1, "E35D28419ED02025CFA69038CD623962458DA5C695FBDEA3C22B0BFB25897092") , CNAME("_443._tcp.www", "_ourca-le-tlsa.example.org.") , CNAME("_443._tcp.www.ipv4", "_ourca-le-tlsa.example.org.") , CNAME("_443._tcp.www.ipv6", "_ourca-le-tlsa.example.org.") diff --git a/commands/test_data/example.org.zone.js b/commands/test_data/example.org.zone.js index 0bbc10899e..908a6a796b 100644 --- a/commands/test_data/example.org.zone.js +++ b/commands/test_data/example.org.zone.js @@ -78,28 +78,28 @@ D("example.org", REG_CHANGEME, AAAA("megalomaniac", "2001:db8:ffef::254"), A("megalomaniac.ipv4", "198.51.100.254"), AAAA("megalomaniac.ipv6", "2001:db8:ffef::254"), - SSHFP("megalomaniac", 1, 2, "4e9ced94d3caf2ce915f85a63ce7279d5118a79ea03dac59cf4859b825d2f619"), - SSHFP("megalomaniac", 3, 2, "d3556a3db83ab9ccec39dc6693dd2f3e28b178c9bba61880924821c426cc61eb"), - SSHFP("megalomaniac", 4, 2, "c60c9d9d4728668f5f46986ff0c5b416c5e913862c4970cbfe211a6f44a111b4"), - SSHFP("megalomaniac.ipv4", 1, 2, "4e9ced94d3caf2ce915f85a63ce7279d5118a79ea03dac59cf4859b825d2f619"), - SSHFP("megalomaniac.ipv4", 3, 2, "d3556a3db83ab9ccec39dc6693dd2f3e28b178c9bba61880924821c426cc61eb"), - SSHFP("megalomaniac.ipv4", 4, 2, "c60c9d9d4728668f5f46986ff0c5b416c5e913862c4970cbfe211a6f44a111b4"), - SSHFP("megalomaniac.ipv6", 1, 2, "4e9ced94d3caf2ce915f85a63ce7279d5118a79ea03dac59cf4859b825d2f619"), - SSHFP("megalomaniac.ipv6", 3, 2, "d3556a3db83ab9ccec39dc6693dd2f3e28b178c9bba61880924821c426cc61eb"), - SSHFP("megalomaniac.ipv6", 4, 2, "c60c9d9d4728668f5f46986ff0c5b416c5e913862c4970cbfe211a6f44a111b4"), + SSHFP("megalomaniac", 1, 2, "4E9CED94D3CAF2CE915F85A63CE7279D5118A79EA03DAC59CF4859B825D2F619"), + SSHFP("megalomaniac", 3, 2, "D3556A3DB83AB9CCEC39DC6693DD2F3E28B178C9BBA61880924821C426CC61EB"), + SSHFP("megalomaniac", 4, 2, "C60C9D9D4728668F5F46986FF0C5B416C5E913862C4970CBFE211A6F44A111B4"), + SSHFP("megalomaniac.ipv4", 1, 2, "4E9CED94D3CAF2CE915F85A63CE7279D5118A79EA03DAC59CF4859B825D2F619"), + SSHFP("megalomaniac.ipv4", 3, 2, "D3556A3DB83AB9CCEC39DC6693DD2F3E28B178C9BBA61880924821C426CC61EB"), + SSHFP("megalomaniac.ipv4", 4, 2, "C60C9D9D4728668F5F46986FF0C5B416C5E913862C4970CBFE211A6F44A111B4"), + SSHFP("megalomaniac.ipv6", 1, 2, "4E9CED94D3CAF2CE915F85A63CE7279D5118A79EA03DAC59CF4859B825D2F619"), + SSHFP("megalomaniac.ipv6", 3, 2, "D3556A3DB83AB9CCEC39DC6693DD2F3E28B178C9BBA61880924821C426CC61EB"), + SSHFP("megalomaniac.ipv6", 4, 2, "C60C9D9D4728668F5F46986FF0C5B416C5E913862C4970CBFE211A6F44A111B4"), A("tower", "192.0.2.42"), AAAA("tower", "2001:db8::1:42"), A("tower.ipv4", "192.0.2.42"), AAAA("tower.ipv6", "2001:db8::1:42"), - SSHFP("tower", 1, 2, "0f211d236e94768911a294f38653c4af6fa935a5b06c975d8162f59142571451"), - SSHFP("tower", 3, 2, "88bf7b7401c11fa2e84871efb06cd73d8fc409154605b354db2dda0b82fe1160"), - SSHFP("tower", 4, 2, "6d30900be0faaae73568fc007a87b4d076cf9a351ecacc1106aef726c34ad61d"), - SSHFP("tower.ipv4", 1, 2, "0f211d236e94768911a294f38653c4af6fa935a5b06c975d8162f59142571451"), - SSHFP("tower.ipv4", 3, 2, "88bf7b7401c11fa2e84871efb06cd73d8fc409154605b354db2dda0b82fe1160"), - SSHFP("tower.ipv4", 4, 2, "6d30900be0faaae73568fc007a87b4d076cf9a351ecacc1106aef726c34ad61d"), - SSHFP("tower.ipv6", 1, 2, "0f211d236e94768911a294f38653c4af6fa935a5b06c975d8162f59142571451"), - SSHFP("tower.ipv6", 3, 2, "88bf7b7401c11fa2e84871efb06cd73d8fc409154605b354db2dda0b82fe1160"), - SSHFP("tower.ipv6", 4, 2, "6d30900be0faaae73568fc007a87b4d076cf9a351ecacc1106aef726c34ad61d"), + SSHFP("tower", 1, 2, "0F211D236E94768911A294F38653C4AF6FA935A5B06C975D8162F59142571451"), + SSHFP("tower", 3, 2, "88BF7B7401C11FA2E84871EFB06CD73D8FC409154605B354DB2DDA0B82FE1160"), + SSHFP("tower", 4, 2, "6D30900BE0FAAAE73568FC007A87B4D076CF9A351ECACC1106AEF726C34AD61D"), + SSHFP("tower.ipv4", 1, 2, "0F211D236E94768911A294F38653C4AF6FA935A5B06C975D8162F59142571451"), + SSHFP("tower.ipv4", 3, 2, "88BF7B7401C11FA2E84871EFB06CD73D8FC409154605B354DB2DDA0B82FE1160"), + SSHFP("tower.ipv4", 4, 2, "6D30900BE0FAAAE73568FC007A87B4D076CF9A351ECACC1106AEF726C34AD61D"), + SSHFP("tower.ipv6", 1, 2, "0F211D236E94768911A294F38653C4AF6FA935A5B06C975D8162F59142571451"), + SSHFP("tower.ipv6", 3, 2, "88BF7B7401C11FA2E84871EFB06CD73D8FC409154605B354DB2DDA0B82FE1160"), + SSHFP("tower.ipv6", 4, 2, "6D30900BE0FAAAE73568FC007A87B4D076CF9A351ECACC1106AEF726C34AD61D"), A("vcs", "192.0.2.228"), AAAA("vcs", "2001:db8::48:4558:4456:4353"), A("vcs.ipv4", "192.0.2.228"), @@ -108,28 +108,28 @@ D("example.org", REG_CHANGEME, CNAME("git.ipv4", "vcs.ipv4.example.org."), CNAME("git.ipv6", "vcs.ipv6.example.org."), AAAA("svn", "2001:db8::48:4558:73:766e"), - SSHFP("vcs", 1, 2, "b518be390babdf43cb2d598aa6befa6ce6878546bf107b829d0cfc65253a97d4"), - SSHFP("vcs", 3, 2, "e92545dc0bf501f72333ddeb7a37afc2c5b408ce39a3ad95fbc66236f0077323"), - SSHFP("vcs", 4, 2, "02289441124a487095a6cda2e946c6a8ed9087faf3592ec4135536c3e615521c"), - SSHFP("vcs.ipv4", 1, 2, "b518be390babdf43cb2d598aa6befa6ce6878546bf107b829d0cfc65253a97d4"), - SSHFP("vcs.ipv4", 3, 2, "e92545dc0bf501f72333ddeb7a37afc2c5b408ce39a3ad95fbc66236f0077323"), - SSHFP("vcs.ipv4", 4, 2, "02289441124a487095a6cda2e946c6a8ed9087faf3592ec4135536c3e615521c"), - SSHFP("vcs.ipv6", 1, 2, "b518be390babdf43cb2d598aa6befa6ce6878546bf107b829d0cfc65253a97d4"), - SSHFP("vcs.ipv6", 3, 2, "e92545dc0bf501f72333ddeb7a37afc2c5b408ce39a3ad95fbc66236f0077323"), - SSHFP("vcs.ipv6", 4, 2, "02289441124a487095a6cda2e946c6a8ed9087faf3592ec4135536c3e615521c"), + SSHFP("vcs", 1, 2, "B518BE390BABDF43CB2D598AA6BEFA6CE6878546BF107B829D0CFC65253A97D4"), + SSHFP("vcs", 3, 2, "E92545DC0BF501F72333DDEB7A37AFC2C5B408CE39A3AD95FBC66236F0077323"), + SSHFP("vcs", 4, 2, "02289441124A487095A6CDA2E946C6A8ED9087FAF3592EC4135536C3E615521C"), + SSHFP("vcs.ipv4", 1, 2, "B518BE390BABDF43CB2D598AA6BEFA6CE6878546BF107B829D0CFC65253A97D4"), + SSHFP("vcs.ipv4", 3, 2, "E92545DC0BF501F72333DDEB7A37AFC2C5B408CE39A3AD95FBC66236F0077323"), + SSHFP("vcs.ipv4", 4, 2, "02289441124A487095A6CDA2E946C6A8ED9087FAF3592EC4135536C3E615521C"), + SSHFP("vcs.ipv6", 1, 2, "B518BE390BABDF43CB2D598AA6BEFA6CE6878546BF107B829D0CFC65253A97D4"), + SSHFP("vcs.ipv6", 3, 2, "E92545DC0BF501F72333DDEB7A37AFC2C5B408CE39A3AD95FBC66236F0077323"), + SSHFP("vcs.ipv6", 4, 2, "02289441124A487095A6CDA2E946C6A8ED9087FAF3592EC4135536C3E615521C"), A("nsauth", "192.0.2.53"), AAAA("nsauth", "2001:db8::53:1"), A("nsauth.ipv4", "192.0.2.53"), AAAA("nsauth.ipv6", "2001:db8::53:1"), - SSHFP("nsauth", 1, 2, "895804ae022fff643b2677563cb850607c5bb564d9919896c521098c8abc40f2"), - SSHFP("nsauth", 3, 2, "28a65470badae611375747e1a803211c41e3d71e97741fa92ccbdf7b01f34e42"), - SSHFP("nsauth", 4, 2, "6e10445c0649c03fa83e18b1873e5b89b3a20893ecb48d01e7cedb3dd563ecf0"), - SSHFP("nsauth.ipv4", 1, 2, "895804ae022fff643b2677563cb850607c5bb564d9919896c521098c8abc40f2"), - SSHFP("nsauth.ipv4", 3, 2, "28a65470badae611375747e1a803211c41e3d71e97741fa92ccbdf7b01f34e42"), - SSHFP("nsauth.ipv4", 4, 2, "6e10445c0649c03fa83e18b1873e5b89b3a20893ecb48d01e7cedb3dd563ecf0"), - SSHFP("nsauth.ipv6", 1, 2, "895804ae022fff643b2677563cb850607c5bb564d9919896c521098c8abc40f2"), - SSHFP("nsauth.ipv6", 3, 2, "28a65470badae611375747e1a803211c41e3d71e97741fa92ccbdf7b01f34e42"), - SSHFP("nsauth.ipv6", 4, 2, "6e10445c0649c03fa83e18b1873e5b89b3a20893ecb48d01e7cedb3dd563ecf0"), + SSHFP("nsauth", 1, 2, "895804AE022FFF643B2677563CB850607C5BB564D9919896C521098C8ABC40F2"), + SSHFP("nsauth", 3, 2, "28A65470BADAE611375747E1A803211C41E3D71E97741FA92CCBDF7B01F34E42"), + SSHFP("nsauth", 4, 2, "6E10445C0649C03FA83E18B1873E5B89B3A20893ECB48D01E7CEDB3DD563ECF0"), + SSHFP("nsauth.ipv4", 1, 2, "895804AE022FFF643B2677563CB850607C5BB564D9919896C521098C8ABC40F2"), + SSHFP("nsauth.ipv4", 3, 2, "28A65470BADAE611375747E1A803211C41E3D71E97741FA92CCBDF7B01F34E42"), + SSHFP("nsauth.ipv4", 4, 2, "6E10445C0649C03FA83E18B1873E5B89B3A20893ECB48D01E7CEDB3DD563ECF0"), + SSHFP("nsauth.ipv6", 1, 2, "895804AE022FFF643B2677563CB850607C5BB564D9919896C521098C8ABC40F2"), + SSHFP("nsauth.ipv6", 3, 2, "28A65470BADAE611375747E1A803211C41E3D71E97741FA92CCBDF7B01F34E42"), + SSHFP("nsauth.ipv6", 4, 2, "6E10445C0649C03FA83E18B1873E5B89B3A20893ECB48D01E7CEDB3DD563ECF0"), A("ns1", "192.0.2.53"), AAAA("ns1", "2001:db8::53:1"), A("ns2", "203.0.113.53"), @@ -140,15 +140,15 @@ D("example.org", REG_CHANGEME, A("hermes.ipv4", "192.0.2.25"), AAAA("hermes.ipv6", "2001:db8::48:4558:736d:7470"), AAAA("hermes.ipv6", "2001:db8::48:4558:696d:6170"), - SSHFP("hermes", 1, 2, "4472ff5bd0528cd49216af4503ba6a1c48f121d0292a31d6af193e5000af4966"), - SSHFP("hermes", 3, 2, "eaba20c1565676a5229184ccfcf82d0ee408f91757a67d9fa51a0b6f3db4a33b"), - SSHFP("hermes", 4, 2, "a9d89920e599d04363c8b35a4ce66c1ed257ea1d16981f060b6aed080bbb7a7c"), - SSHFP("hermes.ipv4", 1, 2, "4472ff5bd0528cd49216af4503ba6a1c48f121d0292a31d6af193e5000af4966"), - SSHFP("hermes.ipv4", 3, 2, "eaba20c1565676a5229184ccfcf82d0ee408f91757a67d9fa51a0b6f3db4a33b"), - SSHFP("hermes.ipv4", 4, 2, "a9d89920e599d04363c8b35a4ce66c1ed257ea1d16981f060b6aed080bbb7a7c"), - SSHFP("hermes.ipv6", 1, 2, "4472ff5bd0528cd49216af4503ba6a1c48f121d0292a31d6af193e5000af4966"), - SSHFP("hermes.ipv6", 3, 2, "eaba20c1565676a5229184ccfcf82d0ee408f91757a67d9fa51a0b6f3db4a33b"), - SSHFP("hermes.ipv6", 4, 2, "a9d89920e599d04363c8b35a4ce66c1ed257ea1d16981f060b6aed080bbb7a7c"), + SSHFP("hermes", 1, 2, "4472FF5BD0528CD49216AF4503BA6A1C48F121D0292A31D6AF193E5000AF4966"), + SSHFP("hermes", 3, 2, "EABA20C1565676A5229184CCFCF82D0EE408F91757A67D9FA51A0B6F3DB4A33B"), + SSHFP("hermes", 4, 2, "A9D89920E599D04363C8B35A4CE66C1ED257EA1D16981F060B6AED080BBB7A7C"), + SSHFP("hermes.ipv4", 1, 2, "4472FF5BD0528CD49216AF4503BA6A1C48F121D0292A31D6AF193E5000AF4966"), + SSHFP("hermes.ipv4", 3, 2, "EABA20C1565676A5229184CCFCF82D0EE408F91757A67D9FA51A0B6F3DB4A33B"), + SSHFP("hermes.ipv4", 4, 2, "A9D89920E599D04363C8B35A4CE66C1ED257EA1D16981F060B6AED080BBB7A7C"), + SSHFP("hermes.ipv6", 1, 2, "4472FF5BD0528CD49216AF4503BA6A1C48F121D0292A31D6AF193E5000AF4966"), + SSHFP("hermes.ipv6", 3, 2, "EABA20C1565676A5229184CCFCF82D0EE408F91757A67D9FA51A0B6F3DB4A33B"), + SSHFP("hermes.ipv6", 4, 2, "A9D89920E599D04363C8B35A4CE66C1ED257EA1D16981F060B6AED080BBB7A7C"), A("kerb-service", "192.0.2.88"), AAAA("kerb-service", "2001:db8::48:4558:6b65:7262"), A("security", "192.0.2.92"), @@ -175,51 +175,51 @@ D("example.org", REG_CHANGEME, CNAME("www.ipv4", "services.ipv4.example.org."), CNAME("www.ipv6", "services.ipv6.example.org."), CAA("@", "issue", "example.net"), - CAA("@", "issue", "letsencrypt.org\; accounturi=https://acme-v01.api.letsencrypt.org/acme/reg/1234567"), - CAA("@", "issue", "letsencrypt.org\; accounturi=https://acme-staging-v02.api.letsencrypt.org/acme/acct/23456789"), - CAA("@", "issue", "letsencrypt.org\; accounturi=https://acme-v02.api.letsencrypt.org/acme/acct/76543210"), + CAA("@", "issue", "letsencrypt.org; accounturi=https://acme-v01.api.letsencrypt.org/acme/reg/1234567"), + CAA("@", "issue", "letsencrypt.org; accounturi=https://acme-staging-v02.api.letsencrypt.org/acme/acct/23456789"), + CAA("@", "issue", "letsencrypt.org; accounturi=https://acme-v02.api.letsencrypt.org/acme/acct/76543210"), CAA("@", "issuewild", ";"), CAA("@", "iodef", "mailto:security@example.org"), - TLSA("_ourcaca4-tlsa", 2, 0, 1, "ea99063a0a3bda9727032cf82da238698b90ba729300703d3956943635f96488"), - TLSA("_ourcaca5-tlsa", 2, 0, 1, "11f058f61f97b8adc66ef4801f918c71b10e5c1e3d39afde10408b3026647ef1"), - TLSA("_cacert-c3-tlsa", 2, 0, 1, "4edde9e55ca453b388887caa25d5c5c5bccf2891d73b87495808293d5fac83c8"), - TLSA("_letsencrypt-tlsa", 2, 1, 1, "60b87575447dcba2a36b7d11ac09fb24a9db406fee12d2cc90180517616e8a18"), - TLSA("_letsencrypt-tlsa", 2, 1, 1, "b111dd8a1c2091a89bd4fd60c57f0716cce50feeff8137cdbee0326e02cf362b"), - TLSA("_amazon-tlsa", 2, 0, 1, "8ecde6884f3d87b1125ba31ac3fcb13d7016de7f57cc904fe1cb97c6ae98196e"), - TLSA("_amazon-tlsa", 2, 0, 1, "1ba5b2aa8c65401a82960118f80bec4f62304d83cec4713a19c39c011ea46db4"), - TLSA("_amazon-tlsa", 2, 0, 1, "18ce6cfe7bf14e60b2e347b8dfe868cb31d02ebb3ada271569f50343b46db3a4"), - TLSA("_amazon-tlsa", 2, 0, 1, "e35d28419ed02025cfa69038cd623962458da5c695fbdea3c22b0bfb25897092"), - TLSA("_ourca-tlsa", 2, 0, 1, "ea99063a0a3bda9727032cf82da238698b90ba729300703d3956943635f96488"), - TLSA("_ourca-tlsa", 2, 0, 1, "11f058f61f97b8adc66ef4801f918c71b10e5c1e3d39afde10408b3026647ef1"), - TLSA("_ourca-cacert-tlsa", 2, 0, 1, "ea99063a0a3bda9727032cf82da238698b90ba729300703d3956943635f96488"), - TLSA("_ourca-cacert-tlsa", 2, 0, 1, "11f058f61f97b8adc66ef4801f918c71b10e5c1e3d39afde10408b3026647ef1"), - TLSA("_ourca-cacert-tlsa", 2, 0, 1, "4edde9e55ca453b388887caa25d5c5c5bccf2891d73b87495808293d5fac83c8"), - TLSA("_ourca-le-tlsa", 2, 0, 1, "ea99063a0a3bda9727032cf82da238698b90ba729300703d3956943635f96488"), - TLSA("_ourca-le-tlsa", 2, 0, 1, "11f058f61f97b8adc66ef4801f918c71b10e5c1e3d39afde10408b3026647ef1"), - TLSA("_ourca-le-tlsa", 2, 1, 1, "60b87575447dcba2a36b7d11ac09fb24a9db406fee12d2cc90180517616e8a18"), - TLSA("_ourca-le-tlsa", 2, 1, 1, "b111dd8a1c2091a89bd4fd60c57f0716cce50feeff8137cdbee0326e02cf362b"), - TLSA("_ourca-cacert-le-tlsa", 2, 0, 1, "ea99063a0a3bda9727032cf82da238698b90ba729300703d3956943635f96488"), - TLSA("_ourca-cacert-le-tlsa", 2, 0, 1, "11f058f61f97b8adc66ef4801f918c71b10e5c1e3d39afde10408b3026647ef1"), - TLSA("_ourca-cacert-le-tlsa", 2, 0, 1, "4edde9e55ca453b388887caa25d5c5c5bccf2891d73b87495808293d5fac83c8"), - TLSA("_ourca-cacert-le-tlsa", 2, 1, 1, "60b87575447dcba2a36b7d11ac09fb24a9db406fee12d2cc90180517616e8a18"), - TLSA("_ourca-cacert-le-tlsa", 2, 1, 1, "b111dd8a1c2091a89bd4fd60c57f0716cce50feeff8137cdbee0326e02cf362b"), - TLSA("_cacert-le-tlsa", 2, 0, 1, "4edde9e55ca453b388887caa25d5c5c5bccf2891d73b87495808293d5fac83c8"), - TLSA("_cacert-le-tlsa", 2, 1, 1, "60b87575447dcba2a36b7d11ac09fb24a9db406fee12d2cc90180517616e8a18"), - TLSA("_cacert-le-tlsa", 2, 1, 1, "b111dd8a1c2091a89bd4fd60c57f0716cce50feeff8137cdbee0326e02cf362b"), - TLSA("_le-amazon-tlsa", 2, 1, 1, "60b87575447dcba2a36b7d11ac09fb24a9db406fee12d2cc90180517616e8a18"), - TLSA("_le-amazon-tlsa", 2, 1, 1, "b111dd8a1c2091a89bd4fd60c57f0716cce50feeff8137cdbee0326e02cf362b"), - TLSA("_le-amazon-tlsa", 2, 0, 1, "8ecde6884f3d87b1125ba31ac3fcb13d7016de7f57cc904fe1cb97c6ae98196e"), - TLSA("_le-amazon-tlsa", 2, 0, 1, "1ba5b2aa8c65401a82960118f80bec4f62304d83cec4713a19c39c011ea46db4"), - TLSA("_le-amazon-tlsa", 2, 0, 1, "18ce6cfe7bf14e60b2e347b8dfe868cb31d02ebb3ada271569f50343b46db3a4"), - TLSA("_le-amazon-tlsa", 2, 0, 1, "e35d28419ed02025cfa69038cd623962458da5c695fbdea3c22b0bfb25897092"), - TLSA("_ourca-le-amazon-tlsa", 2, 0, 1, "ea99063a0a3bda9727032cf82da238698b90ba729300703d3956943635f96488"), - TLSA("_ourca-le-amazon-tlsa", 2, 0, 1, "11f058f61f97b8adc66ef4801f918c71b10e5c1e3d39afde10408b3026647ef1"), - TLSA("_ourca-le-amazon-tlsa", 2, 1, 1, "60b87575447dcba2a36b7d11ac09fb24a9db406fee12d2cc90180517616e8a18"), - TLSA("_ourca-le-amazon-tlsa", 2, 1, 1, "b111dd8a1c2091a89bd4fd60c57f0716cce50feeff8137cdbee0326e02cf362b"), - TLSA("_ourca-le-amazon-tlsa", 2, 0, 1, "8ecde6884f3d87b1125ba31ac3fcb13d7016de7f57cc904fe1cb97c6ae98196e"), - TLSA("_ourca-le-amazon-tlsa", 2, 0, 1, "1ba5b2aa8c65401a82960118f80bec4f62304d83cec4713a19c39c011ea46db4"), - TLSA("_ourca-le-amazon-tlsa", 2, 0, 1, "18ce6cfe7bf14e60b2e347b8dfe868cb31d02ebb3ada271569f50343b46db3a4"), - TLSA("_ourca-le-amazon-tlsa", 2, 0, 1, "e35d28419ed02025cfa69038cd623962458da5c695fbdea3c22b0bfb25897092"), + TLSA("_ourcaca4-tlsa", 2, 0, 1, "EA99063A0A3BDA9727032CF82DA238698B90BA729300703D3956943635F96488"), + TLSA("_ourcaca5-tlsa", 2, 0, 1, "11F058F61F97B8ADC66EF4801F918C71B10E5C1E3D39AFDE10408B3026647EF1"), + TLSA("_cacert-c3-tlsa", 2, 0, 1, "4EDDE9E55CA453B388887CAA25D5C5C5BCCF2891D73B87495808293D5FAC83C8"), + TLSA("_letsencrypt-tlsa", 2, 1, 1, "60B87575447DCBA2A36B7D11AC09FB24A9DB406FEE12D2CC90180517616E8A18"), + TLSA("_letsencrypt-tlsa", 2, 1, 1, "B111DD8A1C2091A89BD4FD60C57F0716CCE50FEEFF8137CDBEE0326E02CF362B"), + TLSA("_amazon-tlsa", 2, 0, 1, "8ECDE6884F3D87B1125BA31AC3FCB13D7016DE7F57CC904FE1CB97C6AE98196E"), + TLSA("_amazon-tlsa", 2, 0, 1, "1BA5B2AA8C65401A82960118F80BEC4F62304D83CEC4713A19C39C011EA46DB4"), + TLSA("_amazon-tlsa", 2, 0, 1, "18CE6CFE7BF14E60B2E347B8DFE868CB31D02EBB3ADA271569F50343B46DB3A4"), + TLSA("_amazon-tlsa", 2, 0, 1, "E35D28419ED02025CFA69038CD623962458DA5C695FBDEA3C22B0BFB25897092"), + TLSA("_ourca-tlsa", 2, 0, 1, "EA99063A0A3BDA9727032CF82DA238698B90BA729300703D3956943635F96488"), + TLSA("_ourca-tlsa", 2, 0, 1, "11F058F61F97B8ADC66EF4801F918C71B10E5C1E3D39AFDE10408B3026647EF1"), + TLSA("_ourca-cacert-tlsa", 2, 0, 1, "EA99063A0A3BDA9727032CF82DA238698B90BA729300703D3956943635F96488"), + TLSA("_ourca-cacert-tlsa", 2, 0, 1, "11F058F61F97B8ADC66EF4801F918C71B10E5C1E3D39AFDE10408B3026647EF1"), + TLSA("_ourca-cacert-tlsa", 2, 0, 1, "4EDDE9E55CA453B388887CAA25D5C5C5BCCF2891D73B87495808293D5FAC83C8"), + TLSA("_ourca-le-tlsa", 2, 0, 1, "EA99063A0A3BDA9727032CF82DA238698B90BA729300703D3956943635F96488"), + TLSA("_ourca-le-tlsa", 2, 0, 1, "11F058F61F97B8ADC66EF4801F918C71B10E5C1E3D39AFDE10408B3026647EF1"), + TLSA("_ourca-le-tlsa", 2, 1, 1, "60B87575447DCBA2A36B7D11AC09FB24A9DB406FEE12D2CC90180517616E8A18"), + TLSA("_ourca-le-tlsa", 2, 1, 1, "B111DD8A1C2091A89BD4FD60C57F0716CCE50FEEFF8137CDBEE0326E02CF362B"), + TLSA("_ourca-cacert-le-tlsa", 2, 0, 1, "EA99063A0A3BDA9727032CF82DA238698B90BA729300703D3956943635F96488"), + TLSA("_ourca-cacert-le-tlsa", 2, 0, 1, "11F058F61F97B8ADC66EF4801F918C71B10E5C1E3D39AFDE10408B3026647EF1"), + TLSA("_ourca-cacert-le-tlsa", 2, 0, 1, "4EDDE9E55CA453B388887CAA25D5C5C5BCCF2891D73B87495808293D5FAC83C8"), + TLSA("_ourca-cacert-le-tlsa", 2, 1, 1, "60B87575447DCBA2A36B7D11AC09FB24A9DB406FEE12D2CC90180517616E8A18"), + TLSA("_ourca-cacert-le-tlsa", 2, 1, 1, "B111DD8A1C2091A89BD4FD60C57F0716CCE50FEEFF8137CDBEE0326E02CF362B"), + TLSA("_cacert-le-tlsa", 2, 0, 1, "4EDDE9E55CA453B388887CAA25D5C5C5BCCF2891D73B87495808293D5FAC83C8"), + TLSA("_cacert-le-tlsa", 2, 1, 1, "60B87575447DCBA2A36B7D11AC09FB24A9DB406FEE12D2CC90180517616E8A18"), + TLSA("_cacert-le-tlsa", 2, 1, 1, "B111DD8A1C2091A89BD4FD60C57F0716CCE50FEEFF8137CDBEE0326E02CF362B"), + TLSA("_le-amazon-tlsa", 2, 1, 1, "60B87575447DCBA2A36B7D11AC09FB24A9DB406FEE12D2CC90180517616E8A18"), + TLSA("_le-amazon-tlsa", 2, 1, 1, "B111DD8A1C2091A89BD4FD60C57F0716CCE50FEEFF8137CDBEE0326E02CF362B"), + TLSA("_le-amazon-tlsa", 2, 0, 1, "8ECDE6884F3D87B1125BA31AC3FCB13D7016DE7F57CC904FE1CB97C6AE98196E"), + TLSA("_le-amazon-tlsa", 2, 0, 1, "1BA5B2AA8C65401A82960118F80BEC4F62304D83CEC4713A19C39C011EA46DB4"), + TLSA("_le-amazon-tlsa", 2, 0, 1, "18CE6CFE7BF14E60B2E347B8DFE868CB31D02EBB3ADA271569F50343B46DB3A4"), + TLSA("_le-amazon-tlsa", 2, 0, 1, "E35D28419ED02025CFA69038CD623962458DA5C695FBDEA3C22B0BFB25897092"), + TLSA("_ourca-le-amazon-tlsa", 2, 0, 1, "EA99063A0A3BDA9727032CF82DA238698B90BA729300703D3956943635F96488"), + TLSA("_ourca-le-amazon-tlsa", 2, 0, 1, "11F058F61F97B8ADC66EF4801F918C71B10E5C1E3D39AFDE10408B3026647EF1"), + TLSA("_ourca-le-amazon-tlsa", 2, 1, 1, "60B87575447DCBA2A36B7D11AC09FB24A9DB406FEE12D2CC90180517616E8A18"), + TLSA("_ourca-le-amazon-tlsa", 2, 1, 1, "B111DD8A1C2091A89BD4FD60C57F0716CCE50FEEFF8137CDBEE0326E02CF362B"), + TLSA("_ourca-le-amazon-tlsa", 2, 0, 1, "8ECDE6884F3D87B1125BA31AC3FCB13D7016DE7F57CC904FE1CB97C6AE98196E"), + TLSA("_ourca-le-amazon-tlsa", 2, 0, 1, "1BA5B2AA8C65401A82960118F80BEC4F62304D83CEC4713A19C39C011EA46DB4"), + TLSA("_ourca-le-amazon-tlsa", 2, 0, 1, "18CE6CFE7BF14E60B2E347B8DFE868CB31D02EBB3ADA271569F50343B46DB3A4"), + TLSA("_ourca-le-amazon-tlsa", 2, 0, 1, "E35D28419ED02025CFA69038CD623962458DA5C695FBDEA3C22B0BFB25897092"), CNAME("_443._tcp.www", "_ourca-le-tlsa.example.org."), CNAME("_443._tcp.www.ipv4", "_ourca-le-tlsa.example.org."), CNAME("_443._tcp.www.ipv6", "_ourca-le-tlsa.example.org."), diff --git a/commands/test_data/example.org.zone.tsv b/commands/test_data/example.org.zone.tsv index abae4c9693..88080b175e 100644 --- a/commands/test_data/example.org.zone.tsv +++ b/commands/test_data/example.org.zone.tsv @@ -171,46 +171,46 @@ example.org @ 7200 IN CAA 0 issue "letsencrypt.org; accounturi=https://acme-stag example.org @ 7200 IN CAA 0 issue "letsencrypt.org; accounturi=https://acme-v02.api.letsencrypt.org/acme/acct/76543210" example.org @ 7200 IN CAA 0 issuewild ";" example.org @ 7200 IN CAA 0 iodef "mailto:security@example.org" -_ourcaca4-tlsa.example.org _ourcaca4-tlsa 7200 IN TLSA 2 0 1 ea99063a0a3bda9727032cf82da238698b90ba729300703d3956943635f96488 -_ourcaca5-tlsa.example.org _ourcaca5-tlsa 7200 IN TLSA 2 0 1 11f058f61f97b8adc66ef4801f918c71b10e5c1e3d39afde10408b3026647ef1 -_cacert-c3-tlsa.example.org _cacert-c3-tlsa 7200 IN TLSA 2 0 1 4edde9e55ca453b388887caa25d5c5c5bccf2891d73b87495808293d5fac83c8 -_letsencrypt-tlsa.example.org _letsencrypt-tlsa 7200 IN TLSA 2 1 1 60b87575447dcba2a36b7d11ac09fb24a9db406fee12d2cc90180517616e8a18 -_letsencrypt-tlsa.example.org _letsencrypt-tlsa 7200 IN TLSA 2 1 1 b111dd8a1c2091a89bd4fd60c57f0716cce50feeff8137cdbee0326e02cf362b -_amazon-tlsa.example.org _amazon-tlsa 7200 IN TLSA 2 0 1 8ecde6884f3d87b1125ba31ac3fcb13d7016de7f57cc904fe1cb97c6ae98196e -_amazon-tlsa.example.org _amazon-tlsa 7200 IN TLSA 2 0 1 1ba5b2aa8c65401a82960118f80bec4f62304d83cec4713a19c39c011ea46db4 -_amazon-tlsa.example.org _amazon-tlsa 7200 IN TLSA 2 0 1 18ce6cfe7bf14e60b2e347b8dfe868cb31d02ebb3ada271569f50343b46db3a4 -_amazon-tlsa.example.org _amazon-tlsa 7200 IN TLSA 2 0 1 e35d28419ed02025cfa69038cd623962458da5c695fbdea3c22b0bfb25897092 -_ourca-tlsa.example.org _ourca-tlsa 7200 IN TLSA 2 0 1 ea99063a0a3bda9727032cf82da238698b90ba729300703d3956943635f96488 -_ourca-tlsa.example.org _ourca-tlsa 7200 IN TLSA 2 0 1 11f058f61f97b8adc66ef4801f918c71b10e5c1e3d39afde10408b3026647ef1 -_ourca-cacert-tlsa.example.org _ourca-cacert-tlsa 7200 IN TLSA 2 0 1 ea99063a0a3bda9727032cf82da238698b90ba729300703d3956943635f96488 -_ourca-cacert-tlsa.example.org _ourca-cacert-tlsa 7200 IN TLSA 2 0 1 11f058f61f97b8adc66ef4801f918c71b10e5c1e3d39afde10408b3026647ef1 -_ourca-cacert-tlsa.example.org _ourca-cacert-tlsa 7200 IN TLSA 2 0 1 4edde9e55ca453b388887caa25d5c5c5bccf2891d73b87495808293d5fac83c8 -_ourca-le-tlsa.example.org _ourca-le-tlsa 7200 IN TLSA 2 0 1 ea99063a0a3bda9727032cf82da238698b90ba729300703d3956943635f96488 -_ourca-le-tlsa.example.org _ourca-le-tlsa 7200 IN TLSA 2 0 1 11f058f61f97b8adc66ef4801f918c71b10e5c1e3d39afde10408b3026647ef1 -_ourca-le-tlsa.example.org _ourca-le-tlsa 7200 IN TLSA 2 1 1 60b87575447dcba2a36b7d11ac09fb24a9db406fee12d2cc90180517616e8a18 -_ourca-le-tlsa.example.org _ourca-le-tlsa 7200 IN TLSA 2 1 1 b111dd8a1c2091a89bd4fd60c57f0716cce50feeff8137cdbee0326e02cf362b -_ourca-cacert-le-tlsa.example.org _ourca-cacert-le-tlsa 7200 IN TLSA 2 0 1 ea99063a0a3bda9727032cf82da238698b90ba729300703d3956943635f96488 -_ourca-cacert-le-tlsa.example.org _ourca-cacert-le-tlsa 7200 IN TLSA 2 0 1 11f058f61f97b8adc66ef4801f918c71b10e5c1e3d39afde10408b3026647ef1 -_ourca-cacert-le-tlsa.example.org _ourca-cacert-le-tlsa 7200 IN TLSA 2 0 1 4edde9e55ca453b388887caa25d5c5c5bccf2891d73b87495808293d5fac83c8 -_ourca-cacert-le-tlsa.example.org _ourca-cacert-le-tlsa 7200 IN TLSA 2 1 1 60b87575447dcba2a36b7d11ac09fb24a9db406fee12d2cc90180517616e8a18 -_ourca-cacert-le-tlsa.example.org _ourca-cacert-le-tlsa 7200 IN TLSA 2 1 1 b111dd8a1c2091a89bd4fd60c57f0716cce50feeff8137cdbee0326e02cf362b -_cacert-le-tlsa.example.org _cacert-le-tlsa 7200 IN TLSA 2 0 1 4edde9e55ca453b388887caa25d5c5c5bccf2891d73b87495808293d5fac83c8 -_cacert-le-tlsa.example.org _cacert-le-tlsa 7200 IN TLSA 2 1 1 60b87575447dcba2a36b7d11ac09fb24a9db406fee12d2cc90180517616e8a18 -_cacert-le-tlsa.example.org _cacert-le-tlsa 7200 IN TLSA 2 1 1 b111dd8a1c2091a89bd4fd60c57f0716cce50feeff8137cdbee0326e02cf362b -_le-amazon-tlsa.example.org _le-amazon-tlsa 7200 IN TLSA 2 1 1 60b87575447dcba2a36b7d11ac09fb24a9db406fee12d2cc90180517616e8a18 -_le-amazon-tlsa.example.org _le-amazon-tlsa 7200 IN TLSA 2 1 1 b111dd8a1c2091a89bd4fd60c57f0716cce50feeff8137cdbee0326e02cf362b -_le-amazon-tlsa.example.org _le-amazon-tlsa 7200 IN TLSA 2 0 1 8ecde6884f3d87b1125ba31ac3fcb13d7016de7f57cc904fe1cb97c6ae98196e -_le-amazon-tlsa.example.org _le-amazon-tlsa 7200 IN TLSA 2 0 1 1ba5b2aa8c65401a82960118f80bec4f62304d83cec4713a19c39c011ea46db4 -_le-amazon-tlsa.example.org _le-amazon-tlsa 7200 IN TLSA 2 0 1 18ce6cfe7bf14e60b2e347b8dfe868cb31d02ebb3ada271569f50343b46db3a4 -_le-amazon-tlsa.example.org _le-amazon-tlsa 7200 IN TLSA 2 0 1 e35d28419ed02025cfa69038cd623962458da5c695fbdea3c22b0bfb25897092 -_ourca-le-amazon-tlsa.example.org _ourca-le-amazon-tlsa 7200 IN TLSA 2 0 1 ea99063a0a3bda9727032cf82da238698b90ba729300703d3956943635f96488 -_ourca-le-amazon-tlsa.example.org _ourca-le-amazon-tlsa 7200 IN TLSA 2 0 1 11f058f61f97b8adc66ef4801f918c71b10e5c1e3d39afde10408b3026647ef1 -_ourca-le-amazon-tlsa.example.org _ourca-le-amazon-tlsa 7200 IN TLSA 2 1 1 60b87575447dcba2a36b7d11ac09fb24a9db406fee12d2cc90180517616e8a18 -_ourca-le-amazon-tlsa.example.org _ourca-le-amazon-tlsa 7200 IN TLSA 2 1 1 b111dd8a1c2091a89bd4fd60c57f0716cce50feeff8137cdbee0326e02cf362b -_ourca-le-amazon-tlsa.example.org _ourca-le-amazon-tlsa 7200 IN TLSA 2 0 1 8ecde6884f3d87b1125ba31ac3fcb13d7016de7f57cc904fe1cb97c6ae98196e -_ourca-le-amazon-tlsa.example.org _ourca-le-amazon-tlsa 7200 IN TLSA 2 0 1 1ba5b2aa8c65401a82960118f80bec4f62304d83cec4713a19c39c011ea46db4 -_ourca-le-amazon-tlsa.example.org _ourca-le-amazon-tlsa 7200 IN TLSA 2 0 1 18ce6cfe7bf14e60b2e347b8dfe868cb31d02ebb3ada271569f50343b46db3a4 -_ourca-le-amazon-tlsa.example.org _ourca-le-amazon-tlsa 7200 IN TLSA 2 0 1 e35d28419ed02025cfa69038cd623962458da5c695fbdea3c22b0bfb25897092 +_ourcaca4-tlsa.example.org _ourcaca4-tlsa 7200 IN TLSA 2 0 1 EA99063A0A3BDA9727032CF82DA238698B90BA729300703D3956943635F96488 +_ourcaca5-tlsa.example.org _ourcaca5-tlsa 7200 IN TLSA 2 0 1 11F058F61F97B8ADC66EF4801F918C71B10E5C1E3D39AFDE10408B3026647EF1 +_cacert-c3-tlsa.example.org _cacert-c3-tlsa 7200 IN TLSA 2 0 1 4EDDE9E55CA453B388887CAA25D5C5C5BCCF2891D73B87495808293D5FAC83C8 +_letsencrypt-tlsa.example.org _letsencrypt-tlsa 7200 IN TLSA 2 1 1 60B87575447DCBA2A36B7D11AC09FB24A9DB406FEE12D2CC90180517616E8A18 +_letsencrypt-tlsa.example.org _letsencrypt-tlsa 7200 IN TLSA 2 1 1 B111DD8A1C2091A89BD4FD60C57F0716CCE50FEEFF8137CDBEE0326E02CF362B +_amazon-tlsa.example.org _amazon-tlsa 7200 IN TLSA 2 0 1 8ECDE6884F3D87B1125BA31AC3FCB13D7016DE7F57CC904FE1CB97C6AE98196E +_amazon-tlsa.example.org _amazon-tlsa 7200 IN TLSA 2 0 1 1BA5B2AA8C65401A82960118F80BEC4F62304D83CEC4713A19C39C011EA46DB4 +_amazon-tlsa.example.org _amazon-tlsa 7200 IN TLSA 2 0 1 18CE6CFE7BF14E60B2E347B8DFE868CB31D02EBB3ADA271569F50343B46DB3A4 +_amazon-tlsa.example.org _amazon-tlsa 7200 IN TLSA 2 0 1 E35D28419ED02025CFA69038CD623962458DA5C695FBDEA3C22B0BFB25897092 +_ourca-tlsa.example.org _ourca-tlsa 7200 IN TLSA 2 0 1 EA99063A0A3BDA9727032CF82DA238698B90BA729300703D3956943635F96488 +_ourca-tlsa.example.org _ourca-tlsa 7200 IN TLSA 2 0 1 11F058F61F97B8ADC66EF4801F918C71B10E5C1E3D39AFDE10408B3026647EF1 +_ourca-cacert-tlsa.example.org _ourca-cacert-tlsa 7200 IN TLSA 2 0 1 EA99063A0A3BDA9727032CF82DA238698B90BA729300703D3956943635F96488 +_ourca-cacert-tlsa.example.org _ourca-cacert-tlsa 7200 IN TLSA 2 0 1 11F058F61F97B8ADC66EF4801F918C71B10E5C1E3D39AFDE10408B3026647EF1 +_ourca-cacert-tlsa.example.org _ourca-cacert-tlsa 7200 IN TLSA 2 0 1 4EDDE9E55CA453B388887CAA25D5C5C5BCCF2891D73B87495808293D5FAC83C8 +_ourca-le-tlsa.example.org _ourca-le-tlsa 7200 IN TLSA 2 0 1 EA99063A0A3BDA9727032CF82DA238698B90BA729300703D3956943635F96488 +_ourca-le-tlsa.example.org _ourca-le-tlsa 7200 IN TLSA 2 0 1 11F058F61F97B8ADC66EF4801F918C71B10E5C1E3D39AFDE10408B3026647EF1 +_ourca-le-tlsa.example.org _ourca-le-tlsa 7200 IN TLSA 2 1 1 60B87575447DCBA2A36B7D11AC09FB24A9DB406FEE12D2CC90180517616E8A18 +_ourca-le-tlsa.example.org _ourca-le-tlsa 7200 IN TLSA 2 1 1 B111DD8A1C2091A89BD4FD60C57F0716CCE50FEEFF8137CDBEE0326E02CF362B +_ourca-cacert-le-tlsa.example.org _ourca-cacert-le-tlsa 7200 IN TLSA 2 0 1 EA99063A0A3BDA9727032CF82DA238698B90BA729300703D3956943635F96488 +_ourca-cacert-le-tlsa.example.org _ourca-cacert-le-tlsa 7200 IN TLSA 2 0 1 11F058F61F97B8ADC66EF4801F918C71B10E5C1E3D39AFDE10408B3026647EF1 +_ourca-cacert-le-tlsa.example.org _ourca-cacert-le-tlsa 7200 IN TLSA 2 0 1 4EDDE9E55CA453B388887CAA25D5C5C5BCCF2891D73B87495808293D5FAC83C8 +_ourca-cacert-le-tlsa.example.org _ourca-cacert-le-tlsa 7200 IN TLSA 2 1 1 60B87575447DCBA2A36B7D11AC09FB24A9DB406FEE12D2CC90180517616E8A18 +_ourca-cacert-le-tlsa.example.org _ourca-cacert-le-tlsa 7200 IN TLSA 2 1 1 B111DD8A1C2091A89BD4FD60C57F0716CCE50FEEFF8137CDBEE0326E02CF362B +_cacert-le-tlsa.example.org _cacert-le-tlsa 7200 IN TLSA 2 0 1 4EDDE9E55CA453B388887CAA25D5C5C5BCCF2891D73B87495808293D5FAC83C8 +_cacert-le-tlsa.example.org _cacert-le-tlsa 7200 IN TLSA 2 1 1 60B87575447DCBA2A36B7D11AC09FB24A9DB406FEE12D2CC90180517616E8A18 +_cacert-le-tlsa.example.org _cacert-le-tlsa 7200 IN TLSA 2 1 1 B111DD8A1C2091A89BD4FD60C57F0716CCE50FEEFF8137CDBEE0326E02CF362B +_le-amazon-tlsa.example.org _le-amazon-tlsa 7200 IN TLSA 2 1 1 60B87575447DCBA2A36B7D11AC09FB24A9DB406FEE12D2CC90180517616E8A18 +_le-amazon-tlsa.example.org _le-amazon-tlsa 7200 IN TLSA 2 1 1 B111DD8A1C2091A89BD4FD60C57F0716CCE50FEEFF8137CDBEE0326E02CF362B +_le-amazon-tlsa.example.org _le-amazon-tlsa 7200 IN TLSA 2 0 1 8ECDE6884F3D87B1125BA31AC3FCB13D7016DE7F57CC904FE1CB97C6AE98196E +_le-amazon-tlsa.example.org _le-amazon-tlsa 7200 IN TLSA 2 0 1 1BA5B2AA8C65401A82960118F80BEC4F62304D83CEC4713A19C39C011EA46DB4 +_le-amazon-tlsa.example.org _le-amazon-tlsa 7200 IN TLSA 2 0 1 18CE6CFE7BF14E60B2E347B8DFE868CB31D02EBB3ADA271569F50343B46DB3A4 +_le-amazon-tlsa.example.org _le-amazon-tlsa 7200 IN TLSA 2 0 1 E35D28419ED02025CFA69038CD623962458DA5C695FBDEA3C22B0BFB25897092 +_ourca-le-amazon-tlsa.example.org _ourca-le-amazon-tlsa 7200 IN TLSA 2 0 1 EA99063A0A3BDA9727032CF82DA238698B90BA729300703D3956943635F96488 +_ourca-le-amazon-tlsa.example.org _ourca-le-amazon-tlsa 7200 IN TLSA 2 0 1 11F058F61F97B8ADC66EF4801F918C71B10E5C1E3D39AFDE10408B3026647EF1 +_ourca-le-amazon-tlsa.example.org _ourca-le-amazon-tlsa 7200 IN TLSA 2 1 1 60B87575447DCBA2A36B7D11AC09FB24A9DB406FEE12D2CC90180517616E8A18 +_ourca-le-amazon-tlsa.example.org _ourca-le-amazon-tlsa 7200 IN TLSA 2 1 1 B111DD8A1C2091A89BD4FD60C57F0716CCE50FEEFF8137CDBEE0326E02CF362B +_ourca-le-amazon-tlsa.example.org _ourca-le-amazon-tlsa 7200 IN TLSA 2 0 1 8ECDE6884F3D87B1125BA31AC3FCB13D7016DE7F57CC904FE1CB97C6AE98196E +_ourca-le-amazon-tlsa.example.org _ourca-le-amazon-tlsa 7200 IN TLSA 2 0 1 1BA5B2AA8C65401A82960118F80BEC4F62304D83CEC4713A19C39C011EA46DB4 +_ourca-le-amazon-tlsa.example.org _ourca-le-amazon-tlsa 7200 IN TLSA 2 0 1 18CE6CFE7BF14E60B2E347B8DFE868CB31D02EBB3ADA271569F50343B46DB3A4 +_ourca-le-amazon-tlsa.example.org _ourca-le-amazon-tlsa 7200 IN TLSA 2 0 1 E35D28419ED02025CFA69038CD623962458DA5C695FBDEA3C22B0BFB25897092 _443._tcp.www.example.org _443._tcp.www 7200 IN CNAME _ourca-le-tlsa.example.org. _443._tcp.www.ipv4.example.org _443._tcp.www.ipv4 7200 IN CNAME _ourca-le-tlsa.example.org. _443._tcp.www.ipv6.example.org _443._tcp.www.ipv6 7200 IN CNAME _ourca-le-tlsa.example.org. diff --git a/commands/test_data/example.org.zone.zone b/commands/test_data/example.org.zone.zone index 384b8979d6..6eee09dbc9 100644 --- a/commands/test_data/example.org.zone.zone +++ b/commands/test_data/example.org.zone.zone @@ -17,14 +17,14 @@ $TTL 7200 IN CAA 0 issuewild ";" 0123456789abcdef0123456789abcdef IN CNAME verify.bing.com. _acme-challenge 15 IN CNAME _acme-challenge.chat-acme.d.example.net. -_amazon-tlsa IN TLSA 2 0 1 18ce6cfe7bf14e60b2e347b8dfe868cb31d02ebb3ada271569f50343b46db3a4 - IN TLSA 2 0 1 1ba5b2aa8c65401a82960118f80bec4f62304d83cec4713a19c39c011ea46db4 - IN TLSA 2 0 1 8ecde6884f3d87b1125ba31ac3fcb13d7016de7f57cc904fe1cb97c6ae98196e - IN TLSA 2 0 1 e35d28419ed02025cfa69038cd623962458da5c695fbdea3c22b0bfb25897092 -_cacert-c3-tlsa IN TLSA 2 0 1 4edde9e55ca453b388887caa25d5c5c5bccf2891d73b87495808293d5fac83c8 -_cacert-le-tlsa IN TLSA 2 0 1 4edde9e55ca453b388887caa25d5c5c5bccf2891d73b87495808293d5fac83c8 - IN TLSA 2 1 1 60b87575447dcba2a36b7d11ac09fb24a9db406fee12d2cc90180517616e8a18 - IN TLSA 2 1 1 b111dd8a1c2091a89bd4fd60c57f0716cce50feeff8137cdbee0326e02cf362b +_amazon-tlsa IN TLSA 2 0 1 18CE6CFE7BF14E60B2E347B8DFE868CB31D02EBB3ADA271569F50343B46DB3A4 + IN TLSA 2 0 1 1BA5B2AA8C65401A82960118F80BEC4F62304D83CEC4713A19C39C011EA46DB4 + IN TLSA 2 0 1 8ECDE6884F3D87B1125BA31AC3FCB13D7016DE7F57CC904FE1CB97C6AE98196E + IN TLSA 2 0 1 E35D28419ED02025CFA69038CD623962458DA5C695FBDEA3C22B0BFB25897092 +_cacert-c3-tlsa IN TLSA 2 0 1 4EDDE9E55CA453B388887CAA25D5C5C5BCCF2891D73B87495808293D5FAC83C8 +_cacert-le-tlsa IN TLSA 2 0 1 4EDDE9E55CA453B388887CAA25D5C5C5BCCF2891D73B87495808293D5FAC83C8 + IN TLSA 2 1 1 60B87575447DCBA2A36B7D11AC09FB24A9DB406FEE12D2CC90180517616E8A18 + IN TLSA 2 1 1 B111DD8A1C2091A89BD4FD60C57F0716CCE50FEEFF8137CDBEE0326E02CF362B _dmarc IN TXT "v=DMARC1; p=none; sp=none; rua=mailto:dmarc-notify@example.org; ruf=mailto:dmarc-notify@example.org; adkim=s" example.com._report._dmarc IN TXT "v=DMARC1" example.net._report._dmarc IN TXT "v=DMARC1" @@ -37,39 +37,39 @@ d201911e2._domainkey IN TXT "v=DKIM1; k=ed25519; p=GBt2k2L39KUb39fg5brOppXDHXvIS 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 - IN TLSA 2 0 1 1ba5b2aa8c65401a82960118f80bec4f62304d83cec4713a19c39c011ea46db4 - IN TLSA 2 0 1 8ecde6884f3d87b1125ba31ac3fcb13d7016de7f57cc904fe1cb97c6ae98196e - IN TLSA 2 0 1 e35d28419ed02025cfa69038cd623962458da5c695fbdea3c22b0bfb25897092 - IN TLSA 2 1 1 60b87575447dcba2a36b7d11ac09fb24a9db406fee12d2cc90180517616e8a18 - IN TLSA 2 1 1 b111dd8a1c2091a89bd4fd60c57f0716cce50feeff8137cdbee0326e02cf362b -_letsencrypt-tlsa IN TLSA 2 1 1 60b87575447dcba2a36b7d11ac09fb24a9db406fee12d2cc90180517616e8a18 - IN TLSA 2 1 1 b111dd8a1c2091a89bd4fd60c57f0716cce50feeff8137cdbee0326e02cf362b +_le-amazon-tlsa IN TLSA 2 0 1 18CE6CFE7BF14E60B2E347B8DFE868CB31D02EBB3ADA271569F50343B46DB3A4 + IN TLSA 2 0 1 1BA5B2AA8C65401A82960118F80BEC4F62304D83CEC4713A19C39C011EA46DB4 + IN TLSA 2 0 1 8ECDE6884F3D87B1125BA31AC3FCB13D7016DE7F57CC904FE1CB97C6AE98196E + IN TLSA 2 0 1 E35D28419ED02025CFA69038CD623962458DA5C695FBDEA3C22B0BFB25897092 + IN TLSA 2 1 1 60B87575447DCBA2A36B7D11AC09FB24A9DB406FEE12D2CC90180517616E8A18 + IN TLSA 2 1 1 B111DD8A1C2091A89BD4FD60C57F0716CCE50FEEFF8137CDBEE0326E02CF362B +_letsencrypt-tlsa IN TLSA 2 1 1 60B87575447DCBA2A36B7D11AC09FB24A9DB406FEE12D2CC90180517616E8A18 + IN TLSA 2 1 1 B111DD8A1C2091A89BD4FD60C57F0716CCE50FEEFF8137CDBEE0326E02CF362B _mta-sts IN TXT "v=STSv1; id=20191231r1;" -_ourca-cacert-le-tlsa IN TLSA 2 0 1 11f058f61f97b8adc66ef4801f918c71b10e5c1e3d39afde10408b3026647ef1 - IN TLSA 2 0 1 4edde9e55ca453b388887caa25d5c5c5bccf2891d73b87495808293d5fac83c8 - IN TLSA 2 0 1 ea99063a0a3bda9727032cf82da238698b90ba729300703d3956943635f96488 - IN TLSA 2 1 1 60b87575447dcba2a36b7d11ac09fb24a9db406fee12d2cc90180517616e8a18 - IN TLSA 2 1 1 b111dd8a1c2091a89bd4fd60c57f0716cce50feeff8137cdbee0326e02cf362b -_ourca-cacert-tlsa IN TLSA 2 0 1 11f058f61f97b8adc66ef4801f918c71b10e5c1e3d39afde10408b3026647ef1 - IN TLSA 2 0 1 4edde9e55ca453b388887caa25d5c5c5bccf2891d73b87495808293d5fac83c8 - IN TLSA 2 0 1 ea99063a0a3bda9727032cf82da238698b90ba729300703d3956943635f96488 -_ourca-le-amazon-tlsa IN TLSA 2 0 1 11f058f61f97b8adc66ef4801f918c71b10e5c1e3d39afde10408b3026647ef1 - IN TLSA 2 0 1 18ce6cfe7bf14e60b2e347b8dfe868cb31d02ebb3ada271569f50343b46db3a4 - IN TLSA 2 0 1 1ba5b2aa8c65401a82960118f80bec4f62304d83cec4713a19c39c011ea46db4 - IN TLSA 2 0 1 8ecde6884f3d87b1125ba31ac3fcb13d7016de7f57cc904fe1cb97c6ae98196e - IN TLSA 2 0 1 e35d28419ed02025cfa69038cd623962458da5c695fbdea3c22b0bfb25897092 - IN TLSA 2 0 1 ea99063a0a3bda9727032cf82da238698b90ba729300703d3956943635f96488 - IN TLSA 2 1 1 60b87575447dcba2a36b7d11ac09fb24a9db406fee12d2cc90180517616e8a18 - IN TLSA 2 1 1 b111dd8a1c2091a89bd4fd60c57f0716cce50feeff8137cdbee0326e02cf362b -_ourca-le-tlsa IN TLSA 2 0 1 11f058f61f97b8adc66ef4801f918c71b10e5c1e3d39afde10408b3026647ef1 - IN TLSA 2 0 1 ea99063a0a3bda9727032cf82da238698b90ba729300703d3956943635f96488 - IN TLSA 2 1 1 60b87575447dcba2a36b7d11ac09fb24a9db406fee12d2cc90180517616e8a18 - IN TLSA 2 1 1 b111dd8a1c2091a89bd4fd60c57f0716cce50feeff8137cdbee0326e02cf362b -_ourca-tlsa IN TLSA 2 0 1 11f058f61f97b8adc66ef4801f918c71b10e5c1e3d39afde10408b3026647ef1 - IN TLSA 2 0 1 ea99063a0a3bda9727032cf82da238698b90ba729300703d3956943635f96488 -_ourcaca4-tlsa IN TLSA 2 0 1 ea99063a0a3bda9727032cf82da238698b90ba729300703d3956943635f96488 -_ourcaca5-tlsa IN TLSA 2 0 1 11f058f61f97b8adc66ef4801f918c71b10e5c1e3d39afde10408b3026647ef1 +_ourca-cacert-le-tlsa IN TLSA 2 0 1 11F058F61F97B8ADC66EF4801F918C71B10E5C1E3D39AFDE10408B3026647EF1 + IN TLSA 2 0 1 4EDDE9E55CA453B388887CAA25D5C5C5BCCF2891D73B87495808293D5FAC83C8 + IN TLSA 2 0 1 EA99063A0A3BDA9727032CF82DA238698B90BA729300703D3956943635F96488 + IN TLSA 2 1 1 60B87575447DCBA2A36B7D11AC09FB24A9DB406FEE12D2CC90180517616E8A18 + IN TLSA 2 1 1 B111DD8A1C2091A89BD4FD60C57F0716CCE50FEEFF8137CDBEE0326E02CF362B +_ourca-cacert-tlsa IN TLSA 2 0 1 11F058F61F97B8ADC66EF4801F918C71B10E5C1E3D39AFDE10408B3026647EF1 + IN TLSA 2 0 1 4EDDE9E55CA453B388887CAA25D5C5C5BCCF2891D73B87495808293D5FAC83C8 + IN TLSA 2 0 1 EA99063A0A3BDA9727032CF82DA238698B90BA729300703D3956943635F96488 +_ourca-le-amazon-tlsa IN TLSA 2 0 1 11F058F61F97B8ADC66EF4801F918C71B10E5C1E3D39AFDE10408B3026647EF1 + IN TLSA 2 0 1 18CE6CFE7BF14E60B2E347B8DFE868CB31D02EBB3ADA271569F50343B46DB3A4 + IN TLSA 2 0 1 1BA5B2AA8C65401A82960118F80BEC4F62304D83CEC4713A19C39C011EA46DB4 + IN TLSA 2 0 1 8ECDE6884F3D87B1125BA31AC3FCB13D7016DE7F57CC904FE1CB97C6AE98196E + IN TLSA 2 0 1 E35D28419ED02025CFA69038CD623962458DA5C695FBDEA3C22B0BFB25897092 + IN TLSA 2 0 1 EA99063A0A3BDA9727032CF82DA238698B90BA729300703D3956943635F96488 + IN TLSA 2 1 1 60B87575447DCBA2A36B7D11AC09FB24A9DB406FEE12D2CC90180517616E8A18 + IN TLSA 2 1 1 B111DD8A1C2091A89BD4FD60C57F0716CCE50FEEFF8137CDBEE0326E02CF362B +_ourca-le-tlsa IN TLSA 2 0 1 11F058F61F97B8ADC66EF4801F918C71B10E5C1E3D39AFDE10408B3026647EF1 + IN TLSA 2 0 1 EA99063A0A3BDA9727032CF82DA238698B90BA729300703D3956943635F96488 + IN TLSA 2 1 1 60B87575447DCBA2A36B7D11AC09FB24A9DB406FEE12D2CC90180517616E8A18 + IN TLSA 2 1 1 B111DD8A1C2091A89BD4FD60C57F0716CCE50FEEFF8137CDBEE0326E02CF362B +_ourca-tlsa IN TLSA 2 0 1 11F058F61F97B8ADC66EF4801F918C71B10E5C1E3D39AFDE10408B3026647EF1 + IN TLSA 2 0 1 EA99063A0A3BDA9727032CF82DA238698B90BA729300703D3956943635F96488 +_ourcaca4-tlsa IN TLSA 2 0 1 EA99063A0A3BDA9727032CF82DA238698B90BA729300703D3956943635F96488 +_ourcaca5-tlsa IN TLSA 2 0 1 11F058F61F97B8ADC66EF4801F918C71B10E5C1E3D39AFDE10408B3026647EF1 _report IN TXT "r=abuse-reports@example.org; rf=ARF; re=postmaster@example.org;" _sip+d2s._sctp IN SRV 0 0 0 . _sips+d2s._sctp IN SRV 0 0 0 . diff --git a/commands/types/dnscontrol.d.ts b/commands/types/dnscontrol.d.ts index 13900ab560..6f252ed10e 100644 --- a/commands/types/dnscontrol.d.ts +++ b/commands/types/dnscontrol.d.ts @@ -250,7 +250,7 @@ declare function AAAA(name: string, address: string, ...modifiers: RecordModifie * * @see https://docs.dnscontrol.org/language-reference/domain-modifiers/service-provider-specific//adguardhome_aaaa_passthrough */ -declare function ADGUARDHOME_AAAA_PASSTHROUGH(source: string, destination: string): DomainModifier; +declare function ADGUARDHOME_AAAA_PASSTHROUGH(source: string, destination: string, ...modifiers: RecordModifier[]): DomainModifier; /** * `ADGUARDHOME_A_PASSTHROUGH` represents the literal 'A'. AdGuardHome uses this to passthrough @@ -269,7 +269,7 @@ declare function ADGUARDHOME_AAAA_PASSTHROUGH(source: string, destination: strin * * @see https://docs.dnscontrol.org/language-reference/domain-modifiers/service-provider-specific//adguardhome_a_passthrough */ -declare function ADGUARDHOME_A_PASSTHROUGH(source: string, destination: string): DomainModifier; +declare function ADGUARDHOME_A_PASSTHROUGH(source: string, destination: string, ...modifiers: RecordModifier[]): DomainModifier; /** * AKAMAICDN is a proprietary record type that is used to configure [Zone Apex Mapping](https://www.akamai.com/blog/security/edge-dns--zone-apex-mapping---dnssec). @@ -671,7 +671,7 @@ declare function CF_TEMP_REDIRECT(source: string, destination: string, ...modifi * * @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; +declare function CF_WORKER_ROUTE(pattern: string, script: string, ...modifiers: RecordModifier[]): DomainModifier; /** * Documentation needed. @@ -855,7 +855,7 @@ declare function DHCID(name: string, digest: string, ...modifiers: RecordModifie /** * `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. + * It replaces the per-record `IGNORE_NAME_DISABLE_SAFETY_CHECK` which is deprecated as of DNSControl v4.0.0. * * See [`IGNORE`](../domain-modifiers/IGNORE.md) for more information. * @@ -1033,11 +1033,14 @@ declare function DKIM_BUILDER(opts: { selector: string; pubkey?: string; label?: * * `nonexistentSubdomainPolicy:` The DMARC policy for nonexistent subdomains (`np=`), 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:` Integer percentage (0-100) of messages to which the DMARC policy is applied (`pct=`, optional) * * `rua:` Array of aggregate report targets (optional) * * `ruf:` Array of failure report targets (optional) * * `publicSuffixDomain:` `"y"`, or `"n"` or `"u"` indicates whether the domain is a Public Suffix Domain (`psd=`, default: `"u"`) * * `testMode:` `"y"` or `"n"` DMARC policy test mode dictates whether p, sp, or np policy tags are applied (`t=`, default: `"n"`) * * `failureOptions:` Object or string; Object containing booleans `SPF` and `DKIM`, string is passed raw (`fo=`, default: `"0"`) + * * `failureFormat:` Format of the message's failure reports (`rf=`); only emitted when `ruf` is also set (optional) + * * `reportInterval:` Requested interval between aggregate reports, as a `Duration` or number of seconds (`ri=`, optional) * * `ttl:` Input for `TTL` method (optional) * * ### Caveats @@ -1047,7 +1050,7 @@ declare function DKIM_BUILDER(opts: { selector: string; pubkey?: string; label?: * * @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'; nonexistentSubdomainPolicy?: 'none' | 'quarantine' | 'reject'; alignmentSPF?: 'strict' | 's' | 'relaxed' | 'r'; alignmentDKIM?: 'strict' | 's' | 'relaxed' | 'r'; rua?: string[]; ruf?: string[]; publicSuffixDomain: 'y' | 'n' | 'u'; testMode: 'y' | 'n'; failureOptions?: { SPF: boolean, DKIM: boolean } | string; ttl?: Duration }): DomainModifier; +declare function DMARC_BUILDER(opts: { label?: string; version?: string; policy: 'none' | 'quarantine' | 'reject'; subdomainPolicy?: 'none' | 'quarantine' | 'reject'; nonexistentSubdomainPolicy?: 'none' | 'quarantine' | 'reject'; alignmentSPF?: 'strict' | 's' | 'relaxed' | 'r'; alignmentDKIM?: 'strict' | 's' | 'relaxed' | 'r'; percent?: number; rua?: string[]; ruf?: string[]; publicSuffixDomain: 'y' | 'n' | 'u'; testMode: 'y' | 'n'; failureOptions?: { SPF: boolean, DKIM: boolean } | string; failureFormat?: string; reportInterval?: Duration | number; ttl?: Duration }): DomainModifier; /** * `DNAME` adds a [Delegation name record](https://www.rfc-editor.org/rfc/rfc6672) to the domain. @@ -1908,9 +1911,11 @@ declare function IP(ip: string): number; * deg1: uint32 * min1: uint32 * sec1: float32 + * ns: string * deg2: uint32 * min2: uint32 * sec2: float32 + * ew: string * altitude: float32 * size: float32 * horizontal_precision: float32 @@ -1983,7 +1988,7 @@ declare function IP(ip: string): number; * * @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; +declare function LOC(name: string, deg1: number, min1: number, sec1: number, ns: "N" | "S" | "n" | "s", deg2: number, min2: number, sec2: number, ew: "E" | "W" | "e" | "w", altitude: number, size: number, horizontal_precision: number, vertical_precision: number, ...modifiers: RecordModifier[]): DomainModifier; /** * `LOC_BUILDER_DD({})` actually takes an object with the following properties: @@ -2494,7 +2499,7 @@ declare function MX(name: string, priority: number, target: string, ...modifiers * * @see https://docs.dnscontrol.org/language-reference/domain-modifiers/nameserver */ -declare function NAMESERVER(name: string, ...modifiers: RecordModifier[]): DomainModifier; +declare function NAMESERVER(name: string): DomainModifier; /** * NAMESERVER_TTL sets the TTL on the domain apex NS RRs defined by [`NAMESERVER`](NAMESERVER.md). @@ -2717,7 +2722,7 @@ declare function NAMESERVER_TTL(ttl: Duration): DomainModifier; * * @see https://docs.dnscontrol.org/language-reference/domain-modifiers/naptr */ -declare function NAPTR(subdomain: string, order: number, preference: number, terminalflag: string, service: string, regexp: string, target: string): DomainModifier; +declare function NAPTR(subdomain: string, order: number, preference: number, terminalflag: string, service: string, regexp: string, target: string, ...modifiers: RecordModifier[]): DomainModifier; /** * `NO_PURGE` indicates that existing records should not be deleted from a domain. Records will be added and updated, but not removed. diff --git a/commands/ultimate.go b/commands/ultimate.go index 2d4b64858a..bca4d7da69 100644 --- a/commands/ultimate.go +++ b/commands/ultimate.go @@ -1,6 +1,6 @@ package commands -import "github.com/DNSControl/dnscontrol/v4/models" +import "github.com/DNSControl/dnscontrol/v5/models" /* I proposed that Go add something like "len()" that returns the highest diff --git a/commands/writeTypes.go b/commands/writeTypes.go index bcfba67ca5..d23a26a51d 100644 --- a/commands/writeTypes.go +++ b/commands/writeTypes.go @@ -5,7 +5,7 @@ import ( _ "embed" // Required by go:embed "os" - "github.com/DNSControl/dnscontrol/v4/pkg/version" + "github.com/DNSControl/dnscontrol/v5/pkg/version" "github.com/urfave/cli/v3" ) diff --git a/docs/flattener/js.go b/docs/flattener/js.go index 5192ab9589..3170e1f6f0 100644 --- a/docs/flattener/js.go +++ b/docs/flattener/js.go @@ -9,7 +9,7 @@ import ( "net/http" "strings" - "github.com/DNSControl/dnscontrol/v4/pkg/spflib" + "github.com/DNSControl/dnscontrol/v5/pkg/spflib" "github.com/gopherjs/jquery" ) diff --git a/documentation/SUMMARY.md b/documentation/SUMMARY.md index 81144131c9..c7c077ac14 100644 --- a/documentation/SUMMARY.md +++ b/documentation/SUMMARY.md @@ -217,11 +217,13 @@ * [Code Style Guide](advanced-features/styleguide-code.md) * [Documentation Style Guide](advanced-features/styleguide-doc.md) +* [Cookbook](developer-info/cookbook.md) * [DNSControl is an opinionated system](advanced-features/opinions.md) * [GitHub actions](developer-info/github-actions.md) * [Writing new DNS providers](advanced-features/writing-providers.md) * [Creating new DNS Resource Types (rtypes)](advanced-features/adding-new-rtypes.md) * [Integration Tests](advanced-features/integration-tests.md) +* [Provider conversion tests](developer-info/provider-conversion-tests.md) * [Test a branch](advanced-features/test-a-branch.md) * [Unit Testing DNS Data](advanced-features/unittests.md) * [Bug Triage Process](advanced-features/bug-triage.md) diff --git a/documentation/advanced-features/adding-new-rtypes-v2.md b/documentation/advanced-features/adding-new-rtypes-v2.md deleted file mode 100644 index 9092adffd2..0000000000 --- a/documentation/advanced-features/adding-new-rtypes-v2.md +++ /dev/null @@ -1,333 +0,0 @@ -# Creating new DNS Resource Types (rtypes) (v4.28 and later) - -Everyone is familiar with A, AAAA, CNAME, NS and other Rtypes. However there are new record types being added all the time. Each new record type requires special handling by DNSControl. - -Version v4.28.0 greatly simplified how to add new record types. As a demonstration of this new method it added the "RP" type and ported the existing "CLOUDFLAREAPI_SINGLE_REDIRECT" type. All other records still use the old method. The old and new methods co-exist, though eventually we hope to migrate everything to the new method. - -# What's new? - -* OLD: the RecordConfig struct keeps getting larger as new record types require more fields. -* NEW: the RecordConfig struct has a pointer to a struct describing the fields of the record. -* Benefit: Saves memory. - -* OLD: helpers.js performs validation, executes builders, etc. Since we don't have a test framework for Javascript, this is brittle and difficult to debug. -* NEW: helpers.js packs up the fields, whatever they are, and handes them off to Go code for processing. The Go test framework is available. -* Benefit: More testable, easier to develop as you don't need to know 2 languages. - -* OLD: Critical things like IDN processing, normalization (downcasing), and validation happen late in the pipeline by `pkg/normalize`. -* NEW: The factory that creates a RecordConfig performs all that. -* Benefit: No code has to be concerned with "has this RecordConfig been normalized/IDN-ized yet?". This makes it easier to write and debug code. - -* OLD: Code that affects a Record Type is splattered all over the code base. -* NEW: Code related to a Record Type is all in one file. -* Benefit: Centralize all concerns about a record type in one file (with some exceptions that we hope to fix eventually). - -# Overview - -There are two parts to adding a new Record Type (rtype). First we activate it in the parser for dnsconfig.js. Then we update any provider to be aware of the rtype. - -Activate it in dnsconfig.js: - -1. Update `pkg/js/helpers.js` (add just 1 line!) -2. Create a file in `pkg/rtype` (for example, `pkg/rtype/rp.go`) with a parser. - -Update providers to be aware of the rtype: - -1. Update the toRC() function (whatever it may be called). -1. Update the toNative() and any create/delete/change functions. - -# Updating the parser - -In these examples, the new type will be called `THING` (or `thing`). - -Step 1: Update helpers.js - -At the end of the file, add a single line named after the record type. - -``` -var RP = rawrecordBuilder('RP'); -``` - -In this example, the first `RP` is the name of the function that users will type in dnsconfig.js. For example, `A("label", "10.2.3.4"),` (though the "A" record type hasn't been ported to the new system yet). - -Step 2: Create the parser - -Create a file in `pkg/rtype/thing.go` named after the record type (all lowercase). - -Copy `pkg/rtype/rp.go` as it is a good prototype. - -Step 2a: Update init() - -Update the init function to register your new type. That is, change `RP` to `THING`. - -``` -func init() { - rtypecontrol.Register(&THING{}) -} -``` - -Step 2b: Create the struct - -Create a struct that will store the fields of this rtype. - -If this is a standard rtype, borrow from miekg/dns: - -``` -type THING struct { - dns.THING -} -``` - -If this is not a standard type, list the fields: - -``` -type THING struct { - ThingField1 uint32 - ThingField2 string - ThingField3 string - ThingField4 uint32 -} -``` - -Step 2c: Create Name() - -Create a function `Name()` that outputs the name of the type. - -``` -func (handle *THING) Name() string { - return "THING" -} -``` - -Step 2d: Create FromArgs - -The "FromArgs" function receives an array of `any` which can contain any type. The "PaveArgs" function will convert them to the types you need. For example, it will convert numbers to strings, or strings to numbers. - -* "s": Convert to string -* "i": Convert to int16 - -`args[0]` is the label. You can skip it as that is already processed for you. (If you want to modify the label, see cfsingle.go as an example of how to do that.) - -If THING takes 4 parameters (2 ints and 2 strings), you might pave the arguments as follows: - -``` - if err := rtypecontrol.PaveArgs(args[1:], "issi"); err != nil { -``` - -Now you can fill the struct as needed: - -``` - fields := &THING{ - dns.THING{ - ThingField1: args[1].(uint16), - ThingField2: args[2].(string), - ThingField3: args[3].(string), - ThingField4: args[4].(uint16), - }, - } -``` - -Now call FromStruct to finsh up. - -``` - return handle.FromStruct(dc, rec, args[0].(string), fields) -``` - -FromStruct does many things: - -1. Installs the struct in .F -2. Converts any names to IDN and Unicode equivalents for future reference. -2. Performs any validation (for example, if ThingField1 has to be between 0 and 999) -2. Generate the .ZonefilePartial field: This is what the record outputs in a zonefile. -2. Generate the .Comparable field: This is an opaque string used to compare two RecordConfigs. If the strings are not an exact match, they are considered "not equal". - -Create the CopyToLegacyFields function - -This updates any of the legacy fields. The most important is the .target field, which we usually store a copy of the .ZonefilePartial. - -When we migrate other rtypes this will populate the legacy RecordConfig fields. For example, when we migrate `SRV`, this function will populate the `Srv*` fields. Then, eventually, we'll remove those legacy fields. - -TODO: `js/parse_test` - -## Add a capability for the record type - -You'll need to mark which providers support this record type. The initial PR should implement this record for the `BIND` provider at a minimum. `BIND` outputs non-standard rtypes as a comment. - -- Add the capability to the file `dnscontrol/providers/capabilities.go` (look for `CanUseAlias` and add it to the end of the list.) -- Run stringer to auto-update the file `dnscontrol/providers/capability_string.go` - -```shell -pushd providers/ -go tool stringer -type=Capability -popd -``` -alternatively - -```shell -pushd providers/ -go generate -popd -``` - -- Add this feature to the feature matrix in `dnscontrol/build/generate/featureMatrix.go`. Add it to the variable `matrix` maintaining alphabetical ordering, which should look like this: - - {% code title="dnscontrol/build/generate/featureMatrix.go" %} - ```diff - func matrixData() *FeatureMatrix { - const ( - ... - DomainModifierCaa = "[`CAA`](language-reference/domain-modifiers/CAA.md)" - + DomainModifierFoo = "[`FOO`](language-reference/domain-modifiers/FOO.md)" - DomainModifierLoc = "[`LOC`](language-reference/domain-modifiers/LOC.md)" - ... - ) - matrix := &FeatureMatrix{ - Providers: map[string]FeatureMap{}, - Features: []string{ - ... - DomainModifierCaa, - + DomainModifierFoo, - DomainModifierLoc, - ... - }, - } - ``` - {% endcode %} - - then add it later in the file with a `setCapability()` statement, which should look like this: - - {% code title="dnscontrol/build/generate/featureMatrix.go" %} - ```diff - ... - + setCapability( - + DomainModifierFoo, - + providers.CanUseFOO, - + ) - ... - ``` - {% endcode %} - -- Add the capability to the list of features that zones are validated against (i.e. if you want DNSControl to report an error if this feature is used with a DNS provider that doesn't support it). That's in the `checkProviderCapabilities` function in `pkg/normalize/validate.go`. It should look like this: - - {% code title="pkg/normalize/validate.go" %} - ```diff - var providerCapabilityChecks = []pairTypeCapability{ - ... - + capabilityCheck("FOO", providers.CanUseFOO), - ... - ``` - {% endcode %} - -- Mark the `bind` provider as supporting this record type by updating `dnscontrol/providers/bind/bindProvider.go` (look for `providers.CanUse` and you'll see what to do). - -DNSControl will warn/error if this new record is used with a provider that does not support the capability. - -- Add the capability to the validations in `pkg/normalize/validate.go` by adding it to `providerCapabilityChecks` -- Some capabilities can't be tested for. If such testing can't be done, add it to the whitelist in function `TestCapabilitiesAreFiltered` in `pkg/normalize/capabilities_test.go` - -If the capabilities testing is not configured correctly, `go test ./...` will report something like the `MISSING` message below. In this example we removed `providers.CanUseCAA` from the `providerCapabilityChecks` list. - -```text ---- FAIL: TestCapabilitiesAreFiltered (0.00s) - capabilities_test.go:66: ok: providers.CanUseAlias (0) is checked for with "ALIAS" - capabilities_test.go:68: MISSING: providers.CanUseCAA (1) is not checked by checkProviderCapabilities - capabilities_test.go:66: ok: providers.CanUseNAPTR (3) is checked for with "NAPTR" -``` - -## Step 6: Add an `integrationTest` test case - -(see old doc) - -## Step 8: Write documentation - -Add a new Markdown file to `documentation/language-reference/domain-modifiers`. Copy an existing file (`CNAME.md` is a good example). The section between the lines of `---` is called the front matter and it has the following keys: - -- `name`: The name of the record. This should match the file name and the name of the record in `helpers.js`. -- `parameters`: A list of parameter names, in order. Feel free to use spaces in the name if necessary. Your last parameter should be `modifiers...` to allow arbitrary modifiers like `TTL` to be applied to your record. -- `parameter_types`: an object with parameter names as keys and TypeScript type names as values. Check out existing record documentation if you’re not sure to put for a parameter. Note that this isn’t displayed on the website, it’s only used to generate the `.d.ts` file. - -The rest of the file is the documentation. You can use Markdown syntax to format the text. - -Add the new file `FOO.md` to the documentation table of contents `documentation/SUMMARY.md` > `Domain Modifiers`, and/or to the `Service Provider specific` section if you made a record specific to a provider, and to the `Record Modifiers` section if you created any `*_BUILDER` or `*_HELPER` or similar functions for the new record type: - -{% code title="documentation/SUMMARY.md" %} -```diff -... -* Domain Modifiers -... - * [DnsProvider](language-reference/domain-modifiers/DnsProvider.md) -+ * [FOO](language-reference/domain-modifiers/FOO.md) - * [FRAME](language-reference/domain-modifiers/FRAME.md) -... - * Service Provider specific -... - * ClouDNS - * [CLOUDNS_WR](language-reference/domain-modifiers/CLOUDNS_WR.md) -+ * ASDF -+ * [ASDF_NINJA](language-reference/domain-modifiers/ASDF_NINJA.md) -... -* Record Modifiers -... - * [DMARC_BUILDER](language-reference/domain-modifiers/DMARC_BUILDER.md) -+ * [FOO_HELPER](language-reference/record-modifiers/FOO_HELPER.md) - * [SPF_BUILDER](language-reference/domain-modifiers/SPF_BUILDER.md) -... -``` -{% endcode %} - -TODO Run the integration tests for BIND - -## Step 9: "Update the index page" - -Edit `documentation/SUMMARY.md` and add a link to the new record type's doc. - -## Step 9: "go generate" - -Re-generate the documentation: - -```shell -go generate ./... -``` - -This will regenerate things like the table of which providers have which features and the `dnscontrol.d.ts` file. - -# Update providers - -When a provider needs to create a THING, they have two choices - -If you have the fields already in variables of the right type, use NewRecordConfigFromStruct: - -``` -rec, err = rtypecontrol.NewRecordConfigFromStruct(name, ttl, "THING", rtype.THING{a, b, c, d}, dc) -``` - -If you have the fields in variables that are strings that need to be converted, use `NewRecordConfigFromRaw()`: - -``` -rec, err := rtypecontrol.NewRecordConfigFromRaw("CF_REDIRECT", ttl, []any{pattern, target}, dc) -``` - -There's a good chance you know the zoneName but don't have a complete models.DomainConfig(). That's ok. As long as you know the zone name, we can fake it: (this is a hack we'll figure out how to eliminate eventually). - -``` -dc := models.MakeFakeDomainConfig(zoneName) -``` - -# Tips for "builders" - -A "builder" is a function that create other records. For example, SPF_BUILDER() creates a `TXT()` record. - -A good example of a builder is `providers/cloudflare/rtypes/cfsingleredirect/cfredirect.go` - -Simply do the processing you need, then create the resulting rtype you want: - -In cfredirect.go, CF_REDIRECT is a builder that generates a CLOUDFLAREAPI_SINGLE_REDIRECT, represented by the SingleRedirectConfig struct: - -``` - sr := SingleRedirectConfig{} - rec.Type = sr.Name() // This record is now a CLOUDFLAREAPI_SINGLE_REDIRECT - err = sr.FromArgs(dc, rec, []any{name, code, srWhen, srThen}) - if err != nil { - return err - } -``` diff --git a/documentation/advanced-features/adding-new-rtypes.md b/documentation/advanced-features/adding-new-rtypes.md index 37330c8b4b..4f2ed6a069 100644 --- a/documentation/advanced-features/adding-new-rtypes.md +++ b/documentation/advanced-features/adding-new-rtypes.md @@ -1,115 +1,241 @@ # Creating new DNS Resource Types (rtypes) -Everyone is familiar with A, AAAA, CNAME, NS and other Rtypes. However there are new record types being added all the time. Each new record type requires special handling by DNSControl. +- [Creating new DNS Resource Types (rtypes)](#creating-new-dns-resource-types-rtypes) + - [How to add a CUSTOM record type (rtype)](#how-to-add-a-custom-record-type-rtype) + - [Step 1. Pick a unique id](#step-1-pick-a-unique-id) + - [Step 2. Describe the custom type in YAML](#step-2-describe-the-custom-type-in-yaml) + - [Step 3. Generate the code](#step-3-generate-the-code) + - [Step 4. Test](#step-4-test) + - [Step 5. Write the remaining functions](#step-5-write-the-remaining-functions) + - [How to add a new record type (rtype)](#how-to-add-a-new-record-type-rtype) + - [Step 1. Update `pkg/js/helpers.js`](#step-1-update-pkgjshelpersjs) + - [Step 2. Update `models/makers.go` (NOT NEEDED FOR CUSTOM TYPES)](#step-2-update-modelsmakersgo-not-needed-for-custom-types) + - [Step 3. Update `models/populatelegacy.go`](#step-3-update-modelspopulatelegacygo) + - [Step 4. Update `models/populaterd.go`](#step-4-update-modelspopulaterdgo) + - [Step 5. Add a `CanUseTYPENAME`](#step-5-add-a-canusetypename) + - [Step 6. Document it](#step-6-document-it) + - [Step 7. Update the matrix](#step-7-update-the-matrix) + - [Step 8: Add a `parse_tests` test case](#step-8-add-a-parse_tests-test-case) + - [Step 9. Test it out with BIND](#step-9-test-it-out-with-bind) + - [Step 10. Add an integration test helper](#step-10-add-an-integration-test-helper) + - [Step 11. Add Integration tests](#step-11-add-integration-tests) + - [Step 12: Support more providers](#step-12-support-more-providers) + - [Step 13: Write documentation](#step-13-write-documentation) + - [Step 14: "go generate"](#step-14-go-generate) + - [How to enable an rtype in a provider](#how-to-enable-an-rtype-in-a-provider) + - [How to add a "builder"](#how-to-add-a-builder) -If a record simply has a single "target", then there is little to do because it is handled similarly to A, CNAME, and so on. However if there are multiple fields within the record you have more work to do. +Everyone is familiar with A, AAAA, CNAME, NS and other Rtypes. However DNSControl also supports: -Our general philosophy is: +- All standard (RFC) record types. Anything that [codeberg.org/miekg/dns supports](https://codeberg.org/miekg/dns) +- Custom record types. DNS Service Providers often add their own unique record types. +- Builders. Functions that can be used in `dnsconfig.js` that generate one or more records. For example, `SPF_BUILDER()` generates one or more `TXT` records. + - Modern builders are implemented in Go, in `models/b_NAME.go` + - Legacy builders are implemented purely in JavaScript in `pkg/js/helpers.js` + - In the future, we plan on migrating all builders to Go. -- Internally the individual fields of a record are kept separate. If a particular provider combines them into one big string, that kind of thing is done in the provider code at the end of the food chain. For example, an MX record has a Target (`aspmx.l.google.com.`) and a preference (`10`). Some systems combine this into one string (`10 aspmx.l.google.com.`). We keep the two values separate in `RecordConfig` and leave it up to the individual providers to merge them when required. An earlier implementation kept everything combined and we found ourselves constantly parsing and re-parsing the target. It was inefficient and lead to many bugs. -- Anywhere we have a special case for a particular Rtype, we use a `switch` statement and have a `case` for every single record type, usually with a `default:` case that calls `panic()`. This way developers adding a new record type will quickly find where they need to add code (the panic will tell them where). Before we did this, missing implementation code would go unnoticed for months. -- Keep things alphabetical. If you are adding your record type to a case statement, function library, or whatever, please list it alphabetically along with the others when possible. +The fields of standard and custom types are stored in a struct called an `RDATA`, which is stored in `models.RecordConfig.rdata`. Use the .GetRDATA() and .SetRDATA() getter/setter to access them. + +Legacy types store their fields directly in `models.RecordConfig`. For example, the MX preference +is in `models.RecordConfig{MxPreference: 10}`. This means space is taken to store the MX Preference even when the record type is something else. While this seemed ok back in 2016, the structure is now very big. The goal of RecordConfig V3 is to save memory by eliminating those fields. + +While we transition to RecordConfig V3, the data is stored in both places (RDATA and the legacy fields). Data is converted bidirectionally. If RDATA is nil, DNSControl will create it automatically by plucking the data from the legacy fields. The reverse also happens: when `SetRDATA()` is called, it populates any legacy fields. + +Eventually we'll get rid of the legacy code. + +The new system consolidates everything related to a record type to the record type's "object" (as much as Go has objects). However the legacy code spreads logic for a given record type in many places in the code. Those places are marked with the comment `// rtype_variations` + +## How to add a CUSTOM record type (rtype) + +Many providers support custom DNS record types. For example, Cloudflare has +type called `CLOUDFLAREAPI_SINGLE_REDIRECT`. + +Note: This is different than a "builder". A builder is a function that can be used in `dnsconfig.js` which outputs one or more DNS records. For example, the `SPF_BUILDER()` function generates `TXT` records. See below. + +To add a custom type, follow these steps: + +### Step 1. Pick a unique id + +Each custom type is assigned a codepoint. + +Here's the last id used. Add one to this value. (There is plenty of error-checking in the system if you guess wrong). -Step 2 requires `stringer` which is available using ```shell -go tool stringer +grep codepoint pkg/privatetypes/types_generate.yaml | sort | tail -1 ``` -## Step 1: Update `RecordConfig` in `models/record.go` -If the record has any unique fields, add them to `RecordConfig`. The field name should be the record type, then the field name as used in `github.com/miekg/dns/types.go`. For example, the `CAA` record has a field called `Flag`, therefore the field name in `RecordConfig` is CaaFlag (not `CaaFlags` or `CAAFlags`). +### Step 2. Describe the custom type in YAML -Here are some examples: +Custom types are described in `pkg/privatetypes/types_generate.yaml`. The generator will create 3 Go files in `pkg/privatetypes`: -```go -type RecordConfig struct { - ... - MxPreference uint16 `json:"mxpreference,omitempty"` - SrvPriority uint16 `json:"srvpriority,omitempty"` - SrvWeight uint16 `json:"srvweight,omitempty"` - SrvPort uint16 `json:"srvport,omitempty"` - CaaTag string `json:"caatag,omitempty"` - CaaFlag uint8 `json:"caaflag,omitempty"` - ... -} -``` +- `t_typename.go` -- structures, parsers, etc. (header + RDATA) +- `t_typename_test.go` -- Unit test of the parser and .String() functions. +- `rdata/rdata_typename.go` -- structures, parsers, etc. (just RDATA) + +Add the custom type to `pkg/privatetypes/types_generate.yaml`. `Cloudflareapi_Single_Redirect` is a good example to copy. -It is important to leave the `omitempty` flag present so that tests for other record types do not start to fail because your new record types insist on being present. +Here's what the fields mean: -## Step 2: Add a capability for the record +- `name:` Must be "snake case" with first letter initial caps. This name is used to generate all the variations: `CLOUDFLAREAPI_SINGLE_REDIRECT`, `CloudflareapiSingleDirect`, and otehrs. +- `codepoint:` The unique ID you picked earlier. +- `fields:` the fields in the record type. + - `type` should match the name of the mustbe.* function used for this field. Typically you'll use: + - IPv4: An IPv4 address. + - IPv6: An IPv6 address. + - Uint8, Uint16, Uint32, Uint64, Int8, Int16, Int32, Int64, Float32, Float64: Various numeric formats. + - Txts: A list of TXT strings. + - Bool, BoolString: Bool and a stringified Bool. + - TargetHost: A hostname that is a target, either a FQDN ending in `.` or `@` if it is the apex. + - TargetHostSRV: Like TargetHost but permits SRV-compatible targets. + - RawString: A string that is not validated, normalized, or altered in any way. + - ToUpperRawString: Like RawString, but passed through strings.ToUpper() so that comparisons are case insensitive. + - Bespoke types like `OpenPGPKey` and `SoaMailbox` which are used by `OPENPGPKEY` and `SOA` respectively. + - `test_data:` is test data for the unit test. One or two simple tests is fine. The system will generate a unit test that round-trips these examples through the parser and String() functions. + - `optionalFields:` (optional) fields that are optional. The Make*() function won't expect them, but they will always be output in the `.String()` function. + - `runtimeFields:` (optional, rarely used) are fields that store data needed during `preview/push`. For example, in `Cloudflareapi_Single_Redirect` the API sends a `SRRRulesetID` which needs to be stored later for use with any updates. -You'll need to mark which providers support this record type. The initial PR should implement this record for the `bind` provider at a minimum. +### Step 3. Generate the code -- Add the capability to the file `dnscontrol/providers/capabilities.go` (look for `CanUseAlias` and add it to the end of the list.) -- Run stringer to auto-update the file `dnscontrol/providers/capability_string.go` +Now that you've created the `types_generate.yaml` file, generate all the code. ```shell -pushd providers/ -go tool stringer -type=Capability -popd +cd pkg/privatetypes && go generate ``` -alternatively + +### Step 4. Test ```shell -pushd providers/ -go generate -popd +go test -failfast -count=1 ./... +``` + +Feelf free to aadd to the code generator `pkg/privatetypes/types_generate.go` if your custom type requires +special code, new field types, etc. + +Now this type is as functional as a standard type, except it is in the `privatetypes` and `privatetypesrdata` names spaces instead of the `dnsv2` and `dnsrdatav2` namespaces. + +Standard types: + +- `dnsv2.TypeSRV` -- the codepoint +- `dnsv2.SRV{}` -- the entire struct (header + RDATA) (rarely used) +- `dnsrdatav2.SRV{}` -- the RDATA struct + +Custom types: + +- `privatetypes.TypeAKAMAICDN` -- the codepoint +- `privatetypes.AKAMAICDN{}` -- the entire struct (header + RDATA) (rarely used) +- `privatetypesrdata.AKAMAICDN{}` -- the RDATA struct + +### Step 5. Write the remaining functions + +Your type is now registered with the system and can be treated +the same as a standard type. + +Follow the instructions in the next section to complete the process. + +## How to add a new record type (rtype) + +Congrats! A new RFC has been published that defines a new DNS record type! +(Or you've added a custom type). How do we add support to DNSControl? + +Note: Since DNSControl depends on `https://codeberg.org/miekg/dns` for basic DNS record types, we must first wait for miekg to add support. He's usually quite good at adding new types but [file an issue](https://codeberg.org/miekg/dns/issues/new) if you want to make sure it is on his radar. + +Addding a new type has 2 major parts. First DNSControl must be updated to support it. Once that is complete, each provider must be updated to handle it. + +Enable the type in DNSControl itself: + +### Step 1. Update `pkg/js/helpers.js` + +- Add to list at the end. Just follow the pattern. +- This enables the record to be used in `dnsconfig.js`. + +### Step 2. Update `models/makers.go` (NOT NEEDED FOR CUSTOM TYPES) + +- Add a Make$TYPENAME + - This takes arguments of any type (like NewRecordConfig()). Every argument must pass through a `mustbe.` function. See `pkg/mustbe/README.md` for details. +- Add this new Make$TYPENAME to the func init(). + +### Step 3. Add a `CanUseTYPENAME` + +Since not all providers support this new record type, add a "capability" so that providers can mark themselves as willing. + +You'll need to have Stringer installed: + +```shell +go tool stringer ``` -- Add this feature to the feature matrix in `dnscontrol/build/generate/featureMatrix.go`. Add it to the variable `matrix` maintaining alphabetical ordering, which should look like this: +- Update `pkg/providers/capabilities.go` (search for CanUseSRV and add something similar. Please add it in alphabetical order!) +- Update `build/generate/featureMatrix.go` (search for SRV and do something similar for your type) +- Run: `cd pkg/providers && go generate` + +### Step 4. Document it + +Add documentation: + +- `documentation/language-reference/domain-modifiers/TYPENAME.md` (see SRV.md as an example) +- `documentation/SUMMARY.md` Add your doc to the TOC. + +### Step 5. Update the matrix + +Add this feature to the feature matrix in `dnscontrol/build/generate/featureMatrix.go`. Add it to the variable `matrix` maintaining alphabetical ordering, which should look like this: - {% code title="dnscontrol/build/generate/featureMatrix.go" %} - ```diff - func matrixData() *FeatureMatrix { - const ( +{% code title="dnscontrol/build/generate/featureMatrix.go" %} + +```diff +func matrixData() *FeatureMatrix { + const ( + ... + DomainModifierCaa = "[`CAA`](language-reference/domain-modifiers/CAA.md)" ++ DomainModifierFoo = "[`FOO`](language-reference/domain-modifiers/FOO.md)" + DomainModifierLoc = "[`LOC`](language-reference/domain-modifiers/LOC.md)" + ... + ) + matrix := &FeatureMatrix{ + Providers: map[string]FeatureMap{}, + Features: []string{ ... - DomainModifierCaa = "[`CAA`](language-reference/domain-modifiers/CAA.md)" - + DomainModifierFoo = "[`FOO`](language-reference/domain-modifiers/FOO.md)" - DomainModifierLoc = "[`LOC`](language-reference/domain-modifiers/LOC.md)" + DomainModifierCaa, ++ DomainModifierFoo, + DomainModifierLoc, ... - ) - matrix := &FeatureMatrix{ - Providers: map[string]FeatureMap{}, - Features: []string{ - ... - DomainModifierCaa, - + DomainModifierFoo, - DomainModifierLoc, - ... - }, - } - ``` - {% endcode %} - - then add it later in the file with a `setCapability()` statement, which should look like this: - - {% code title="dnscontrol/build/generate/featureMatrix.go" %} - ```diff - ... - + setCapability( - + DomainModifierFoo, - + providers.CanUseFOO, - + ) - ... - ``` - {% endcode %} - -- Add the capability to the list of features that zones are validated against (i.e. if you want DNSControl to report an error if this feature is used with a DNS provider that doesn't support it). That's in the `checkProviderCapabilities` function in `pkg/normalize/validate.go`. It should look like this: - - {% code title="pkg/normalize/validate.go" %} - ```diff - var providerCapabilityChecks = []pairTypeCapability{ - ... - + capabilityCheck("FOO", providers.CanUseFOO), - ... - ``` - {% endcode %} - -- Mark the `bind` provider as supporting this record type by updating `dnscontrol/providers/bind/bindProvider.go` (look for `providers.CanUse` and you'll see what to do). + }, + } +``` + +{% endcode %} + +Then add it later in the file with a `setCapability()` statement, which should look like this: + +{% code title="dnscontrol/build/generate/featureMatrix.go" %} + +```diff +... ++ setCapability( ++ DomainModifierFoo, ++ providers.CanUseFOO, ++ ) +... +``` + +{% endcode %} + +Add the capability to the list of features that zones are validated against (i.e. if you want DNSControl to report an error if this feature is used with a DNS provider that doesn't support it). That's in the `checkProviderCapabilities` function in `pkg/normalize/validate.go`. It should look like this: + +{% code title="pkg/normalize/validate.go" %} + +```diff +var providerCapabilityChecks = []pairTypeCapability{ +... ++ capabilityCheck("FOO", providers.CanUseFOO), +... +``` + +{% endcode %} DNSControl will warn/error if this new record is used with a provider that does not support the capability. -- Add the capability to the validations in `pkg/normalize/validate.go` by adding it to `providerCapabilityChecks` -- Some capabilities can't be tested for. If such testing can't be done, add it to the whitelist in function `TestCapabilitiesAreFiltered` in `pkg/normalize/capabilities_test.go` +- Add the capability to the validations in `pkg/normalize/validate.go` by adding it to `providerCapabilityChecks` +- Some capabilities can't be tested for. If such testing can't be done, add it to the whitelist in function `TestCapabilitiesAreFiltered` in `pkg/normalize/capabilities_test.go` If the capabilities testing is not configured correctly, `go test ./...` will report something like the `MISSING` message below. In this example we removed `providers.CanUseCAA` from the `providerCapabilityChecks` list. @@ -120,83 +246,85 @@ If the capabilities testing is not configured correctly, `go test ./...` will re capabilities_test.go:66: ok: providers.CanUseNAPTR (3) is checked for with "NAPTR" ``` -## Step 3: Add a helper function +### Step 6: Add a `parse_tests` test case -Add a function to `pkg/js/helpers.js` for the new record type. This is the JavaScript file that defines `dnsconfig.js`'s functions like [`A()`](../language-reference/domain-modifiers/A.md) and [`MX()`](../language-reference/domain-modifiers/MX.md). Look at the definition of `A`, `MX` and `CAA` for good examples to use as a base. +Add at least one test case to the `pkg/js/parse_tests` directory. Test `013-mx.js` is a very simple one and is good for cloning. See also `017-txt.js`. -Please add the function alphabetically with the others. Also, please run [prettier](https://github.com/prettier/prettier) on the file to ensure your code conforms to our coding standard: +Run these tests via: ```shell -npm install prettier -node_modules/.bin/prettier --write pkg/js/helpers.js +cd pkg/js +go test ./... + +# To run only your new test, use the -run flag. In this example, we only run test 058: +go test -v -run 'TestParsedFiles/058' ``` -## Step 4: Search for `#rtype_variations` +If these tests pass you know the `dnsconfig.js` and `helpers.js` code is working correctly. -Anywhere a `rtype` requires special handling has been marked with a comment that includes the string `#rtype_variations`. Search for this string and add your new type to this code. +The tests also verify that for every "capability" there is a validation. This is explained in Step 2 (search for `TestCapabilitiesAreFiltered` or `MISSING`) -## Step 5: Add a `parse_tests` test case +### Step 7. Test it out with BIND -Add at least one test case to the `pkg/js/parse_tests` directory. Test `013-mx.js` is a very simple one and is good for cloning. See also `017-txt.js`. +The `BIND` provider supports all record types. Update `providers/bind` to support this +record type. The next section describes how to enable a new record type on a provider. -Run these tests via: +Here's how to run the integration tests on the `BIND` provider: ```shell -pushd pkg/js/ -go test ./... -popd +cd integrationTest +go test -failfast -v -args -verbose -profile BIND ``` -If this works, then you know the `dnsconfig.js` and `helpers.js` code is working correctly. +### Step 8. Add an integration test helper -As you debug, if there are places that haven't been marked `#rtype_variations` that should be, add such a comment. Every time you do this, an angel gets its wings. +- Edit `integrationTest/helpers_integration_test.go` +- Add a typename() function (alphabetically). For example, there are functions like `mx()` and `a()` which make it easy to write test cases. -The tests also verify that for every "capability" there is a validation. This is explained in Step 2 (search for `TestCapabilitiesAreFiltered` or `MISSING`) +### Step 9. Add Integration tests -## Step 6: Add an `integrationTest` test case +Add at least one test case to the `integrationTest/integration_test.go` file. Add tests that create the type then changes each field individually. For example, the MX records are tested by creating an MX record, changing the target, changing the preference, then deleting the record. -Add at least one test case to the `integrationTest/integration_test.go` file. Look for `func makeTests` and add the test to the end of this list. +Look for `func makeTests` and add the test to the end of this list. Each `testgroup()` is a named list of tests. {% code title="integration_test.go" lineNumbers="true" %} + ```go testgroup("MX", tc("MX record", mx("@", 5, "foo.com.")), tc("Change MX pref", mx("@", 10, "foo.com.")), - tc("MX record", - mx("@", 10, "foo.com."), - mx("@", 20, "bar.com."), + tc("Change MX target", mx("@", 10, "mx.foo.com.")), + tc("Make MX and A", + mx("@", 10, "mx.foo.com."), + a("@", "1.2.3.4"), ), ) ``` + {% endcode %} Line 1: `testgroup()` gives a name to a group of tests. It also tells the system to delete all records for this domain so that the tests begin with a blank slate. -Line 2: Each `tc()` encodes all the records of a zone. The test framework will try to do the smallest changes to bring the zone up to date. In this case, we know the zone is empty, so this will add one MX record. +Line 2-4: Each `tc()` encodes all the records of a zone. -Line 3: In this example, we just change one field of an existing record. To get to this configuration, the provider will have to either change the priority on an existing record, or delete the old record and insert a new one. Either way, this test case assures us that the diff'ing functionality is working properly. +The test framework will create the equivalent of a `dnsconfig.js` for each `tc()`. In this example, the first `dnsconfig.js` is a zone with a single MX record. The next `dnsconfig.js` is similar but with a different MX preference. The next `dnsconfig.js` changes the target. The last `tc()` creates a zone with two records, an MX and A. -If you look at the tests for `CAA`, it inserts a few records then attempts to modify each field of a record one at a time. This test was useful because it turns out we hadn't written the code to properly see a change in priority. We fixed this bug before the code made it into production. + The test framework will run the equivalent of `dnscontrol push` twice for each `tc()`. The first time it expects changes. The second run it expects no changes are required because the first was successful. Otherwise, the test will fail. -Line 4: In this example, the next zone adds a second MX record. To get to this configuration, the provider will add an additional MX record to the same label. New tests don't need to do this kind of test because we're pretty sure that that part of the diffing engine works fine. It is here as an example. +If you look at the tests for `CAA`, it inserts a few records then attempts to modify each field of a record one at a time. This test was useful because it turns out we hadn't written the code to properly see a change in priority. We fixed this bug before the code made it into production. -Also notice that some tests include `requires()`, `not()` and `only()` statements. This is how we restrict tests to certain providers. These options must be listed first in a `testgroup`. More details are in the source code. +Notice that some tests include `requires()`, `not()` and `only()` statements. This is how we restrict tests to certain providers. These options must be listed first in a `testgroup`. More details are in the source code. To run the integration test with the BIND provider: ```shell -pushd integrationTest +cd integrationTest go test -v -args -verbose -profile BIND -popd ``` -Once the code works for BIND, consider submitting a PR at this point. (The earlier you submit a PR, the earlier we can provide feedback.) - -If you find places that haven't been marked `#rtype_variations` but should be, please add that comment. Every time you fail to do this, God kills a cute little kitten. Please do it for the kittens. - -## Step 7: Support more providers +### Step 10: Support more providers Now add support in other providers. Add the `providers.CanUse...` flag to the provider and re-run the integration tests: @@ -215,19 +343,20 @@ The test should reveal any bugs. Keep iterating between fixing the code and runn If you find bugs that aren't covered by the tests, please please please add a test that demonstrates the bug (then fix the bug, of course). This will help all future contributors. If you need help with adding tests, please ask! -## Step 8: Write documentation +### Step 11: Write documentation Add a new Markdown file to `documentation/language-reference/domain-modifiers`. Copy an existing file (`CNAME.md` is a good example). The section between the lines of `---` is called the front matter and it has the following keys: -- `name`: The name of the record. This should match the file name and the name of the record in `helpers.js`. -- `parameters`: A list of parameter names, in order. Feel free to use spaces in the name if necessary. Your last parameter should be `modifiers...` to allow arbitrary modifiers like `TTL` to be applied to your record. -- `parameter_types`: an object with parameter names as keys and TypeScript type names as values. Check out existing record documentation if you’re not sure to put for a parameter. Note that this isn’t displayed on the website, it’s only used to generate the `.d.ts` file. +- `name`: The name of the record. This should match the file name and the name of the record in `helpers.js`. +- `parameters`: A list of parameter names, in order. Feel free to use spaces in the name if necessary. Your last parameter should be `modifiers...` to allow arbitrary modifiers like `TTL` to be applied to your record. +- `parameter_types`: an object with parameter names as keys and TypeScript type names as values. Check out existing record documentation if you’re not sure to put for a parameter. Note that this isn’t displayed on the website, it’s only used to generate the `.d.ts` file. The rest of the file is the documentation. You can use Markdown syntax to format the text. Add the new file `FOO.md` to the documentation table of contents `documentation/SUMMARY.md` > `Domain Modifiers`, and/or to the `Service Provider specific` section if you made a record specific to a provider, and to the `Record Modifiers` section if you created any `*_BUILDER` or `*_HELPER` or similar functions for the new record type: {% code title="documentation/SUMMARY.md" %} + ```diff ... * Domain Modifiers @@ -250,9 +379,10 @@ Add the new file `FOO.md` to the documentation table of contents `documentation/ * [SPF_BUILDER](language-reference/domain-modifiers/SPF_BUILDER.md) ... ``` + {% endcode %} -## Step 9: "go generate" +### Step 12: "go generate" Re-generate the documentation: @@ -261,3 +391,47 @@ go generate ./... ``` This will regenerate things like the table of which providers have which features and the `dnscontrol.d.ts` file. + +## How to enable an rtype in a provider + +Now that DNSControl understands the new record type, each provider must be updated +to recognize the new type. + +This is different for every provider. Usually the steps are: + +1. Add `CanUseTYPENAME` to the init() function +2. Update the toNative() function to support the type when `GetZoneRecords()` runs. +3. Update `GetZoneRecordsCorrections()`'s create/update/delete functions to support the type. +4. Run [the integration tests](https://docs.dnscontrol.org/developer-info/integration-tests) until they all pass. + +ProTip: The integration tests work by running teach test case twice. The first time they expect changes, the second time they expect no changes: + +- If there is an error in the first run, that probably indicates the toNative() or GetZoneRecordsCorrections() is broken. That is, the record is not being created properly. +- If there is an error in the second run, that probably indicates toRC() is broken (the native record is not being parsed properly) or the modify/delete functionality has a bug (the new record is not being generated properly). + +It can be useful to check the DNS server provider's web console to see if the records are being created properly. + +## How to add a "builder" + +A builder is a function that can be used in `dnsconfig.js` which outputs one or +more DNS records. For example, the `SPF_BUILDER()` function generates `TXT` +records. + +Assume the builder is named "robert" and appears in `dnsconfig.js` as `ROBERT(label, data)` + +Step 1. Create the builder in `models/b_robert.go` +Step 2. Register the builder: (see `models/b_loc.go` as an example) + +```go +func init() { + RegisterBuilder("LOC", BuilderLOC) +} +``` + +Step 3. Add the `BuilderNAME()` function + +Add a function called BuilderROBERT() with this signature: + +```go +func BuilderROBERT(dc *DomainConfig, ttl uint32, args []any, subdomain string) (Records, error) { +``` diff --git a/documentation/advanced-features/ordering.md b/documentation/advanced-features/ordering.md index a0817c8cbf..be09a1b1e0 100644 --- a/documentation/advanced-features/ordering.md +++ b/documentation/advanced-features/ordering.md @@ -39,7 +39,7 @@ If you encounter any issues with the reordering please [open an issue](https://g ## Internals -DNSControl sorts all changes based on the dependencies within these changes. Each record define it's dependencies in `models.Record`. For DNSControl it doesn't matter of a CNAME's target is an A or AAAA or TXT, it will ensure all changes on the target get sorted before the depending CNAME record. The creation of the graph happens in `dnsgraph.CreateGraph([]Graphable)` and thereafter the sorting happens in `graphsort.SortUsingGraph([]Graphable)`. +DNSControl sorts all changes based on the dependencies within these changes. Each record define it's dependencies in `models.RecordConfig`. For DNSControl it doesn't matter of a CNAME's target is an A or AAAA or TXT, it will ensure all changes on the target get sorted before the depending CNAME record. The creation of the graph happens in `dnsgraph.CreateGraph([]Graphable)` and thereafter the sorting happens in `dnssort.SortUsingGraph([]Graphable)`. The Graphable is an interface to make the sorting module more separate from the rest of the DNSControl code, currently the only Graphable implementation is `diff2.Change`. -In order to add a new sortable rtype one should add it to the `models.Record.GetGetDependencies()` and return the dependent records, this is used inside the `diff2.Change` to detect if a dependency is backwards (dependent on the old state) or forward (dependent on new state). Now the new rtype should be sorted accordingly just like MX and CNAME records. +In order to add a new sortable rtype one should add it to the `models.Record.GetDependencies()` and return the dependent records, this is used inside the `diff2.Change` to detect if a dependency is backwards (dependent on the old state) or forward (dependent on new state). Now the new rtype should be sorted accordingly just like MX and CNAME records. diff --git a/documentation/advanced-features/testing-txt-records.md b/documentation/advanced-features/testing-txt-records.md index f8c8ab9e45..b90579148a 100644 --- a/documentation/advanced-features/testing-txt-records.md +++ b/documentation/advanced-features/testing-txt-records.md @@ -8,8 +8,6 @@ The problem relates to TXT records that have a string with quotes in them. If a user creates a TXT record whose contents are `"something"` (yes, with double quotes), some APIs get confused. -This bug is most likely to appear in a provider that uses `RecordConfig.PopulateFromString()` (see `models/t_parse.go`) to create TXT records. That function assumes the string should always have the quotes stripped, though it is more likely that the string should be taken verbatim. - # The test To complete this test, you will need a test domain that you can add records to. It won't be modified otherwise. @@ -64,3 +62,11 @@ Refresh your provider's web UI and you should see the changes as expected: t1 sh ## Step 5: That's it! Remove the lines from `dnsconfig.js` and run `dnscontrol push` to clean up. + +## Fixing a failed test + +If the test fails, this bug is most likely to be that the provider is processing TXT records incorrectly. + +If the provider uses `dc.NewRecordConfigParse()` to create TXT records, it might be more appropriate to use `dc.NewRecordConfig()` instead (which does no parsing). You can also use `dc.NewRecordConfigParse()` with `nrc.Flags{TxtDontParse: true}`. + +If that doesn't work, please open an issue and we'll assist you. \ No newline at end of file diff --git a/documentation/advanced-features/writing-providers.md b/documentation/advanced-features/writing-providers.md index c86cd509b4..6ae7dd0939 100644 --- a/documentation/advanced-features/writing-providers.md +++ b/documentation/advanced-features/writing-providers.md @@ -1,28 +1,53 @@ # Writing new DNS providers -Writing a new DNS provider is a relatively straightforward process. You essentially need to implement the [providers.DNSServiceProvider interface.](https://pkg.go.dev/github.com/DNSControl/dnscontrol/v4/pkg/providers#DNSServiceProvider) and the system takes care of the rest. - -Please do note that if you submit a new provider you will be assigned bugs related to the provider in the future (unless you designate someone else as the maintainer). More details [here](../provider/index.md). +- [Writing new DNS providers](#writing-new-dns-providers) + - [Overview](#overview) + - [Step 1: General advice](#step-1-general-advice) + - [Step 2: Pick a base provider](#step-2-pick-a-base-provider) + - [Step 3: Create the driver skeleton](#step-3-create-the-driver-skeleton) + - [Step 4: Activate the driver](#step-4-activate-the-driver) + - [Step 5: Onboarding metadata for `dnscontrol init` (optional)](#step-5-onboarding-metadata-for-dnscontrol-init-optional) + - [Step 6: Implement the provider](#step-6-implement-the-provider) + - [Step 7: Create `auditrecords.go`](#step-7-create-auditrecordsgo) + - [Step 8: Unit Test](#step-8-unit-test) + - [Step 9: Integration Test](#step-9-integration-test) + - [Step 10: Verify TXT records](#step-10-verify-txt-records) + - [Step 11: Update docs, CICD and other files](#step-11-update-docs-cicd-and-other-files) + - [Step 12: Capabilities](#step-12-capabilities) + - [Step 13: Automated code tests](#step-13-automated-code-tests) + - [Step 14: Dependencies](#step-14-dependencies) + - [Step 15: Update `pr_integration_tests.yml`](#step-15-update-pr_integration_testsyml) + - [Step 16: Check your work](#step-16-check-your-work) + - [Step 17: Submit a PR](#step-17-submit-a-pr) + - [Step 18: After the PR is merged](#step-18-after-the-pr-is-merged) + +Writing a new DNS provider is a relatively straightforward process. You essentially need to implement the [providers.DNSServiceProvider interface.](https://pkg.go.dev/github.com/DNSControl/dnscontrol/v5/pkg/providers#DNSServiceProvider) and the system takes care of the rest. + +Please do note that if you submit a new provider you will be assigned bugs related to the provider in the future (unless you designate someone else as the maintainer). [More details here](../provider/index.md). Please follow the [DNSControl Code Style Guide](styleguide-code.md) and the [DNSControl Documentation Style Guide](styleguide-doc.md). +An important concept you'll need to understand is "existing vs. desired". "Existing" is when you've gathered data that describes how things are now: i.e. a list of DNS records +we've downloaded via the API, that represents the current state of the zone. "Desired" describes how we want the world to be: i.e. the zone as described in `dnsconfig.js`. +So, for example, you'll frequently see code with two variables: `var existing, desired []*models.RecordConfig`, or variables with names that begin with `e` or `d`, such as `var ex, dx int`. A mnemonic is "D, desired, comes from dnsconfig.js". + ## Overview I'll ignore all the small stuff and get to the point. A typical provider implements 3 methods and DNSControl takes care of the rest: -* GetZoneRecords() -- Download the list of DNS records and return them as a list of RecordConfig structs. +* GetZoneRecords() -- Download the list of DNS records. * GetZoneRecordsCorrections() -- Generate a list of corrections. * GetNameservers() -- Query the API and return the list of parent nameservers. These three functions are all that's needed for `dnscontrol preview` and `dnscontrol push`. -The goal of `GetZoneRecords()` is to download all the DNS records, convert them to `models.RecordConfig` format, and return them as one big list (`models.Records`). +The goal of `GetZoneRecords()` is to download all the DNS records for that zone, convert them to `models.RecordConfig` format, and return them as one big list (`models.Records`). -The goal of `GetZoneRecordsCorrections()` is to return a list of corrections. Each correction is a text string describing the change ("Delete CNAME record foo") and a function that, if called, will make the change (i.e. call the API and delete record foo). `dnscontrol preview` simply prints the text strings. `dnscontrol push` prints the strings and calls the functions. Because of how Go's functions work, the function will have everything it needs to make the change. Pretty cool, eh? +The goal of `GetZoneRecordsCorrections()` is to return a list of corrections. Each correction is a text string describing the change ("Delete CNAME record foo") and a function that, if called, will make the change (i.e. call the API and delete record foo). `dnscontrol preview` simply prints the text strings. `dnscontrol push` prints the strings and calls the functions. Because of how Go's functions work, the function will have everything it needs to make the change. Pretty cool, eh? -Calculating the difference between existing and desired is difficult. Luckily the work is done for you. `GetZoneRecordsCorrections()` calls a a function in the `pkg/diff2` module that generates a list of changes (usually an ADD, CHANGE, or DELETE) that can easily be turned into the API calls mentioned previously. +Calculating the difference between existing and desired is difficult. Luckily the work is done for you by `pkg/diff2`. `GetZoneRecordsCorrections()` calls a a function in the `pkg/diff2` module that generates a list of changes (usually an ADD, CHANGE, or DELETE) that can easily be turned into the API calls mentioned previously. So, what does all this mean? @@ -38,7 +63,7 @@ A provider can be a DnsProvider, a Registrar, or both. We recommend you write th If you have any questions, please discuss them in the GitHub issue related to the request for this provider. -This document is constantly being updated. Please let us know what was confusing so we can update this document with advice for future authors (or even better send a PR!). +This document is constantly being updated. Please let us know what was confusing so we can update this document with advice for future authors (or even better send a PR! We love PRs!). ## Step 2: Pick a base provider @@ -50,25 +75,27 @@ Each DNS provider's API falls into one of 4 category. Some update one DNS record 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. +* Updates are done one record at a time (ByRecord) +* Updates are done one label at a time (ByLabel) +* Updates are done one label+type at a time (ByRecordSet) +* Updates require the entire zone to be uploaded (ByZone). 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`. The functions are: -* 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. +* [diff2.ByRecord()](https://pkg.go.dev/github.com/DNSControl/dnscontrol/v5/pkg/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()](https://pkg.go.dev/github.com/DNSControl/dnscontrol/v5/pkg/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()](https://pkg.go.dev/github.com/DNSControl/dnscontrol/v5/pkg/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()](https://pkg.go.dev/github.com/DNSControl/dnscontrol/v5/pkg/diff2#ByZone) -- Updates are done by uploading the entire zone every time. + +To determine your provider's category, review your API documentation. + +To find a similar provider to copy, look at which `diff2.By*()` function is used: `grep diff2.By providers/*.go` + +The file [`pkg/diff2/diff2.go`](https://github.com/DNSControl/dnscontrol/blob/main/pkg/diff2/diff2.go) has instructions about how to use the diff2 system. -The file `pkg/diff2/diff2.go` has instructions about how to use the diff2 system. +FYI: We are in the middle of converting to a new way to create `models.RecordConfig` structs. So far, BIND and CLOUDFLAREAPI are two providers that do things the new way. Old code creates RecordConfigs directly: `rc = &models.RecordConfig`. New code uses factories: `NewRecordConfig()` or `NewRecordConfigParse()`. Any new providers should use the new methods. ## Step 3: Create the driver skeleton @@ -82,13 +109,11 @@ Directory names should be consistent. It should be all lowercase and match the Edit [providers/\_all/all.go](https://github.com/DNSControl/dnscontrol/blob/main/pkg/providers/_all/all.go). Add the provider list so DNSControl knows it exists. -### Onboarding metadata for `dnscontrol init` (optional) +## Step 5: Onboarding metadata for `dnscontrol init` (optional) -If you want your provider to appear in the interactive -[`dnscontrol init`](../commands/init.md) wizard, register a -`CredsMetadata` block in the same `init()` function where you call -`RegisterDomainServiceProviderType` and `RegisterMaintainer`. A simple -provider reduces to a few lines: +This step allows users of your provider to use the interactive [`dnscontrol init`](../commands/init.md) wizard. + +Register a `CredsMetadata` block in the same `init()` function where you call `RegisterDomainServiceProviderType` and `RegisterMaintainer`. A simple provider reduces to a few lines: ```go providers.RegisterCredsMetadata("MYPROVIDER", providers.CredsMetadata{ @@ -105,7 +130,7 @@ providers.RegisterCredsMetadata("MYPROVIDER", providers.CredsMetadata{ A field can carry any of the following flags: | Flag | Effect | -|---|---| +| ---- | ---- | | `Required` | Empty answers are rejected. | | `Secret` | Input is masked. | | `Multiline` | Opens `$EDITOR` so PEM blocks and other multi line values can be entered intact. | @@ -120,44 +145,65 @@ The optional `PostWrite` hook on `CredsMetadata` lets the provider prepare local resources after the wizard writes `creds.json` (BIND uses this to create the zone files directory). -The BIND and TransIP registrations in this repository are worked -examples maintainers can copy from: +The BIND and TransIP registrations in this repository are worked examples maintainers can copy from: -- [`providers/bind/bindProvider.go`][bind-source]: the simple shape, plus a `PostWrite` hook that creates the zone files directory. -- [`providers/transip/transipProvider.go`][transip-source]: an auth method selector (`Internal` plus `ShowIf`) that branches between a short lived access token and an account name paired with a PEM private key. +* [`providers/bind/bindProvider.go`][bind-source]: the simple shape, plus a `PostWrite` hook that creates the zone files directory. +* [`providers/transip/transipProvider.go`][transip-source]: an auth method selector (`Internal` plus `ShowIf`) that branches between a short lived access token and an account name paired with a PEM private key. [bind-source]: https://github.com/StackExchange/dnscontrol/blob/main/providers/bind/bindProvider.go [transip-source]: https://github.com/StackExchange/dnscontrol/blob/main/providers/transip/transipProvider.go Providers without registered metadata still work; users just create the -`creds.json` entry from the provider's documentation page rather than -via the wizard. +`creds.json` entry manually, using the help of the provider's documentation page. + +## Step 6: Implement the provider -## Step 5: Implement +**If you are implementing a DNS Registrar:** + +Implement all the calls in the [providers.Registrar interface](https://pkg.go.dev/github.com/DNSControl/dnscontrol/v5/pkg/providers#Registrar). + +The function `GetRegistrarCorrections()` returns a list of corrections to be made. These are in the form of functions that DNSControl can call to actually make the corrections. **If you are implementing a DNS Service Provider:** -Implement all the calls in the [providers.DNSServiceProvider interface](https://pkg.go.dev/github.com/DNSControl/dnscontrol/v4/pkg/providers#DNSServiceProvider). +Implement all the calls in the [providers.DNSServiceProvider interface](https://pkg.go.dev/github.com/DNSControl/dnscontrol/v5/pkg/providers#DNSServiceProvider). + +* The function that converts the API's native records to `models.RecordConfig` structs should be called toRC(). +* There are helper functions (factories) for creating `models.RecordConfig`'s. See [The Cookbook](developer-info/cookbook.md) "Create a `models.RecordConfig`" for details. The function `GetDomainCorrections()` is a bit interesting. It returns a list of corrections to be made. These are in the form of functions that DNSControl can call to actually make the corrections. -**If you are implementing a DNS Registrar:** +* The "create" function will probably need to convert an `models.RecordConfig` to the native API struct. Please name this function toNative() +* To access or change the RDATA in a field, use `rd := rc.GetRDATA()` and `rc.SetRDATA(rd)`. Full details are in [The Cookbook](developer-info/cookbook.md) "Getters/Setters for RDATA in `models.RecordConfig`". +* Of course, if you need to create a `models.RecordConfig` please use the factories listed above. -Implement all the calls in the [providers.Registrar interface](https://pkg.go.dev/github.com/DNSControl/dnscontrol/v4/pkg/providers#Registrar). +The remaining steps assume you're creating a DNS Service Provider. -The function `GetRegistrarCorrections()` returns a list of corrections to be made. These are in the form of functions that DNSControl can call to actually make the corrections. +## Step 7: Create `auditrecords.go` -## Step 6: Unit Test +The `auditrecords.go` file lists special cases that a provider doesn't support. -Make sure the existing unit tests work. Add unit tests for any complex algorithms in the new code. +For example, the `AXFRDDNS` provider doesn't support empty TXT records. `providers/axfrddns/auditrecords.go` records that fact. The integration test system will skip any tests with empty TXT records. + +Use an empty list for now (copy `providers/bind/auditrecords.go`). When integration testing, you'll add to it. + +## Step 8: Unit Test + +ProTip: Unit tests tests functions in isolation ("just the function"). + +Add unit tests for any complex algorithms in the new code. Good examples include: custom parsers, complex string manipulation functions, the toRC() function (if it is complex). Run the unit tests with this command: +```shell go test ./... +``` + +## Step 9: Integration Test -## Step 7: Integration Test +ProTip: Integration tests are tests that verify the parts of the system are working together as expected. -This is the most important kind of testing when adding a new provider. Integration tests use a test account and a test domain. +Integration testing is the most important kind of testing when adding a new provider. Integration tests run add/change/delete operations on a real domain. You'll need to set up an account and add a domain (technically a "zone") to the account. {% hint style="danger" %} All records will be deleted from the test domain! Use a OTE domain or a real domain that isn't otherwise in use and can be destroyed. @@ -171,7 +217,7 @@ Now you can run the integration tests. For example, test BIND: ```shell -cd integrationTest # NOTE: Not needed if already there +cd integrationTest export BIND_DOMAIN='example.com' go test -v -args -verbose -profile BIND ``` @@ -182,18 +228,18 @@ This will run the tests on Amazon AWS Route53: ```shell 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 there +export R53_KEY_ID='REDACTED_ID' +export R53_KEY='REDACTED_KEY' +cd integrationTest go test -v -args -verbose -profile ROUTE53 ``` -Some useful `go test` flags: +Some useful `go test` tips: -* Flags before `-args` go to the `go test` program. Flags after `-args` go to the program being tested. +* Flags before `-args` go to the `go test` program. Flags after `-args` go to DNSControl. * Run only certain tests using the `-start` and `-end` flags. * Rather than running all the tests, run just the tests you want. - * These flags must be *after* the `-profile FOO` flag. + * These flags must be *after* the `-args` flag. * Example: `go test -v -args -verbose -profile ROUTE53 -start 10 -end 20` run tests 10-20 inclusive. * Example: `go test -v -args -verbose -profile ROUTE53 -start 5 -end 5` runs only test 5. * Example: `go test -v -args -verbose -profile ROUTE53 -start 20` skip the first 19 tests. @@ -202,21 +248,24 @@ Some useful `go test` flags: * `go test` kills the tests after 10 minutes by default. Some providers need more time. * This flag must be *before* the `-args` flag. * Example: `go test -timeout 20m -v -args -verbose -profile CLOUDFLAREAPI` -* If a test will always fail because the provider doesn't support the feature, you can opt out of the test. Look at `func makeTests()` in [integrationTest/integration_test.go](https://github.com/DNSControl/dnscontrol/blob/2f65533e1b92c2967229a92a304fff7c14f7f4b6/integrationTest/integration_test.go#L675) for more details. -## Step 8: Manual tests +You can opt out of tests if they will always fail for that provider. For example, if it doesn't support a particular feature. Look at `func makeTests()` in [integrationTest/integration_test.go](https://github.com/DNSControl/dnscontrol/blob/2f65533e1b92c2967229a92a304fff7c14f7f4b6/integrationTest/integration_test.go#L675) for more details. + +You can also opt-out of special edge cases (like not supporting a "null MX") by adding to the `auditrecoreds.go` file. -This is optional. +The [Integration Testing](../developer-info/integration-tests) page has more tips. + +## Step 10: Verify TXT records There is a potential bug in how TXT records are handled. Sadly we haven't found an automated way to test for this bug. The manual steps are here in [documentation/testing-txt-records.md](testing-txt-records.md) -## Step 9: Update docs, CICD and other files +## Step 11: Update docs, CICD and other files -* Edit `README.md`: - * Add the provider to the bullet list. * Edit `documentation/providers.md`: * Remove the provider from the `Requested providers` list (near the end of the doc) (if needed). * Add the new provider to the [Providers with "contributor support"](../provider/index.md#providers-with-contributor-support) section. +* Edit `README.md`: + * Add the provider to the list. * Edit `documentation/SUMMARY.md`: * Add the provider to the "Providers" list. * Create `documentation/provider/PROVIDERNAME.md`: @@ -227,7 +276,7 @@ There is a potential bug in how TXT records are handled. Sadly we haven't found a particular integration test, or request feedback. {% endhint %} -## Step 10: Capabilities +## Step 12: Capabilities Some DNS providers have features that others do not. For example some support the SRV record. A provider announces what it can do using the capabilities system. @@ -243,7 +292,7 @@ Enable optional capabilities in the `nameProvider.go` file and run the integrati FYI: If a provider's capabilities changes, run `go generate` to update the documentation. -## Step 11: Automated code tests +## Step 13: Automated code tests We use a number of automated code-checking systems. Please run your code through all of them and fix all warnings and errors. Some of the automated fixes may not alway sbe perfect. Therefore, it is best to commit your code before running these and verify that you agree with the changes. @@ -275,69 +324,73 @@ staticcheck ./... Commit any changes. -## Step 12: Dependencies +## Step 14: Dependencies See [documentation/release-engineering.md](../release/release-engineering.md) for tips about managing modules and checking for outdated dependencies. -## Step 13: Update `pr_integration_tests.yml` - -This assures that in the future it will be easy to test this provider using GitHub Actions. +## Step 15: Update `pr_integration_tests.yml` Edit `.github/workflows/pr_integration_tests.yml` -1. Add your providers `_DOMAIN` env variable: - -* Add it to the `env` section of `integration-tests`. -* Please keep this list sorted alphabetically. - -To find this section, search for `PROVIDER SECRET LIST`. +* Add your providers `_DOMAIN` env variable: + * Add it to the `env` section of `integration-tests`. + * Please keep this list sorted alphabetically. + * To find this section, search for `PROVIDER SECRET LIST`. For example, the entry for BIND looks like: {% code title=".github/workflows/pr_integration_tests.yml" %} -``` + +```yaml BIND_DOMAIN: ${{ vars.BIND_DOMAIN }} ``` -{% endcode %} - -2. Add your providers other ENV variables: -Every provider requires different variables set to perform the integration tests. The list of such variables is in `integrationTest/profiles.json`. +{% endcode %} -You've already added `*_DOMAIN` to `pr_integration_tests.yml`. Now we're going to add the remaining ones. +* Add your providers other ENV variables: + * Every provider requires different variables set to perform the integration tests. The list of such variables is in `integrationTest/profiles.json`. + * You've already added `*_DOMAIN` to `pr_integration_tests.yml`. Now we're going to add the remaining ones. To find this section, search for `PROVIDER SECRET LIST`. For example, the entry for CLOUDFLAREAPI looks like this: {% code title=".github/workflows/pr_integration_tests.yml" %} -``` + +```yaml CLOUDFLAREAPI_ACCOUNTID: ${{ secrets.CLOUDFLAREAPI_ACCOUNTID }} CLOUDFLAREAPI_TOKEN: ${{ secrets.CLOUDFLAREAPI_TOKEN }} ``` + {% endcode %} -## Step 14: Check your work +## Step 16: Check your work + +You're almost done! These are the things we'll be checking when you submit the PR. Please try to complete all or as many of these as possible. 1. Run `go generate ./...` to make sure all generated files are fresh. 2. Make sure the following files were created and/or updated: - * `.github/CODEOWNERS` - * `README.md` - * `.github/workflows/pr_integration_tests.yml` (env variables for your provider) - * `documentation/SUMMARY.md` - * `documentation/provider/index.md` (the autogenerated table + the second one; make sure it is removed from the `requested` list) - * `documentation/provider/`PROVIDERNAME`.md` - * `integrationTest/profiles.json` - * `pkg/providers/_all/all.go` + +* `.github/CODEOWNERS` +* `README.md` +* `.github/workflows/pr_integration_tests.yml` (env variables for your provider) +* `documentation/SUMMARY.md` +* `documentation/provider/index.md` (the autogenerated table + the second one; make sure it is removed from the `requested` list) +* `documentation/provider/`PROVIDERNAME`.md` +* `integrationTest/profiles.json` +* `pkg/providers/_all/all.go` + 3. Review the code for style issues, remove debug statements, make sure all exported functions have a comment, and generally tighten up the code. -4. Verify you're using the most recent version of anything you import. (See [Step 12](#step-12-dependencies)) -5. Re-run the [integration test](#step-7-integration-test) one last time. - * Post the results as a comment to your PR. +4. Verify you're using the most recent version of anything you import. (See [Step 14](#step-14-dependencies)) +5. Re-run the [integration test](#step-9-integration-test) one last time. + +* Post the results as a comment to your PR. + 6. Re-read the [maintainer's responsibilities](../provider/index.md#providers-with-contributor-support) 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 15: Submit a PR +## Step 17: Submit a PR At this point you can submit a PR. @@ -345,7 +398,7 @@ The PR should include the sentence: "Please create the GitHub label 'provider-PR Actually you can submit the PR earlier if you just want feedback, or have questions. However if you haven't submitted a PR by now, this is the time to do it. -## Step 16: After the PR is merged +## Step 18: After the PR is merged 1. Close any related GitHub issues. -3. Would you like your provider to be tested automatically as part of every PR? Sure you would! Follow the instructions in [Bring-Your-Own-Secrets for automated testing](byo-secrets.md) +2. Would you like your provider to be tested automatically as part of every PR? Sure you would! Follow the instructions in [Bring-Your-Own-Secrets for automated testing](byo-secrets.md) diff --git a/documentation/developer-info/cookbook.md b/documentation/developer-info/cookbook.md new file mode 100644 index 0000000000..7c7172afd3 --- /dev/null +++ b/documentation/developer-info/cookbook.md @@ -0,0 +1,353 @@ +# Cookbook + +This document provides "cookbook" recipes for doing common tasks. + +- [Cookbook](#cookbook) + - [Create a `models.DomainConfig`](#create-a-modelsdomainconfig) + - [Create a `models.RecordConfig`](#create-a-modelsrecordconfig) + - [Getters/Setters for RDATA in `models.RecordConfig`](#getterssetters-for-rdata-in-modelsrecordconfig) + - [Create `models.RecordConfig` literals for testdata](#create-modelsrecordconfig-literals-for-testdata) + - [How to create a "builder"](#how-to-create-a-builder) + - [How to manipulate domain/zone names](#how-to-manipulate-domainzone-names) + - [What you should know about TXT records](#what-you-should-know-about-txt-records) + - [TXT functions](#txt-functions) + - [How to label imports](#how-to-label-imports) + +## Create a `models.DomainConfig` + +- What: Create a `models.DomainConfig` +- Why: Providers are handed a `models.DomainConfig` that is already created. However often when we write tests we need to create a list of `models.RecordConfig`'s which are stored in a `models.DomainConfig`. + +Recommended: + +```go +dc, err := models.NewDomainConfig(zone) +dc.AddTestRC(t, label, ttl, type, arg, arg1, arg2, ...) +dc.AddTestRCParse(t, label, ttl, type, arg) +fmt.Printf("Count: %d", len(dc.Records)) + +// Make individual RCs: +rc1 := dc.MustNewRecordConfig(label, ttl, type, arg, arg1, arg2, ...) +rc2 := dc.MustNewRecordConfigParse(label, ttl, type, arg) +``` + +Deprecated: + +```go +dc := &models.DomainConfig{Name: origin} +``` + +## Create a `models.RecordConfig` + +- What: Create a `models.RecordConfig` +- Why: One of the most important functions of a provider is to translate the native DNS records (as received from the API) to standard `models.RecordConfig` structs. Previously there were many ways to do this. Starting in DNSControl v5, we've standaredized on two factories: + +Recommended: + +```go +rc1, err := dc.NewRecordConfig(LABEL, TTL, TYPE_STR_OR_NUM, ARGS...) +rc2, err := dc.NewRecordConfigParse(LABEL, TTL, TYPE_STR_OR_NUM, RFC1038_STRING) +``` + +- These are a method of `models.DomainConfig` (typically the variable name is `dc`). Records only exist in the context of a domain. For example, if an MX record's target it "@", this is meaningless unless we know what the domain is. This also makes the call shorter: it eliminates parameters that contain info already stored in `dc` such as the zone name (required for normalizing labels). +- `NewRecordConfig()` takes a list of arguments. It doesn't matter if the arguments are strings, ints, `netip.Addrs`... the function will convert them to the correct type and return and error if they can't be converted. +- `NewRecordConfigParse()` takes the arguments as one long string, which is parsed. If your provider returns (for example) the MX record data as `10 mx.example.com.` and the SRV record data as `4 100 123 three.example.com.`, you can just send the whole string to this function. This replaces `models.PopulateFromString()` + +- `LABEL`: Must be the output of one of these functions: + - `dc.LabelFromShort()`: Use this if your provider always gives you the shortname (`foo` of `foo.example.com`) + - `dc.LabelFromFQDNNoDot()`: Use this if your provider always gives you the FQDN (`foo.example.com`) + - `dc.LabelFromFQDNWithDot()`: Use this if your provider always give syou the FQDN+"." (`foo.example.com.`) +- Which to use? + - Unsurer? Try LabelFromFQDNWithDot() and watch for errors. They often suggest what function to use. + - Errors like `DEBUG: LabelFromFQDNWithDot(quux.a.dnscontrol-azure.com) called WRONG.' + - In this case, the hostname (`quux.a.dnscontrol-azure.com`) indicates `LabelFromFQDNNoDot` is more appropriate. + - If you see a shortname, use `dc.LabelFromShort()` + - If the integration tests for IGNORE() fail, you've probably picked the wrong function. +- Why 3 functions? Can't NewRecordConfig figure it out? + - There are ambiguous cases that make it impossible to guess with 100 percent accurately. + - It is faster and more accurate to simply have multiple functions, one for each situation. + - The truth is that your provider's API is going to only deliver the label one way. They're not going to change. + +- `TTL` must be the desired TTL or `0` if it is unknown. Unknown TTLs are converted into the default TTL. + +- `TYPE_STR_OR_NUM` can be either the record type's codepoint or a string: + - codepoint: e.g. `dnsv2.TypeA`, `dnsv2.TypeMX`, `dnsv2.TypeCNAME`, `privatetypes.CLOUDFLAREAPISINGLEREDIRECT` + - string (`"A"`, `"MX"`, `"CNAME"`, `"CLOUDFLAREAPI_SINGLE_REDIRECT"`) + - Please use the constant when possible. Eventually we'll eliminate the strings. However, if all you have is the string, please let the factory do the conversion for you. + +- `ARGS` is a list of fields in the order they appear in the struct. The type doesn't matter as they will be converted automatically. No need to convert strings to ints and so on. Even IP addresses are handled properly. Examples: + - `dc.NewRecordConfig("mxhost", 0, dnsv2.TypeMX, "10", "mx.example.com.")` + - `dc.NewRecordConfig("mxback", 0, dnsv2.TypeMX, 20, "mx2.example.com.")` + - `dc.NewRecordConfig("www", 0, dnsv2.TypeA, "1.2.3.4")` + - `addr, _ := netip.ParseAddr("192.168.1.1"); dc.NewRecordConfig("www", 0, dnsv2.TypeA, addr)` + - `dc.NewRecordConfig("public", 0, dnsv2.TypeLOC, 42, 21, 54, "N", 71, 6, 18, "W", -24.05, 30, 0, 0)` + - `dc.NewRecordConfig("public", 0, dnsv2.TypeLOC, "42", "21", "54", "N", "71", "6", "18", "W", "-24.05", 30, "0", 0)` + +- `RFC1038_STRING` is a string that is parsed like the fields in a ZoneFile + - `dc.NewRecordConfigParse("mxhost", 0, dnsv2.TypeMX, "10 mx.example.com.")` + - `dc.NewRecordConfigParse("mxback", 0, dnsv2.TypeMX, "20 mx2.example.com.")` + - `dc.NewRecordConfigParse("www", 0, dnsv2.TypeA, "1.2.3.4")` + - `dc.NewRecordConfigParse("public", 0, dnsv2.TypeLOC, "42 21 54 N 71 6 18 W -24.05 30 0 0)` + +Typically either `dc.NewRecordConfig()` or `dc.NewRecordConfigParse()` will satisfy all of your needs. However occasionally there are situations where a particular record type needs special handling. We recommend using a switch statement to handle the special case. + +In this example, `*Parse` works just fine for all cases except `MX` records. Therefore, we process `MX` records first as a special case: + +```go + switch rtype { + case dnsv2.TypeMX: + preference := extractPreference(nativeRec) + target := extractTarget(nativeRec) + rc, err := dc.NewRecordConfig(label, ttl, dnsv2.TypeMX, preference, target) + default: + rc, err := dc.NewRecordConfigParse(label, 0, rtype, combined_fields) + } + if err != nil { + return err + } + dc.AddRecord(rc) +``` + +Deprecated: + +Please do not create your own `RecordConfig`'s: + +```go +rc := &models.RecordConfig{Name: label, Type: "MX"} +rc.MxPreference = pref +... +``` + +## Getters/Setters for RDATA in `models.RecordConfig` + +The fields of a DNS record are called the `RDATA` (resource data). + +Accessing the RDATA using the `.GetRDATA()` getter, and the `.SetRDATA()` setter. + +`.GetRDATA()`) returns the generic interface (`dnsv2.RDATA`). The `.String()` function generates a zonefile-like string representing every field in the struct: + +```go +rd := rc.GetRDATA() // The generic RDATA +fmt.Printf("Like in a zonefile: %s\n", rd.String()) +``` + +Generally you then need to cast it to the correct type. + +``` +rd := rc.GetRDATA() // The generic RDATA +mx1 := rc.GetRDATA().(dnsv2.MX) // Cast as a MX so we can work with it. +mx2 := rc.AsMX() // Same as mx1, but less typing. +``` + +Typical useage: + +``` +switch rtype { +case "MX": + mx = rc.AsMX() +case "SRV": + srv = rc.AsSRV() +case "CLOUDFLAREAPI_SINGLE_REDIRECT": + csr = rc.AsCLOUDFLAREAPISINGLEREDIRECT() +} +``` + +```go +mx := rc.AsMX() // Cast to the MX record +fmt.Printf("my MX is preference=%d target=%q\n", mx.Preference, mx.Mx) +fmt.Printf("Like in a zonefile: %s\n", mx.String()) // Same as rd.String() +``` + +To alter fields call `GetRDATA()`, change the fields, then call `SetRDATA()` to save it back. `GetRDATA()` returns a copy of the RDATA, therefore mutating it without saving it back is fruitless. + +```go +rd := rc.AsMX() // Get the RDATA, cast as an MX +mx.Preference = 999 // Alter a field. +rc.SetRDATA(mx) // Save it back. +``` + +## Create `models.RecordConfig` literals for testdata + +This is for creating test data only. They panic on error. + +```go +dc, err := models.NewDomainConfig(zone) +dc.AddTestRC("www", 0, dnsv2.TypeA, "1.2.3.4") +dc.AddTestRC("mail", 0, dnsv2.TypeMX, 10, "mx1.example.com.") +dc.AddTestRCParse("mail", 0, dnsv2.TypeMX, "20 mx2.example.com.") +``` + +If you want to create an `models.RecordConfig` without adding it to a `dc`, there are `Must` versions +of `dc.NewRecordConfig()` and `dc.NewRecordConfigParse()`: + +```go +dc, err := models.NewDomainConfig(zone) +rc0 := dc.MustNewRecordConfig("www", 0, dnsv2.TypeA, "1.2.3.4") +rc1 := dc.MustNewRecordConfig("mail", 0, dnsv2.TypeMX, 10, "mx1.example.com.") +rc2 := dc.MustNewRecordConfigParse("mail", 0, dnsv2.TypeMX, "20 mx2.example.com.") +``` + +## How to create a "builder" + +A builder is a function that can be used in `dnsconfig.js` which outputs one or +more DNS records. For example, the `SPF_BUILDER()` function generates `TXT` +records. + +Assume the builder is named "robert" and appears in `dnsconfig.js` as `ROBERT(label, data)` + +- Create the builder in `models/b_robert.go` +. Register the builder: + +```go +func init() { + RegisterBuilder("LOC", BuilderLOC) +} +``` + +(see `models/b_loc.go` for an example) + +- Create the `BuilderNAME()` function + +Add a function called BuilderROBERT() with this signature: + +```go +func BuilderROBERT(dc *DomainConfig, ttl uint32, args []any, metadata map[string]string, subdomain string) (Records, error) { +``` + +- `dc`: The domain the builder was called in. +- `ttl`: the desired TTL or `0` if it is unknown. Unknown TTLs are converted into the default TTL. +- `args`: the arguments passed to the function in `dnsconfig.js`. Each should be passed through a `mustbe.*` function before use. +- `metadata`: Any `{foo: "foo"}` (Javascript objects) passed to the function in `dnsconfig.js`. +- `subdomain`: If the builder was used in a `D_EXTEND()`, the subdomain will be non-nil. + - If `D("example.com")` is followed by `D_EXTEND("foo.example.com")`, subdomain will be `foo`. + - To calculate the label: `name, _ := dc.LabelFromDnsconfigjs(args[0].(string), subdomain)` + - To calcuate a target name: `name, _ := mustbe.TagetHostWithSubdoman(dc.Name, subdomain, name)` + +The builder function can do basically anything and generate as many records as it wants. `SPF_BUILDER()` returns many records. `LOC()` returns just one record. + +All builders must have unit tests. + +## How to manipulate domain/zone names + +Rather than use strings.Trim() or other functions, use these functions. They +handle "@", apex domains, and other edge cases properly. See the unit tests for +examples. + +Turn a short name (`foo`) into a FQDN (`foo.example.com.`) (with trailing dot). + +```go +f1 := nameutil.ToFqdnWithDot("foo", "example.com") +f2 := dc.ToFqdnWithDot("foo") // Assume dc.Name = "example.com" +# result: foo.example.com. +# The result will always end in ".". +``` + +Turn a short name (`foo`) into a FQDN (`foo.example.com`) (no trailing dot). + +```go +f1 := nameutil.ToFqdnNoDot("foo", "example.com") +f2 := dc.ToFqdnNoDot("foo") // Assume dc.Name = "example.com" +# result: foo.example.com +# The result will never end in "." (even if the origin did). +``` + +Turn a name (FQDN end with a ".") into a shortname: +```go +short1 := nameutil.ToShort("foo.example.com.", "example.com") +short2 := dc.ToShort("foo.example.com.") // Assume dc.Name = "example.com" +# result: foo +# The result ends in "." if it is a FQDN (even if the origin didn't.) +``` + +## What you should know about TXT records + +The DNS protocol stores a TXT record as a series of segements: +* Each segment can be a maximum of 255-octets (octets == bytes). +* It's possible to have no segments. +* It's possible to zero-length segments. +* In a DNS Zone File, TXT records are presented as quoted strings (each segment quoted individually), with \DDD (3-digit) escapes for non-printing chars and \x (1-char escapes) for literals (typically `\\` to represent a backslach and `\"` to represent a double-quote inside a quoted string). + +DNSControl stores TXT records as segments. However... +* We "re-segment" strings so that all but the last one is 255-octets. +* Zero-length segments are removed. +* Records with no segments are "improved" to have a single 0-length segment. This eliminates an edge case to deal with. + +To manage this, we have getters and setters that assure the above rules happen transparently. + +### TXT functions + +Reading TXT data: + +```go +j := rc.GetTargetTXTJoined() // One big string +s := rc.GetTargetTXTSegmented() // []string with each element 255-octets except the last. +``` + +Creating TXT records from scratch: + +```go +rc1, err := dc.NewRecordConfig(LABEL, TTL, dnsv2.TypeTXT, "raw bytes") +rc2, err := dc.NewRecordConfigParse(LABEL, TTL, dnsv2.TypeTXT, `"quoted" "like" "from" "zonefile"`) +``` + +Updating existing records: + +* `SetTargetTXT(string)`: Takes one (possibly long) string. +* `SetTargetTXTs([]string)`: Takes a []string. Will re-segment if needed. + +FYI: The above functions will re-segment the text such that each segment is 255 +octets long, except the last one which contains the remainder. If a record is +(for example) 3 segments of length 200, 200, and 200 each, they will be merged +and resegmented to lengths 255, 255, and 90. + +Please do not use `rc.GetTargetField()` on TXT records. + +## How to change the rtype of a RecordConfig + +Suppose you have a models.RecordConfig{} but the type needs to change. +For example, the provider doesn't support ALIAS but they call it a CNAME. + +```go + rc = rc.ChangeTypeToCNAME(dc, rc.AsALIAS().Target) +``` + +For any other transformation: + +1. Set .Type and .TypeNum + +2. Create the RDATA using a MakeFOO() function and use the SetRDATA() to store + it. Be sure to use SetDATA() last since it rebuilds any pre-computed + strings. + +Example: + +```go + rec.Type = "AKAMAITLC" + rec.TypeNum = privatetypes.TypeAKAMAITLC + rd, err := privatetypesrdata.MakeAKAMAITLC(dc.Name, nil, nrc.Flags{}, "DUAL", target) + if err != nil { + return err + } + rec.SetRDATA(rd) +``` + +Doing it this way preserves all other fields such as `.Metadata`. + +## How to label imports + +To avoid confusion between old and new DNS modules, we always import them with explicit `v1` and `v2` names. + +Here is the canonical list: + +```go +import ( + dnsv1 "github.com/miekg/dns" + dnsv2 "codeberg.org/miekg/dns" + dnsutilv1 "github.com/miekg/dns/dnsutil" + dnsutilv2 "codeberg.org/miekg/dns/dnsutil" + dnsrdatav2 "codeberg.org/miekg/dns/rdata" + dnstestv2 "codeberg.org/miekg/dns/dnstest" + svcbv1 "github.com/miekg/dns/svcb" + svcbv2 "codeberg.org/miekg/dns/svcb" +) +``` diff --git a/documentation/developer-info/goldenfiles.md b/documentation/developer-info/goldenfiles.md new file mode 100644 index 0000000000..161422823e --- /dev/null +++ b/documentation/developer-info/goldenfiles.md @@ -0,0 +1,72 @@ +# Provider conversion golden files + +Provider conversion tests replay the exact calls made at the boundary between a +provider's native record type and `models.RecordConfig`. The fixtures live in +`providers//test_data` and require neither credentials nor a domain +environment variable when replayed. + +## Recording + +Run a known-good integration test with `-record`: + +```shell +go test -failfast -run TestDNSProviders -v ./integrationTest \ + -args -verbose -profile CLOUDNS -record +``` + +The conversion observer is injected while the provider is constructed. Each +instrumented conversion reports its input and result. `-record` writes both as +a matched, indexed pair, so recording does not require a later `-update` step. +Only check in recordings from successful integration tests. + +Use `-recorddir` to override the provider's normal `test_data` directory. A +relative path is resolved from the repository root. + +{% hint style="danger" %} +Review every recorded file for credentials, private names, addresses, zone IDs, +and other sensitive data before committing it. +{% endhint %} + +## Files + +`test_data/meta.json` stores the fixture version and the domains and conversion +functions recorded for the provider. A provider may have more than one domain. + +For native-to-RecordConfig (`ToRC`) conversions: + +- `recorded_torc_input__.json` +- `expected_torc_output__.records` + +For RecordConfig-to-native (`ToNative`) conversions: + +- `recorded_tonative_input__.records` +- `expected_tonative_output__.json` + +The provider name is omitted because the containing package already identifies +it. The domain is included because one provider can be tested against several +zones. + +Every JSON value has an `index` and a `value`. Every `.records` line starts +with the same integer and a tab. Repeated indexes represent one conversion +which consumes or produces multiple records. Consequently, one-to-many and +many-to-one conversions remain synchronized even when record counts differ. + +## Intentional output changes + +`-record` replaces both sides of the fixture pair using a passing integration +run. `-update` is separate: it preserves recorded inputs and rewrites only the +expected outputs using the current conversion code. + +```shell +go test ./providers/cloudns -update +``` + +Review the resulting diff. `-update` can bless current behavior, including a +bug, so use it only when an output change is intentional. + +## Mutation checks + +The observer snapshots both sides of each boundary. A `ToRC` conversion must +not mutate its native input, and a `ToNative` conversion must not mutate its +`RecordConfig` input. Recording reports these mutations as errors; replay tests +report them as test failures. diff --git a/documentation/developer-info/modernizingproviders.md b/documentation/developer-info/modernizingproviders.md new file mode 100644 index 0000000000..10090dbe1a --- /dev/null +++ b/documentation/developer-info/modernizingproviders.md @@ -0,0 +1,240 @@ +t # How to "Modernize" a provider + + +"Modernize" means adopting the new RecordConfig v3 structs, factories, etc. + +## What work do you need to do? + +This script will find any old code that needs to be updated: + +```shell +$ cd providers/azuredns +$ ../../bin/is_modern.sh +$ ../../bin/is_modern.sh +========== DomainConfig{ +========== RecordConfig{ +ovhProvider.go: rec := &models.RecordConfig{ +========== PopulateFromString{ +ovhProvider.go: if err := rec.PopulateFromString(rtype, r.Target, origin); err != nil { +========== SetTarget +./protocol.go: Target: rc.GetTargetCombined(), +./protocol.go: Target: rc.GetTargetCombined(), +========== GetTarget +``` + +## Dev tips + +ProTip: Run the intergration tests after each small change. That +way if something breaks, you know it was the most recent change. +G +ProTip: Sometimes its useful to make the change in two steps. First, write +code that calculates something the old and new ways, compare the results +to make sure they're the same. + +Original code: + +``` +rec.Metadata[metaOriginalIP] = rec.GetTargetField() +``` + +Verify our new code is correct: + +``` +tryOld := rec.GetTargetField() +tryNew := rec.GetTargetIP().String() +if tryOld != tryNew { + panic("houston, we have a problem") +} +rec.Metadata[metaOriginalIP] = tryOld +``` + +Adopt the new code: + +``` +rec.Metadata[metaOriginalIP] = rec.GetTargetIP().String() +``` + +## Step 1: Adopt `models.NewDomainConfig()` + +Change any `DomainConfig{}` to the new factory: + +OLD: + +``` +dc := &DomainConfig{} +``` + +NEW: + +``` +dc := models.NewDomainConfig(zoneName) +``` + +## Step 2. Adopt `models.NewRecordConfig()` + +Change any `RecordConfig{}` to the new factory: + +OLD: + +``` +rc := &RecordConfig{} +``` + +NEW: + +``` +rc := dc.NewRecordConfig(...) // Typical +or +rc := dc.NewRecordConfigParse(...) // Replaces PopulateFromString() +``` + +If `dc` doesn't exist in this function, add it to the signature. Most functions +pass `origin` or `domain` as a string. Change that to `dc *modelsDomainConfig`. + +OLD: + +```go +func (a *azurednsProvider) getExistingRecords(domain string) (models.Records, []*adns.RecordSet, string, error) { +... +``` + +NEW: + +```go +func (a *azurednsProvider) getExistingRecords(dc *models.DomainConfig) (models.Records, []*adns.RecordSet, string, error) { + domain := dc.Name + +... + + rc := dc.NewRecordConfig(... +``` + +You may have to follow the function calling chain a few levels. If you use VS +Code or other editor that warns you of errors, change the signature of the +function, wait for VS Code to report errors in the callers. Fix those. If +those don't have `dc`, change their signatures. Keep working you way up the +chain. + +## Step 3. Remove obsolete setters + +`PopulateFromString()` can be replaced by `dc.NewRecordConfigParse(...)`. + +Since `NewRecordConfigParse()` defaults to a `txtutil.ParseQuoted`-compatible TXT parser, +`PopulateFromStringFunc(... , contents, txtutil.ParseQuoted)` can be replaced by: + +``` + rc, err := dc.NewRecordConfigParse(LABEL, TTL, rType, contents) + if err != nil { whatever } +``` + +If you use something other that `txtutil.ParseQuoted`, then `PopulateFromStringFunc(... , contents, MyFunc)` can be replaced by: + +``` +switch rType { +case "TXT": + t := MyFunc(contents) + rc, err := dc.NewRecordConfig(LABEL, TTL, dnsv2.TypeTXT, t) +default: + rc, err := dc.NewRecordConfigParse(LABEL, TTL, rType, contents) +} +if err != nil { whatever } + +## Step 4. Replace dnsutilv1.AddOrigin() + +OLD: + +```go +n := dnsutilv1.AddOrigin(ns.Name, domain.Name+".") +``` + +NEW: + +n1 := nameutil.ToFqdnWithDot(ns.Name, domain.Name) // result always ends with "." +n2 := nameutil.ToFqdnNoDot(ns.Name, domain.Name) // result never ends with "." + +## Step 5. Replace TrimDomainName() + +OLD: + +```go +shortname := dnsutilv1.TrimDomainName(label, origin) +``` + +NEW: + +```go +shortname := nameutil.ToShort(label, origin) +or +shortname := dc.ToShort(label) +``` + +## Step 3a. Upgrade any remaining dnsv1 or dnsutilv1 references + +Replace any remaining uses of dnsv1 or dnsutilv1 with dnsv2 and dnsutilv2 respectively. + +## Step 7. Remove obsolete setters + +`rc.GetTargetCombined()` is now `rc.GetRDATA().String()` + +`rc.GetTargetRFC1035Quoted()` is now `rc.GetRDATA().String()` + +`rc.GetTargetCombinedFunc(..., txtutil.EncodeQuoted)` is now `rc.GetRDATA().String()` + +`rc.GetTargetCombinedFunc(..., MyFunc)` is now: + +``` +switch rType { +case "TXT": + t := MyFunc(rc.GetTargetTXTJoined()) +default: + t := rc.GetRDATA().String() +} +``` + +`rc.GetTargetField()` can still be used, but replace it if possible. + +* `rc.GetRDATA().String()` (if we know the struct only has 1 field) + +If it is a TXT record, there are 3 permitted getters: + +* `rc.GetTargetTXTJoined()` +* `rc.GetTargetTXTSegmented()` +* `rc.GetRDATA().String()` // quoted and escaped. + +## Step 6. Remove obsolete getters + +OLD: + +`SetTargetCAA()` +`SetTargetCAAStrings()` +`SetTargetCAAString()` +`SetTargetDNSKEYString()` +`SetTargetDSString()` +`SetTargetLOCString()` +`SetTargetMX()` +`SetTargetMXString()` +`SetTargetNAPTR()` +`SetTargetNAPTRString()` +`SetTargetSMIMEA()` +`SetTargetSOA()` +`SetTargetSRV()` +`SetTargetSRVPriorityString()` +`SetTargetSRVString()` +`SetTargetSSHFP()` +`SetTargetSSHFPStrings()` +`SetTargetSSHFPString()` +`SetTargetSVCBString()` +`SetTargetTLSA()` +`SetTargetTLSAString()` + +In general these are no longer needed if you use `NewRecordConfig*()` functions. + +However, if you want to alter an existing RC... + +```go +mx := rc.AsMX() // Get the RDATA as an MX. +mx.Preference = 999 // Alter a field. +rc.SetRDATA(mx) // Save it back. +``` + +See the [cookbook](cookbook.md) for more details. diff --git a/documentation/developer-info/provider-conversion-tests.md b/documentation/developer-info/provider-conversion-tests.md new file mode 100644 index 0000000000..dc64842776 --- /dev/null +++ b/documentation/developer-info/provider-conversion-tests.md @@ -0,0 +1,60 @@ +# Adding provider conversion golden tests + +`pkg/providergolden` records and replays the exact conversion calls exercised by +integration tests. See [goldenfiles.md](goldenfiles.md) for the recording +workflow and file formats. + +## Instrument the provider + +Add a `providers.ConversionObserver` field to the provider and implement +`SetConversionObserver`. Around each conversion boundary, pass the same input +to `Begin` before conversion and `End` after conversion, together with the +result and error: + +```go +before := providers.BeginToRC(p.observer, "toRc", native) +records, err := toRc(dc, native) +providers.EndToRC(p.observer, "toRc", before, native, records, err) +``` + +For the other direction: + +```go +input := models.Records{record} +before := providers.BeginToNative(p.observer, "toReq", input) +request, err := toReq(record) +providers.EndToNative(p.observer, "toReq", before, input, request, err) +``` + +Observe the conversion at every call site used by integration tests. Use the +conversion function's exact name as the observer name. + +## Add replay tests + +Adapters receive the domain from `test_data/meta.json`; no environment variable +is needed. + +```go +func TestToRcGolden(t *testing.T) { + providergolden.CheckToRC(t, "toRc", + func(dc *models.DomainConfig, native domainRecord) (models.Records, error) { + rc, err := toRc(dc, &native) + return models.Records{rc}, err + }) +} + +func TestToReqGolden(t *testing.T) { + providergolden.CheckToNative(t, "toReq", + func(_ *models.DomainConfig, records models.Records) (requestParams, error) { + return toReq(records[0]) + }) +} +``` + +`CheckToNative` passes all records sharing an index in one call, which supports +record-set conversions. `CheckRoundTrip` can additionally verify providers +whose two conversions are compatible. + +An unrecorded function is skipped. Once a passing integration run is available, +record it with `-record`, inspect the new files, and run the provider package +normally to verify replay. diff --git a/documentation/language-reference/domain-modifiers/ADGUARDHOME_AAAA_PASSTHROUGH.md b/documentation/language-reference/domain-modifiers/ADGUARDHOME_AAAA_PASSTHROUGH.md index 939f8c22e9..66d897e0cf 100644 --- a/documentation/language-reference/domain-modifiers/ADGUARDHOME_AAAA_PASSTHROUGH.md +++ b/documentation/language-reference/domain-modifiers/ADGUARDHOME_AAAA_PASSTHROUGH.md @@ -3,10 +3,12 @@ name: ADGUARDHOME_AAAA_PASSTHROUGH parameters: - source - destination + - modifiers... provider: ADGUARDHOME parameter_types: source: string destination: string + "modifiers...": RecordModifier[] --- `ADGUARDHOME_AAAA_PASSTHROUGH` represents the literal 'A'. AdGuardHome uses this to passthrough diff --git a/documentation/language-reference/domain-modifiers/ADGUARDHOME_A_PASSTHROUGH.md b/documentation/language-reference/domain-modifiers/ADGUARDHOME_A_PASSTHROUGH.md index 8b618ecd78..cc87ea4407 100644 --- a/documentation/language-reference/domain-modifiers/ADGUARDHOME_A_PASSTHROUGH.md +++ b/documentation/language-reference/domain-modifiers/ADGUARDHOME_A_PASSTHROUGH.md @@ -3,10 +3,12 @@ name: ADGUARDHOME_A_PASSTHROUGH parameters: - source - destination + - modifiers... provider: ADGUARDHOME parameter_types: source: string destination: string + "modifiers...": RecordModifier[] --- `ADGUARDHOME_A_PASSTHROUGH` represents the literal 'A'. AdGuardHome uses this to passthrough diff --git a/documentation/language-reference/domain-modifiers/CF_WORKER_ROUTE.md b/documentation/language-reference/domain-modifiers/CF_WORKER_ROUTE.md index e05d6d1ef1..e8cccdc3d0 100644 --- a/documentation/language-reference/domain-modifiers/CF_WORKER_ROUTE.md +++ b/documentation/language-reference/domain-modifiers/CF_WORKER_ROUTE.md @@ -3,9 +3,11 @@ name: CF_WORKER_ROUTE parameters: - pattern - script + - modifiers... parameter_types: pattern: string script: string + "modifiers...": RecordModifier[] provider: CLOUDFLAREAPI --- diff --git a/documentation/language-reference/domain-modifiers/DISABLE_IGNORE_SAFETY_CHECK.md b/documentation/language-reference/domain-modifiers/DISABLE_IGNORE_SAFETY_CHECK.md index 9bb021d761..518adca11b 100644 --- a/documentation/language-reference/domain-modifiers/DISABLE_IGNORE_SAFETY_CHECK.md +++ b/documentation/language-reference/domain-modifiers/DISABLE_IGNORE_SAFETY_CHECK.md @@ -4,7 +4,7 @@ name: DISABLE_IGNORE_SAFETY_CHECK `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. +It replaces the per-record `IGNORE_NAME_DISABLE_SAFETY_CHECK` which is deprecated as of DNSControl v4.0.0. See [`IGNORE`](../domain-modifiers/IGNORE.md) for more information. diff --git a/documentation/language-reference/domain-modifiers/DMARC_BUILDER.md b/documentation/language-reference/domain-modifiers/DMARC_BUILDER.md index 6550bb71d2..22d7566693 100644 --- a/documentation/language-reference/domain-modifiers/DMARC_BUILDER.md +++ b/documentation/language-reference/domain-modifiers/DMARC_BUILDER.md @@ -8,11 +8,14 @@ parameters: - nonexistentSubdomainPolicy - alignmentSPF - alignmentDKIM + - percent - rua - ruf - publicSuffixDomain - testMode - failureOptions + - failureFormat + - reportInterval - ttl parameters_object: true parameter_types: @@ -23,11 +26,14 @@ parameter_types: nonexistentSubdomainPolicy: "'none' | 'quarantine' | 'reject'?" alignmentSPF: "'strict' | 's' | 'relaxed' | 'r'?" alignmentDKIM: "'strict' | 's' | 'relaxed' | 'r'?" + percent: number? rua: string[]? ruf: string[]? publicSuffixDomain: "'y' | 'n' | 'u'" testMode: "'y' | 'n'" failureOptions: "{ SPF: boolean, DKIM: boolean } | string?" + failureFormat: string? + reportInterval: "Duration | number?" ttl: Duration? --- @@ -115,11 +121,14 @@ insecure IN TXT "v=DMARC1; p=none; ruf=mailto:mailauth-reports@example.com; * `nonexistentSubdomainPolicy:` The DMARC policy for nonexistent subdomains (`np=`), 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:` Integer percentage (0-100) of messages to which the DMARC policy is applied (`pct=`, optional) * `rua:` Array of aggregate report targets (optional) * `ruf:` Array of failure report targets (optional) * `publicSuffixDomain:` `"y"`, or `"n"` or `"u"` indicates whether the domain is a Public Suffix Domain (`psd=`, default: `"u"`) * `testMode:` `"y"` or `"n"` DMARC policy test mode dictates whether p, sp, or np policy tags are applied (`t=`, default: `"n"`) * `failureOptions:` Object or string; Object containing booleans `SPF` and `DKIM`, string is passed raw (`fo=`, default: `"0"`) +* `failureFormat:` Format of the message's failure reports (`rf=`); only emitted when `ruf` is also set (optional) +* `reportInterval:` Requested interval between aggregate reports, as a `Duration` or number of seconds (`ri=`, optional) * `ttl:` Input for `TTL` method (optional) ### Caveats diff --git a/documentation/language-reference/domain-modifiers/LOC.md b/documentation/language-reference/domain-modifiers/LOC.md index 2878b20c49..defccb2ffa 100644 --- a/documentation/language-reference/domain-modifiers/LOC.md +++ b/documentation/language-reference/domain-modifiers/LOC.md @@ -1,29 +1,35 @@ --- name: LOC parameters: + - name - deg1 - min1 - sec1 + - ns - deg2 - min2 - sec2 + - ew - altitude - size - horizontal_precision - vertical_precision + - modifiers... parameter_types: name: string - target: string deg1: number min1: number sec1: number + ns: '"N" | "S" | "n" | "s"' deg2: number min2: number sec2: number + ew: '"E" | "W" | "e" | "w"' altitude: number size: number horizontal_precision: number vertical_precision: number + "modifiers...": RecordModifier[] --- `LOC` add a [Location record](https://www.rfc-editor.org/rfc/rfc1876) to the domain. @@ -36,9 +42,11 @@ target: string deg1: uint32 min1: uint32 sec1: float32 +ns: string deg2: uint32 min2: uint32 sec2: float32 +ew: string altitude: float32 size: float32 horizontal_precision: float32 diff --git a/documentation/language-reference/domain-modifiers/NAMESERVER.md b/documentation/language-reference/domain-modifiers/NAMESERVER.md index 8f28e78eeb..2a6400a03a 100644 --- a/documentation/language-reference/domain-modifiers/NAMESERVER.md +++ b/documentation/language-reference/domain-modifiers/NAMESERVER.md @@ -2,10 +2,8 @@ name: NAMESERVER parameters: - name - - modifiers... parameter_types: name: string - "modifiers...": RecordModifier[] --- `NAMESERVER()` instructs DNSControl to inform the domain's registrar where to find this zone. For some registrars this will also add NS records to the zone itself. diff --git a/documentation/language-reference/domain-modifiers/NAMESERVER_TTL.md b/documentation/language-reference/domain-modifiers/NAMESERVER_TTL.md index 54a3094472..dbb1c5e29a 100644 --- a/documentation/language-reference/domain-modifiers/NAMESERVER_TTL.md +++ b/documentation/language-reference/domain-modifiers/NAMESERVER_TTL.md @@ -4,8 +4,6 @@ parameters: - ttl parameter_types: ttl: Duration - target: string - modifiers...: RecordModifier[] --- NAMESERVER_TTL sets the TTL on the domain apex NS RRs defined by [`NAMESERVER`](NAMESERVER.md). diff --git a/documentation/language-reference/domain-modifiers/NAPTR.md b/documentation/language-reference/domain-modifiers/NAPTR.md index 739c86e1a9..e6ba3315d0 100644 --- a/documentation/language-reference/domain-modifiers/NAPTR.md +++ b/documentation/language-reference/domain-modifiers/NAPTR.md @@ -8,6 +8,7 @@ parameters: - service - regexp - target + - modifiers... parameter_types: subdomain: string order: number @@ -16,6 +17,7 @@ parameter_types: service: string regexp: string target: string + "modifiers...": RecordModifier[] --- ## Introduction diff --git a/documentation/provider/akamaiedgedns.md b/documentation/provider/akamaiedgedns.md index 900a8686ab..dce5aaba1f 100644 --- a/documentation/provider/akamaiedgedns.md +++ b/documentation/provider/akamaiedgedns.md @@ -51,6 +51,21 @@ The AKAMAITLC record can only be used once per zone. #### ALIAS Akamai Edge DNS does directly support `ALIAS` records. This provider will convert `ALIAS` records used at the zone apex (`@`) to `AKAMAITLC` records, and any other names to `CNAME` records. +#### IGNORE + +`IGNORE()` is supported. Records matched by an `IGNORE()` rule will be left as-is on Akamai Edge DNS and not deleted. + +#### TTL with IGNORE + +Akamai Edge DNS stores a single TTL for all records that share the same name and type (a "recordset"). If you manage some records in a recordset while ignoring others, the TTL you set on the managed records will be applied to the whole recordset — including the ignored ones. + +If the ignored records currently have a different TTL than what you've set, DNSControl will print a warning during both `preview` and `push`: + +``` +WARNING: TTL mismatch in app.example.com A: using 900 (managed), ignoring 300 +``` + + ### Secondary zones This provider only supports creating primary zones in Akamai. If a secondary zone has been manually created, only `AKAMAICDN` and `AKAMAITLC` records can be managed, as all other records are read-only. diff --git a/documentation/provider/desec.md b/documentation/provider/desec.md index c8d361a28a..b72fb3294e 100644 --- a/documentation/provider/desec.md +++ b/documentation/provider/desec.md @@ -76,5 +76,5 @@ Upon domain creation, the DNSKEY and DS records needed for DNSSEC setup are prin - DNSSEC - [`AUTODNSSEC`](../language-reference/domain-modifiers/AUTODNSSEC_ON.md): ✅ - [`DNSKEY`](../language-reference/domain-modifiers/DNSKEY.md): ✅ - - [`DS`](../language-reference/domain-modifiers/DS.md): ✅ + - [`DS`](../language-reference/domain-modifiers/DS.md): ❌ diff --git a/documentation/provider/dnsmadeeasy.md b/documentation/provider/dnsmadeeasy.md index fb5c4452cd..60a5902a6b 100644 --- a/documentation/provider/dnsmadeeasy.md +++ b/documentation/provider/dnsmadeeasy.md @@ -6,6 +6,7 @@ along with your `api_key` and `secret_key`. More info about authentication can b Example: {% code title="creds.json" %} + ```json { "dnsmadeeasy": { @@ -15,6 +16,7 @@ Example: } } ``` + {% endcode %} ## Records @@ -26,23 +28,26 @@ This provider does not support HTTPRED records. SPF records are ignored by this provider. Use TXT records instead. ## Metadata + This provider does not recognize any special metadata fields unique to DNS Made Easy. ## Usage + An example configuration: {% code title="dnsconfig.js" %} + ```javascript -var REG_NONE = NewRegistrar("none"); -var DSP_DNSMADEEASY = NewDnsProvider("dnsmadeeasy"); +var REG_NONE = NewRegistrar('none'); +var DSP_DNSMADEEASY = NewDnsProvider('dnsmadeeasy'); -D("example.com", REG_NONE, DnsProvider(DSP_DNSMADEEASY), - A("test", "1.2.3.4"), -); +D('example.com', REG_NONE, DnsProvider(DSP_DNSMADEEASY), A('test', '1.2.3.4')); ``` + {% endcode %} ## Activation + You can generate your `api_key` and `secret_key` in [Control Panel](https://cp.dnsmadeeasy.com/) in Account Information in Config menu. API is only available for Business plan and higher plans. @@ -50,15 +55,39 @@ API is only available for Business plan and higher plans. ## Caveats ### Global Traffic Director + Global Traffic Director feature is not supported. ## Development +### DNS Made Easy sandbox environment + +Sandbox control panel is available at [https://sandbox.dnsmadeeasy.com/](sandbox.dnsmadeeasy.com). To generate sandbox API credentials, sign up for a free trial and go to [Account Information](https://sandbox.dnsmadeeasy.com/account/info) in Config menu. + +Set `sandbox` key to a non-empty value in credentials JSON alongside `TYPE`, `api_key` and `secret_key` to make all API calls against DNS Made Easy sandbox environment. Details in [DNS Made Easy API documentation](https://api-docs.dnsmadeeasy.com/). + ### Debugging -Set `DNSMADEEASY_DEBUG_HTTP` environment variable to dump all API calls made by this provider. -### Testing -Set `sandbox` key to any non-empty value in credentials JSON alongside `api_key` and `secret_key` to make all API calls against DNS Made Easy sandbox environment. +Set `DNSMADEEASY_DEBUG_HTTP` environment variable to `1` to dump all API calls made by this provider. + +```bash +export DNSMADEEASY_DEBUG_HTTP=1 +``` + +### Integration testing + +For integration testing sandbox environment is used automatically. See `DNSMADEEASY` in `integrationTest/profiles.json`. + +Run integration tests against DNS Made Easy sandbox environment. Increased test timeout is needed due to DNS Made Easy rate limits. Example: + +```bash +export DNSMADEEASY_DOMAIN=dnscontroltest.com +export DNSMADEEASY_API_KEY=4aede38d-f8b4-41d7-9712-374336624046 +export DNSMADEEASY_SECRET_KEY=fcf5d4f8-765e-4c90-a79e-0369d332a890 + +cd integrationTest +go test -v -test.timeout 2h -args -verbose -profile DNSMADEEASY +``` ## Feature Summary @@ -94,3 +123,4 @@ Set `sandbox` key to any non-empty value in credentials JSON alongside `api_key` - [`DNSKEY`](../language-reference/domain-modifiers/DNSKEY.md): ❔ - [`DS`](../language-reference/domain-modifiers/DS.md): ❌ + diff --git a/documentation/provider/domainnameshop.md b/documentation/provider/domainnameshop.md index 74788be875..af38ccfbde 100644 --- a/documentation/provider/domainnameshop.md +++ b/documentation/provider/domainnameshop.md @@ -40,6 +40,7 @@ D("example.com", REG_NONE, DnsProvider(DSP_DOMAINNAMESHOP), ## Limitations - Domainnameshop DNS only supports TTLs which are a multiple of 60. + ## Feature Summary diff --git a/documentation/provider/exoscale.md b/documentation/provider/exoscale.md index a1261f1320..c0acced14d 100644 --- a/documentation/provider/exoscale.md +++ b/documentation/provider/exoscale.md @@ -34,7 +34,7 @@ D("example.com", REG_NONE, DnsProvider(DSP_EXOSCALE), - [`ALIAS`](../language-reference/domain-modifiers/ALIAS.md): ✅ - [`DNAME`](../language-reference/domain-modifiers/DNAME.md): ❔ - [`LOC`](../language-reference/domain-modifiers/LOC.md): ❌ - - [`PTR`](../language-reference/domain-modifiers/PTR.md): ✅ + - [`PTR`](../language-reference/domain-modifiers/PTR.md): ❌ - [`SOA`](../language-reference/domain-modifiers/SOA.md): ❔ - Service discovery - [`DHCID`](../language-reference/domain-modifiers/DHCID.md): ❔ diff --git a/documentation/provider/index.md b/documentation/provider/index.md index 606dfd3305..0934f7469b 100644 --- a/documentation/provider/index.md +++ b/documentation/provider/index.md @@ -165,7 +165,7 @@ Jump to a table: | [`TRANSIP`](transip.md) | ✅ | ❌ | ❌ | ✅ | | [`UNIFI`](unifi.md) | ❌ | ❔ | ❌ | ❌ | | [`VERCEL`](vercel.md) | ❔ | ❌ | ❌ | ❌ | -| [`VULTR`](vultr.md) | ❔ | ❔ | ✅ | ✅ | +| [`VULTR`](vultr.md) | ✅ | ❔ | ✅ | ✅ | | [`WEBSUPPORT`](websupport.md) | ❔ | ❌ | ❌ | ❌ | @@ -192,7 +192,7 @@ Jump to a table: | [`DNSMADEEASY`](dnsmadeeasy.md) | ✅ | ❔ | ❌ | ✅ | ❔ | | [`DOMAINNAMESHOP`](domainnameshop.md) | ❔ | ❔ | ❌ | ❌ | ❌ | | [`DYNU`](dynu.md) | ❌ | ✅ | ✅ | ✅ | ❔ | -| [`EXOSCALE`](exoscale.md) | ✅ | ❔ | ❌ | ✅ | ❔ | +| [`EXOSCALE`](exoscale.md) | ✅ | ❔ | ❌ | ❌ | ❔ | | [`FORTIGATE`](fortigate.md) | ❔ | ❔ | ❌ | ❌ | ❔ | | [`GANDI_V5`](gandiv5.md) | ✅ | ❔ | ✅ | ✅ | ❔ | | [`GCLOUD`](gcloud.md) | ✅ | ❔ | ❌ | ✅ | ❔ | @@ -231,7 +231,7 @@ Jump to a table: | [`SAKURACLOUD`](sakuracloud.md) | ✅ | ❌ | ❌ | ✅ | ❌ | | [`SCALEWAY`](scaleway.md) | ✅ | ✅ | ❌ | ✅ | ❌ | | [`SOFTLAYER`](softlayer.md) | ❔ | ❔ | ❌ | ❔ | ❔ | -| [`TENCENTDNS`](tencentdns.md) | ✅ | ❔ | ❔ | ✅ | ❔ | +| [`TENCENTDNS`](tencentdns.md) | ❌ | ❔ | ❔ | ❌ | ❔ | | [`TRANSIP`](transip.md) | ✅ | ❌ | ❌ | ❌ | ❌ | | [`UNIFI`](unifi.md) | ❌ | ❔ | ❌ | ❌ | ❔ | | [`VERCEL`](vercel.md) | ✅ | ❌ | ❌ | ❌ | ❌ | @@ -386,7 +386,7 @@ Jump to a table: | [`CLOUDFLAREAPI`](cloudflareapi.md) | ❔ | ❌ | ✅ | | [`CLOUDNS`](cloudns.md) | ✅ | ❌ | ❌ | | [`CNR`](cnr.md) | ✅ | ❔ | ❔ | -| [`DESEC`](desec.md) | ✅ | ✅ | ✅ | +| [`DESEC`](desec.md) | ✅ | ✅ | ❌ | | [`DIGITALOCEAN`](digitalocean.md) | ❌ | ❌ | ❌ | | [`DNSIMPLE`](dnsimple.md) | ✅ | ❔ | ❌ | | [`DNSMADEEASY`](dnsmadeeasy.md) | ❔ | ❔ | ❌ | @@ -418,6 +418,7 @@ Jump to a table: | [`SCALEWAY`](scaleway.md) | ❌ | ❔ | ❌ | | [`TRANSIP`](transip.md) | ❌ | ❌ | ❌ | | [`VERCEL`](vercel.md) | ❌ | ❌ | ❌ | +| [`VULTR`](vultr.md) | ✅ | ❔ | ❔ | | [`WEBSUPPORT`](websupport.md) | ❔ | ❔ | ❌ | diff --git a/documentation/provider/openwrt.md b/documentation/provider/openwrt.md index 55723a6e44..8e42a2570d 100644 --- a/documentation/provider/openwrt.md +++ b/documentation/provider/openwrt.md @@ -55,6 +55,8 @@ D("example.com", REG_NONE, DnsProvider(DSP_OPENWRT), ``` {% endcode %} +## Feature Summary + - Provider Type - [Official Support](../provider/index.md#providers-with-official-support): ❌ diff --git a/documentation/provider/scaleway.md b/documentation/provider/scaleway.md index f96236c49f..773bdadfe3 100644 --- a/documentation/provider/scaleway.md +++ b/documentation/provider/scaleway.md @@ -65,6 +65,8 @@ in the console — this provider does not create zones. Zones must be created via the Scaleway console or API before they can be managed by DNSControl. +## Feature Summary + - Provider Type - [Official Support](../provider/index.md#providers-with-official-support): ❌ diff --git a/documentation/provider/tencentdns.md b/documentation/provider/tencentdns.md index b18150c48f..0f36991e65 100644 --- a/documentation/provider/tencentdns.md +++ b/documentation/provider/tencentdns.md @@ -166,10 +166,10 @@ Reference: https://docs.dnspod.com/dns/faq-dns-resolution/?lang=en - create-domains: ✅ - [get-zones](../commands/get-zones.md): ✅ - DNS extensions - - [`ALIAS`](../language-reference/domain-modifiers/ALIAS.md): ✅ + - [`ALIAS`](../language-reference/domain-modifiers/ALIAS.md): ❌ - [`DNAME`](../language-reference/domain-modifiers/DNAME.md): ❔ - [`LOC`](../language-reference/domain-modifiers/LOC.md): ❔ - - [`PTR`](../language-reference/domain-modifiers/PTR.md): ✅ + - [`PTR`](../language-reference/domain-modifiers/PTR.md): ❌ - [`SOA`](../language-reference/domain-modifiers/SOA.md): ❔ - Service discovery - [`DHCID`](../language-reference/domain-modifiers/DHCID.md): ❔ diff --git a/documentation/provider/vultr.md b/documentation/provider/vultr.md index 30ae977e0b..212fd3a169 100644 --- a/documentation/provider/vultr.md +++ b/documentation/provider/vultr.md @@ -46,7 +46,7 @@ Vultr depends on a Vultr personal access token. - DNS Provider: ✅ - Registrar: ❌ - Provider API - - [Concurrency Verified](../advanced-features/concurrency-verified.md): ❔ + - [Concurrency Verified](../advanced-features/concurrency-verified.md): ✅ - [dual host](../advanced-features/dual-host.md): ❔ - create-domains: ✅ - [get-zones](../commands/get-zones.md): ✅ @@ -68,7 +68,7 @@ Vultr depends on a Vultr personal access token. - [`SSHFP`](../language-reference/domain-modifiers/SSHFP.md): ✅ - [`TLSA`](../language-reference/domain-modifiers/TLSA.md): ❌ - DNSSEC - - [`AUTODNSSEC`](../language-reference/domain-modifiers/AUTODNSSEC_ON.md): ❔ + - [`AUTODNSSEC`](../language-reference/domain-modifiers/AUTODNSSEC_ON.md): ✅ - [`DNSKEY`](../language-reference/domain-modifiers/DNSKEY.md): ❔ - [`DS`](../language-reference/domain-modifiers/DS.md): ❔ diff --git a/documentation/provider/websupport.md b/documentation/provider/websupport.md index 8b9da133c2..a7fdfbca27 100644 --- a/documentation/provider/websupport.md +++ b/documentation/provider/websupport.md @@ -80,6 +80,17 @@ secret itself is never transmitted. * `ALIAS`/`ANAME` — WebSupport only allows `ANAME` at the apex and rejects it when other apex records exist, so it cannot be supported generically. * `LOC`, `NAPTR`, `PTR`, `SSHFP`, `TLSA`, `DS`. +* **`TXT` records may not end in a space.** The API silently strips trailing + whitespace, so such records are rejected rather than churning forever. +* **Null MX ([RFC 7505](https://www.rfc-editor.org/rfc/rfc7505.html)) is not + supported.** A null MX has an empty target and the API rejects a record with + empty `content`, so `MX("@", 0, ".")` is rejected with a clear error. +* **MX and SRV reads cost one extra API request each.** WebSupport's record + listing endpoints return `null` for `priority`, `port` and `weight` on every + record, even though the values are stored correctly and served in DNS. The + provider re-reads each `MX` and `SRV` record through the v1 single-record + endpoint, which still reports them. This is a workaround for a bug on + WebSupport's side and stops by itself once they fix the listing. * The provider automatically resolves each domain to its numeric WebSupport service id (used internally by the v2 API); you only need to supply `api_key` and `secret`. diff --git a/go.mod b/go.mod index 6f4c18cd66..1deac66fb6 100644 --- a/go.mod +++ b/go.mod @@ -1,116 +1,80 @@ -module github.com/DNSControl/dnscontrol/v4 +module github.com/DNSControl/dnscontrol/v5 -go 1.26 - -retract v4.8.0 - -require ( - github.com/aws/aws-sdk-go-v2/internal/v4a v1.4.36 // indirect - github.com/benbjohnson/clock v1.3.5 // indirect - github.com/eclipse/paho.golang v0.23.0 // indirect - github.com/fsnotify/fsnotify v1.10.1 // indirect - github.com/go-ozzo/ozzo-validation/v4 v4.3.0 // indirect - github.com/go-playground/locales v0.14.0 // indirect - github.com/go-playground/universal-translator v0.18.0 // indirect - github.com/go-playground/validator/v10 v10.9.0 // indirect - github.com/gorilla/websocket v1.5.3 // indirect - github.com/jtolds/gls v4.20.0+incompatible // indirect - github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51 // indirect - github.com/leodido/go-urn v1.2.1 // indirect - github.com/mgutz/ansi v0.0.0-20170206155736-9520e82c474b // indirect - github.com/pelletier/go-toml/v2 v2.4.3 // indirect - github.com/sagikazarmark/locafero v0.12.0 // indirect - github.com/sony/gobreaker/v2 v2.4.0 // indirect - github.com/spf13/afero v1.15.0 // indirect - github.com/spf13/cast v1.10.0 // indirect - github.com/spf13/pflag v1.0.10 // indirect - github.com/spf13/viper v1.21.0 // indirect - github.com/subosito/gotenv v1.6.0 // indirect - go.uber.org/ratelimit v0.3.1 // indirect - go.yaml.in/yaml/v3 v3.0.5 // indirect - google.golang.org/protobuf v1.36.11 // indirect - gopkg.in/yaml.v2 v2.4.0 // indirect -) - -require golang.org/x/net v0.57.0 +go 1.27 require ( + codeberg.org/miekg/dns v0.6.90 + github.com/AlecAivazis/survey/v2 v2.3.7 + github.com/Azure/azure-sdk-for-go/sdk/azcore v1.22.0 github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.14.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.3.0 github.com/DisposaBoy/JsonConfigReader v0.0.0-20201129172854-99cf318d67e7 + github.com/G-Core/gcore-dns-sdk-go v0.3.3 github.com/PuerkitoBio/goquery v1.12.0 github.com/TomOnTime/utfutil v1.0.0 - github.com/andreyvit/diff v0.0.0-20170406064948-c7f18ee00883 + github.com/akamai/AkamaiOPEN-edgegrid-golang/v12 v12.3.0 + github.com/aliyun/alibaba-cloud-sdk-go v1.63.107 github.com/aws/aws-sdk-go-v2 v1.43.4 github.com/aws/aws-sdk-go-v2/config v1.32.35 github.com/aws/aws-sdk-go-v2/credentials v1.19.34 github.com/aws/aws-sdk-go-v2/service/route53 v1.65.6 github.com/aws/aws-sdk-go-v2/service/route53domains v1.38.4 + github.com/aws/aws-sdk-go-v2/service/sts v1.45.4 github.com/babolivier/go-doh-client v0.0.0-20201028162107-a76cff4cb8b6 + github.com/centralnicgroup-opensource/rtldev-middleware-go-sdk/v5 v5.0.19 github.com/cloudflare/cloudflare-go v0.117.0 github.com/digitalocean/godo v1.203.0 github.com/ditashi/jsbeautifier-go v0.0.0-20141206144643-2520a8026a9c github.com/dnsimple/dnsimple-go/v8 v8.3.0 - github.com/exoscale/egoscale/v3 v3.1.43 - github.com/go-gandi/go-gandi v0.7.0 - github.com/gobwas/glob v0.2.4-0.20181002190808-e7a84e9525fe - github.com/gopherjs/jquery v0.0.0-20191017083323-73f4c7416038 - github.com/jinzhu/copier v0.4.0 - github.com/miekg/dns v1.1.72 - github.com/mittwald/go-powerdns v0.6.7 - github.com/namedotcom/go v0.0.0-20180403034216-08470befbe04 - github.com/nrdcg/goinwx v0.12.0 - github.com/ovh/go-ovh v1.9.0 - github.com/philhug/opensrs-go v0.0.0-20171126225031-9dfa7433020d - github.com/pkg/errors v0.9.1 - github.com/pquerna/otp v1.5.0 - github.com/qdm12/reprint v0.0.0-20200326205758-722754a53494 - github.com/robertkrimen/otto v0.5.1 - github.com/softlayer/softlayer-go v1.2.1 - github.com/stretchr/testify v1.11.1 - github.com/transip/gotransip/v6 v6.27.3 - github.com/xddxdd/ottoext v0.0.0-20221109171055-210517fa4419 - golang.org/x/crypto v0.54.0 // indirect - golang.org/x/oauth2 v0.36.0 - google.golang.org/api v0.292.0 - gopkg.in/ns1/ns1-go.v2 v2.18.0 -) - -require ( - codeberg.org/miekg/dns v0.6.90 - github.com/AlecAivazis/survey/v2 v2.3.7 - github.com/Azure/azure-sdk-for-go/sdk/azcore v1.22.0 - github.com/G-Core/gcore-dns-sdk-go v0.3.3 - github.com/aliyun/alibaba-cloud-sdk-go v1.63.107 - github.com/aws/aws-sdk-go-v2/service/sts v1.45.4 - github.com/centralnicgroup-opensource/rtldev-middleware-go-sdk/v5 v5.0.19 github.com/dustin/go-humanize v1.0.1 + github.com/exoscale/egoscale/v3 v3.1.43 github.com/failsafe-go/failsafe-go v0.9.6 github.com/fatih/color v1.19.0 github.com/fbiville/markdown-table-formatter v0.3.0 + github.com/go-gandi/go-gandi v0.7.0 + github.com/gobwas/glob v0.2.4-0.20181002190808-e7a84e9525fe github.com/google/go-cmp v0.7.0 github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510 + github.com/gopherjs/jquery v0.0.0-20191017083323-73f4c7416038 github.com/hetznercloud/hcloud-go/v2 v2.47.0 github.com/huaweicloud/huaweicloud-sdk-go-v3 v0.1.210 github.com/kylelemons/godebug v1.1.0 github.com/luadns/luadns-go v0.3.0 github.com/mattn/go-isatty v0.0.24 + github.com/mittwald/go-powerdns v0.6.7 + github.com/namedotcom/go v0.0.0-20180403034216-08470befbe04 github.com/netnod/netnod-primary-dns-client v1.1.1 github.com/nicholas-fedor/shoutrrr v0.17.0 github.com/nozzle/throttler v0.0.0-20180817012639-2ea982251481 + github.com/nrdcg/goinwx v0.12.0 github.com/oracle/oci-go-sdk/v65 v65.123.0 + github.com/ovh/go-ovh v1.9.0 + github.com/philhug/opensrs-go v0.0.0-20171126225031-9dfa7433020d + github.com/pkg/errors v0.9.1 + github.com/pquerna/otp v1.5.0 + github.com/qdm12/reprint v0.0.0-20200326205758-722754a53494 + github.com/robertkrimen/otto v0.5.1 github.com/scaleway/scaleway-sdk-go v1.0.0-beta.37 + github.com/softlayer/softlayer-go v1.2.1 + github.com/stretchr/testify v1.11.1 github.com/tencentcloud/tencentcloud-sdk-go-intl-en v3.0.1462+incompatible github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/common v1.3.154 github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/dnspod v1.3.131 github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/domain v1.3.66 + github.com/transip/gotransip/v6 v6.27.3 github.com/urfave/cli/v3 v3.10.1 github.com/vercel/terraform-provider-vercel v1.14.1 - github.com/vultr/govultr/v2 v2.17.2 + github.com/vultr/govultr/v3 v3.32.0 github.com/willpower232/go-namecheap v0.0.0-20260720171816-b13495139f3c + github.com/xddxdd/ottoext v0.0.0-20221109171055-210517fa4419 + golang.org/x/net v0.57.0 + golang.org/x/oauth2 v0.36.0 golang.org/x/text v0.40.0 golang.org/x/time v0.15.0 + golang.org/x/tools v0.48.0 + google.golang.org/api v0.292.0 + gopkg.in/ns1/ns1-go.v2 v2.18.0 gopkg.in/yaml.v3 v3.0.1 ) @@ -120,26 +84,33 @@ require ( cloud.google.com/go/compute/metadata v0.9.0 // indirect github.com/Azure/azure-sdk-for-go/sdk/internal v1.12.0 // indirect github.com/AzureAD/microsoft-authentication-library-for-go v1.7.2 // indirect - github.com/akamai/AkamaiOPEN-edgegrid-golang/v12 v12.3.0 github.com/andybalholm/cascadia v1.3.3 // indirect github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.18.35 // indirect github.com/aws/aws-sdk-go-v2/internal/configsources v1.4.35 // indirect github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.7.35 // indirect + github.com/aws/aws-sdk-go-v2/internal/v4a v1.4.36 // indirect github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.13.15 // indirect github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.13.35 // indirect github.com/aws/aws-sdk-go-v2/service/signin v1.5.4 // indirect github.com/aws/aws-sdk-go-v2/service/sso v1.33.4 // indirect github.com/aws/aws-sdk-go-v2/service/ssooidc v1.38.4 // indirect github.com/aws/smithy-go v1.27.6 // indirect + github.com/benbjohnson/clock v1.3.5 // indirect github.com/beorn7/perks v1.0.1 // indirect github.com/bits-and-blooms/bitset v1.24.4 // indirect github.com/boombuler/barcode v1.0.1 // indirect github.com/cespare/xxhash/v2 v2.3.0 // indirect github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect + github.com/eclipse/paho.golang v0.23.0 // indirect github.com/fatih/structs v1.1.0 // indirect github.com/felixge/httpsnoop v1.0.4 // indirect + github.com/fsnotify/fsnotify v1.10.1 // indirect github.com/go-logr/logr v1.4.4 // indirect github.com/go-logr/stdr v1.2.2 // indirect + github.com/go-ozzo/ozzo-validation/v4 v4.3.0 // indirect + github.com/go-playground/locales v0.14.0 // indirect + github.com/go-playground/universal-translator v0.18.0 // indirect + github.com/go-playground/validator/v10 v10.9.0 // indirect github.com/go-viper/mapstructure/v2 v2.5.0 // indirect github.com/goccy/go-json v0.10.5 // indirect github.com/goccy/go-yaml v1.9.8 // indirect @@ -151,20 +122,26 @@ require ( github.com/googleapis/enterprise-certificate-proxy v0.3.19 // indirect github.com/googleapis/gax-go/v2 v2.23.0 // indirect github.com/gopherjs/gopherjs v1.17.2 // indirect + github.com/gorilla/websocket v1.5.3 // indirect github.com/hashicorp/go-cleanhttp v0.5.2 // indirect github.com/hashicorp/go-hclog v1.6.3 // indirect - github.com/hashicorp/go-retryablehttp v0.7.7 // indirect + github.com/hashicorp/go-retryablehttp v0.7.8 // indirect github.com/hashicorp/terraform-plugin-log v0.9.0 // indirect github.com/influxdata/tdigest v0.0.1 // indirect github.com/jmespath/go-jmespath v0.4.0 // indirect github.com/json-iterator/go v1.1.13-0.20220915233716-71ac16282d12 // indirect + github.com/jtolds/gls v4.20.0+incompatible // indirect + github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51 // indirect github.com/kolo/xmlrpc v0.0.0-20220921171641-a4b6fa1dd06b // indirect + github.com/leodido/go-urn v1.2.1 // indirect github.com/mattn/go-colorable v0.1.15 // indirect + github.com/mgutz/ansi v0.0.0-20170206155736-9520e82c474b // indirect github.com/mitchellh/go-homedir v1.1.0 // indirect github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect github.com/modern-go/reflect2 v1.0.2 // indirect github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect github.com/opentracing/opentracing-go v1.2.1-0.20220228012449-10b1cf09e00b // indirect + github.com/pelletier/go-toml/v2 v2.4.3 // indirect github.com/peterhellberg/link v1.2.0 // indirect github.com/pkg/browser v0.0.0-20240102092130-5ac0b6a4141c // indirect github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect @@ -172,11 +149,17 @@ require ( github.com/prometheus/client_model v0.6.2 // indirect github.com/prometheus/common v0.67.5 // indirect github.com/prometheus/procfs v0.20.0 // indirect - github.com/sergi/go-diff v1.2.0 // indirect + github.com/sagikazarmark/locafero v0.12.0 // indirect github.com/shopspring/decimal v1.4.0 // indirect github.com/smartystreets/assertions v1.2.0 // indirect github.com/softlayer/xmlrpc v0.0.0-20200409220501-5f089df7cb7e // indirect + github.com/sony/gobreaker/v2 v2.4.0 // indirect + github.com/spf13/afero v1.15.0 // indirect + github.com/spf13/cast v1.10.0 // indirect + github.com/spf13/pflag v1.0.10 // indirect + github.com/spf13/viper v1.21.0 // indirect github.com/stretchr/objx v0.5.3 // indirect + github.com/subosito/gotenv v1.6.0 // indirect github.com/tjfoc/gmsm v1.4.1 // indirect github.com/youmark/pkcs8 v0.0.0-20240726163527-a2c0da244d78 // indirect go.mongodb.org/mongo-driver v1.17.7 // indirect @@ -185,18 +168,24 @@ require ( go.opentelemetry.io/otel v1.44.0 // indirect go.opentelemetry.io/otel/metric v1.44.0 // indirect go.opentelemetry.io/otel/trace v1.44.0 // indirect + go.uber.org/ratelimit v0.3.1 // indirect go.yaml.in/yaml/v2 v2.4.3 // indirect + go.yaml.in/yaml/v3 v3.0.5 // indirect + golang.org/x/crypto v0.54.0 // indirect golang.org/x/mod v0.38.0 // indirect golang.org/x/sync v0.22.0 // indirect golang.org/x/sys v0.47.0 // indirect golang.org/x/term v0.45.0 // indirect - golang.org/x/tools v0.48.0 golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 // indirect google.golang.org/genproto/googleapis/rpc v0.0.0-20260803160001-6ac0973c030d // indirect google.golang.org/grpc v1.83.0 // indirect + google.golang.org/protobuf v1.36.11 // indirect gopkg.in/ini.v1 v1.67.0 // indirect gopkg.in/sourcemap.v1 v1.0.5 // indirect + gopkg.in/yaml.v2 v2.4.0 // indirect moul.io/http2curl v1.0.0 // indirect ) tool golang.org/x/tools/cmd/stringer + +replace codeberg.org/miekg/dns => codeberg.org/TomOnTime/dns v0.5.4-0.20260810000946-b7d86015068d diff --git a/go.sum b/go.sum index b8b0d5c31f..772211e2ab 100644 --- a/go.sum +++ b/go.sum @@ -5,8 +5,8 @@ cloud.google.com/go/auth/oauth2adapt v0.2.8 h1:keo8NaayQZ6wimpNSmW5OPc283g65QNIi cloud.google.com/go/auth/oauth2adapt v0.2.8/go.mod h1:XQ9y31RkqZCcwJWNSx2Xvric3RrU88hAYYbjDWYDL+c= cloud.google.com/go/compute/metadata v0.9.0 h1:pDUj4QMoPejqq20dK0Pg2N4yG9zIkYGdBtwLoEkH9Zs= cloud.google.com/go/compute/metadata v0.9.0/go.mod h1:E0bWwX5wTnLPedCKqk3pJmVgCBSM6qQI1yTBdEb3C10= -codeberg.org/miekg/dns v0.6.90 h1:Trqn1KlkSsjWz3bJ6Q2/bfymmPwdfBZDQm2MCiN3Gog= -codeberg.org/miekg/dns v0.6.90/go.mod h1:58Y3ZTg6Z5ZEm/ZAAwHehbZfrD4u5mE4RByHoPEMyKk= +codeberg.org/TomOnTime/dns v0.5.4-0.20260810000946-b7d86015068d h1:GN42aj86hUnyv6aLWqHSB0LS99dbgMfnWj/ewzyZrnM= +codeberg.org/TomOnTime/dns v0.5.4-0.20260810000946-b7d86015068d/go.mod h1:58Y3ZTg6Z5ZEm/ZAAwHehbZfrD4u5mE4RByHoPEMyKk= dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU= github.com/AlecAivazis/survey/v2 v2.3.7 h1:6I/u8FvytdGsgonrYsVn2t8t4QiRnh6QSTqkkhIiSjQ= github.com/AlecAivazis/survey/v2 v2.3.7/go.mod h1:xUTIdE4KCOIjsBAE1JYsUPoCqYdZ1reCfTwbto0Fduo= @@ -50,8 +50,6 @@ github.com/akamai/AkamaiOPEN-edgegrid-golang/v12 v12.3.0 h1:iGVPe/gPqzpXggbbmVLW github.com/akamai/AkamaiOPEN-edgegrid-golang/v12 v12.3.0/go.mod h1:76JtkiCKMwTdTOlKe9goT4Md+oWjfMouGBQgy+u1bgc= github.com/aliyun/alibaba-cloud-sdk-go v1.63.107 h1:qagvUyrgOnBIlVRQWOyCZGVKUIYbMBdGdJ104vBpRFU= github.com/aliyun/alibaba-cloud-sdk-go v1.63.107/go.mod h1:SOSDHfe1kX91v3W5QiBsWSLqeLxImobbMX1mxrFHsVQ= -github.com/andreyvit/diff v0.0.0-20170406064948-c7f18ee00883 h1:bvNMNQO63//z+xNgfBlViaCIJKLlCJ6/fmUseuG0wVQ= -github.com/andreyvit/diff v0.0.0-20170406064948-c7f18ee00883/go.mod h1:rCTlJbsFo29Kk6CurOXKm700vrz8f0KW0JNfpkRJY/8= github.com/andybalholm/cascadia v1.3.3 h1:AG2YHrzJIm4BZ19iwJ/DAua6Btl3IwJX+VI4kktS1LM= github.com/andybalholm/cascadia v1.3.3/go.mod h1:xNd9bqTn98Ln4DwST8/nG+H0yuB8Hmgu1YHNnWw0GeA= github.com/asaskevich/govalidator v0.0.0-20200108200545-475eaeb16496/go.mod h1:oGkLhpf+kjZl6xBf758TQhh5XrAeiJv/7FRz/2spLIg= @@ -237,8 +235,8 @@ github.com/hashicorp/go-cleanhttp v0.5.2 h1:035FKYIWjmULyFRBKPs8TBQoi0x6d9G4xc9n github.com/hashicorp/go-cleanhttp v0.5.2/go.mod h1:kO/YDlP8L1346E6Sodw+PrpBSV4/SoxCXGY6BqNFT48= github.com/hashicorp/go-hclog v1.6.3 h1:Qr2kF+eVWjTiYmU7Y31tYlP1h0q/X3Nl3tPGdaB11/k= github.com/hashicorp/go-hclog v1.6.3/go.mod h1:W4Qnvbt70Wk/zYJryRzDRU/4r0kIg0PVHBcfoyhpF5M= -github.com/hashicorp/go-retryablehttp v0.7.7 h1:C8hUCYzor8PIfXHa4UrZkU4VvK8o9ISHxT2Q8+VepXU= -github.com/hashicorp/go-retryablehttp v0.7.7/go.mod h1:pkQpWZeYWskR+D1tR2O5OcBFOxfA7DoAO6xtkuQnHTk= +github.com/hashicorp/go-retryablehttp v0.7.8 h1:ylXZWnqa7Lhqpk0L1P1LzDtGcCR0rPVUrx/c8Unxc48= +github.com/hashicorp/go-retryablehttp v0.7.8/go.mod h1:rjiScheydd+CxvumBsIrFKlx3iS0jrZ7LvzFGFmuKbw= github.com/hashicorp/terraform-plugin-log v0.9.0 h1:i7hOA+vdAItN1/7UrfBqBwvYPQ9TFvymaRGZED3FCV0= github.com/hashicorp/terraform-plugin-log v0.9.0/go.mod h1:rKL8egZQ/eXSyDqzLUuwUYLVdlYeamldAHSxjUFADow= github.com/hetznercloud/hcloud-go/v2 v2.47.0 h1:SI7C4cvdYReb2aHUEQ8KBMOqxNnmd4hOZti1SbPq3Qk= @@ -251,8 +249,6 @@ github.com/influxdata/tdigest v0.0.1 h1:XpFptwYmnEKUqmkcDjrzffswZ3nvNeevbUSLPP/Z github.com/influxdata/tdigest v0.0.1/go.mod h1:Z0kXnxzbTC2qrx4NaIzYkE1k66+6oEDQTvL95hQFh5Y= github.com/jarcoal/httpmock v1.4.2 h1:dKwiP/9zITCPfBLsDn3kchbSOu16JrnxtVEmL0fPRcI= github.com/jarcoal/httpmock v1.4.2/go.mod h1:ftW1xULwo+j0R0JJkJIIi7UKigZUXCLLanykgjwBXL0= -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= github.com/jmespath/go-jmespath v0.4.0/go.mod h1:T8mJZnbsbmF+m6zOOFylbeCJqk5+pHWvzYPziyZiYoo= github.com/jmespath/go-jmespath/internal/testify v1.5.1 h1:shLQSRRSCCPj3f2gpwzGwWFoC7ycTf1rcQZHOlsJ6N8= @@ -303,8 +299,6 @@ github.com/maxatome/go-testdeep v1.12.0 h1:Ql7Go8Tg0C1D/uMMX59LAoYK7LffeJQ6X2T04 github.com/maxatome/go-testdeep v1.12.0/go.mod h1:lPZc/HAcJMP92l7yI6TRz1aZN5URwUBUAfUNvrclaNM= github.com/mgutz/ansi v0.0.0-20170206155736-9520e82c474b h1:j7+1HpAFS1zy5+Q4qx1fWh90gTKwiN4QCGoY9TWyyO4= github.com/mgutz/ansi v0.0.0-20170206155736-9520e82c474b/go.mod h1:01TrycV0kFyexm33Z7vhZRXopbI8J3TDReVlkTgMUxE= -github.com/miekg/dns v1.1.72 h1:vhmr+TF2A3tuoGNkLDFK9zi36F2LS+hKTRW0Uf8kbzI= -github.com/miekg/dns v1.1.72/go.mod h1:+EuEPhdHOsfk6Wk5TT2CzssZdqkmFhf8r+aVyDEToIs= github.com/mitchellh/go-homedir v1.1.0 h1:lukF9ziXFxDFPkA1vsr5zpc1XuPDn/wFntq5mG+4E0Y= github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0= github.com/mitchellh/go-testing-interface v1.14.1 h1:jrgshOhYAUVNMAJiKbEu7EqAwgJJ2JqpQmpLJOu07cU= @@ -378,8 +372,6 @@ github.com/sagikazarmark/locafero v0.12.0 h1:/NQhBAkUb4+fH1jivKHWusDYFjMOOKU88ee github.com/sagikazarmark/locafero v0.12.0/go.mod h1:sZh36u/YSZ918v0Io+U9ogLYQJ9tLLBmM4eneO6WwsI= github.com/scaleway/scaleway-sdk-go v1.0.0-beta.37 h1:1Q6K8D0BagYYEnCTkT9fn3YHUFb06bS1OvIHWcc3JQM= github.com/scaleway/scaleway-sdk-go v1.0.0-beta.37/go.mod h1:Rtb4r3WZ5x4AqmL3t/wiF/DmQi+7GlU/nCRdqFbClV4= -github.com/sergi/go-diff v1.2.0 h1:XU+rvMAioB0UC3q1MFrIQy4Vo5/4VsRDQQXHsEya6xQ= -github.com/sergi/go-diff v1.2.0/go.mod h1:STckp+ISIX8hZLjrqAeVduY0gWCT9IjLuqbuNXdaHfM= github.com/shopspring/decimal v1.4.0 h1:bxl37RwXBklmTi0C79JfXCEBD1cqqHt0bbgBAGFp81k= github.com/shopspring/decimal v1.4.0/go.mod h1:gawqmDU56v4yIKSwfBSFip1HdCCXN8/+DMd9qYNcwME= github.com/smartystreets/assertions v1.2.0 h1:42S6lae5dvLc7BrLu/0ugRtcFVjoJNMC/N3yZFZkDFs= @@ -439,8 +431,8 @@ github.com/urfave/cli/v3 v3.10.1 h1:7Kx9H50hrHbRbyxgO1KP6/BcbiGRz0uYh5YyQ30JEEY= github.com/urfave/cli/v3 v3.10.1/go.mod h1:ysVLtOEmg2tOy6PknnYVhDoouyC/6N42TMeoMzskhso= github.com/vercel/terraform-provider-vercel v1.14.1 h1:ghAjFkMMzka4XuoBYdu1OXM/K7FQEj8wUd+xMPPOGrg= github.com/vercel/terraform-provider-vercel v1.14.1/go.mod h1:AdFCiUD0XP8XOi6tnhaCh7I0vyq2TAPmI+GcIp3+7SI= -github.com/vultr/govultr/v2 v2.17.2 h1:gej/rwr91Puc/tgh+j33p/BLR16UrIPnSr+AIwYWZQs= -github.com/vultr/govultr/v2 v2.17.2/go.mod h1:ZFOKGWmgjytfyjeyAdhQlSWwTjh2ig+X49cAp50dzXI= +github.com/vultr/govultr/v3 v3.32.0 h1:QS9IAeSB3BIhSoP0jIYtmGAvtsYkprjWTZAGPx8keo8= +github.com/vultr/govultr/v3 v3.32.0/go.mod h1:2zyUw9yADQaGwKnwDesmIOlBNLrm7edsCfWHFJpWKf8= github.com/willpower232/go-namecheap v0.0.0-20260720171816-b13495139f3c h1:crbR1KcJIrVWMm1rNmKwrTFO8LwcC/O9J3ZSQK0Fwm0= github.com/willpower232/go-namecheap v0.0.0-20260720171816-b13495139f3c/go.mod h1:geRAHdcGE14UKJ835LVWlIC6X9c7Ft+c+UCXQ571Mig= github.com/xddxdd/ottoext v0.0.0-20221109171055-210517fa4419 h1:PT5KYEimicg1GRkBtBxCLcHWvMcBRGljOLwG/y4+T5c= @@ -657,7 +649,6 @@ google.golang.org/protobuf v1.36.11 h1:fV6ZwhNocDyBLK0dj+fg8ektcVegBBuEolpbTQyBN google.golang.org/protobuf v1.36.11/go.mod h1:HTf+CrKn2C3g5S8VImy6tdcUvCska2kB7j23XfzDpco= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= -gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q= @@ -672,7 +663,6 @@ gopkg.in/readline.v1 v1.0.0-20160726135117-62c6fe619375/go.mod h1:lNEQeAhU009zbR gopkg.in/sourcemap.v1 v1.0.5 h1:inv58fC9f9J3TK2Y2R1NPntXEn3/wjWHkonhIUODNTI= gopkg.in/sourcemap.v1 v1.0.5/go.mod h1:2RlvNNSMglmRrcvhfuzp4hQHwOtjxlbjX7UPY/GXb78= gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= -gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY= gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ= diff --git a/integrationTest/helpers_integration_test.go b/integrationTest/helpers_integration_test.go index 58863399ef..b17bea2aff 100644 --- a/integrationTest/helpers_integration_test.go +++ b/integrationTest/helpers_integration_test.go @@ -13,14 +13,14 @@ import ( "testing" "time" - "github.com/DNSControl/dnscontrol/v4/models" - "github.com/DNSControl/dnscontrol/v4/pkg/domaintags" - "github.com/DNSControl/dnscontrol/v4/pkg/nameservers" - "github.com/DNSControl/dnscontrol/v4/pkg/providers" - "github.com/DNSControl/dnscontrol/v4/pkg/rtypecontrol" - "github.com/DNSControl/dnscontrol/v4/pkg/transform" - "github.com/DNSControl/dnscontrol/v4/pkg/zonerecs" - dnsutilv1 "github.com/miekg/dns/dnsutil" + dnsv2 "codeberg.org/miekg/dns" + "github.com/DNSControl/dnscontrol/v5/models" + "github.com/DNSControl/dnscontrol/v5/pkg/domaintags" + "github.com/DNSControl/dnscontrol/v5/pkg/nameservers" + "github.com/DNSControl/dnscontrol/v5/pkg/nameutil" + "github.com/DNSControl/dnscontrol/v5/pkg/privatetypes" + "github.com/DNSControl/dnscontrol/v5/pkg/providers" + "github.com/DNSControl/dnscontrol/v5/pkg/zonerecs" ) var ( @@ -34,9 +34,20 @@ var ( // This is an ugly, ugly, hack. We have to find something better. var globalDC *models.DomainConfig -// Global variable to hold the current DomainConfig for use in FromRaw calls. +// Global variable to hold the current DomainConfig for use in FromRaw calls. var globalDCN *domaintags.DomainNameVarieties +var globalCfg map[string]string + +// Default TTL used in integration tests. +var defaultTTL = uint32(300) + +// Helper functions to perform substitutions + +func fillTemplate(s string) string { + return strings.Replace(s, "**current-domain**", globalDC.Name, 1) +} + // Helper constants/funcs for the HEDNS Dynamic DNS testing: func hednsDynamicA(name, target, status string) *models.RecordConfig { @@ -99,7 +110,6 @@ func CfFlattenOn() *TestCase { func getDomainConfigWithNameservers(t *testing.T, prv providers.DNSServiceProvider, domainName string) *models.DomainConfig { dc := models.MustNewDomainConfig(domainName) dc.PostProcess() - rtypecontrol.FixLegacyDC(dc) // fix up nameservers ns, err := prv.GetNameservers(domainName) @@ -160,7 +170,6 @@ func testPermitted(p string, f TestGroup) error { // makeChanges runs one set of DNS record tests. Returns true on success. func makeChanges(t *testing.T, prv providers.DNSServiceProvider, dc *models.DomainConfig, tst *TestCase, desc string, expectChanges bool, origConfig map[string]string, domainMeta map[string]string) bool { - domainName := dc.Name return t.Run(desc+":"+tst.Desc, func(t *testing.T) { dom, _ := dc.Copy() @@ -173,24 +182,22 @@ func makeChanges(t *testing.T, prv providers.DNSServiceProvider, dc *models.Doma maps.Copy(dom.Metadata, domainMeta) } + // testRecords holds only the records this test case contributes. dom + // additionally contains the zone's delegation NS records, which + // getDomainConfigWithNameservers() synthesized via + // nameservers.AddNSRecords(). Those must not be audited: in production + // AuditRecords() runs in pkg/normalize on the user's records, long + // before generateDelegationCorrections() synthesizes the apex NS + // records. Auditing them here makes a provider that rejects apex NS + // records (or NS records generally) skip every test in the suite. + testRecords := make(models.Records, 0, len(tst.Records)) for _, r := range tst.Records { rc := models.RecordConfig(*r) - if strings.Contains(rc.GetTargetField(), "**current-domain**") { - _ = rc.SetTarget(strings.Replace(rc.GetTargetField(), "**current-domain**", domainName, 1)) - } - if strings.Contains(rc.GetLabelFQDN(), "**current-domain**") { - rc.SetLabelFromFQDN(strings.Replace(rc.GetLabelFQDN(), "**current-domain**", domainName, 1), domainName) - } - - if strings.Contains(rc.GetTargetField(), "**subscription-id**") { - _ = rc.SetTarget(strings.Replace(rc.GetTargetField(), "**subscription-id**", origConfig["SubscriptionID"], 1)) - } - if strings.Contains(rc.GetTargetField(), "**resource-group**") { - _ = rc.SetTarget(strings.Replace(rc.GetTargetField(), "**resource-group**", origConfig["ResourceGroup"], 1)) - } + replaceIntegrationTargetTokens(&rc, origConfig["SubscriptionID"], origConfig["ResourceGroup"]) dom.Records = append(dom.Records, &rc) + testRecords = append(testRecords, &rc) } dom.Unmanaged = tst.Unmanaged dom.UnmanagedUnsafe = tst.UnmanagedUnsafe @@ -206,11 +213,11 @@ func makeChanges(t *testing.T, prv providers.DNSServiceProvider, dc *models.Doma RTypePattern: "A", TargetPattern: "", }) - models.PostProcessRecords(dom.Records) - rtypecontrol.FixLegacyDC(dom) dom2, _ := dom.Copy() - if err := providers.AuditRecords(*providerFlag, dom.Records); err != nil { + // testRecords shares its pointers with dom.Records, so the records + // audited here are the same objects this test will push. + if err := providers.AuditRecords(*providerFlag, testRecords); err != nil { t.Skipf("***SKIPPED(PROVIDER DOES NOT SUPPORT '%s' ::%q)", err, desc) return } @@ -218,9 +225,10 @@ func makeChanges(t *testing.T, prv providers.DNSServiceProvider, dc *models.Doma //fmt.Printf("DEBUG: Running test %q: Names %q %q %q\n", desc, dom.Name, dom.NameRaw, dom.NameUnicode) // get and run corrections for first time + _, corrections, actualChangeCount, err := zonerecs.CorrectZoneRecords(prv, dom) if err != nil { - t.Fatal(fmt.Errorf("runTests: %w", err)) + t.Fatal(fmt.Errorf("runTests: CZR %w", err)) } if tst.Changeless { if actualChangeCount != 0 { @@ -251,6 +259,7 @@ func makeChanges(t *testing.T, prv providers.DNSServiceProvider, dc *models.Doma } // run a second time and expect zero corrections + _, corrections, actualChangeCount, err = zonerecs.CorrectZoneRecords(prv, dom2) if err != nil { t.Fatal(err) @@ -265,10 +274,34 @@ func makeChanges(t *testing.T, prv providers.DNSServiceProvider, dc *models.Doma }) } +func replaceIntegrationTargetTokens(rc *models.RecordConfig, subscriptionID, resourceGroup string) { + if rc.Type != "AZURE_ALIAS" { + return + } + + originalTarget := rc.AsAZUREALIAS().Target + target := strings.NewReplacer( + "**subscription-id**", subscriptionID, + "**resource-group**", strings.ToLower(resourceGroup), + ).Replace(originalTarget) + if target == originalTarget { + return + } + + if rc.Type == "AZURE_ALIAS" { + rd := rc.AsAZUREALIAS() + rd.Target = target + rc.SetRDATA(rd) + return + } + + rc.ClearRDATA() +} + func runTests(t *testing.T, prv providers.DNSServiceProvider, domainName string, origConfig map[string]string) { dc := getDomainConfigWithNameservers(t, prv, domainName) globalDC = dc - globalDCN = dc.DomainNameVarieties() + globalCfg = origConfig testGroups := makeTests() @@ -337,7 +370,7 @@ type TestGroup struct { type TestCase struct { Desc string - Records []*models.RecordConfig + Records models.Records Unmanaged []*models.UnmanagedConfig UnmanagedUnsafe bool // DISABLE_IGNORE_SAFETY_CHECK Changeless bool // set to true if any changes would be an error @@ -364,7 +397,7 @@ func (tc *TestCase) UnsafeIgnore() *TestCase { func SetLabel(r *models.RecordConfig, label, domain string) { r.Name = label - r.NameFQDN = dnsutilv1.AddOrigin(label, "**current-domain**.") + r.NameFQDN = nameutil.ToFqdnWithDot(label, "**current-domain**.") } func withMeta(record *models.RecordConfig, metadata map[string]string) *models.RecordConfig { @@ -373,28 +406,34 @@ func withMeta(record *models.RecordConfig, metadata map[string]string) *models.R } func a(name, target string) *models.RecordConfig { - return makeRec(name, target, "A") + r, err := globalDC.NewRecordConfig(name, defaultTTL, dnsv2.TypeA, target) + panicOnErr(err) + return r } func aaaa(name, target string) *models.RecordConfig { - return makeRec(name, target, "AAAA") + r, err := globalDC.NewRecordConfig(name, defaultTTL, dnsv2.TypeAAAA, target) + panicOnErr(err) + return r } func alias(name, target string) *models.RecordConfig { - return makeRec(name, target, "ALIAS") + target = fillTemplate(target) + r, err := globalDC.NewRecordConfig(name, defaultTTL, privatetypes.TypeALIAS, target) + panicOnErr(err) + return r } func azureAlias(name, aliasType, target string) *models.RecordConfig { - r := makeRec(name, target, "AZURE_ALIAS") - r.AzureAlias = map[string]string{ - "type": aliasType, - } + target = fillTemplate(target) + r, err := globalDC.NewRecordConfig(name, defaultTTL, privatetypes.TypeAZUREALIAS, aliasType, target) + panicOnErr(err) return r } func caa(name string, flag uint8, tag string, target string) *models.RecordConfig { - r := makeRec(name, target, "CAA") - panicOnErr(r.SetTargetCAA(flag, tag, target)) + r, err := globalDC.NewRecordConfig(name, defaultTTL, dnsv2.TypeCAA, flag, tag, target) + panicOnErr(err) return r } @@ -438,99 +477,82 @@ func cfSingleRedirectEnabled() bool { } func cfSingleRedirect(name string, code any, when, then string) *models.RecordConfig { - rec, err := rtypecontrol.NewRecordConfigFromRaw(rtypecontrol.FromRawOpts{ - Type: "CLOUDFLAREAPI_SINGLE_REDIRECT", - TTL: 1, - Args: []any{name, code, when, then}, - DCN: globalDCN, - }) + r, err := globalDC.NewRecordConfig("@", 1, privatetypes.TypeCLOUDFLAREAPISINGLEREDIRECT, name, code, when, then) panicOnErr(err) - return rec + return r } func cfWorkerRoute(pattern, target string) *models.RecordConfig { - t := fmt.Sprintf("%s,%s", pattern, target) - r := makeRec("@", t, "CF_WORKER_ROUTE") + pattern = fillTemplate(pattern) + r, err := globalDC.NewRecordConfig("@", 1, privatetypes.TypeCFWORKERROUTE, pattern, target) + panicOnErr(err) return r } func bunnyPullZone(name, pullZoneID string) *models.RecordConfig { - return makeRec(name, pullZoneID, "BUNNY_DNS_PZ") -} - -// func cfRedir(pattern, target string) *models.RecordConfig { -// rec, err := rtypecontrol.NewRecordConfigFromRaw(rtypecontrol.FromRawOpts{ -// Type: "CF_REDIRECT", -// TTL: 1, -// Args: []any{pattern, target}, -// DCN: globalDCN, -// }) -// panicOnErr(err) -// return rec -// } - -// func cfRedirTemp(pattern, target string) *models.RecordConfig { -// rec, err := rtypecontrol.NewRecordConfigFromRaw(rtypecontrol.FromRawOpts{ -// Type: "CF_TEMP_REDIRECT", -// TTL: 1, -// Args: []any{pattern, target}, -// DCN: globalDCN, -// }) -// panicOnErr(err) -// return rec -// } + r, err := globalDC.NewRecordConfig(name, 1, privatetypes.TypeBUNNYDNSPZ, pullZoneID) + panicOnErr(err) + return r +} func aghAPassthrough(pattern, target string) *models.RecordConfig { - r := makeRec(pattern, target, "ADGUARDHOME_A_PASSTHROUGH") + r, err := globalDC.NewRecordConfig(pattern, defaultTTL, privatetypes.TypeADGUARDHOMEAPASSTHROUGH, target) + panicOnErr(err) return r } func aghAAAAPassthrough(pattern, target string) *models.RecordConfig { - r := makeRec(pattern, target, "ADGUARDHOME_AAAA_PASSTHROUGH") + r, err := globalDC.NewRecordConfig(pattern, defaultTTL, privatetypes.TypeADGUARDHOMEAAAAPASSTHROUGH, target) + panicOnErr(err) return r } func mikrotikFwd(name, target string) *models.RecordConfig { - return makeRec(name, target, "MIKROTIK_FWD") + r, err := globalDC.NewRecordConfig(name, defaultTTL, privatetypes.TypeMIKROTIKFWD, target) + panicOnErr(err) + return r } func mikrotikNxdomain(name string) *models.RecordConfig { - return makeRec(name, "NXDOMAIN", "MIKROTIK_NXDOMAIN") + r, err := globalDC.NewRecordConfig(name, defaultTTL, privatetypes.TypeMIKROTIKNXDOMAIN) + panicOnErr(err) + return r } func cname(name, target string) *models.RecordConfig { - return makeRec(name, target, "CNAME") + target = fillTemplate(target) + r, err := globalDC.NewRecordConfig(name, defaultTTL, dnsv2.TypeCNAME, target) + panicOnErr(err) + return r } func dhcid(name, target string) *models.RecordConfig { - return makeRec(name, target, "DHCID") + r, err := globalDC.NewRecordConfig(name, defaultTTL, dnsv2.TypeDHCID, target) + panicOnErr(err) + return r } func dname(name, target string) *models.RecordConfig { - return makeRec(name, target, "DNAME") + r, err := globalDC.NewRecordConfig(name, defaultTTL, dnsv2.TypeDNAME, target) + panicOnErr(err) + return r } func ds(name string, keyTag uint16, algorithm, digestType uint8, digest string) *models.RecordConfig { - rec, err := rtypecontrol.NewRecordConfigFromRaw(rtypecontrol.FromRawOpts{ - Type: "DS", - TTL: 300, - Args: []any{name, keyTag, algorithm, digestType, digest}, - DCN: globalDCN, - }) + r, err := globalDC.NewRecordConfig(name, defaultTTL, dnsv2.TypeDS, keyTag, algorithm, digestType, digest) panicOnErr(err) - return rec + return r } func dnskey(name string, flags uint16, protocol, algorithm uint8, publicKey string) *models.RecordConfig { - r := makeRec(name, "", "DNSKEY") - panicOnErr(r.SetTargetDNSKEY(flags, protocol, algorithm, publicKey)) + r, err := globalDC.NewRecordConfig(name, defaultTTL, dnsv2.TypeDNSKEY, flags, protocol, algorithm, publicKey) + panicOnErr(err) return r } func https(name string, priority uint16, target string, params string) *models.RecordConfig { - r := makeRec(name, target, "HTTPS") - r.SvcPriority = priority - r.SvcParams = params + r, err := globalDC.NewRecordConfig(name, defaultTTL, dnsv2.TypeHTTPS, priority, target, params) + panicOnErr(err) return r } @@ -543,11 +565,13 @@ func ignoreTarget(targetSpec string, typeSpec string) *models.RecordConfig { } func ignore(labelSpec string, typeSpec string, targetSpec string) *models.RecordConfig { - r := &models.RecordConfig{ - Type: "IGNORE", - Metadata: map[string]string{}, - } + // There is no "ignore" record. IGNORE is a macro in helpers.js that records info + // into the DomainConfig. Since we want to be able to test it, we stash the info + // in Metadata then later we pluck it out and put it on the domain in test. + r := &models.RecordConfig{Type: "IGNORE", Metadata: map[string]string{}} + // We stash the *Spec values in Metadata temporarily. Later in tc() we + // pluck them out and install them in the DomainConfig. r.Metadata["ignore_LabelPattern"] = labelSpec r.Metadata["ignore_RTypePattern"] = typeSpec r.Metadata["ignore_TargetPattern"] = targetSpec @@ -557,66 +581,63 @@ func ignore(labelSpec string, typeSpec string, targetSpec string) *models.Record func loc(name string, d1 uint8, m1 uint8, s1 float32, ns string, d2 uint8, m2 uint8, s2 float32, ew string, al float32, sz float32, hp float32, vp float32, ) *models.RecordConfig { - r := makeRec(name, "", "LOC") - panicOnErr(r.SetLOCParams(d1, m1, s1, ns, d2, m2, s2, ew, al, sz, hp, vp)) - return r -} - -func makeRec(name, target, typ string) *models.RecordConfig { - r := &models.RecordConfig{ - Type: typ, - TTL: 300, - } - SetLabel(r, name, "**current-domain**.") - r.MustSetTarget(target) + r, err := globalDC.NewRecordConfig(name, defaultTTL, dnsv2.TypeLOC, d1, m1, s1, ns, d2, m2, s2, ew, al, sz, hp, vp) + panicOnErr(err) return r } -func manyA(namePattern, target string, n int) []*models.RecordConfig { - recs := []*models.RecordConfig{} +func manyA(namePattern, target string, n int) models.Records { + recs := models.Records{} for i := range n { - recs = append(recs, makeRec(fmt.Sprintf(namePattern, i), target, "A")) + r, err := globalDC.NewRecordConfig(fmt.Sprintf(namePattern, i), defaultTTL, dnsv2.TypeA, target) + panicOnErr(err) + recs = append(recs, r) } return recs } func mx(name string, prio uint16, target string) *models.RecordConfig { - r := makeRec(name, target, "MX") - r.MxPreference = prio + target = fillTemplate(target) + r, err := globalDC.NewRecordConfig(name, defaultTTL, dnsv2.TypeMX, prio, target) + panicOnErr(err) return r } func ns(name, target string) *models.RecordConfig { - return makeRec(name, target, "NS") + target = fillTemplate(target) + r, err := globalDC.NewRecordConfig(name, defaultTTL, dnsv2.TypeNS, target) + panicOnErr(err) + return r } func naptr(name string, order uint16, preference uint16, flags string, service string, regexp string, target string) *models.RecordConfig { - r := makeRec(name, target, "NAPTR") - panicOnErr(r.SetTargetNAPTR(order, preference, flags, service, regexp, target)) + r, err := globalDC.NewRecordConfig(name, defaultTTL, dnsv2.TypeNAPTR, order, preference, flags, service, regexp, target) + panicOnErr(err) return r } func openpgpkey(name, target string) *models.RecordConfig { - target, err := transform.OPENPGPKEY(target) + r, err := globalDC.NewRecordConfig(name, defaultTTL, dnsv2.TypeOPENPGPKEY, target) panicOnErr(err) - return makeRec(name, target, "OPENPGPKEY") + return r } func ptr(name, target string) *models.RecordConfig { - return makeRec(name, target, "PTR") + r, err := globalDC.NewRecordConfig(name, defaultTTL, dnsv2.TypePTR, target) + panicOnErr(err) + return r } func r53alias(name, aliasType, target, evalTargetHealth string) *models.RecordConfig { - r := makeRec(name, target, "R53_ALIAS") - r.R53Alias = map[string]string{ - "type": aliasType, - "evaluate_target_health": evalTargetHealth, - } + target = fillTemplate(target) + r, err := globalDC.NewRecordConfig(name, defaultTTL, privatetypes.TypeR53ALIAS, aliasType, target, evalTargetHealth) + panicOnErr(err) return r } func r53weighted(name, target, rtype string, weight int, setID string) *models.RecordConfig { - r := makeRec(name, target, rtype) + r, err := globalDC.NewRecordConfig(name, defaultTTL, rtype, target) + panicOnErr(err) r.Metadata = map[string]string{ "r53_weight": fmt.Sprintf("%d", weight), "r53_set_identifier": setID, @@ -625,44 +646,38 @@ func r53weighted(name, target, rtype string, weight int, setID string) *models.R } func rp(name string, m, t string) *models.RecordConfig { - rec, err := rtypecontrol.NewRecordConfigFromRaw(rtypecontrol.FromRawOpts{ - Type: "RP", - TTL: 300, - Args: []any{name, m, t}, - DCN: globalDCN, - }) + r, err := globalDC.NewRecordConfig(name, defaultTTL, dnsv2.TypeRP, m, t) panicOnErr(err) - return rec + return r } func smimea(name string, usage, selector, matchingtype uint8, target string) *models.RecordConfig { - r := makeRec(name, target, "SMIMEA") - panicOnErr(r.SetTargetSMIMEA(usage, selector, matchingtype, target)) + r, err := globalDC.NewRecordConfig(name, defaultTTL, dnsv2.TypeSMIMEA, usage, selector, matchingtype, target) + panicOnErr(err) return r } func soa(name string, ns, mbox string, serial, refresh, retry, expire, minttl uint32) *models.RecordConfig { - r := makeRec(name, "", "SOA") - panicOnErr(r.SetTargetSOA(ns, mbox, serial, refresh, retry, expire, minttl)) + r, err := globalDC.NewRecordConfig(name, defaultTTL, dnsv2.TypeSOA, ns, mbox, serial, refresh, retry, expire, minttl) + panicOnErr(err) return r } func srv(name string, priority, weight, port uint16, target string) *models.RecordConfig { - r := makeRec(name, target, "SRV") - panicOnErr(r.SetTargetSRV(priority, weight, port, target)) + r, err := globalDC.NewRecordConfig(name, defaultTTL, dnsv2.TypeSRV, priority, weight, port, target) + panicOnErr(err) return r } func sshfp(name string, algorithm uint8, fingerprint uint8, target string) *models.RecordConfig { - r := makeRec(name, target, "SSHFP") - panicOnErr(r.SetTargetSSHFP(algorithm, fingerprint, target)) + r, err := globalDC.NewRecordConfig(name, defaultTTL, dnsv2.TypeSSHFP, algorithm, fingerprint, target) + panicOnErr(err) return r } func svcb(name string, priority uint16, target string, params string) *models.RecordConfig { - r := makeRec(name, target, "SVCB") - r.SvcPriority = priority - r.SvcParams = params + r, err := globalDC.NewRecordConfig(name, defaultTTL, dnsv2.TypeSVCB, priority, target, params) + panicOnErr(err) return r } @@ -679,10 +694,10 @@ func ovhdmarc(name, target string) *models.RecordConfig { } func makeOvhNativeRecord(name, target, rType string) *models.RecordConfig { - r := makeRec(name, "", "TXT") - r.Metadata = make(map[string]string) + r, err := globalDC.NewRecordConfig(name, defaultTTL, dnsv2.TypeTXT, target) + panicOnErr(err) + r.Metadata = map[string]string{} r.Metadata["create_ovh_native_record"] = rType - r.MustSetTarget(target) return r } @@ -733,7 +748,7 @@ func testgroup(desc string, items ...any) *TestGroup { } func tc(desc string, recs ...*models.RecordConfig) *TestCase { - var records []*models.RecordConfig + var records models.Records var unmanagedItems []*models.UnmanagedConfig for _, r := range recs { if r == nil { @@ -759,8 +774,8 @@ func tc(desc string, recs ...*models.RecordConfig) *TestCase { } func txt(name, target string) *models.RecordConfig { - r := makeRec(name, "", "TXT") - panicOnErr(r.SetTargetTXT(target)) + r, err := globalDC.NewRecordConfig(name, defaultTTL, dnsv2.TypeTXT, target) + panicOnErr(err) return r } @@ -771,30 +786,33 @@ func ttl(r *models.RecordConfig, t uint32) *models.RecordConfig { } func tlsa(name string, usage, selector, matchingtype uint8, target string) *models.RecordConfig { - r := makeRec(name, target, "TLSA") - panicOnErr(r.SetTargetTLSA(usage, selector, matchingtype, target)) + r, err := globalDC.NewRecordConfig(name, defaultTTL, dnsv2.TypeTLSA, usage, selector, matchingtype, target) + panicOnErr(err) return r } -func porkbunUrlfwd(name, target, t, includePath, wildcard string) *models.RecordConfig { - r := makeRec(name, target, "PORKBUN_URLFWD") - r.Metadata = make(map[string]string) - r.Metadata["type"] = t - r.Metadata["includePath"] = includePath - r.Metadata["wildcard"] = wildcard - return r +func porkbunUrlfwd(name, target string) *models.RecordConfig { + rc, err := globalDC.NewRecordConfig(name, defaultTTL, privatetypes.TypePORKBUNURLFWD, target) + panicOnErr(err) + return rc } func url(name, target string) *models.RecordConfig { - return makeRec(name, target, "URL") + rc, err := globalDC.NewRecordConfig(name, defaultTTL, privatetypes.TypeURL, target) + panicOnErr(err) + return rc } func url301(name, target string) *models.RecordConfig { - return makeRec(name, target, "URL301") + rc, err := globalDC.NewRecordConfig(name, defaultTTL, privatetypes.TypeURL301, target) + panicOnErr(err) + return rc } func frame(name, target string) *models.RecordConfig { - return makeRec(name, target, "FRAME") + rc, err := globalDC.NewRecordConfig(name, defaultTTL, privatetypes.TypeFRAME, target) + panicOnErr(err) + return rc } func tcEmptyZone() *TestCase { diff --git a/integrationTest/helpers_test.go b/integrationTest/helpers_test.go index 1abd2b9a32..1ceaf221e0 100644 --- a/integrationTest/helpers_test.go +++ b/integrationTest/helpers_test.go @@ -9,20 +9,50 @@ import ( "strings" "testing" - "github.com/DNSControl/dnscontrol/v4/pkg/credsfile" - "github.com/DNSControl/dnscontrol/v4/pkg/providers" - "github.com/DNSControl/dnscontrol/v4/providers/cloudflare" + "github.com/DNSControl/dnscontrol/v5/models" + "github.com/DNSControl/dnscontrol/v5/pkg/credsfile" + "github.com/DNSControl/dnscontrol/v5/pkg/privatetypes" + "github.com/DNSControl/dnscontrol/v5/pkg/providergolden" + "github.com/DNSControl/dnscontrol/v5/pkg/providers" + "github.com/DNSControl/dnscontrol/v5/providers/cloudflare" + "github.com/DNSControl/dnscontrol/v5/providers/ovh" ) +func TestReplaceIntegrationTargetTokensAzureAlias(t *testing.T) { + dc := models.MustNewDomainConfig("example.com") + rc := dc.MustNewRecordConfig("alias", 300, privatetypes.TypeAZUREALIAS, "A", + "/subscriptions/**subscription-id**/resourceGroups/**resource-group**/providers/Microsoft.Network/dnszones/example.com/A/target") + + replaceIntegrationTargetTokens(rc, "SUB123", "MyResourceGroup") + + want := "/subscriptions/SUB123/resourceGroups/myresourcegroup/providers/Microsoft.Network/dnszones/example.com/A/target" + if got := rc.AsAZUREALIAS().Target; got != want { + t.Fatalf("AZURE_ALIAS target = %q, want %q", got, want) + } + if rc.GetRDATA() == nil { + t.Fatal("AZURE_ALIAS RDATA is nil after placeholder replacement") + } + if rc.ComparableV3 == "" { + t.Fatal("AZURE_ALIAS ComparableV3 is empty after placeholder replacement") + } +} + var ( providerFlag = flag.String("provider", "", "Provider to run (if empty, deduced from -profile)") profileFlag = flag.String("profile", "", "Entry in profiles.json to use (if empty, copied from -provider)") - enableCFWorkers = flag.Bool("cfworkers", true, "enable CF worker tests (default false)") - enableCFRedirectMode = flag.Bool("cfredirect", true, "enable CF SingleRedirect tests (default false)") + recordFlag = flag.Bool("record", false, "Write the record conversion inputs seen during the run") + recordDirFlag = flag.String("recorddir", "", "Directory to record into, and implies -record (default: the provider's test_data directory)") + enableCFWorkers = flag.Bool("cfworkers", true, "enable CF worker tests (default true)") + enableCFRedirectMode = flag.Bool("cfredirect", true, "enable CF SingleRedirect tests (default true)") enableCFFlatten = flag.Bool("cfflatten", false, "enable CF CNAME flattening tests (requires paid plan, default false)") enableCFTags = flag.Bool("cftags", false, "enable CF tag tests (requires paid plan, default false)") + disableListZones = flag.Bool("disablelistzones", false, "disable ListZones() (OVH only)") ) +// recorder accumulates the conversion inputs of every provider call made by +// this run, and is written out when -record is given. +var recorder = providergolden.NewRecorder() + func init() { testing.Init() @@ -38,6 +68,10 @@ func panicOnErr(err error) { } func getProvider(t *testing.T) (providers.DNSServiceProvider, string, map[string]string) { + if flag.NArg() != 0 { + t.Fatalf("unexpected argument %q; the recording directory is set with -recorddir", flag.Arg(0)) + } + if *providerFlag == "" && *profileFlag == "" { t.Log("No -provider or -profile specified") return nil, "", nil @@ -112,7 +146,18 @@ func getProvider(t *testing.T) (providers.DNSServiceProvider, string, map[string metadata = []byte(`{ ` + strings.Join(items, `, `) + ` }`) } - provider, err := providers.CreateDNSProvider(profileType, cfg, metadata) + // The -disablelistzones flag is only for OVH at this time. The API key we + // use for integration tests does not have the ability to issue the + // ListZones API call. Therefore, we added this hack. + if *disableListZones { + ovh.NoListZone = true + } + + var createOptions []providers.CreateOption + if *recordFlag || *recordDirFlag != "" { + createOptions = append(createOptions, providers.WithConversionObserver(recorder.ForDomain(cfg["domain"]))) + } + provider, err := providers.CreateDNSProvider(profileType, cfg, metadata, createOptions...) if err != nil { t.Fatal(err) } @@ -124,5 +169,34 @@ func getProvider(t *testing.T) (providers.DNSServiceProvider, string, map[string } } + if *recordFlag || *recordDirFlag != "" { + dir, err := recordingDir(provider) + if err != nil { + t.Fatal(err) + } + t.Cleanup(func() { writeRecording(t, dir) }) + return provider, cfg["domain"], cfg + } + return provider, cfg["domain"], cfg } + +// recordingDir is where a recording of p is written: -recorddir when it is +// given, and otherwise p's own test_data directory. +func recordingDir(p providers.DNSServiceProvider) (string, error) { + if *recordDirFlag != "" { + return providergolden.ResolveDir(*recordDirFlag) + } + return providergolden.TestdataDir(p) +} + +// writeRecording writes every observed conversion input/output pair to dir. +func writeRecording(t *testing.T, dir string) { + written, err := recorder.WriteTo(dir) + for _, path := range written { + t.Logf("Recorded %s", path) + } + if err != nil { + t.Error(err) + } +} diff --git a/integrationTest/integration_test.go b/integrationTest/integration_test.go index dcbb18754d..e0bd33509e 100644 --- a/integrationTest/integration_test.go +++ b/integrationTest/integration_test.go @@ -3,18 +3,15 @@ package main // Data-driven tests that exercize the DNS Provider APIs. import ( - "runtime/debug" "strings" "testing" - "github.com/DNSControl/dnscontrol/v4/models" - "github.com/DNSControl/dnscontrol/v4/pkg/providers" - _ "github.com/DNSControl/dnscontrol/v4/pkg/providers/_all" - _ "github.com/DNSControl/dnscontrol/v4/pkg/rtype" + "github.com/DNSControl/dnscontrol/v5/models" + "github.com/DNSControl/dnscontrol/v5/pkg/providers" + _ "github.com/DNSControl/dnscontrol/v5/pkg/providers/_all" ) func TestDNSProviders(t *testing.T) { - debug.SetTraceback("all") provider, domain, cfg := getProvider(t) if provider == nil { return @@ -35,8 +32,7 @@ func TestMakeTests(t *testing.T) { } globalDC = dc globalDCN = dc.DomainNameVarieties() - - debug.SetTraceback("all") + globalCfg = map[string]string{} _ = makeTests() } @@ -76,7 +72,7 @@ func makeTests() []*TestGroup { // whether or not a certain kind of record can be created and // deleted. - // emptyzone() is the same as tc("Empty"). It removes all records. + // tcEmptyZone() is the same as tc("Empty"). It removes all records. // Each testgroup() begins with tcEmptyZone() automagically. You do not // have to include the tcEmptyZone() in each testgroup(). @@ -141,8 +137,8 @@ func makeTests() []*TestGroup { // Same test, but do it with a wildcard. testgroup("Protocol-Wildcard", not("HEDNS"), // Not supported by dns.he.net due to abuse - tc("Create wildcard", a("*", "3.3.3.3"), a("www", "5.5.5.5")), - tc("Delete wildcard", a("www", "5.5.5.5")), + tc("Create wildcard", a("*", "3.3.3.3"), a("www", "5.4.5.4")), + tc("Delete wildcard", a("www", "5.4.5.4")), ), ///// Test the basic DNS types @@ -193,7 +189,8 @@ func makeTests() []*TestGroup { "NAMECHEAP", ), tc("Create MX", mx("testmx", 5, "foo.com.")), - tc("Change MX p", mx("testmx", 100, "foo.com.")), + // TENCENT restricts MX preference to 1-50 + tc("Change MX p", mx("testmx", 50, "foo.com.")), ), testgroup("RP", @@ -238,11 +235,12 @@ func makeTests() []*TestGroup { ), testgroup("manyTypesAtOnce", - tc("CreateManyTypesAtLabel", a("www", "1.1.1.1"), mx("testmx", 5, "foo.com."), mx("testmx", 100, "bar.com.")), + // TENCENT restricts MX preference to 1-50 + tc("CreateManyTypesAtLabel", a("www", "1.1.1.1"), mx("testmx", 5, "foo.com."), mx("testmx", 50, "bar.com.")), tcEmptyZone(), tc("Create an A record", a("www", "1.1.1.1")), tc("Add Type At Label", a("www", "1.1.1.1"), mx("testmx", 5, "foo.com.")), - tc("Add Type At Label", a("www", "1.1.1.1"), mx("testmx", 5, "foo.com."), mx("testmx", 100, "bar.com.")), + tc("Add Type At Label", a("www", "1.1.1.1"), mx("testmx", 5, "foo.com."), mx("testmx", 50, "bar.com.")), ), // Exercise TTL operations. @@ -252,13 +250,16 @@ func makeTests() []*TestGroup { // weirdest edge-case we've ever seen. testgroup("Attl", + not("DESEC"), // deSEC does not support TTL lower than 3600. not("LINODE"), // Linode does not support arbitrary TTLs: both are rounded up to 3600. not("OPENWRT"), // OpenWRT does not support per record TTL + not("NETCUP"), // NETCUP does not support custom TTLs. tc("Create Arc", ttl(a("testa", "1.1.1.1"), 333)), tc("Change TTL", ttl(a("testa", "1.1.1.1"), 999)), ), testgroup("TTL", + not("DESEC"), // deSEC does not support TTL lower than 3600. not("NETCUP"), // NETCUP does not support TTLs. not("LINODE"), // Linode does not support arbitrary TTLs: 666 and 1000 are both rounded up to 3600. not("OPENWRT"), // OpenWRT does not support per record TTL @@ -433,6 +434,7 @@ func makeTests() []*TestGroup { testgroup("NullMX", not( "TRANSIP", // TRANSIP is slow and doesn't support NullMX. Skip to save time. + "LINODE", // Linode doesn't support setting a null MX record on a subdomain ), tc("create", // Install a Null MX. a("nmx", "1.2.3.3"), // Install this so it is ready for the next tc() @@ -491,17 +493,21 @@ func makeTests() []*TestGroup { testgroup("NS only APEX", not( "AZURE_PRIVATE_DNS", // Apex NS records are managed by Azure. + "BUNNY_DNS", // Apex NS records are managed by BunnyDNS. "DNSCALE", // Apex NS records are managed by DNScale. "DNSIMPLE", // Does not support NS records nor subdomains. "DYNU", // Apex NS records are managed by Dynu. "EXOSCALE", // Not supported. "GANDI_V5", // "Gandi does not support changing apex NS records. Ignoring ns1.foo.com." + "GIDINET", // "GIDINET does not support modifying NS records at apex." "JOKER", // Not supported via the Zone API. - "NAMEDOTCOM", // "Ignores @ for NS records" "NAMECHEAP", // cannot handle single NS at apex but does handle dual + "NAMEDOTCOM", // "Ignores @ for NS records" "NETCUP", // NS records not currently supported. "NEXDNS", // The apex NS records follow the zone's nameserver group and are not editable. + "NS1", // Test leaves NS1 in a confused state. "PORKBUN", // Record ignored. + "REALTIMEREGISTER", // "Cannot be a SOA level record for type NS" "SAKURACLOUD", // Silently ignores requests to remove NS at @. "TRANSIP", // "it is not allowed to have an NS for an @ record" "VERCEL", // "invalid_name - Cannot set NS records at the root level. Only subdomain NS records are supported" @@ -577,7 +583,7 @@ func makeTests() []*TestGroup { tc("TXT with semicolon ws", txt("foosc2", `wssemi ; colon`)), tc("TXT interior ws", txt("foosp", "with spaces")), - // tc("TXT leading ws", txt("foowsb", " leadingspace")), + //c("TXT leading ws", txt("foowsb", " leadingspace")), tc("TXT trailing ws", txt("foows1", "trailingws ")), // Vultr syntax-checks TXT records with SPF contents. @@ -720,10 +726,12 @@ func makeTests() []*TestGroup { not( "AZURE_DNS", // Removed because it is too slow "AZURE_PRIVATE_DNS", // Removed because it is too slow + "CLOUDNS", // Removed because it is too slow "CLOUDFLAREAPI", // Infinite pagesize but due to slow speed, skipping. - "CNR", // Test beaks limits. + "CNR", // Test breaks limits. // "CSCGLOBAL", // Doesn't page. Works fine. Due to the slow API we skip. "DESEC", // Skip due to daily update limits. + "DNSIMPLE", // Daily update quota. "DIGITALOCEAN", // No paging. Why bother? "FORTIGATE", // No paging "GANDI_V5", // Their API is so damn slow. We'll add it back as needed. @@ -744,9 +752,11 @@ func makeTests() []*TestGroup { only( // "AZURE_DNS", // Removed because it is too slow // "AZURE_PRIVATE_DNS", // Removed because it is too slow + // "CLOUDNS", // Removed because it is too slow // "CLOUDFLAREAPI", // Infinite pagesize but due to slow speed, skipping. // "CSCGLOBAL", // Doesn't page. Works fine. Due to the slow API we skip. // "DESEC", // Skip due to daily update limits. + // "DNSIMPLE", // Daily update quota. // "GANDI_V5", // Their API is so damn slow. We'll add it back as needed. // "GCLOUD", "ORACLE", @@ -761,9 +771,11 @@ func makeTests() []*TestGroup { // "AKAMAIEDGEDNS", // No paging done. No need to test. // "AZURE_DNS", // Too slow // "AZURE_PRIVATE_DNS", // Too slow + // "CLOUDNS", // Removed because it is too slow // "CLOUDFLAREAPI", // Fails with >1000 corrections. See https://github.com/DNSControl/dnscontrol/issues/1440 // "CSCGLOBAL", // Doesn't page. Works fine. Due to the slow API we skip. // "DESEC", // Skip due to daily update limits. + // "DNSIMPLE", // Daily update quota. // "GANDI_V5", // Their API is so damn slow. We'll add it back as needed. "GCLOUD", // "HEDNS", // No paging done. No need to test. @@ -858,7 +870,10 @@ func makeTests() []*TestGroup { naptr("test", 100, 10, "U", "E2U+sip", "!^.*$!sip:customer-service@example.com!", "."), naptr("test", 102, 10, "U", "E2U+email", "!^.*$!mailto:information@example.com!", "."), ), - tc("NAPTR delete second record", naptr("test", 100, 10, "U", "E2U+sip", "!^.*$!sip:customer-service@example.com!", ".")), + // AllowNoChanges: providers that audit-reject multiple NAPTRs at + // one label (e.g. GIGAHOST) skip "NAPTR second record" above, so + // this state may already be converged. + tc("NAPTR delete second record", naptr("test", 100, 10, "U", "E2U+sip", "!^.*$!sip:customer-service@example.com!", ".")).AllowNoChanges(), tc("NAPTR change order", naptr("test", 103, 10, "U", "E2U+email", "!^.*$!mailto:information@example.com!", ".")), tc("NAPTR change preference", naptr("test", 103, 20, "U", "E2U+email", "!^.*$!mailto:information@example.com!", ".")), tc("NAPTR change flags", naptr("test", 103, 20, "A", "E2U+email", "!^.*$!mailto:information@example.com!", ".")), @@ -917,11 +932,14 @@ func makeTests() []*TestGroup { testgroup("SRV", requires(providers.CanUseSRV), not( + "NETCUP", // NETCUP does not support per record TTL "OPENWRT", // OpenWRT does not support per record TTL "NAMECHEAP", // Namecheap does not support per record TTL + "UNIFI", // Per record TTLs not supported. ), tc("Create SRV333", ttl(srv("_sip._tcp", 5, 6, 7, "foo.com."), 333)), - tc("Change TTL999", ttl(srv("_sip._tcp", 5, 6, 7, "foo.com."), 999)), + // The next TTL needs to fall in a different bucket than the previous one for LINODE + tc("Change TTL4400", ttl(srv("_sip._tcp", 5, 6, 7, "foo.com."), 4400)), ), testgroup("SSHFP", @@ -945,7 +963,7 @@ func makeTests() []*TestGroup { testgroup("DS", requires(providers.CanUseDS), - not("CLOUDFLAREAPI"), + not("CLOUDFLAREAPI", "POWERDNS"), // PowerDNS: DS records are not supported for the apex domain. // Use a valid digest value here. Some providers verify that a valid digest is in use. See RFC 4034 and // https://www.iana.org/assignments/dns-sec-alg-numbers/dns-sec-alg-numbers.xhtml // https://www.iana.org/assignments/ds-rr-types/ds-rr-types.xhtml @@ -1070,6 +1088,7 @@ func makeTests() []*TestGroup { testgroup("ALIAS to nonfqdn", requires(providers.CanUseAlias), + not("DNSMADEEASY"), // DME validates ANAME target resolvability at create time; an unpublished in-zone target can't resolve tc("ALIAS at root", a("foo", "1.2.3.4"), alias("@", "foo"), @@ -1305,8 +1324,10 @@ func makeTests() []*TestGroup { ), // Tencent Cloud DNSPod resolution lines and weighted routing. + // China site line list: https://cloud.tencent.com/document/product/1427/56167 testgroup("TENCENTDNS_LINE_WEIGHT", only("TENCENTDNS"), + alltrue(!strings.EqualFold(globalCfg["site"], "intl")), tc("create records on the default and telecom lines", a("tencent-line", "1.2.3.4"), withMeta(a("tencent-line", "1.2.3.4"), map[string]string{ @@ -1594,14 +1615,14 @@ func makeTests() []*TestGroup { testgroup("IGNORE main", // Vercel has a very strict rate limit, let's just skip IGNORE* tests for Vercel not("VERCEL"), - - not("NETBIRD"), // MX/TXT records not supported - not("OPENWRT"), // OpenWRT does not support TXT records + not("FORTIGATE"), // TXT records not supported + not("NETBIRD"), // MX/TXT records not supported + not("OPENWRT"), // OpenWRT does not support TXT records tc("Create some records", a("foo", "1.2.3.4"), a("foo", "2.3.4.5"), txt("foo", "simple"), - a("bar", "5.5.5.5"), + a("bar", "5.4.5.4"), cname("mail", "ghs.googlehosted.com."), ), @@ -1612,7 +1633,7 @@ func makeTests() []*TestGroup { // a("foo", "1.2.3.4"), // a("foo", "2.3.4.5"), // txt("foo", "simple"), - a("bar", "5.5.5.5"), + a("bar", "5.4.5.4"), cname("mail", "ghs.googlehosted.com."), ignore("foo", "", ""), ).ExpectNoChanges(), @@ -1620,7 +1641,7 @@ func makeTests() []*TestGroup { a("foo", "1.2.3.4"), a("foo", "2.3.4.5"), txt("foo", "simple"), - a("bar", "5.5.5.5"), + a("bar", "5.4.5.4"), cname("mail", "ghs.googlehosted.com."), ).ExpectNoChanges(), @@ -1628,7 +1649,7 @@ func makeTests() []*TestGroup { // a("foo", "1.2.3.4"), // a("foo", "2.3.4.5"), txt("foo", "simple"), - a("bar", "5.5.5.5"), + a("bar", "5.4.5.4"), cname("mail", "ghs.googlehosted.com."), ignore("foo", "A", ""), ).ExpectNoChanges(), @@ -1636,7 +1657,7 @@ func makeTests() []*TestGroup { a("foo", "1.2.3.4"), a("foo", "2.3.4.5"), txt("foo", "simple"), - a("bar", "5.5.5.5"), + a("bar", "5.4.5.4"), cname("mail", "ghs.googlehosted.com."), ).ExpectNoChanges(), @@ -1644,7 +1665,7 @@ func makeTests() []*TestGroup { // a("foo", "1.2.3.4"), a("foo", "2.3.4.5"), txt("foo", "simple"), - a("bar", "5.5.5.5"), + a("bar", "5.4.5.4"), cname("mail", "ghs.googlehosted.com."), ignore("foo", "A", "1.2.3.4"), ).ExpectNoChanges(), @@ -1652,7 +1673,7 @@ func makeTests() []*TestGroup { a("foo", "1.2.3.4"), a("foo", "2.3.4.5"), txt("foo", "simple"), - a("bar", "5.5.5.5"), + a("bar", "5.4.5.4"), cname("mail", "ghs.googlehosted.com."), ).ExpectNoChanges(), @@ -1660,7 +1681,7 @@ func makeTests() []*TestGroup { // a("foo", "1.2.3.4"), // a("foo", "2.3.4.5"), txt("foo", "simple"), - // a("bar", "5.5.5.5"), + // a("bar", "5.4.5.4"), cname("mail", "ghs.googlehosted.com."), ignore("", "A", ""), ).ExpectNoChanges(), @@ -1668,7 +1689,7 @@ func makeTests() []*TestGroup { a("foo", "1.2.3.4"), a("foo", "2.3.4.5"), txt("foo", "simple"), - a("bar", "5.5.5.5"), + a("bar", "5.4.5.4"), cname("mail", "ghs.googlehosted.com."), ).ExpectNoChanges(), @@ -1676,7 +1697,7 @@ func makeTests() []*TestGroup { a("foo", "1.2.3.4"), // a("foo", "2.3.4.5"), txt("foo", "simple"), - a("bar", "5.5.5.5"), + a("bar", "5.4.5.4"), cname("mail", "ghs.googlehosted.com."), ignore("", "A", "2.3.4.5"), ).ExpectNoChanges(), @@ -1684,7 +1705,7 @@ func makeTests() []*TestGroup { a("foo", "1.2.3.4"), a("foo", "2.3.4.5"), txt("foo", "simple"), - a("bar", "5.5.5.5"), + a("bar", "5.4.5.4"), cname("mail", "ghs.googlehosted.com."), ).ExpectNoChanges(), @@ -1692,7 +1713,7 @@ func makeTests() []*TestGroup { a("foo", "1.2.3.4"), // a("foo", "2.3.4.5"), txt("foo", "simple"), - a("bar", "5.5.5.5"), + a("bar", "5.4.5.4"), cname("mail", "ghs.googlehosted.com."), ignore("", "", "2.3.4.5"), ).ExpectNoChanges(), @@ -1700,7 +1721,7 @@ func makeTests() []*TestGroup { a("foo", "1.2.3.4"), a("foo", "2.3.4.5"), txt("foo", "simple"), - a("bar", "5.5.5.5"), + a("bar", "5.4.5.4"), cname("mail", "ghs.googlehosted.com."), ).ExpectNoChanges(), @@ -1709,7 +1730,7 @@ func makeTests() []*TestGroup { // a("foo", "1.2.3.4"), // a("foo", "2.3.4.5"), // txt("foo", "simple"), - // a("bar", "5.5.5.5"), + // a("bar", "5.4.5.4"), cname("mail", "ghs.googlehosted.com."), ignore("", "A,TXT", ""), ).ExpectNoChanges(), @@ -1717,7 +1738,7 @@ func makeTests() []*TestGroup { a("foo", "1.2.3.4"), a("foo", "2.3.4.5"), txt("foo", "simple"), - a("bar", "5.5.5.5"), + a("bar", "5.4.5.4"), cname("mail", "ghs.googlehosted.com."), ).ExpectNoChanges(), @@ -1726,7 +1747,7 @@ func makeTests() []*TestGroup { a("foo", "1.2.3.4"), a("foo", "2.3.4.5"), txt("foo", "simple"), - a("bar", "5.5.5.5"), + a("bar", "5.4.5.4"), // cname("mail", "ghs.googlehosted.com."), ignore("", "CNAME", "*.googlehosted.com."), ).ExpectNoChanges(), @@ -1734,23 +1755,23 @@ func makeTests() []*TestGroup { a("foo", "1.2.3.4"), a("foo", "2.3.4.5"), txt("foo", "simple"), - a("bar", "5.5.5.5"), + a("bar", "5.4.5.4"), cname("mail", "ghs.googlehosted.com."), ).ExpectNoChanges(), ), // Same as "main" but with an apex ("@") record. testgroup("IGNORE apex", + not("FORTIGATE"), // TXT records not supported // Vercel has a very strict rate limit, let's just skip IGNORE* tests for Vercel not("VERCEL"), - not("NETBIRD"), // MX/TXT records not supported not("OPENWRT"), // OpenWRT does not support TXT records tc("Create some records", a("@", "1.2.3.4"), a("@", "2.3.4.5"), txt("@", "simple"), - a("bar", "5.5.5.5"), + a("bar", "5.4.5.4"), cname("mail", "ghs.googlehosted.com."), ), @@ -1761,7 +1782,7 @@ func makeTests() []*TestGroup { // a("@", "1.2.3.4"), // a("@", "2.3.4.5"), // txt("@", "simple"), - a("bar", "5.5.5.5"), + a("bar", "5.4.5.4"), cname("mail", "ghs.googlehosted.com."), ignore("@", "", ""), // ignore("", "NS", ""), @@ -1773,7 +1794,7 @@ func makeTests() []*TestGroup { a("@", "1.2.3.4"), a("@", "2.3.4.5"), txt("@", "simple"), - a("bar", "5.5.5.5"), + a("bar", "5.4.5.4"), cname("mail", "ghs.googlehosted.com."), ).ExpectNoChanges(), @@ -1781,7 +1802,7 @@ func makeTests() []*TestGroup { // a("@", "1.2.3.4"), // a("@", "2.3.4.5"), txt("@", "simple"), - a("bar", "5.5.5.5"), + a("bar", "5.4.5.4"), cname("mail", "ghs.googlehosted.com."), ignore("@", "A", ""), ).ExpectNoChanges(), @@ -1789,7 +1810,7 @@ func makeTests() []*TestGroup { a("@", "1.2.3.4"), a("@", "2.3.4.5"), txt("@", "simple"), - a("bar", "5.5.5.5"), + a("bar", "5.4.5.4"), cname("mail", "ghs.googlehosted.com."), ).ExpectNoChanges(), @@ -1797,7 +1818,7 @@ func makeTests() []*TestGroup { // a("@", "1.2.3.4"), a("@", "2.3.4.5"), txt("@", "simple"), - a("bar", "5.5.5.5"), + a("bar", "5.4.5.4"), cname("mail", "ghs.googlehosted.com."), ignore("@", "A", "1.2.3.4"), // NB(tlim): .UnsafeIgnore is needed because the NS records @@ -1808,7 +1829,7 @@ func makeTests() []*TestGroup { a("@", "1.2.3.4"), a("@", "2.3.4.5"), txt("@", "simple"), - a("bar", "5.5.5.5"), + a("bar", "5.4.5.4"), cname("mail", "ghs.googlehosted.com."), ).ExpectNoChanges(), @@ -1816,7 +1837,7 @@ func makeTests() []*TestGroup { // a("@", "1.2.3.4"), // a("@", "2.3.4.5"), txt("@", "simple"), - // a("bar", "5.5.5.5"), + // a("bar", "5.4.5.4"), cname("mail", "ghs.googlehosted.com."), ignore("", "A", ""), ).ExpectNoChanges(), @@ -1824,7 +1845,7 @@ func makeTests() []*TestGroup { a("@", "1.2.3.4"), a("@", "2.3.4.5"), txt("@", "simple"), - a("bar", "5.5.5.5"), + a("bar", "5.4.5.4"), cname("mail", "ghs.googlehosted.com."), ).ExpectNoChanges(), @@ -1832,7 +1853,7 @@ func makeTests() []*TestGroup { a("@", "1.2.3.4"), // a("@", "2.3.4.5"), txt("@", "simple"), - a("bar", "5.5.5.5"), + a("bar", "5.4.5.4"), cname("mail", "ghs.googlehosted.com."), ignore("", "A", "2.3.4.5"), ).ExpectNoChanges(), @@ -1840,7 +1861,7 @@ func makeTests() []*TestGroup { a("@", "1.2.3.4"), a("@", "2.3.4.5"), txt("@", "simple"), - a("bar", "5.5.5.5"), + a("bar", "5.4.5.4"), cname("mail", "ghs.googlehosted.com."), ).ExpectNoChanges(), @@ -1848,7 +1869,7 @@ func makeTests() []*TestGroup { a("@", "1.2.3.4"), // a("@", "2.3.4.5"), txt("@", "simple"), - a("bar", "5.5.5.5"), + a("bar", "5.4.5.4"), cname("mail", "ghs.googlehosted.com."), ignore("", "", "2.3.4.5"), ).ExpectNoChanges(), @@ -1856,7 +1877,7 @@ func makeTests() []*TestGroup { a("@", "1.2.3.4"), a("@", "2.3.4.5"), txt("@", "simple"), - a("bar", "5.5.5.5"), + a("bar", "5.4.5.4"), cname("mail", "ghs.googlehosted.com."), ).ExpectNoChanges(), @@ -1865,7 +1886,7 @@ func makeTests() []*TestGroup { // a("@", "1.2.3.4"), // a("@", "2.3.4.5"), // txt("@", "simple"), - // a("bar", "5.5.5.5"), + // a("bar", "5.4.5.4"), cname("mail", "ghs.googlehosted.com."), ignore("", "A,TXT", ""), ).ExpectNoChanges(), @@ -1873,7 +1894,7 @@ func makeTests() []*TestGroup { a("@", "1.2.3.4"), a("@", "2.3.4.5"), txt("@", "simple"), - a("bar", "5.5.5.5"), + a("bar", "5.4.5.4"), cname("mail", "ghs.googlehosted.com."), ).ExpectNoChanges(), ), @@ -1925,14 +1946,14 @@ func makeTests() []*TestGroup { testgroup("IGNORE wilds", // Vercel has a very strict rate limit, let's just skip IGNORE* tests for Vercel not("VERCEL"), - - not("NETBIRD"), // MX/TXT records not supported - not("OPENWRT"), // OpenWRT does not support TXT records + not("FORTIGATE"), // TXT records not supported + not("NETBIRD"), // MX/TXT records not supported + not("OPENWRT"), // OpenWRT does not support TXT records tc("Create some records", a("foo.bat", "1.2.3.4"), a("foo.bat", "2.3.4.5"), txt("foo.bat", "simple"), - a("bar.bat", "5.5.5.5"), + a("bar.bat", "5.4.5.4"), cname("mail.bat", "ghs.googlehosted.com."), ), @@ -1940,7 +1961,7 @@ func makeTests() []*TestGroup { // a("foo.bat", "1.2.3.4"), // a("foo.bat", "2.3.4.5"), // txt("foo.bat", "simple"), - a("bar.bat", "5.5.5.5"), + a("bar.bat", "5.4.5.4"), cname("mail.bat", "ghs.googlehosted.com."), ignore("foo.*", "", ""), ).ExpectNoChanges(), @@ -1948,7 +1969,7 @@ func makeTests() []*TestGroup { a("foo.bat", "1.2.3.4"), a("foo.bat", "2.3.4.5"), txt("foo.bat", "simple"), - a("bar.bat", "5.5.5.5"), + a("bar.bat", "5.4.5.4"), cname("mail.bat", "ghs.googlehosted.com."), ).ExpectNoChanges(), @@ -1956,7 +1977,7 @@ func makeTests() []*TestGroup { // a("foo.bat", "1.2.3.4"), // a("foo.bat", "2.3.4.5"), txt("foo.bat", "simple"), - // a("bar.bat", "5.5.5.5"), + // a("bar.bat", "5.4.5.4"), cname("mail.bat", "ghs.googlehosted.com."), ignore("*.bat", "A", ""), ).ExpectNoChanges(), @@ -1964,7 +1985,7 @@ func makeTests() []*TestGroup { a("foo.bat", "1.2.3.4"), a("foo.bat", "2.3.4.5"), txt("foo.bat", "simple"), - a("bar.bat", "5.5.5.5"), + a("bar.bat", "5.4.5.4"), cname("mail.bat", "ghs.googlehosted.com."), ).ExpectNoChanges(), @@ -1972,7 +1993,7 @@ func makeTests() []*TestGroup { a("foo.bat", "1.2.3.4"), a("foo.bat", "2.3.4.5"), txt("foo.bat", "simple"), - a("bar.bat", "5.5.5.5"), + a("bar.bat", "5.4.5.4"), // cname("mail.bat", "ghs.googlehosted.com."), ignore("", "", "*.googlehosted.com."), ).ExpectNoChanges(), @@ -1980,7 +2001,7 @@ func makeTests() []*TestGroup { a("foo.bat", "1.2.3.4"), a("foo.bat", "2.3.4.5"), txt("foo.bat", "simple"), - a("bar.bat", "5.5.5.5"), + a("bar.bat", "5.4.5.4"), cname("mail.bat", "ghs.googlehosted.com."), ).ExpectNoChanges(), ), @@ -2190,11 +2211,11 @@ func makeTests() []*TestGroup { only("OVH"), tc("Create TXT", txt("spf", "v=spf1 ip4:99.99.99.99 -all"), - txt("dkim", "v=DKIM1;t=s;p=MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCzwOUgwGWVIwQG8PBl89O37BdaoqEd/rT6r/Iot4PidtPJkPbVxWRi0mUgduAnsO8zHCz2QKAd5wPe9+l+Stwy6e0h27nAOkI/Edx3qwwWqWSUfwfIBWZG+lrFrhWgSIWCj2/TMkMMzBZJdhVszCzdGQiNPkGvKgjfqW5T0TZt0QIDAQAB"), + txt("dkim._domainkey", "v=DKIM1;t=s;p=MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCzwOUgwGWVIwQG8PBl89O37BdaoqEd/rT6r/Iot4PidtPJkPbVxWRi0mUgduAnsO8zHCz2QKAd5wPe9+l+Stwy6e0h27nAOkI/Edx3qwwWqWSUfwfIBWZG+lrFrhWgSIWCj2/TMkMMzBZJdhVszCzdGQiNPkGvKgjfqW5T0TZt0QIDAQAB"), txt("_dmarc", "v=DMARC1; p=none; rua=mailto:dmarc@yourdomain.com")), tc("Update TXT", txt("spf", "v=spf1 a mx -all"), - txt("dkim", "v=DKIM1;t=s;p=MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDk72yk6UML8LGIXFobhvx6UDUntqGzmyie2FLMyrOYk1C7CVYR139VMbO9X1rFvZ8TaPnMCkMbuEGWGgWNc27MLYKfI+wP/SYGjRS98TNl9wXxP8tPfr6id5gks95sEMMaYTu8sctnN6sBOvr4hQ2oipVcBn/oxkrfhqvlcat5gQIDAQAB"), + txt("dkim._domainkey", "v=DKIM1;t=s;p=MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDk72yk6UML8LGIXFobhvx6UDUntqGzmyie2FLMyrOYk1C7CVYR139VMbO9X1rFvZ8TaPnMCkMbuEGWGgWNc27MLYKfI+wP/SYGjRS98TNl9wXxP8tPfr6id5gks95sEMMaYTu8sctnN6sBOvr4hQ2oipVcBn/oxkrfhqvlcat5gQIDAQAB"), txt("_dmarc", "v=DMARC1; p=none; rua=mailto:dmarc@example.com")), ), @@ -2202,40 +2223,61 @@ func makeTests() []*TestGroup { only("OVH"), tc("Create native OVH records", ovhspf("spf", "v=spf1 ip4:99.99.99.99 -all"), - ovhdkim("dkim", "v=DKIM1;t=s;p=MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCzwOUgwGWVIwQG8PBl89O37BdaoqEd/rT6r/Iot4PidtPJkPbVxWRi0mUgduAnsO8zHCz2QKAd5wPe9+l+Stwy6e0h27nAOkI/Edx3qwwWqWSUfwfIBWZG+lrFrhWgSIWCj2/TMkMMzBZJdhVszCzdGQiNPkGvKgjfqW5T0TZt0QIDAQAB"), + ovhdkim("dkim._domainkey", "v=DKIM1;t=s;p=MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCzwOUgwGWVIwQG8PBl89O37BdaoqEd/rT6r/Iot4PidtPJkPbVxWRi0mUgduAnsO8zHCz2QKAd5wPe9+l+Stwy6e0h27nAOkI/Edx3qwwWqWSUfwfIBWZG+lrFrhWgSIWCj2/TMkMMzBZJdhVszCzdGQiNPkGvKgjfqW5T0TZt0QIDAQAB"), ovhdmarc("_dmarc", "v=DMARC1; p=none; rua=mailto:dmarc@yourdomain.com")), tc("Update native OVH records", ovhspf("spf", "v=spf1 a mx -all"), - ovhdkim("dkim", "v=DKIM1;t=s;p=MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDk72yk6UML8LGIXFobhvx6UDUntqGzmyie2FLMyrOYk1C7CVYR139VMbO9X1rFvZ8TaPnMCkMbuEGWGgWNc27MLYKfI+wP/SYGjRS98TNl9wXxP8tPfr6id5gks95sEMMaYTu8sctnN6sBOvr4hQ2oipVcBn/oxkrfhqvlcat5gQIDAQAB"), + ovhdkim("dkim._domainkey", "v=DKIM1;t=s;p=MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDk72yk6UML8LGIXFobhvx6UDUntqGzmyie2FLMyrOYk1C7CVYR139VMbO9X1rFvZ8TaPnMCkMbuEGWGgWNc27MLYKfI+wP/SYGjRS98TNl9wXxP8tPfr6id5gks95sEMMaYTu8sctnN6sBOvr4hQ2oipVcBn/oxkrfhqvlcat5gQIDAQAB"), ovhdmarc("_dmarc", "v=DMARC1; p=none; rua=mailto:dmarc@example.com")), + tc("Create native OVH DKIM record longer than 255 bytes", + ovhdkim("dkimbig._domainkey", "v=DKIM1; t=s; p=MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAtNHHaHjrlPU5hvNyp5LKkhINqUNo3rwvHP3RMYvBMdxs0W34SLMc52QSn+O8QN5P2rU9Hs3qiD5kaIjGfU77EwMnrUh0MhRgWPKED5R66/BXYh9tIv9aLBeGgrO8Tj1zvW2CO9HI9V5TcuEe8OKgY4EvtuBtlgG7DbM2fwm2VL9nbvM15hxQjAkDxfDNBLMXozsk86Fp9EzOwtUykRH1VoCusC0qYqmOMpPknDoJ2vJKZMm1Cpx0ICnsdWbmLVKPpgdBdj28jCXU/bm4jvXcSL9oGb3rBxVmpsgA+JHEZH2XMbDDzHjLnH7DsavP/Xth19KA/opQ4h6vFxAQOX+yzQIDAQAB")), ), // CLOUDNS features - testgroup("CLOUDNS geodns tests", - only("CLOUDNS"), - tc("Add record with geodns code", withMeta(a("@", "1.2.3.4"), map[string]string{ - "cloudns_geodns_code": "US", - })), - tc("Update record with default geodns code", withMeta(a("@", "1.2.3.4"), map[string]string{ - "cloudns_geodns_code": "DEFAULT", - })), - tc("Update record with geodns code", withMeta(a("@", "1.2.3.4"), map[string]string{ - "cloudns_geodns_code": "BR", - })), - tc("Delete metadata from record", a("@", "1.2.3.4")), - tc("Update a record with the value DEFAULT after removing the metadata should do nothing", withMeta(a("@", "1.2.3.4"), map[string]string{ - "cloudns_geodns_code": "DEFAULT", - })).ExpectNoChanges(), - ), + // NB(tlim): This is disabled because we don't have access to an account + // with this feature. Neither Free nor Premium include it. + // + // You know your account has geodns enabled if this outputs: "1" + // curl -X POST https://api.cloudns.net/dns/is-geodns-available.json -d "auth-id=YOUR_ID" -d "auth-password=YOUR_PASSWORD" | jq . + // + // testgroup("CLOUDNS geodns tests", + // only("CLOUDNS"), + // tc("Add record with geodns code", withMeta(a("@", "1.2.3.4"), map[string]string{ + // "cloudns_geodns_code": "US", + // })), + // tc("Update record with default geodns code", withMeta(a("@", "1.2.3.4"), map[string]string{ + // "cloudns_geodns_code": "DEFAULT", + // })), + // tc("Update record with geodns code", withMeta(a("@", "1.2.3.4"), map[string]string{ + // "cloudns_geodns_code": "BR", + // })), + // tc("Delete metadata from record", a("@", "1.2.3.4")), + // tc("Update a record with the value DEFAULT after removing the metadata should do nothing", withMeta(a("@", "1.2.3.4"), map[string]string{ + // "cloudns_geodns_code": "DEFAULT", + // })).ExpectNoChanges(), + // ), // PORKBUN features - testgroup("PORKBUN_URLFWD tests", + testgroup("PORKBUN url forwarding tests", only("PORKBUN"), - tc("Add a urlfwd", porkbunUrlfwd("urlfwd1", "http://example.com", "", "", "")), - tc("Update a urlfwd", porkbunUrlfwd("urlfwd1", "http://example.org", "", "", "")), - tc("Update a urlfwd with metadata", porkbunUrlfwd("urlfwd1", "http://example.org", "permanent", "no", "no")), + tc("Add a urlfwd", porkbunUrlfwd("urlfwd1", "http://example.com")), + tc("Update a urlfwd with metadata", withMeta(porkbunUrlfwd("urlfwd1", "http://example.com"), map[string]string{ + "type": "permanent", + "includePath": "yes", + "wildcard": "no", + })), + tc("Add a url", url("urlfwd2", "http://example.com")), + tc("Update a url with metadata", withMeta(url("urlfwd2", "http://example.com"), map[string]string{ + "includePath": "yes", + "wildcard": "no", + })), + tc("Add a url301", url301("urlfwd3", "http://example.com")), + tc("Update a url with metadata", withMeta(url301("urlfwd3", "http://example.com"), map[string]string{ + "includePath": "yes", + "wildcard": "no", + })), ), // GCORE features @@ -2319,8 +2361,8 @@ func makeTests() []*TestGroup { testgroup("Bunny DNS Pull Zone", only("BUNNY_DNS"), - tc("Create PZ", bunnyPullZone("@", "5269987")), - tc("Change PZ", bunnyPullZone("@", "5269992")), + tc("Create PZ", bunnyPullZone("@", "6214614")), + tc("Change PZ", bunnyPullZone("@", "6214615")), ), // HEDNS: Dynamic DNS @@ -2370,6 +2412,9 @@ func makeTests() []*TestGroup { ), ), + // Clear everything out. + testgroup("CLEAR"), //tc("Create A", a("testa", "1.1.1.1")), + // This MUST be the last test. testgroup("final", tc("final", txt("final", `TestDNSProviders was successful!`)), diff --git a/integrationTest/profiles.json b/integrationTest/profiles.json index 5ab6c34f80..53e2a7bfe5 100644 --- a/integrationTest/profiles.json +++ b/integrationTest/profiles.json @@ -131,7 +131,7 @@ }, "DNSIMPLE": { "TYPE": "DNSIMPLE", - "baseurl": "https://api.sandbox.dnsimple.com", + "baseurl": "$DNSIMPLE_BASEURL", "domain": "$DNSIMPLE_DOMAIN", "token": "$DNSIMPLE_TOKEN" }, @@ -417,6 +417,7 @@ "UNIFI": { "TYPE": "UNIFI", "api_key": "$UNIFI_API_KEY", + "console_id": "$UNIFI_CONSOLE_ID", "domain": "$UNIFI_DOMAIN", "host": "$UNIFI_HOST", "knownFailures": "26,43", diff --git a/integrationTest/provider_test.go b/integrationTest/provider_test.go index 220d520fe9..c072edd9a8 100644 --- a/integrationTest/provider_test.go +++ b/integrationTest/provider_test.go @@ -6,10 +6,10 @@ import ( "strings" "testing" - "github.com/DNSControl/dnscontrol/v4/models" - "github.com/DNSControl/dnscontrol/v4/pkg/nameservers" - "github.com/DNSControl/dnscontrol/v4/pkg/providers" - "github.com/DNSControl/dnscontrol/v4/pkg/zonerecs" + "github.com/DNSControl/dnscontrol/v5/models" + "github.com/DNSControl/dnscontrol/v5/pkg/nameservers" + "github.com/DNSControl/dnscontrol/v5/pkg/providers" + "github.com/DNSControl/dnscontrol/v5/pkg/zonerecs" ) // TestDualProviders verifies that providers labeled DocDualHost support having @@ -50,7 +50,12 @@ func TestDualProviders(t *testing.T) { t.Log("Clearing everything") run() // add bogus nameservers - dc.Records = []*models.RecordConfig{} + // Clear dc.Records first: getDomainConfigWithNameservers() already called + // AddNSRecords() to populate the provider's own NS records. Without this + // reset, the AddNSRecords() below appends a second copy of them, producing + // duplicate NS records that ByRecordSet providers (ROUTE53, GCLOUD, ...) + // reject ("Duplicate Resource Record" / "already exists"). + dc.Records = models.Records{} nsList, _ := models.ToNameservers([]string{"ns1.example.com", "ns2.example.com"}) dc.Nameservers = append(dc.Nameservers, nsList...) nameservers.AddNSRecords(dc) @@ -74,7 +79,7 @@ func TestDualProviders(t *testing.T) { } t.Log("Removing test nameservers") - dc.Records = []*models.RecordConfig{} + dc.Records = models.Records{} n := 0 for _, ns := range dc.Nameservers { if ns.Name == "ns1.example.com" || ns.Name == "ns2.example.com" { @@ -170,7 +175,7 @@ func TestDuplicateNameservers(t *testing.T) { } t.Log("Clearing everything") - dc.Records = []*models.RecordConfig{} + dc.Records = models.Records{} n := 0 for _, ns := range dc.Nameservers { if ns.Name == "ns1.example.com" || ns.Name == "ns2.example.com" { @@ -184,7 +189,7 @@ func TestDuplicateNameservers(t *testing.T) { run(0, "Clearing everything", true) // add bogus nameservers and duplicate nameservers - dc.Records = []*models.RecordConfig{} + dc.Records = models.Records{} nsList, _ := models.ToNameservers([]string{"ns1.example.com"}) dc.Nameservers = append(dc.Nameservers, dc.Nameservers...) dc.Nameservers = append(dc.Nameservers, nsList...) @@ -197,7 +202,7 @@ func TestDuplicateNameservers(t *testing.T) { run(0, "Expect no corrections on second run, but found %d.", false) t.Log("Removing test nameservers") - dc.Records = []*models.RecordConfig{} + dc.Records = models.Records{} n = 0 for _, ns := range dc.Nameservers { if ns.Name == "ns1.example.com" || ns.Name == "ns2.example.com" { diff --git a/integrationTest/recording_test.go b/integrationTest/recording_test.go new file mode 100644 index 0000000000..e06271a8b6 --- /dev/null +++ b/integrationTest/recording_test.go @@ -0,0 +1,49 @@ +package main + +// Test where a recording is written. + +import ( + "os" + "path/filepath" + "strings" + "testing" + + "github.com/DNSControl/dnscontrol/v5/pkg/providergolden" + "github.com/DNSControl/dnscontrol/v5/pkg/providers" +) + +func TestARecordingIsNamedAfterTheProvidersPackageNotItsType(t *testing.T) { + provider, err := providers.CreateDNSProvider("GANDI_V5", map[string]string{"token": "not used"}, nil) + if err != nil { + t.Fatal(err) + } + + name, err := providergolden.ProviderName(provider) + if err != nil { + t.Fatalf("ProviderName() error: %v", err) + } + if name != "gandiv5" { + t.Errorf("ProviderName() = %q, want %q", name, "gandiv5") + } +} + +func TestRecordingDirResolvesRecordDirFromTheModuleRoot(t *testing.T) { + rel := filepath.Join("providers", "bind", "test_data") + + old := *recordDirFlag + *recordDirFlag = rel + defer func() { *recordDirFlag = old }() + + dir, err := recordingDir(nil) + if err != nil { + t.Fatalf("recordingDir() error: %v", err) + } + if !filepath.IsAbs(dir) { + t.Fatalf("recordingDir() = %q, want an absolute path", dir) + } + + root := strings.TrimSuffix(dir, string(filepath.Separator)+rel) + if _, err := os.Stat(filepath.Join(root, "go.mod")); err != nil { + t.Errorf("recordingDir() = %q, want a path under the directory holding go.mod: %v", dir, err) + } +} diff --git a/main.go b/main.go index 47dc6bb028..0797d8c2a4 100644 --- a/main.go +++ b/main.go @@ -5,10 +5,11 @@ import ( "os" "runtime/debug" - "github.com/DNSControl/dnscontrol/v4/commands" - _ "github.com/DNSControl/dnscontrol/v4/pkg/providers/_all" - _ "github.com/DNSControl/dnscontrol/v4/pkg/rtype" - "github.com/DNSControl/dnscontrol/v4/pkg/version" + "github.com/DNSControl/dnscontrol/v5/commands" + _ "github.com/DNSControl/dnscontrol/v5/pkg/privatetypes" + _ "github.com/DNSControl/dnscontrol/v5/pkg/privatetypes/rdata" + _ "github.com/DNSControl/dnscontrol/v5/pkg/providers/_all" + "github.com/DNSControl/dnscontrol/v5/pkg/version" "github.com/fatih/color" ) diff --git a/models/addrecord.go b/models/addrecord.go new file mode 100644 index 0000000000..1b12697c57 --- /dev/null +++ b/models/addrecord.go @@ -0,0 +1,5 @@ +package models + +func (dc *DomainConfig) AddRecordConfig(rc *RecordConfig) { + dc.Records = append(dc.Records, rc) +} diff --git a/models/b_loc.go b/models/b_loc.go new file mode 100644 index 0000000000..b74c85c6d1 --- /dev/null +++ b/models/b_loc.go @@ -0,0 +1,44 @@ +package models + +import ( + "errors" + "fmt" + + dnsv2 "codeberg.org/miekg/dns" + "github.com/DNSControl/dnscontrol/v5/pkg/mustbe" + "github.com/DNSControl/dnscontrol/v5/pkg/txtutil" +) + +func init() { + RegisterBuilder("LOC", BuilderLOC) +} + +func BuilderLOC(dc *DomainConfig, ttl uint32, args []any, subdomain string) (Records, error) { + + // args includes the label at args[0], so the parameter counts are +1: + // 8 = label + 7 preprocessed LOC fields; 13 = label + 12 DMS parameters. + if len(args) != 8 && len(args) != 13 { + return nil, errors.New("LOC should have 7 or 12 parameters") + } + + label, err := dc.LabelFromDnsconfigjs( + mustbe.RawString(args[0]), + subdomain, + ) + if err != nil { + return nil, fmt.Errorf("invalid label in BuilderLOC at [LOC(%s)]: %w", txtutil.ZoneifyManyAny(args), err) + } + + rec, err := dc.NewRecordConfig( + label, + ttl, + dnsv2.TypeLOC, + args[1:]..., + ) + if err != nil { + return nil, fmt.Errorf("record error in BuilderLOC at [LOC(%s)]: %w", txtutil.ZoneifyManyAny(args), err) + } + + return Records{rec}, nil + +} diff --git a/models/builders.go b/models/builders.go new file mode 100644 index 0000000000..c6e93a8600 --- /dev/null +++ b/models/builders.go @@ -0,0 +1,26 @@ +package models + +import "fmt" + +type RecordBuilderFn func(dc *DomainConfig, ttl uint32, args []any, subdomain string) (Records, error) + +var mapBuilderNameToFn = make(map[string]RecordBuilderFn) + +// RegisterBuilder registers a fake type that generates one or more RecordConfigs. +func RegisterBuilder(typeName string, genFn RecordBuilderFn) { + + // typenum -> function that runs the generator and returns a list of RecordConfigs. + if s, exists := mapBuilderNameToFn[typeName]; exists { + panic(fmt.Sprintf("mapGeneratorNameToFn[%s] already in use by %v", typeName, s)) + } + mapBuilderNameToFn[typeName] = genFn +} + +func IsBuilder(name string) bool { + _, ok := mapBuilderNameToFn[name] + return ok +} + +func (dc *DomainConfig) runBuilder(typeName string, ttl uint32, args []any, subdomain string) (Records, error) { + return mapBuilderNameToFn[typeName](dc, ttl, args, subdomain) +} diff --git a/models/comparablev3.go b/models/comparablev3.go new file mode 100644 index 0000000000..42f0f429c9 --- /dev/null +++ b/models/comparablev3.go @@ -0,0 +1,32 @@ +package models + +import ( + "fmt" + "strings" +) + +// generateComparableV3 generates or regenerates the .ComparableV3 field from the current .RDATA. It does not modify .RDATA. +func (rc *RecordConfig) generateComparableV3() { + switch rc.Type { + + case "IGNORE": + return + + case "IMPORT_TRANSFORM": + return + + case "SOA": + // The comparable string for SOA intentionally excludes the serial + // number, because the serial number changes on every update and + // would prevent correct diffing. List it as "X" so-as it stands out + // in debug output that the serial is intentionally excluded. + rd := rc.AsSOA() + rc.ComparableV3 = fmt.Sprintf("%s %s X %d %d %d %d", rd.Ns, rd.Mbox, rd.Refresh, rd.Retry, rd.Expire, rd.Minttl) + + default: + if rc.GetRDATA() == nil { + panic(fmt.Sprintf("BUG: FixUp: .RDATA is nil for type %s", rc.Type)) + } + rc.ComparableV3 = strings.TrimSpace(rc.GetRDATA().String()) + } +} diff --git a/models/dns.go b/models/dns.go index e824333113..1bb3300524 100644 --- a/models/dns.go +++ b/models/dns.go @@ -109,7 +109,6 @@ type Correction struct { func (config *DNSConfig) PostProcess() error { for _, domain := range config.Domains { domain.PostProcess() - // No need to call FixLegacyDC here. These records were created from dnsconfig.js, not from a provider. } return nil } diff --git a/models/dns_test.go b/models/dns_test.go deleted file mode 100644 index e67f75460f..0000000000 --- a/models/dns_test.go +++ /dev/null @@ -1,101 +0,0 @@ -package models - -import "testing" - -func TestRR(t *testing.T) { - experiment := RecordConfig{ - Type: "A", - Name: "foo", - NameFQDN: "foo.example.com", - target: "1.2.3.4", - TTL: 0, - MxPreference: 0, - } - expected := "foo.example.com.\t300\tIN\tA\t1.2.3.4" - found := experiment.ToRR().String() - if found != expected { - t.Errorf("RR expected (%#v) got (%#v)\n", expected, found) - } - - experiment = RecordConfig{ - Type: "CAA", - Name: "@", - NameFQDN: "example.com", - target: "mailto:test@example.com", - TTL: 300, - CaaTag: "iodef", - CaaFlag: 1, - } - expected = "example.com.\t300\tIN\tCAA\t1 iodef \"mailto:test@example.com\"" - found = experiment.ToRR().String() - if found != expected { - t.Errorf("RR expected (%#v) got (%#v)\n", expected, found) - } - - experiment = RecordConfig{ - Type: "TLSA", - Name: "@", - NameFQDN: "_443._tcp.example.com", - target: "abcdef0123456789", - TTL: 300, - TlsaUsage: 0, - TlsaSelector: 0, - TlsaMatchingType: 1, - } - expected = "_443._tcp.example.com.\t300\tIN\tTLSA\t0 0 1 abcdef0123456789" - found = experiment.ToRR().String() - if found != expected { - t.Errorf("RR expected (%#v) got (%#v)\n", expected, found) - } -} - -func TestRRInvalidIPNoPanic(t *testing.T) { - // A malformed AAAA target (e.g. an incomplete IPv6 address) leaves the - // stored target unparseable. ToRR must not panic while building the RR so - // that normalize validation can report the error to the user. - experiment := RecordConfig{ - Type: "AAAA", - Name: "@", - NameFQDN: "example.com", - target: "2a00:1450:4003:809:1", - TTL: 300, - } - experiment.ToRR() -} - -func TestSvcbAutoHintsTargetCombined(t *testing.T) { - experiment := RecordConfig{ - Type: "HTTPS", - Name: "foo", - NameFQDN: "foo.example.com", - SvcPriority: 1, - SvcParams: "alpn=h3,h2 ipv4hint=auto ipv6hint=auto", - TTL: 300, - } - experiment.MustSetTarget(".") - - expected := "1 . alpn=h3,h2 ipv4hint=auto ipv6hint=auto" - if found := experiment.ToComparableNoTTL(); found != expected { - t.Errorf("ToComparableNoTTL expected (%#v) got (%#v)\n", expected, found) - } -} - -func TestDowncase(t *testing.T) { - dc := DomainConfig{Records: Records{ - &RecordConfig{Type: "MX", Name: "lower", target: "targetmx"}, - &RecordConfig{Type: "MX", Name: "UPPER", target: "TARGETMX"}, - }} - Downcase(dc.Records) - if !dc.Records.HasRecordTypeName("MX", "lower") { - t.Errorf("%v: expected (%v) got (%v)\n", dc.Records, false, true) - } - if !dc.Records.HasRecordTypeName("MX", "upper") { - t.Errorf("%v: expected (%v) got (%v)\n", dc.Records, false, true) - } - if dc.Records[0].GetTargetField() != "targetmx" { - t.Errorf("%v: target0 expected (%v) got (%v)\n", dc.Records, "targetmx", dc.Records[0].GetTargetField()) - } - if dc.Records[1].GetTargetField() != "targetmx" { - t.Errorf("%v: target1 expected (%v) got (%v)\n", dc.Records, "targetmx", dc.Records[1].GetTargetField()) - } -} diff --git a/models/dnsrr.go b/models/dnsrr.go index ac4157daac..2d85ac32df 100644 --- a/models/dnsrr.go +++ b/models/dnsrr.go @@ -1,8 +1,30 @@ package models -// methods that make RecordConfig meet the dns.RR interface. +import ( + "fmt" + "maps" + "slices" + "strconv" + "strings" +) -// String returns the text representation of the resource record. -func (rc *RecordConfig) String() string { - return rc.GetTargetCombined() +// LineString returns the text representation of the resource record, including the label, ttl, type, and fields. +// This may change some day to include metadata and other fields, skip zero TTLs, and more. +func (rc *RecordConfig) LineString() string { + return fmt.Sprintf("%s %d IN %s %s", rc.Name, rc.TTL, rc.Type, rc.GetRDATA().String()) +} + +// StringWithMeta returns LineString followed by sorted, quoted metadata. +func (rc *RecordConfig) StringWithMeta() string { + if len(rc.Metadata) == 0 { + return rc.LineString() + } + + var b strings.Builder + b.WriteString(rc.LineString()) + b.WriteString(" ;") + for _, k := range slices.Sorted(maps.Keys(rc.Metadata)) { + fmt.Fprintf(&b, " %s=%s", k, strconv.Quote(rc.Metadata[k])) + } + return b.String() } diff --git a/models/dnsrr_test.go b/models/dnsrr_test.go new file mode 100644 index 0000000000..b5dde2721f --- /dev/null +++ b/models/dnsrr_test.go @@ -0,0 +1,53 @@ +package models + +import "testing" + +func TestStringWithMeta(t *testing.T) { + dc := MustNewDomainConfig("example.com") + + tests := []struct { + name string + rc *RecordConfig + metadata map[string]string + want string + }{ + { + name: "A", + rc: dc.MustNewRecordConfig("www", 300, "A", "192.0.2.1"), + want: "www 300 IN A 192.0.2.1", + }, + { + name: "zero TTL is included", + rc: dc.MustNewRecordConfig("www", 0, "A", "192.0.2.1"), + want: "www 0 IN A 192.0.2.1", + }, + { + name: "MX at the apex", + rc: dc.MustNewRecordConfig("@", 3600, "MX", 10, "mail.example.com."), + want: "@ 3600 IN MX 10 mail.example.com.", + }, + { + name: "metadata is sorted and quoted", + rc: dc.MustNewRecordConfig("fwd", 300, "A", "192.0.2.1"), + metadata: map[string]string{"wildcard": "no", "includePath": "yes"}, + want: `fwd 300 IN A 192.0.2.1 ; includePath="yes" wildcard="no"`, + }, + { + name: "metadata value with a space and a quote", + rc: dc.MustNewRecordConfig("fwd", 300, "A", "192.0.2.1"), + metadata: map[string]string{"note": `a "b" c`}, + want: `fwd 300 IN A 192.0.2.1 ; note="a \"b\" c"`, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + if tt.metadata != nil { + tt.rc.Metadata = tt.metadata + } + if got := tt.rc.StringWithMeta(); got != tt.want { + t.Errorf("StringWithMeta() = %q, want %q", got, tt.want) + } + }) + } +} diff --git a/models/domain.go b/models/domain.go index d791d93d70..271d8d62a5 100644 --- a/models/domain.go +++ b/models/domain.go @@ -5,27 +5,13 @@ import ( "strings" "sync" - "github.com/DNSControl/dnscontrol/v4/pkg/domaintags" + "github.com/DNSControl/dnscontrol/v5/pkg/domaintags" + "github.com/DNSControl/dnscontrol/v5/pkg/nameutil" "github.com/qdm12/reprint" - "golang.org/x/net/idna" -) - -const ( - // DomainTag is the key used to store a copy of DomainConfig.Tag in the Metadata map. - DomainTag = "dnscontrol_tag" - - // DomainUniqueName is the key used to store a copy of DomainConfig.UniqueName in the Metadata map. - DomainUniqueName = "dnscontrol_uniquename" - - // DomainNameRaw is the key used to store a copy of DomainConfig.NameRaw in the Metadata map. - DomainNameRaw = "dnscontrol_nameraw" - - // DomainNameUnicode is the key used to store a copy of DomainConfig.NameUnicode in the Metadata map. - DomainNameUnicode = "dnscontrol_nameunicode" ) // DomainConfig describes a DNS domain (technically a DNS zone). -// Do not create your own `&models.DomainConfig{}`. Use `models.NewDomainConfig(name)`. +// Do not create your own `models.DomainConfig`. Use `models.NewDomainConfig(name)`. type DomainConfig struct { NameRaw string `json:"-"` // name as entered by user in dnsconfig.js Name string `json:"name"` // NO trailing "." Converted to IDN (punycode) early in the pipeline. @@ -96,6 +82,32 @@ func MustNewDomainConfig(name string) *DomainConfig { return dc } +// ToFqdnWithDot converts a shortname to a FQDN+".". +// (Assume dc.Name == "bar.com") +// ToFqdnWithDot("foo") = "foo.bar.com." // Typical use. +// ToFqdnWithDot("@") = "bar.com." // Apex returns the apex. +// ToFqdnWithDot("") = "bar.com." // Apex returns the apex. +// ToFqdnWithDot("foo.com.") = "foo.com." // FQDNs are unmodified. +// ToFqdnWithDot("foo"") = "foo.bar.com." // If origin ends with a ".", DTRT. +// Similar to nameutil.ToFqdnWithDot() but uses the domain name from dc. +func (dc *DomainConfig) ToFqdnWithDot(s string) string { + return nameutil.ToFqdnWithDot(s, dc.Name) +} + +// ToFqdnNoDot is the same as ToFqdnWithDot but the result does not include a trailing ".". +// Similar to DomainConfig.ToFqdnNoDot() but it takes origin from dc.Name. +func (dc *DomainConfig) ToFqdnNoDot(s string) string { + return nameutil.ToFqdnNoDot(s, dc.Name) +} + +// ToShort returns the shortname by stripping the domain's name from "name". If name is not below dc.Name, name is returned unchanged. +// If the name was shortened, the result never ends with a ".". If the name was untouched, it always ends with a ".". +// Calling ToShort on a string that is already a shortname is unsupported. Names that do not end with "." are assumed to be FQDNs without a trailing ".". +// Similar to nameutil.ToShort() but uses the domain name from dc. +func (dc *DomainConfig) ToShort(name string) string { + return nameutil.ToShort(name, dc.Name) +} + func (dc *DomainConfig) PopulateNamesFromRaw(rawname string) { dcn := domaintags.MakeDomainNameVarieties(rawname) dc.Name = dcn.NameASCII @@ -109,23 +121,6 @@ func (dc *DomainConfig) PopulateNamesFromRaw(rawname string) { // PostProcess performs and post-processing required after running dnsconfig.js and loading the result. // It is called by dns.go's PostProcess() function. func (dc *DomainConfig) PostProcess() { - // Ensure the metadata map is initialized. - if dc.Metadata == nil { - dc.Metadata = map[string]string{} - } - - // Turn the user-supplied name into the fixed forms. - ff := domaintags.MakeDomainNameVarieties(dc.Name) - dc.Tag, dc.NameRaw, dc.Name, dc.NameUnicode, dc.UniqueName, dc.DisplayName = ff.Tag, ff.NameRaw, ff.NameASCII, ff.NameUnicode, ff.UniqueName, ff.DisplayName - - // Store the FixForms is Metadata so we don't have to change the signature of every function that might need them. - // This is a bit ugly but avoids a huge refactor. Please avoid using these to make the future refactor easier. - if dc.Tag != "" { - dc.Metadata[DomainTag] = dc.Tag - } - dc.Metadata[DomainNameRaw] = dc.NameRaw - dc.Metadata[DomainNameUnicode] = dc.NameUnicode - dc.Metadata[DomainUniqueName] = dc.UniqueName } // GetSplitHorizonNames returns the domain's name, uniquename, and tag. @@ -149,7 +144,7 @@ func (dc *DomainConfig) Copy() (*DomainConfig, error) { // Filter removes all records that don't match the filter f. func (dc *DomainConfig) Filter(f func(r *RecordConfig) bool) { - recs := []*RecordConfig{} + var recs Records for _, r := range dc.Records { if f(r) { recs = append(recs, r) @@ -158,49 +153,6 @@ func (dc *DomainConfig) Filter(f func(r *RecordConfig) bool) { dc.Records = recs } -// Punycode will convert all records to punycode format. -// It will encode: -// - Name -// - NameFQDN -// - Target (CNAME and MX only). -// NOTE: This will go away when RCv3 is adopted. -func (dc *DomainConfig) Punycode() error { - for _, rec := range dc.Records { - if rec.IsModernType() { - continue // Modern types handle punycode themselves. - } - - // Update the label: - t, err := idna.ToASCII(rec.GetLabelFQDN()) - if err != nil { - return err - } - rec.SetLabelFromFQDN(t, dc.Name) - - // Set the target: - switch rec.Type { // #rtype_variations - case "ALIAS", "MX", "NS", "CNAME", "DNAME", "PTR", "SRV", "URL", "URL301", "FRAME", "R53_ALIAS", "AKAMAICDN", "AKAMAITLC", "CLOUDNS_WR", "PORKBUN_URLFWD", "BUNNY_DNS_RDR": - // These rtypes are hostnames, therefore need to be converted (unlike, for example, an AAAA record) - t, err := idna.ToASCII(rec.GetTargetField()) - if err != nil { - return err - } - if err := rec.SetTarget(t); err != nil { - return err - } - case "CLOUDFLAREAPI_SINGLE_REDIRECT", "CF_REDIRECT", "CF_TEMP_REDIRECT", "CF_WORKER_ROUTE", "ADGUARDHOME_A_PASSTHROUGH", "ADGUARDHOME_AAAA_PASSTHROUGH", "BUNNY_DNS_PZ", "MIKROTIK_FWD", "MIKROTIK_NXDOMAIN", "MIKROTIK_FORWARDER": - if err := rec.SetTarget(rec.GetTargetField()); err != nil { - return err - } - case "A", "AAAA", "CAA", "DHCID", "DNSKEY", "DS", "HTTPS", "LOC", "LUA", "NAPTR", "OPENPGPKEY", "SMIMEA", "SOA", "SSHFP", "SVCB", "TXT", "TLSA", "AZURE_ALIAS": - // Nothing to do. - default: - return fmt.Errorf("Punycode rtype %v unimplemented", rec.Type) - } - } - return nil -} - // StoreCorrections accumulates corrections in a thread-safe way. func (dc *DomainConfig) StoreCorrections(providerName string, corrections []*Correction) { dc.pendingCorrectionsMutex.Lock() diff --git a/models/makers.go b/models/makers.go new file mode 100644 index 0000000000..07abb3243c --- /dev/null +++ b/models/makers.go @@ -0,0 +1,427 @@ +package models + +// Make*() functions for built-in types. +// TODO(tlim): Autogenerate this. use mustbe.* while we're at it. + +import ( + "fmt" + "slices" + "strings" + + dnsv2 "codeberg.org/miekg/dns" + dnsrdatav2 "codeberg.org/miekg/dns/rdata" + svcbv2 "codeberg.org/miekg/dns/svcb" + + "github.com/DNSControl/dnscontrol/v5/pkg/mustbe" + "github.com/DNSControl/dnscontrol/v5/pkg/nrc" + "github.com/DNSControl/dnscontrol/v5/pkg/privatetypes" + _ "github.com/DNSControl/dnscontrol/v5/pkg/privatetypes" + privatetypesrdata "github.com/DNSControl/dnscontrol/v5/pkg/privatetypes/rdata" +) + +func init() { + // Register the Maker*() function for public types. + privatetypes.RegisterMaker(dnsv2.TypeA, MakeA) + privatetypes.RegisterMaker(dnsv2.TypeAAAA, MakeAAAA) + privatetypes.RegisterMaker(dnsv2.TypeCAA, MakeCAA) + privatetypes.RegisterMaker(dnsv2.TypeCNAME, MakeCNAME) + privatetypes.RegisterMaker(dnsv2.TypeDHCID, MakeDHCID) + privatetypes.RegisterMaker(dnsv2.TypeDNAME, MakeDNAME) + privatetypes.RegisterMaker(dnsv2.TypeDNSKEY, MakeDNSKEY) + privatetypes.RegisterMaker(dnsv2.TypeDS, MakeDS) + privatetypes.RegisterMaker(dnsv2.TypeHTTPS, MakeHTTPS) + privatetypes.RegisterMaker(dnsv2.TypeLOC, MakeLOC) + privatetypes.RegisterMaker(dnsv2.TypeMX, MakeMX) + privatetypes.RegisterMaker(dnsv2.TypeNAPTR, MakeNAPTR) + privatetypes.RegisterMaker(dnsv2.TypeNS, MakeNS) + privatetypes.RegisterMaker(dnsv2.TypeOPENPGPKEY, MakeOPENPGPKEY) + privatetypes.RegisterMaker(dnsv2.TypePTR, MakePTR) + privatetypes.RegisterMaker(dnsv2.TypeRP, MakeRP) + privatetypes.RegisterMaker(dnsv2.TypeSMIMEA, MakeSMIMEA) + privatetypes.RegisterMaker(dnsv2.TypeSOA, MakeSOA) + privatetypes.RegisterMaker(dnsv2.TypeSRV, MakeSRV) + privatetypes.RegisterMaker(dnsv2.TypeSSHFP, MakeSSHFP) + privatetypes.RegisterMaker(dnsv2.TypeSVCB, MakeSVCB) + privatetypes.RegisterMaker(dnsv2.TypeTLSA, MakeTLSA) + privatetypes.RegisterMaker(dnsv2.TypeTXT, MakeTXT) +} + +func MakeA(origin string, _ map[string]string, isEnabled nrc.Flags, args ...any) (dnsv2.RDATA, error) { + mustbe.ValidArgs(args) + if len(args) != 1 { + return nil, fmt.Errorf("MakeA expects exactly 1 argument, got %d: %+v", len(args), args) + } + target := args[0] + ip, err := mustbe.IPv4(target) + if err != nil { + return nil, err + } + return dnsrdatav2.A{Addr: ip}, nil +} + +func MakeALIAS(origin string, _ map[string]string, isEnabled nrc.Flags, args ...any) (dnsv2.RDATA, error) { + mustbe.ValidArgs(args) + if len(args) != 1 { + return nil, fmt.Errorf("MakeALIAS expects exactly 1 argument, got %d: %+v", len(args), args) + } + target, err := mustbe.TargetHost(origin, isEnabled, args[0]) + if err != nil { + return nil, err + } + return privatetypesrdata.ALIAS{Target: target}, nil +} +func MakeAAAA(origin string, _ map[string]string, isEnabled nrc.Flags, args ...any) (dnsv2.RDATA, error) { + mustbe.ValidArgs(args) + if len(args) != 1 { + return nil, fmt.Errorf("MakeAAAA expects exactly 1 argument, got %d: %+v", len(args), args) + } + ip, err := mustbe.IPv6(args[0]) + if err != nil { + return nil, err + } + return dnsrdatav2.AAAA{Addr: ip}, nil +} + +func MakeCAA(origin string, metadata map[string]string, isEnabled nrc.Flags, args ...any) (dnsv2.RDATA, error) { + mustbe.ValidArgs(args) + if len(args) != 2 && len(args) != 3 { + return nil, fmt.Errorf("MakeCAA expects 2 or 3 arguments, got %d: %+v", len(args), args) + } + if len(args) == 2 { + var flag any = uint8(0) + if cf, ok := metadata["caaflag"]; ok { + flag = cf + } + return dnsrdatav2.CAA{Flag: mustbe.Uint8(flag), Tag: mustbe.RawString(args[0]), Value: mustbe.RawString(args[1])}, nil + } + + tag := mustbe.RawString(args[1]) + allowedTags := []string{"issue", "issuewild", "iodef", "contactemail", "contactphone", "issuemail", "issuevmc"} + if !slices.Contains(allowedTags, tag) { + return nil, fmt.Errorf("CAA tag (%v) is not one of the valid types", tag) + } + + return dnsrdatav2.CAA{Flag: mustbe.Uint8(args[0]), Tag: tag, Value: mustbe.RawString(args[2])}, nil + +} +func MakeCNAME(origin string, _ map[string]string, isEnabled nrc.Flags, args ...any) (dnsv2.RDATA, error) { + mustbe.ValidArgs(args) + if len(args) != 1 { + return nil, fmt.Errorf("MakeCNAME expects exactly 1 argument, got %d: %+v", len(args), args) + } + target, err := mustbe.TargetHost(origin, isEnabled, args[0]) + if err != nil { + return nil, err + } + return dnsrdatav2.CNAME{Target: target}, nil +} + +func MakeDHCID(origin string, _ map[string]string, isEnabled nrc.Flags, args ...any) (dnsv2.RDATA, error) { + mustbe.ValidArgs(args) + if len(args) != 1 { + return nil, fmt.Errorf("MakeDHCID expects exactly 1 argument, got %d: %+v", len(args), args) + } + return dnsrdatav2.DHCID{Digest: mustbe.RawString(args[0])}, nil +} +func MakeDNAME(origin string, _ map[string]string, isEnabled nrc.Flags, args ...any) (dnsv2.RDATA, error) { + mustbe.ValidArgs(args) + if len(args) != 1 { + return nil, fmt.Errorf("MakeDNAME expects exactly 1 argument, got %d: %+v", len(args), args) + } + target, err := mustbe.TargetHost(origin, isEnabled, args[0]) + if err != nil { + return nil, err + } + return dnsrdatav2.DNAME{Target: target}, nil +} +func MakeDNSKEY(origin string, _ map[string]string, isEnabled nrc.Flags, args ...any) (dnsv2.RDATA, error) { + mustbe.ValidArgs(args) + if len(args) != 4 { + return nil, fmt.Errorf("MakeDNSKEY expects exactly 4 arguments, got %d: %+v", len(args), args) + } + return dnsrdatav2.DNSKEY{ + Flags: mustbe.Uint16(args[0]), + Protocol: mustbe.Uint8(args[1]), + Algorithm: mustbe.Uint8(args[2]), + PublicKey: mustbe.RawString(args[3]), + //Tag: mustbe.Uint16(args[4]), + }, nil +} + +func MakeDS(origin string, _ map[string]string, isEnabled nrc.Flags, args ...any) (dnsv2.RDATA, error) { + mustbe.ValidArgs(args) + if len(args) != 4 { + return nil, fmt.Errorf("MakeDS expects exactly 4 arguments, got %d: %+v", len(args), args) + } + return dnsrdatav2.DS{KeyTag: mustbe.Uint16(args[0]), Algorithm: mustbe.Uint8(args[1]), DigestType: mustbe.Uint8(args[2]), Digest: mustbe.ToUpperRawString(args[3])}, nil +} + +func MakeHTTPS(origin string, _ map[string]string, isEnabled nrc.Flags, args ...any) (dnsv2.RDATA, error) { + mustbe.ValidArgs(args) + if len(args) != 3 { + return nil, fmt.Errorf("MakeHTTPS expects exactly 3 arguments, got %d: %+v", len(args), args) + } + return MakeSVCB(origin, nil, isEnabled, args[0], args[1], args[2]) +} + +func MakeLOC(origin string, _ map[string]string, isEnabled nrc.Flags, args ...any) (dnsv2.RDATA, error) { + if len(args) != 7 && len(args) != 12 { + return nil, fmt.Errorf("MakeLOC expects either 7 or 12 arguments, got %d: %+v", len(args), args) + } + + if len(args) == 7 { + return dnsrdatav2.LOC{ + Version: mustbe.Uint8(args[0]), + Size: mustbe.Uint8(args[1]), + HorizPre: mustbe.Uint8(args[2]), + VertPre: mustbe.Uint8(args[3]), + Latitude: mustbe.Uint32(args[4]), + Longitude: mustbe.Uint32(args[5]), + Altitude: mustbe.Uint32(args[6]), + }, nil + } + + a0 := mustbe.Uint8(args[0]) + a1 := mustbe.Uint8(args[1]) + a2 := mustbe.Float32(args[2]) + a3 := mustbe.RawString(args[3]) + a4 := mustbe.Uint8(args[4]) + a5 := mustbe.Uint8(args[5]) + a6 := mustbe.Float32(args[6]) + a7 := mustbe.RawString(args[7]) + a8 := mustbe.Float64(args[8]) + a9 := mustbe.Float32(args[9]) + a10 := mustbe.Float32(args[10]) + a11 := mustbe.Float32(args[11]) + // TODO(tlim): Add bounds checking. Then uncomment the lines in 045-loc.js + // that test that. Return 045-loc.json and the zone files to how it was at + // tag v4.45.0. There will be a few cosmetic changes. + + // The 12-item version needs to be turned into the 7-item packed version. + // The easiest way to do that is to let dnsv2 do it for us. + // It is a little extra parsing, but why re-invent the wheel? + x := fmt.Sprintf("%d %d %.2f %s %d %d %.2f %s %.2f %.2f %0.2f %0.2f ", a0, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11) + // y := fmt.Sprintf("0=%d 1=%d 2=%.2f 3=%s 4=%d 5=%d 6=%.2f 7=%s 8=%.2f 9=%.2f 10=%0.2f 11=%0.2f ", a0, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11) + // fmt.Printf("DEBUG: loc y=%q\n", y) + rd, err := dnsv2.NewData(dnsv2.TypeLOC, x, origin) + + return rd, err +} + +func MakeMIKROTIKFWD(origin string, _ map[string]string, isEnabled nrc.Flags, args ...any) (dnsv2.RDATA, error) { + mustbe.ValidArgs(args) + forwardTo, err := mustbe.TargetHost(origin, isEnabled, args[0]) + if err != nil { + return nil, err + } + return privatetypesrdata.MIKROTIKFWD{ForwardTo: forwardTo}, nil +} +func MakeMIKROTIKNXDOMAIN(origin string, _ map[string]string, isEnabled nrc.Flags, args ...any) (dnsv2.RDATA, error) { + mustbe.ValidArgs(args) + return privatetypesrdata.MIKROTIKNXDOMAIN{}, nil +} +func MakeMX(origin string, _ map[string]string, isEnabled nrc.Flags, args ...any) (dnsv2.RDATA, error) { + mustbe.ValidArgs(args) + if len(args) != 2 { + return nil, fmt.Errorf("MakeMX expects exactly 2 arguments, got %d: %+v", len(args), args) + } + + target, err := mustbe.TargetHost(origin, isEnabled, args[1]) + if err != nil { + return nil, err + } + + return dnsrdatav2.MX{Preference: mustbe.Uint16(args[0]), Mx: target}, nil + +} + +func MakeNS(origin string, _ map[string]string, isEnabled nrc.Flags, args ...any) (dnsv2.RDATA, error) { + mustbe.ValidArgs(args) + if len(args) != 1 { + return nil, fmt.Errorf("MakeNS expects exactly 1 argument, got %d: %+v", len(args), args) + } + + target, err := mustbe.TargetHost(origin, isEnabled, args[0]) + if err != nil { + return nil, err + } + + return dnsrdatav2.NS{Ns: target}, nil +} +func MakeNAPTR(origin string, _ map[string]string, isEnabled nrc.Flags, args ...any) (dnsv2.RDATA, error) { + mustbe.ValidArgs(args) + if len(args) != 6 { + return nil, fmt.Errorf("MakeNAPTR expects exactly 6 arguments, got %d: %+v", len(args), args) + } + // The NAPTR replacement is a domain name; an empty replacement is canonically + // the root, ".". Normalize so it renders consistently in zone files. + replacement := mustbe.RawString(args[5]) + if replacement == "" { + replacement = "." + } + return dnsrdatav2.NAPTR{ + Order: mustbe.Uint16(args[0]), + Preference: mustbe.Uint16(args[1]), + Flags: mustbe.RawString(args[2]), + Service: mustbe.RawString(args[3]), + Regexp: mustbe.RawString(args[4]), + Replacement: replacement, + }, nil +} + +func MakeOPENPGPKEY(origin string, _ map[string]string, isEnabled nrc.Flags, args ...any) (dnsv2.RDATA, error) { + mustbe.ValidArgs(args) + if len(args) != 1 { + return nil, fmt.Errorf("MakeOPENPGPKEY expects exactly 1 argument, got %d: %+v", len(args), args) + } + return dnsrdatav2.OPENPGPKEY{PublicKey: mustbe.OpenPGPKey(args[0])}, nil +} + +func MakePORKBUNURLFWD(origin string, _ map[string]string, isEnabled nrc.Flags, args ...any) (dnsv2.RDATA, error) { + mustbe.ValidArgs(args) + return privatetypesrdata.PORKBUNURLFWD{}, nil +} + +func MakePTR(origin string, _ map[string]string, isEnabled nrc.Flags, args ...any) (dnsv2.RDATA, error) { + mustbe.ValidArgs(args) + if len(args) != 1 { + return nil, fmt.Errorf("MakePTR expects exactly 1 argument, got %d: %+v", len(args), args) + } + ptr, err := mustbe.TargetHost(origin, isEnabled, args[0]) + if err != nil { + return nil, err + } + return dnsrdatav2.PTR{Ptr: ptr}, nil +} + +func MakeRP(origin string, _ map[string]string, isEnabled nrc.Flags, args ...any) (dnsv2.RDATA, error) { + mustbe.ValidArgs(args) + if len(args) != 2 { + return nil, fmt.Errorf("MakeRP expects exactly 2 arguments, got %d: %+v", len(args), args) + } + mbox, err := mustbe.TargetHost(origin, isEnabled, args[0]) + if err != nil { + return nil, err + } + txt, err := mustbe.TargetHost(origin, isEnabled, args[1]) + if err != nil { + return nil, err + } + return dnsrdatav2.RP{Mbox: mbox, Txt: txt}, nil +} + +func MakeSMIMEA(origin string, _ map[string]string, isEnabled nrc.Flags, args ...any) (dnsv2.RDATA, error) { + mustbe.ValidArgs(args) + if len(args) != 4 { + return nil, fmt.Errorf("MakeSMIMEA expects exactly 4 arguments, got %d: %+v", len(args), args) + } + return dnsrdatav2.SMIMEA{Usage: mustbe.Uint8(args[0]), Selector: mustbe.Uint8(args[1]), MatchingType: mustbe.Uint8(args[2]), Certificate: mustbe.RawString(args[3])}, nil +} + +func MakeSOA(origin string, _ map[string]string, isEnabled nrc.Flags, args ...any) (dnsv2.RDATA, error) { + mustbe.ValidArgs(args) + if len(args) != 6 && len(args) != 7 { + return nil, fmt.Errorf("MakeSOA expects exactly 6 or 7 arguments, got %d: %+v", len(args), args) + } + // dnsconfig.js's SOA() passes 6 args (no serial): the user can not specify + // the serial number, it is managed by DNSControl. Re-deriving the RDATA from + // an existing RecordConfig or parsing a zone (e.g. BIND) passes 7 + // args, with the serial at args[2]. + // The one exception is that for hermetic builds/tests, "dnscontrol preview --bindserial" exists. + var serial any = uint32(0) + rest := args[2:] + if len(args) == 7 { + serial = args[2] + rest = args[3:] + } + ns, err := mustbe.TargetHost(origin, isEnabled, args[0]) + if err != nil { + return nil, err + } + return dnsrdatav2.SOA{ + Ns: ns, + Mbox: mustbe.SoaMailbox(args[1]), + Serial: mustbe.Uint32(serial), + Refresh: mustbe.Uint32(rest[0]), + Retry: mustbe.Uint32(rest[1]), + Expire: mustbe.Uint32(rest[2]), + Minttl: mustbe.Uint32(rest[3]), + }, nil +} + +func MakeSRV(origin string, _ map[string]string, isEnabled nrc.Flags, args ...any) (dnsv2.RDATA, error) { + mustbe.ValidArgs(args) + if len(args) != 4 { + return nil, fmt.Errorf("MakeSRV expects exactly 4 arguments, got %d: %+v", len(args), args) + } + target, err := mustbe.TargetHostSRV(origin, isEnabled, args[3]) + if err != nil { + return nil, err + } + return dnsrdatav2.SRV{Priority: mustbe.Uint16(args[0]), Weight: mustbe.Uint16(args[1]), Port: mustbe.Uint16(args[2]), Target: target}, nil +} + +func MakeSSHFP(origin string, _ map[string]string, isEnabled nrc.Flags, args ...any) (dnsv2.RDATA, error) { + mustbe.ValidArgs(args) + if len(args) != 3 { + return nil, fmt.Errorf("MakeSSHFP expects exactly 3 arguments, got %d: %+v", len(args), args) + } + return dnsrdatav2.SSHFP{Algorithm: mustbe.Uint8(args[0]), Type: mustbe.Uint8(args[1]), FingerPrint: mustbe.ToUpperRawString(args[2])}, nil +} + +func MakeSVCB(origin string, _ map[string]string, isEnabled nrc.Flags, args ...any) (dnsv2.RDATA, error) { + mustbe.ValidArgs(args) + // args can be a string (which we parse) or a []svcbv2.Pair. + // If it's a string, this is where we turn `ech=IGNORE` into `ech=1000`. + if len(args) != 3 { + return nil, fmt.Errorf("MakeSVCB expects exactly 3 arguments, got %d: %+v", len(args), args) + } + priority := args[0] + params := args[2] + target, err := mustbe.TargetHost(origin, isEnabled, args[1]) + if err != nil { + return nil, err + } + + if priority == 0 { + return dnsrdatav2.SVCB{Priority: mustbe.Uint16(priority), Target: target}, nil + } + + switch v := params.(type) { + case []svcbv2.Pair: + return dnsrdatav2.SVCB{Priority: mustbe.Uint16(priority), Target: target, Value: v}, nil + case string: + // ech=IGNORE is special. It means "take the ech value from the existing + // record". We replace it with the byte sequence 0x10 0x00 here. Later, + // we look for that value and replace it with the existing record's + // value. This works because we can assume there are no ech= values that + // are actually 0x10 0x00. (The ech=IGNORE value is stored as ech=1000 + // in the wire format.) + v = strings.ReplaceAll(v, "IGNORE", "1000") + + pairs, err := stringToSvcbv2Values(origin, v) + if err != nil { + return nil, err + } + return dnsrdatav2.SVCB{Priority: mustbe.Uint16(priority), Target: target, Value: pairs}, nil + + } + + panic(fmt.Sprintf("BUG: Invalid params type for SVCB/HTTPS record: %T", params)) +} + +func MakeTLSA(origin string, _ map[string]string, isEnabled nrc.Flags, args ...any) (dnsv2.RDATA, error) { + mustbe.ValidArgs(args) + if len(args) != 4 { + return nil, fmt.Errorf("MakeTLSA expects exactly 4 arguments, got %d: %+v", len(args), args) + } + return dnsrdatav2.TLSA{Usage: mustbe.Uint8(args[0]), Selector: mustbe.Uint8(args[1]), MatchingType: mustbe.Uint8(args[2]), Certificate: mustbe.ToUpperRawString(args[3])}, nil +} + +func MakeTXT(origin string, _ map[string]string, isEnabled nrc.Flags, args ...any) (dnsv2.RDATA, error) { + mustbe.ValidArgs(args) + if len(args) != 1 { + return nil, fmt.Errorf("MakeTXT expects exactly 1 argument, got %d: %+v", len(args), args) + } + return dnsrdatav2.TXT{Txt: mustbe.Txts(args[0])}, nil +} diff --git a/models/metadata.go b/models/metadata.go new file mode 100644 index 0000000000..3ce80dddd5 --- /dev/null +++ b/models/metadata.go @@ -0,0 +1,21 @@ +package models + +import "fmt" + +func mergeMetas(metas []map[string]any) (map[string]string, error) { + + m := map[string]string{} + + // Fill in the metadata fields. + for _, meta := range metas { + for k, v := range meta { + oldv, exists := m[k] + if exists { + return nil, fmt.Errorf("duplicate metadata key %q (%q -- %q)", k, oldv, fmt.Sprintf("%s", v)) + } + m[k] = fmt.Sprintf("%s", v) + } + } + + return m, nil +} diff --git a/models/quotes.go b/models/quotes.go deleted file mode 100644 index 531167d766..0000000000 --- a/models/quotes.go +++ /dev/null @@ -1,68 +0,0 @@ -package models - -import ( - "fmt" - "strings" - - dnsv1 "github.com/miekg/dns" -) - -/* -TODO(tlim): Move this file to pkgs/txtutil. It doesn't need to be part -*/ - -// isQuoted returns true if the string starts and ends with a double quote. -func isQuoted(s string) bool { - if s == "" { - return false - } - if len(s) < 2 { - return false - } - if s[0] == '"' && s[len(s)-1] == s[0] { - return true - } - return false -} - -// StripQuotes returns the string with the starting and ending quotes removed. -// If it is not quoted, the original string is returned. -func StripQuotes(s string) string { - if isQuoted(s) { - return s[1 : len(s)-1] - } - return s -} - -// ParseQuotedTxt returns the individual strings of a combined quoted string. -// -// `foo` -> []string{"foo"} -// `"foo"` -> []string{"foo"} -// `"foo" "bar"` -> []string{"foo", "bar"} -// `"f"oo" "bar"` -> []string{`f"oo`, "bar"} -// -// NOTE: It is assumed there is exactly one space between the quotes. -// NOTE: This doesn't handle escaped quotes. -// NOTE: You probably want to use ParseQuotedFields() for RFC 1035-compliant quoting. -func ParseQuotedTxt(s string) []string { - if !isQuoted(s) { - return []string{s} - } - return strings.Split(StripQuotes(s), `" "`) -} - -// ParseQuotedFields is like strings.Fields except individual fields -// might be quoted using `"`. -func ParseQuotedFields(s string) ([]string, error) { - // Parse according to RFC1035 zonefile specifications. - // "foo" -> one string: `foo`` - // "foo" "bar" -> two strings: `foo` and `bar` - - // The dns package doesn't expose the quote parser. Therefore we create a TXT record and extract the strings. - rr, err := dnsv1.NewRR("example.com. IN TXT " + s) - if err != nil { - return nil, fmt.Errorf("could not parse %q TXT: %w", s, err) - } - - return rr.(*dnsv1.TXT).Txt, nil -} diff --git a/models/quotes_test.go b/models/quotes_test.go deleted file mode 100644 index 2cf2145528..0000000000 --- a/models/quotes_test.go +++ /dev/null @@ -1,138 +0,0 @@ -package models - -import ( - "strings" - "testing" -) - -func TestIsQuoted(t *testing.T) { - tests := []struct { - d1 string - e1 bool - }{ - {``, false}, - {`foo`, false}, - {`""`, true}, - {`"a"`, true}, - {`"bb"`, true}, - {`"ccc"`, true}, - {`"aaa" "bbb"`, true}, - } - for i, test := range tests { - r := isQuoted(test.d1) - if r != test.e1 { - t.Errorf("%v: expected (%v) got (%v)", i, test.e1, r) - } - } -} - -func TestStripQuotes(t *testing.T) { - tests := []struct { - d1 string - e1 string - }{ - {``, ``}, - {`a`, `a`}, - {`bb`, `bb`}, - {`ccc`, `ccc`}, - {`dddd`, `dddd`}, - {`"A"`, `A`}, - {`"BB"`, `BB`}, - {`"CCC"`, `CCC`}, - {`"DDDD"`, `DDDD`}, - {`"EEEEE"`, `EEEEE`}, - {`"aaa" "bbb"`, `aaa" "bbb`}, - } - for i, test := range tests { - r := StripQuotes(test.d1) - if r != test.e1 { - t.Errorf("%v: expected (%v) got (%v)", i, test.e1, r) - } - } -} - -func r(s string, c int) string { return strings.Repeat(s, c) } - -func TestParseQuotedTxt(t *testing.T) { - tests := []struct { - d1 string - e2 []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`}}, - //{"\"backs\\\\lash\"", []string{`back\slash`}}, - } - for i, test := range tests { - ls := ParseQuotedTxt(test.d1) - if len(ls) != len(test.e2) { - 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=q(%q) got q(%q)", i, test.e2, ls) - } - } - } -} - -func TestParseQuotedFields(t *testing.T) { - tests := []struct { - d1 string - e1 []string - }{ - {`1 2 3`, []string{`1`, `2`, `3`}}, - {`1 "2" 3`, []string{`1`, `2`, `3`}}, - {`1 2 "three 3"`, []string{`1`, `2`, `three 3`}}, - {`1 2 "qu\"te" "4"`, []string{`1`, `2`, `qu\"te`, `4`}}, - {`0 issue "letsencrypt.org; validationmethods=dns-01; accounturi=https://acme-v02.api.letsencrypt.org/acme/acct/1234"`, []string{`0`, `issue`, `letsencrypt.org; validationmethods=dns-01; accounturi=https://acme-v02.api.letsencrypt.org/acme/acct/1234`}}, - } - for i, test := range tests { - ls, _ := ParseQuotedFields(test.d1) - // fmt.Printf("%v: expected TxtStrings:\nWANT: %v\n GOT: %v\n", i, test.e1, ls) - if len(ls) != len(test.e1) { - t.Errorf("%v: expected TxtStrings=(%v) got (%v)", i, test.e1, ls) - } - for i := range ls { - if ls[i] != test.e1[i] { - t.Errorf("%v: expected TxtStrings=(%v) got (%v)", i, test.e1, ls) - } - } - } -} diff --git a/models/rawrecord.go b/models/rawrecord.go index 1b073a803b..a4dc0d281b 100644 --- a/models/rawrecord.go +++ b/models/rawrecord.go @@ -10,4 +10,8 @@ type RawRecordConfig struct { Metas []map[string]any `json:"metas,omitempty"` TTL uint32 `json:"ttl,omitempty"` FilePos string `json:"filepos"` // Where in the file this record was defined. + // SubDomain (if non-empty) is the D_EXTEND() subdomain this record was + // declared under. It is used to rewrite the label and is stored in the + // resulting RecordConfig.SubDomain. See ImportRawRecords. + SubDomain string `json:"subdomain,omitempty"` } diff --git a/models/rawrecord_import.go b/models/rawrecord_import.go new file mode 100644 index 0000000000..023648a812 --- /dev/null +++ b/models/rawrecord_import.go @@ -0,0 +1,113 @@ +package models + +import ( + "fmt" + "strings" + + dnsutilv2 "codeberg.org/miekg/dns/dnsutil" + "golang.org/x/net/idna" + + "github.com/DNSControl/dnscontrol/v5/pkg/txtutil" +) + +// ImportRawRecords iterates over the dc.RawRecords from each domain, +// converting each to a RecordConfig and deleting the raw version (to save +// memory). This is how records get from dnsconfig.js to dc.Records. +func (config *DNSConfig) ImportRawRecords() error { + // subdomainToASCII converts a D_EXTEND() subdomain to its IDNA (punycode) + // form. idna.ToASCII is comparatively expensive and every record in a + // D_EXTEND block shares the same subdomain value, so the results are + // memoized (keyed by the raw subdomain) across the whole import. + subdomainCache := map[string]string{} + subdomainToASCII := func(s string) (string, error) { + if s == "" { + return "", nil + } + if a, ok := subdomainCache[s]; ok { + return a, nil + } + a, err := idna.ToASCII(s) + if err != nil { + return "", err + } + a = strings.ToLower(a) + subdomainCache[s] = a + return a, nil + } + + for _, dc := range config.Domains { + for _, rawRec := range dc.RawRecords { + filePos := FixPosition(rawRec.FilePos) + typeName := rawRec.Type + + // NB(tlim): We check if something is a builder first because LOC could be a builder or a dnsrdatav2. + if IsBuilder(typeName) { + records, err := dc.runBuilder(typeName, rawRec.TTL, rawRec.Args, rawRec.SubDomain) + if err != nil { + return err + } + // Annotate the .FilePos on all generated records. + for _, record := range records { + record.FilePos = filePos + } + // Generation complete! Append the results. + dc.Records = append(dc.Records, records...) + } else { + typeNum, err := dnsutilv2.StringToType(typeName) + if err != nil { + return fmt.Errorf("unknown record type at %s [%s(%s)]: %w", filePos, typeName, txtutil.ZoneifyManyAny(rawRec.Args), err) + } + + // Apply D_EXTEND() subdomain label rewriting (in Go, on + // post-IDNA strings). Excluded types keep their label as-is. + // The subdomain is converted to IDNA (punycode) once and reused + // for the label, the target origin, and rec.SubDomain. + subdomain := rawRec.SubDomain + if subdomainExcludedTypes[typeName] { + subdomain = "" + } else { + subdomain, err = subdomainToASCII(subdomain) + if err != nil { + return fmt.Errorf("subdomain error at %s [%s(%s)]: %w", filePos, typeName, txtutil.ZoneifyManyAny(rawRec.Args), err) + } + } + mm, err := mergeMetas(rawRec.Metas) + if err != nil { + return fmt.Errorf("metadata error at %s [%s(%s)]: %w", filePos, typeName, txtutil.ZoneifyManyAny(rawRec.Args), err) + } + + rec, err := dc.newRecordConfigFromDnsconfigjs(rawRec.Args[0].(string), rawRec.TTL, typeNum, rawRec.Args[1:], mm, subdomain) + if err != nil { + return fmt.Errorf("ImportRawRecords error at %s [%s(%s)]: %w", filePos, typeName, txtutil.ZoneifyManyAny(rawRec.Args), err) + } + rec.FilePos = filePos + rec.SubDomain = subdomain + if rec.Metadata, err = mergeMetas(rawRec.Metas); err != nil { + return fmt.Errorf("metadata error at %s [%s(%s)]: %w", filePos, typeName, txtutil.ZoneifyManyAny(rawRec.Args), err) + } + + // The stutter check catches labels that mistakenly include the + // zone name. It is skipped when the record opts out via + // skip_fqdn_check, and for reverse zones, where labels are + // legitimately written as full reverse names (e.g. via REV()) + // and are reduced to relative form later by normalization. + if rec.Metadata["skip_fqdn_check"] != "true" && !isReverseZone(dc.Name) && doesStutter(rec.Name, dc.Name) { + // return fmt.Errorf("stutter error at %s %s(%s). Add DISABLE_REPEATED_DOMAIN_CHECK to override", filePos, typeName, txtutil.ZoneifyManyAny(rawRec.Args)) + return stutterError(rec, dc.Name) + } + + // Conversion complete! Append it. + dc.AddRecordConfig(rec) + } + + // We're never going to see this rawRec again. Free its Args. + clear(rawRec.Args) + rawRec.Args = nil + } + + // We're never going to see these RawRecords again. Let them go. + dc.RawRecords = nil + } + + return nil +} diff --git a/models/rdata.go b/models/rdata.go new file mode 100644 index 0000000000..c0b8408a8c --- /dev/null +++ b/models/rdata.go @@ -0,0 +1,151 @@ +package models + +//go:generate go run github.com/DNSControl/dnscontrol/v5/build/astypegen + +import ( + "fmt" + "os" + "reflect" + "runtime/debug" + "strings" + + dnsv2 "codeberg.org/miekg/dns" + dnsrdatav2 "codeberg.org/miekg/dns/rdata" + _ "github.com/DNSControl/dnscontrol/v5/pkg/privatetypes" + _ "github.com/DNSControl/dnscontrol/v5/pkg/privatetypes/rdata" +) + +// SetRDATA is a setter for RecordConfig.rdata. +func (rc *RecordConfig) SetRDATA(rd dnsv2.RDATA) { + if txt, ok := rd.(dnsrdatav2.TXT); ok { + txt.Txt = TXTSegmented(txt) + rd = txt + } + rd = normalizeRDATA(rd) + rc.rdata = rd + rc.validateRDATA() + rc.generateComparableV3() +} + +// GetRDATA is a getter for RecordConfig.rdata. +func (rc *RecordConfig) GetRDATA() (rd dnsv2.RDATA) { + if rd, ok := rc.rdata.(dnsrdatav2.TXT); ok { + if !txtProperlySegmented(rd.Txt) { + fmt.Fprintf(os.Stderr, "WARNING: GetRDATA: TXT record not properly segmented. Someone is not using SetRDATA? txt=%+v\n", rd.Txt) + } + } + return rc.rdata +} + +// ClearRDATA sets rc.rdata to nil. This is a workaround for +// integrationTest/helpers_integration_test.go and will eventually be +// eliminated. No new uses, please! +func (rc *RecordConfig) ClearRDATA() { + rc.rdata = nil + rc.ComparableV3 = "" +} + +func MyNewData(typeNum uint16, contents string, origin string) (dnsv2.RDATA, error) { + switch typeNum { + + case dnsv2.TypeTXT: + // NewData expects quotes around TXT contents. + if len(contents) > 0 && (contents[0] != '"' && contents[len(contents)-1] != '"') { + contents = `"` + contents + `"` + } + + } + + rd2, err := dnsv2.NewData(typeNum, contents, origin+".") + if err != nil { + return nil, fmt.Errorf("NewData(%d, %q, %q) failed: %w", typeNum, contents, origin+".", err) + } + return normalizeRDATA(rd2), nil +} + +// validateRDATA is used to verify that .rdata didn't accidentally get set to +// rdata (instead of *rdata). This shouldn't be needed, but it catches coding +// mistakes. Eventually this may become a no-op. +func (rc *RecordConfig) validateRDATA() { + + rd := rc.GetRDATA() + if rd == nil { + return + } + + // Good: `rdata.A` or `privatetypesrdata.CLOUDFLARE_WORKER_ROUTER` + // Bad: `*rdata.A` or `*privatetypesrdata.CLOUDFLARE_WORKER_ROUTER` + // Really Bad: `**rdata.A` or `**privatetypesrdata.CLOUDFLARE_WORKER_ROUTER` + if reflect.TypeOf(rd).Kind() != reflect.Pointer { + return + } + // The common path uses reflection for speed. The old code looked like: + // if ts := fmt.Sprintf("%T", rd); ts[0] != '*' {} + + // On the other hand, we use %T for the error path, which is rarely taken and can be slow. + l := fmt.Sprintf("\nERROR: validateRDATA: typeNum=%d type=%q type=%T", rc.TypeNum, rc.Type, rd) + fmt.Println(l) + fmt.Println(string(debug.Stack())) + panic(l) +} + +func normalizeRDATA(rd2 dnsv2.RDATA) dnsv2.RDATA { + // TODO(tlim): This duplicates code in the MakeTYPE() functions, but + // sadly those functions aren't called by dnsv2.NewData(). + // Fixing this would be difficult since we can't add methods to the + // dnsv2.RDATA interface. We could use interfaces that only get called when they exist. + + switch v := rd2.(type) { + + case dnsrdatav2.DS: + // Uppercase to make comparisons case-insensitive. + v.Digest = strings.ToUpper(v.Digest) + return v + + case dnsrdatav2.SSHFP: + // Uppercase to make comparisons case-insensitive. + v.FingerPrint = strings.ToUpper(v.FingerPrint) + return v + + case dnsrdatav2.TLSA: + // Uppercase to make comparisons case-insensitive. + v.Certificate = strings.ToUpper(v.Certificate) + return v + + case dnsrdatav2.TXT: + // Store TXT data segments with each segment being 255 octets, the remainder in the final segment. + v.Txt = TXTSegmented(v) + return v + + } + + return rd2 +} + +/* + +FUTURE(): + +Add this interface. normalizeRDATA() will call the interface (if it exists for +the RDATA). The type-specific code currently in normalizeRDATA will move to +files such as t_ds.go, t_sshfp.go, t_tlsa.go, t_txt.go. + +type Normalizer interface { + Normalize(*RecordConfig) +} + +*/ + +/* + +TODO(): + +Add this interface. Update pkg/normalize/validate.go to call the interface (if it exists for the RDATA). The type-specific code currently +in pkg/normalize/validate.go files such as t_ds.go, t_sshfp.go, t_tlsa.go, t_txt.go (all in `models/`). +The functions rejectifTargetEqualsLabel and rejectifInvalidR53Weight providers/route53/auditrecords.go will move to models/t_r53alias.go + +type Validater interface { + Validate(*RecordConfig) +} + +*/ diff --git a/models/rdfields.go b/models/rdfields.go new file mode 100644 index 0000000000..29e6611238 --- /dev/null +++ b/models/rdfields.go @@ -0,0 +1,105 @@ +package models + +import ( + "encoding/json" + "fmt" + "reflect" + "strings" + + dnsv2 "codeberg.org/miekg/dns" + dnsrdatav2 "codeberg.org/miekg/dns/rdata" +) + +// RDtoFields extracts the exported fields from an RD into []any. +// Fileds prefixed with "RT_" are not included, as they are "Runtime" values, not part of the RD itself. +func RDtoFields(s dnsv2.RDATA) ([]any, error) { + v := reflect.ValueOf(s) + + // Dereference pointer if a pointer to a struct was passed + if v.Kind() == reflect.Pointer { + v = v.Elem() + // } else { + // return nil, fmt.Errorf("expected pointer to struct, got %v", v.Kind()) + } + + if v.Kind() != reflect.Struct { + return nil, fmt.Errorf("expected struct or pointer to struct, got %v", v.Kind()) + } + + t := v.Type() + + var result []any + for i := 0; i < v.NumField(); i++ { + fieldType := t.Field(i) + + // Skip unexported fields + if fieldType.PkgPath != "" && !fieldType.Anonymous { + continue // skip private fields + } + if strings.HasPrefix(fieldType.Name, "RT_") { + continue + } + + result = append(result, v.Field(i).Interface()) + } + + return result, nil +} + +// RDtoFieldsStrings returns the fields of a RDATA struct as strings. +// Floats are restricted to 2 digits after the decimal. +func RDtoFieldsStrings(s dnsv2.RDATA) ([]string, error) { + items, err := RDtoFields(s) + if err != nil { + return nil, err + } + result := make([]string, len(items)) + for i, item := range items { + switch v := item.(type) { + case string: + result[i] = v + case float32, float64: + result[i] = fmt.Sprintf("%.2f", v) + default: + result[i] = fmt.Sprintf("%v", v) + } + } + return result, nil +} + +// RDtoFieldsJS returns the fields of a RDATA struct as Javascript-constants. +// Examples: int: `2`; string: `"mystring"` +// Floats are restricted to 2 digits after the decimal. +func RDtoFieldsJS(s dnsv2.RDATA) ([]string, error) { + + // Special cases: + + switch v := s.(type) { + case dnsrdatav2.A, dnsrdatav2.AAAA: + return []string{`"` + v.String() + `"`}, nil + } + + // General case: + + items, err := RDtoFields(s) + if err != nil { + return nil, err + } + result := make([]string, len(items)) + for i, item := range items { + switch v := item.(type) { + case string: + // https://stackoverflow.com/questions/51691901 + b, err := json.Marshal(item) + if err != nil { + return nil, err + } + result[i] = string(b) + case float32, float64: + result[i] = fmt.Sprintf("%.2f", v) + default: + result[i] = fmt.Sprintf("%v", v) + } + } + return result, nil +} diff --git a/models/rdfields_test.go b/models/rdfields_test.go new file mode 100644 index 0000000000..1ecfe871a3 --- /dev/null +++ b/models/rdfields_test.go @@ -0,0 +1,39 @@ +package models_test + +import ( + "slices" + "testing" + + dnsv2 "codeberg.org/miekg/dns" + dnsrdatav2 "codeberg.org/miekg/dns/rdata" + "github.com/DNSControl/dnscontrol/v5/models" +) + +func TestRDtoFieldsJS(t *testing.T) { + tests := []struct { + name string // description of this test case + // Named input parameters for target function. + s dnsv2.RDATA + want []string + wantErr bool + }{ + {"mx", dnsrdatav2.MX{Preference: 10, Mx: "foo.example.com."}, []string{"10", `"foo.example.com."`}, false}, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + got, gotErr := models.RDtoFieldsJS(tt.s) + if gotErr != nil { + if !tt.wantErr { + t.Errorf("RDtoFieldsJS() failed: %v", gotErr) + } + return + } + if tt.wantErr { + t.Fatal("RDtoFieldsJS() succeeded unexpectedly") + } + if !slices.Equal(got, tt.want) { + t.Errorf("RDtoFieldsJS() = %v, want %v", got, tt.want) + } + }) + } +} diff --git a/models/record.go b/models/record.go index f6fcdc51bd..94713c62ea 100644 --- a/models/record.go +++ b/models/record.go @@ -6,56 +6,50 @@ import ( "log" "strings" - "github.com/DNSControl/dnscontrol/v4/pkg/txtutil" - "github.com/jinzhu/copier" - dnsv1 "github.com/miekg/dns" - dnsutilv1 "github.com/miekg/dns/dnsutil" + dnsv2 "codeberg.org/miekg/dns" + "github.com/DNSControl/dnscontrol/v5/pkg/nameutil" "github.com/qdm12/reprint" ) // RecordConfig stores a DNS record whether it was created from data downloaded from // a provider's API ("actual") or from user input in dndsconfig.js ("desired"). +// FYI: If you add a field to this struct, also add it to the list in the UnmarshalJSON function. type RecordConfig struct { - // Type is the DNS record type (rtype), all caps, "A", "MX", etc. + + // TypeNum is the assigned number of the record's type. 1 for A, 5 for CNAME, etc. See dnsv2.TypeToString and dnsv2.StringToType. + TypeNum uint16 `json:"typenum,omitempty"` + + // Type is the DNS record type (rtype), all caps, "A", "MX", etc. (Deprecated. Use .TypeNum) Type string `json:"type"` + // rdata is the fields of the record. + rdata dnsv2.RDATA + // TTL is the DNS record's TTL in seconds. 0 means provider default. TTL uint32 `json:"ttl,omitempty"` // Name is the shortname i.e. the FQDN without the parent domains's suffix. // It should never be "". Record at the apex (naked domain) are represented by "@". - NameRaw string `json:"name_raw,omitempty"` // .Name as the user entered it in dnsconfig.js Name string `json:"name"` // The short name, PunyCode. See above. NameUnicode string `json:"name_unicode,omitempty"` // .Name as Unicode (downcased, then convertedot Unicode). // This is the FQDN version of .Name. It should never have a trailing ".". - NameFQDNRaw string `json:"-"` // .NameFQDN as the user entered it in dnsconfig.js (downcased). NameFQDN string `json:"-"` // Must end with ".$origin". NameFQDNUnicode string `json:"-"` // .NameFQDN as Unicode (downcased, then convertedot Unicode). - // F is the binary representation of the record's data usually a dns.XYZ struct. - // Always stored in Punycode, not Unicode. Downcased where applicable. - F any `json:"fields,omitempty"` - //FieldsAsRaw []string // Fields as received from the dnsconfig.js file, converted to strings. - //FieldsAsUnicode []string // fields with IDN fields converted to Unicode for display purposes. - - // Comparable is an opaque string that can be used to compare two - // RecordConfigs for equality. Typically this is the Zonefile line minus the - // label and TTL. - Comparable string `json:"comparable,omitempty"` // Cache of ToComparableNoTTL() - - // ZonefilePartial is the partial zonefile line for this record, excluding - // the label and TTL. If this is not an official RR type, we invent the format. - ZonefilePartial string `json:"zonfefilepartial,omitempty"` + // ComparableV3 is an opaque string that can be used to compare two + // RecordConfigs for equality. Typically this is the Zonefile line + // minus the label and TTL. + // The V3 distingues itself from .Comparable, which it will eventually replace. + // NB(tlim): Not currently used. Placeholder for future feature. + ComparableV3 string `json:"comparablev3,omitempty"` //// Fields only relevant when RecordConfig was created from data in dnsconfig.js: // Metadata (desired) added to the record via dnsconfig.js. For example: A("foo", "1.2.3.4", {metakey: "value"}) Metadata map[string]string `json:"meta,omitempty"` - // FilePos (desired) is "filename:line:char" of the record in dnsconfig.js (desired). FilePos string `json:"filepos"` - // Subdomain (if non-empty) contains the subdomain path for this record. // When .Name* fields are updated to include the subdomain, this field is // cleared. @@ -67,70 +61,23 @@ type RecordConfig struct { // getting the records via the API, we store the original object here. // Later if we need to pull out an ID or other provider-specific field, we // can. Typically deleting or updating a record requires knowing its ID. + // ProTip: Rather than storing the entire struct, store the specific field needed. Original any `json:"-"` //// Legacy fields we hope to remove someday - // If you add a field to this struct, also add it to the list in the UnmarshalJSON function. - target string // If a name, must end with "." - MxPreference uint16 `json:"mxpreference,omitempty"` - SrvPriority uint16 `json:"srvpriority,omitempty"` - SrvWeight uint16 `json:"srvweight,omitempty"` - SrvPort uint16 `json:"srvport,omitempty"` - CaaTag string `json:"caatag,omitempty"` - CaaFlag uint8 `json:"caaflag,omitempty"` - DsKeyTag uint16 `json:"dskeytag,omitempty"` - DsAlgorithm uint8 `json:"dsalgorithm,omitempty"` - DsDigestType uint8 `json:"dsdigesttype,omitempty"` - DsDigest string `json:"dsdigest,omitempty"` - DnskeyFlags uint16 `json:"dnskeyflags,omitempty"` - DnskeyProtocol uint8 `json:"dnskeyprotocol,omitempty"` - DnskeyAlgorithm uint8 `json:"dnskeyalgorithm,omitempty"` - DnskeyPublicKey string `json:"dnskeypublickey,omitempty"` - LocVersion uint8 `json:"locversion,omitempty"` - LocSize uint8 `json:"locsize,omitempty"` - LocHorizPre uint8 `json:"lochorizpre,omitempty"` - LocVertPre uint8 `json:"locvertpre,omitempty"` - LocLatitude uint32 `json:"loclatitude,omitempty"` - LocLongitude uint32 `json:"loclongitude,omitempty"` - LocAltitude uint32 `json:"localtitude,omitempty"` - LuaRType string `json:"luartype,omitempty"` - NaptrOrder uint16 `json:"naptrorder,omitempty"` - NaptrPreference uint16 `json:"naptrpreference,omitempty"` - NaptrFlags string `json:"naptrflags,omitempty"` - NaptrService string `json:"naptrservice,omitempty"` - NaptrRegexp string `json:"naptrregexp,omitempty"` - SmimeaUsage uint8 `json:"smimeausage,omitempty"` - SmimeaSelector uint8 `json:"smimeaselector,omitempty"` - SmimeaMatchingType uint8 `json:"smimeamatchingtype,omitempty"` - SshfpAlgorithm uint8 `json:"sshfpalgorithm,omitempty"` - SshfpFingerprint uint8 `json:"sshfpfingerprint,omitempty"` - SoaMbox string `json:"soambox,omitempty"` - SoaSerial uint32 `json:"soaserial,omitempty"` - SoaRefresh uint32 `json:"soarefresh,omitempty"` - SoaRetry uint32 `json:"soaretry,omitempty"` - SoaExpire uint32 `json:"soaexpire,omitempty"` - SoaMinttl uint32 `json:"soaminttl,omitempty"` - SvcPriority uint16 `json:"svcpriority,omitempty"` - SvcParams string `json:"svcparams,omitempty"` - TlsaUsage uint8 `json:"tlsausage,omitempty"` - TlsaSelector uint8 `json:"tlsaselector,omitempty"` - TlsaMatchingType uint8 `json:"tlsamatchingtype,omitempty"` - R53Alias map[string]string `json:"r53_alias,omitempty"` - AzureAlias map[string]string `json:"azure_alias,omitempty"` - AnswerType string `json:"answer_type,omitempty"` - UnknownTypeName string `json:"unknown_type_name,omitempty"` + UnknownTypeName string `json:"unknown_type_name,omitempty"` } // MarshalJSON marshals RecordConfig. func (rc *RecordConfig) MarshalJSON() ([]byte, error) { recj := &struct { RecordConfig - Target string `json:"target"` + RDATA dnsv2.RDATA `json:"rdata,omitempty"` }{ RecordConfig: *rc, - Target: rc.GetTargetField(), } + recj.RDATA = rc.GetRDATA() j, err := json.Marshal(*recj) if err != nil { return nil, err @@ -138,109 +85,11 @@ func (rc *RecordConfig) MarshalJSON() ([]byte, error) { return j, nil } -// UnmarshalJSON unmarshals RecordConfig. -func (rc *RecordConfig) UnmarshalJSON(b []byte) error { - recj := &struct { - Target string `json:"target"` - - Type string `json:"type"` // All caps rtype name. - Name string `json:"name"` // The short name. See above. - SubDomain string `json:"subdomain,omitempty"` - NameFQDN string `json:"-"` // Must end with ".$origin". See above. - target string // If a name, must end with "." - TTL uint32 `json:"ttl,omitempty"` - Metadata map[string]string `json:"meta,omitempty"` - FilePos string `json:"filepos"` // Where in the file this record was defined. - Original any `json:"-"` // Store pointer to provider-specific record object. Used in diffing. - Args []any `json:"args,omitempty"` - - MxPreference uint16 `json:"mxpreference,omitempty"` - SrvPriority uint16 `json:"srvpriority,omitempty"` - SrvWeight uint16 `json:"srvweight,omitempty"` - SrvPort uint16 `json:"srvport,omitempty"` - CaaTag string `json:"caatag,omitempty"` - CaaFlag uint8 `json:"caaflag,omitempty"` - DsKeyTag uint16 `json:"dskeytag,omitempty"` - DsAlgorithm uint8 `json:"dsalgorithm,omitempty"` - DsDigestType uint8 `json:"dsdigesttype,omitempty"` - DsDigest string `json:"dsdigest,omitempty"` - DnskeyFlags uint16 `json:"dnskeyflags,omitempty"` - DnskeyProtocol uint8 `json:"dnskeyprotocol,omitempty"` - DnskeyAlgorithm uint8 `json:"dnskeyalgorithm,omitempty"` - DnskeyPublicKey string `json:"dnskeypublickey,omitempty"` - LocVersion uint8 `json:"locversion,omitempty"` - LocSize uint8 `json:"locsize,omitempty"` - LocHorizPre uint8 `json:"lochorizpre,omitempty"` - LocVertPre uint8 `json:"locvertpre,omitempty"` - LocLatitude uint32 `json:"loclatitude,omitempty"` - LocLongitude uint32 `json:"loclongitude,omitempty"` - LocAltitude uint32 `json:"localtitude,omitempty"` - LuaRType string `json:"luartype,omitempty"` - NaptrOrder uint16 `json:"naptrorder,omitempty"` - NaptrPreference uint16 `json:"naptrpreference,omitempty"` - NaptrFlags string `json:"naptrflags,omitempty"` - NaptrService string `json:"naptrservice,omitempty"` - NaptrRegexp string `json:"naptrregexp,omitempty"` - SmimeaUsage uint8 `json:"smimeausage,omitempty"` - SmimeaSelector uint8 `json:"smimeaselector,omitempty"` - SmimeaMatchingType uint8 `json:"smimeamatchingtype,omitempty"` - SshfpAlgorithm uint8 `json:"sshfpalgorithm,omitempty"` - SshfpFingerprint uint8 `json:"sshfpfingerprint,omitempty"` - SoaMbox string `json:"soambox,omitempty"` - SoaSerial uint32 `json:"soaserial,omitempty"` - SoaRefresh uint32 `json:"soarefresh,omitempty"` - SoaRetry uint32 `json:"soaretry,omitempty"` - SoaExpire uint32 `json:"soaexpire,omitempty"` - SoaMinttl uint32 `json:"soaminttl,omitempty"` - SvcPriority uint16 `json:"svcpriority,omitempty"` - SvcParams string `json:"svcparams,omitempty"` - TlsaUsage uint8 `json:"tlsausage,omitempty"` - TlsaSelector uint8 `json:"tlsaselector,omitempty"` - TlsaMatchingType uint8 `json:"tlsamatchingtype,omitempty"` - R53Alias map[string]string `json:"r53_alias,omitempty"` - AzureAlias map[string]string `json:"azure_alias,omitempty"` - AnswerType string `json:"answer_type,omitempty"` - UnknownTypeName string `json:"unknown_type_name,omitempty"` - - EnsureAbsent bool `json:"ensure_absent,omitempty"` // Override NO_PURGE and delete this record - - // NB(tlim): If anyone can figure out how to do this without listing all - // the fields, please let us know! - }{} - if err := json.Unmarshal(b, &recj); err != nil { - return err - } - - recj.FilePos = FixPosition(recj.FilePos) - - // Copy the exported fields. - if err := copier.CopyWithOption(&rc, &recj, copier.Option{IgnoreEmpty: true, DeepCopy: true}); err != nil { - return err - } - // Set each unexported field. - if err := rc.SetTarget(recj.Target); err != nil { - return err - } - - // Some sanity checks: - if recj.Type != rc.Type { - panic("DEBUG: TYPE NOT COPIED\n") - } - if recj.Type == "" { - panic("DEBUG: TYPE BLANK\n") - } - if recj.Name != rc.Name { - panic("DEBUG: NAME NOT COPIED\n") - } - - return nil -} - // FixPosition takes the string representation of a position in a file that // comes from dnsconfig.js's initial execution, and reduces it down to just the // line/position we display to the user. The input is not well-defined, thus if // we find something we don't expect, we just return the original input. -// TODO: Move this to rtypecontrol or a similar package. +// TODO: Move this closer to where it is used. func FixPosition(str string) string { if str == "" { return "" @@ -258,7 +107,7 @@ func (rc *RecordConfig) Copy() (*RecordConfig, error) { // Copy the exported fields. err := reprint.FromTo(rc, newR) // Deep copy // Set each unexported field. - newR.target = rc.target + newR.rdata = rc.rdata return newR, err } @@ -268,12 +117,17 @@ func (rc *RecordConfig) Copy() (*RecordConfig, error) { // // short must not have a training dot: That would mean you have a FQDN, and // shouldn't be using SetLabel(). Maybe SetLabelFromFQDN()? +// Deprecated: NewRecordConfig and NewRecordConfigParse remove the need for this. func (rc *RecordConfig) SetLabel(short, origin string) { // Assertions that make sure the function is being used correctly: if strings.HasSuffix(origin, ".") { panic(fmt.Errorf("origin (%s) is not supposed to end with a dot", origin)) } if strings.HasSuffix(short, ".") { + if strings.HasSuffix(short, origin+".") { + fmt.Printf("DEBUG: ******** SetLabel on FQDNdot: %q origin=%q\n", short, origin) + + } if short != "**current-domain**" { panic(fmt.Errorf("short (%s) is not supposed to end with a dot", short)) } @@ -289,29 +143,9 @@ func (rc *RecordConfig) SetLabel(short, origin string) { rc.NameFQDN = origin } else { rc.Name = short - rc.NameFQDN = dnsutilv1.AddOrigin(short, origin) - } -} - -// 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. -func (rc *RecordConfig) SetLabelFromFQDN(fqdn, origin string) { - // Assertions that make sure the function is being used correctly: - if strings.HasSuffix(origin, ".") { - panic(fmt.Errorf("origin (%s) is not supposed to end with a dot", origin)) - } - if strings.HasSuffix(fqdn, "..") { - panic(fmt.Errorf("fqdn (%s) is not supposed to end with double dots", origin)) + rc.NameFQDN = nameutil.ToFqdnNoDot(short, origin) } - - // Trim off a trailing dot. - fqdn = strings.TrimSuffix(fqdn, ".") - - fqdn = strings.ToLower(fqdn) - origin = strings.ToLower(origin) - rc.Name = dnsutilv1.TrimDomainName(fqdn, origin) - rc.NameFQDN = fqdn + // TODO(tlim): This also needs to make .NameUnicode / .NameFQDNUnicode } // GetLabel returns the shortname of the label associated with this RecordConfig. @@ -328,181 +162,82 @@ func (rc *RecordConfig) GetLabelFQDN() string { return rc.NameFQDN } -// ToComparableNoTTL returns a comparison string. If you need to compare two -// RecordConfigs, you can simply compare the string returned by this function. -// The comparison includes all fields except TTL and any provider-specific -// metafields. Provider-specific metafields like CF_PROXY are not the same as -// pseudo-records like ANAME or R53_ALIAS. -func (rc *RecordConfig) ToComparableNoTTL() string { - if rc.IsModernType() { - return rc.Comparable - } - - switch rc.Type { - case "SOA": - return fmt.Sprintf("%s %v %d %d %d %d", rc.target, rc.SoaMbox, rc.SoaRefresh, rc.SoaRetry, rc.SoaExpire, rc.SoaMinttl) - // SoaSerial is not included because it isn't used in comparisons. - case "TXT": - // fmt.Fprintf(os.Stdout, "DEBUG: ToComNoTTL raw txts=%s q=%q\n", rc.target, rc.target) - r := txtutil.EncodeSingle(rc.target) - // fmt.Fprintf(os.Stdout, "DEBUG: ToComNoTTL cmp txts=%s q=%q\n", r, r) - return r - case "LUA": - return rc.luaCombined() - case "UNKNOWN": - return fmt.Sprintf("rtype=%s rdata=%s", rc.UnknownTypeName, rc.target) - case "HTTPS", "SVCB": - return rc.targetCombinedSVCBRaw() - } - return rc.GetTargetCombined() -} - -// ToRR converts a RecordConfig to a dns.RR. -func (rc *RecordConfig) ToRR() dnsv1.RR { - // Function is not valid on pseudo-types. - rdtype, ok := dnsv1.StringToType[rc.Type] +// ToRRv2 converts a RecordConfig to a dnsv2.RR. +func (rc *RecordConfig) ToRRv2() dnsv2.RR { + // Function is only valid on defined types. + rdtype, ok := dnsv2.StringToType[rc.Type] if !ok { log.Fatalf("No such DNS type as (%#v)\n", rc.Type) } - - // If this IsModernType, the dns.RR is already in rc.F. - if rr, ok := rc.F.(dnsv1.RR); ok { - rr.Header().Name = rc.NameFQDN + "." - rr.Header().Rrtype = rdtype - rr.Header().Class = dnsv1.ClassINET - rr.Header().Ttl = rc.TTL - if rc.TTL == 0 { - rr.Header().Ttl = DefaultTTL - } - return rr + if rdtype != rc.TypeNum { + panic("should not happen: ToRRv2") } - // Magically create an RR of the correct type. - rr := dnsv1.TypeToRR[rdtype]() - - // Fill in the header. - rr.Header().Name = rc.NameFQDN + "." - rr.Header().Rrtype = rdtype - rr.Header().Class = dnsv1.ClassINET - rr.Header().Ttl = rc.TTL - if rc.TTL == 0 { - rr.Header().Ttl = DefaultTTL + ttl := rc.TTL + if ttl == 0 { + ttl = DefaultTTL } - // Fill in the data. - switch rdtype { // #rtype_variations - case dnsv1.TypeA: - addr := rc.GetTargetIP() - if s := addr.AsSlice(); len(s) == 4 { - rr.(*dnsv1.A).A = s - } - case dnsv1.TypeAAAA: - addr := rc.GetTargetIP() - if s := addr.AsSlice(); len(s) == 16 { - rr.(*dnsv1.AAAA).AAAA = s - } - case dnsv1.TypeCAA: - rr.(*dnsv1.CAA).Flag = rc.CaaFlag - rr.(*dnsv1.CAA).Tag = rc.CaaTag - rr.(*dnsv1.CAA).Value = rc.GetTargetField() - case dnsv1.TypeCNAME: - rr.(*dnsv1.CNAME).Target = rc.GetTargetField() - case dnsv1.TypeDHCID: - rr.(*dnsv1.DHCID).Digest = rc.GetTargetField() - case dnsv1.TypeDNAME: - rr.(*dnsv1.DNAME).Target = rc.GetTargetField() - case dnsv1.TypeDS: - panic("DS should have been handled as modern type") - case dnsv1.TypeDNSKEY: - rr.(*dnsv1.DNSKEY).Flags = rc.DnskeyFlags - rr.(*dnsv1.DNSKEY).Protocol = rc.DnskeyProtocol - rr.(*dnsv1.DNSKEY).Algorithm = rc.DnskeyAlgorithm - rr.(*dnsv1.DNSKEY).PublicKey = rc.DnskeyPublicKey - case dnsv1.TypeHTTPS: - rr.(*dnsv1.HTTPS).Priority = rc.SvcPriority - rr.(*dnsv1.HTTPS).Target = rc.GetTargetField() - rr.(*dnsv1.HTTPS).Value = rc.GetSVCBValue() - case dnsv1.TypeLOC: - // fmt.Printf("ToRR long: %d, lat:%d, sz: %d, hz:%d, vt:%d\n", rc.LocLongitude, rc.LocLatitude, rc.LocSize, rc.LocHorizPre, rc.LocVertPre) - // fmt.Printf("ToRR rc: %+v\n", *rc) - rr.(*dnsv1.LOC).Version = rc.LocVersion - rr.(*dnsv1.LOC).Longitude = rc.LocLongitude - rr.(*dnsv1.LOC).Latitude = rc.LocLatitude - rr.(*dnsv1.LOC).Altitude = rc.LocAltitude - rr.(*dnsv1.LOC).Size = rc.LocSize - rr.(*dnsv1.LOC).HorizPre = rc.LocHorizPre - rr.(*dnsv1.LOC).VertPre = rc.LocVertPre - case dnsv1.TypeMX: - rr.(*dnsv1.MX).Preference = rc.MxPreference - rr.(*dnsv1.MX).Mx = rc.GetTargetField() - case dnsv1.TypeNAPTR: - rr.(*dnsv1.NAPTR).Order = rc.NaptrOrder - rr.(*dnsv1.NAPTR).Preference = rc.NaptrPreference - rr.(*dnsv1.NAPTR).Flags = rc.NaptrFlags - rr.(*dnsv1.NAPTR).Service = rc.NaptrService - rr.(*dnsv1.NAPTR).Regexp = rc.NaptrRegexp - rr.(*dnsv1.NAPTR).Replacement = rc.GetTargetField() - case dnsv1.TypeNS: - rr.(*dnsv1.NS).Ns = rc.GetTargetField() - case dnsv1.TypeOPENPGPKEY: - rr.(*dnsv1.OPENPGPKEY).PublicKey = rc.GetTargetField() - case dnsv1.TypePTR: - rr.(*dnsv1.PTR).Ptr = rc.GetTargetField() - case dnsv1.TypeSMIMEA: - rr.(*dnsv1.SMIMEA).Usage = rc.SmimeaUsage - rr.(*dnsv1.SMIMEA).MatchingType = rc.SmimeaMatchingType - rr.(*dnsv1.SMIMEA).Selector = rc.SmimeaSelector - rr.(*dnsv1.SMIMEA).Certificate = rc.GetTargetField() - case dnsv1.TypeSOA: - rr.(*dnsv1.SOA).Ns = rc.GetTargetField() - rr.(*dnsv1.SOA).Mbox = rc.SoaMbox - rr.(*dnsv1.SOA).Serial = rc.SoaSerial - rr.(*dnsv1.SOA).Refresh = rc.SoaRefresh - rr.(*dnsv1.SOA).Retry = rc.SoaRetry - rr.(*dnsv1.SOA).Expire = rc.SoaExpire - rr.(*dnsv1.SOA).Minttl = rc.SoaMinttl - case dnsv1.TypeSPF: - rr.(*dnsv1.SPF).Txt = rc.GetTargetTXTSegmented() - case dnsv1.TypeSRV: - rr.(*dnsv1.SRV).Priority = rc.SrvPriority - rr.(*dnsv1.SRV).Weight = rc.SrvWeight - rr.(*dnsv1.SRV).Port = rc.SrvPort - rr.(*dnsv1.SRV).Target = rc.GetTargetField() - case dnsv1.TypeSSHFP: - rr.(*dnsv1.SSHFP).Algorithm = rc.SshfpAlgorithm - rr.(*dnsv1.SSHFP).Type = rc.SshfpFingerprint - rr.(*dnsv1.SSHFP).FingerPrint = rc.GetTargetField() - case dnsv1.TypeSVCB: - rr.(*dnsv1.SVCB).Priority = rc.SvcPriority - rr.(*dnsv1.SVCB).Target = rc.GetTargetField() - rr.(*dnsv1.SVCB).Value = rc.GetSVCBValue() - case dnsv1.TypeTLSA: - rr.(*dnsv1.TLSA).Usage = rc.TlsaUsage - rr.(*dnsv1.TLSA).MatchingType = rc.TlsaMatchingType - rr.(*dnsv1.TLSA).Selector = rc.TlsaSelector - rr.(*dnsv1.TLSA).Certificate = rc.GetTargetField() - case dnsv1.TypeTXT: - rr.(*dnsv1.TXT).Txt = rc.GetTargetTXTSegmented() - default: - panic(fmt.Sprintf("ToRR: Unimplemented rtype %v", rc.Type)) - // We panic so that we quickly find any switch statements - // that have not been updated for a new RR type. + // Make the header + hdr := dnsv2.Header{ + Name: rc.NameFQDN + ".", + TTL: ttl, + Class: dnsv2.ClassINET, } + rd := rc.GetRDATA() + + rr := dnsv2.TypeToRR[rdtype]() // Magically create an RR of the correct type. + *rr.Header() = hdr // Point the header at the header we created. + dnsv2.TypeToRDATA[rdtype](rr, rd) // Copy rd into the fields. + return rr } -// GetDependencies returns the FQDNs on which this record dependents. -func (rc *RecordConfig) GetDependencies() []string { +// Dependency is a record another record depends on. NameFQDN picks the label; +// OnlyType restricts to that record type there ("" = any). +// E.g. a CNAME depends on {NameFQDN: its *target*, OnlyType: ""}. +// E.g. a DS depends on the NS record at the same label: {NameFQDN: its *label*, OnlyType: "NS"}. +type Dependency struct { + NameFQDN string + OnlyType string +} + +// GetDependencies returns the records on which this record depends. +// For example, some providers won't create a CNAME until the target already exists. +// DNSControl will assure that the target exists before the CNAME is created if +// this function returns the target name when called on a CNAME record. +// The reverse is true for deletions: DNSControl will delete the records for +// rc.GetDependencies() before deleting the rc. +func (rc *RecordConfig) GetDependencies() []Dependency { switch rc.Type { - // #rtype_variations - case "NS", "SRV", "CNAME", "DNAME", "MX", "ALIAS", "AZURE_ALIAS", "R53_ALIAS": - return []string{ - rc.target, - } + case "NS": + return []Dependency{{NameFQDN: rc.AsNS().Ns}} + case "SRV": + return []Dependency{{NameFQDN: rc.AsSRV().Target}} + case "CNAME": + return []Dependency{{NameFQDN: rc.AsCNAME().Target}} + case "DNAME": + return []Dependency{{NameFQDN: rc.AsDNAME().Target}} + case "MX": + return []Dependency{{NameFQDN: rc.AsMX().Mx}} + case "ALIAS": + return []Dependency{{NameFQDN: rc.AsALIAS().Target}} + case "AZURE_ALIAS": + return []Dependency{{NameFQDN: rc.AsAZUREALIAS().Target}} + case "R53_ALIAS": + return []Dependency{{NameFQDN: rc.AsR53ALIAS().Target}} + case "DS": + // A DS delegation signs the NS records at the same label: the + // NS must exist before the DS is created, and the DS must be + // removed before the NS is deleted. OnlyType restricts this to + // the NS (There are also DS records at the same label, so + // OnlyType is used otherwise we'd get a false circular + // dependency). + return []Dependency{{NameFQDN: rc.GetLabelFQDN(), OnlyType: "NS"}} } - return []string{} + return nil } // RecordKey represents a resource record in a format used by some systems. @@ -518,17 +253,16 @@ func (rk *RecordKey) String() string { // Key converts a RecordConfig into a RecordKey. func (rc *RecordConfig) Key() RecordKey { t := rc.Type - if rc.R53Alias != nil { - if v, ok := rc.R53Alias["type"]; ok { + if rc.GetRDATA() != nil { + switch rc.Type { + case "R53_ALIAS": // Route53 aliases append their alias type, so that records for the same // label with different alias types are considered separate. - t = fmt.Sprintf("%s_%s", t, v) - } - } else if rc.AzureAlias != nil { - if v, ok := rc.AzureAlias["type"]; ok { + t = fmt.Sprintf("%s_%s", t, rc.AsR53ALIAS().AliasType) + case "AZURE_ALIAS": // Azure aliases append their alias type, so that records for the same // label with different alias types are considered separate. - t = fmt.Sprintf("%s_%s", t, v) + t = fmt.Sprintf("%s_%s", t, rc.AsAZUREALIAS().AliasType) } } // Route 53 weighted/failover routing: records with different @@ -540,46 +274,25 @@ func (rc *RecordConfig) Key() RecordKey { return RecordKey{rc.NameFQDN, t} } -// GetSVCBValue returns the SVCB Key/Values as a list of Key/Values. -func (rc *RecordConfig) GetSVCBValue() []dnsv1.SVCBKeyValue { - if !strings.Contains(rc.SvcParams, "IGNORE+DNSCONTROL") { - rc.SvcParams = strings.ReplaceAll(rc.SvcParams, "ech=IGNORE", "ech=IGNORE+DNSCONTROL+++") - } - - record, err := dnsv1.NewRR(fmt.Sprintf("%s %s %d %s %s", rc.NameFQDN, rc.Type, rc.SvcPriority, rc.target, rc.SvcParams)) - if err != nil { - log.Fatalf("could not parse SVCB record: %s", err) - } - switch r := record.(type) { - case *dnsv1.HTTPS: - return r.Value - case *dnsv1.SVCB: - return r.Value - } - return nil -} - -// IsModernType returns true if this RecordConfig is a record type implemented -// in the new ("Modern") style (i.e. uses the RecordConfig .F field to store -// the rdata of the record). -// -// Since this relies on .F, it must be used only after the RecordConfig -// has been populated. Otherwise, use rtypecontrol.IsModernType(recordTypeName), -// which takes the type name as input. -// -// NOTE: Do not confuse this with rtypeinfo.IsModernType() which provides -// similar functionality. This function is used to have a RecordConfig reveal -// if it uses a modern type. rtypeinfo.IsModernType() takes the rtype name as -// a string argument. -// -// FUTURE(tlim): Once all record types have been migrated to use ".F", this function can be removed. -func (rc *RecordConfig) IsModernType() bool { - return rc.F != nil +func (rc *RecordConfig) IsTTLSignificant() bool { + // "private types" don't really have a useful TTL. + // There may be better ways to determine this. Right now + // this only affects checkRecordSetHasMultipleTTLs(). + return rc.TypeNum < 65280 } // Records is a list of *RecordConfig. type Records []*RecordConfig +// StringEach returns a list of strings, one for each RecordConfig in recs. +func (recs Records) StringEach() []string { + r := make([]string, 0, len(recs)) + for _, rc := range recs { + r = append(r, rc.GetRDATA().String()) + } + return r +} + // HasRecordTypeName returns True if there is a record with this rtype and name. func (recs Records) HasRecordTypeName(rtype, name string) bool { for _, r := range recs { @@ -601,99 +314,22 @@ func (recs Records) GetByType(typeName string) Records { return results } -// GroupedByKey returns a map of keys to records. -func (recs Records) GroupedByKey() map[RecordKey]Records { - groups := map[RecordKey]Records{} - for _, rec := range recs { - groups[rec.Key()] = append(groups[rec.Key()], rec) - } - return groups -} - // GroupedByFQDN returns a map of keys to records, grouped by FQDN. -func (recs Records) GroupedByFQDN() ([]string, map[string]Records) { - order := []string{} +func (recs Records) GroupedByFQDN() map[string]Records { groups := map[string]Records{} for _, rec := range recs { namefqdn := rec.GetLabelFQDN() - if _, found := groups[namefqdn]; !found { - order = append(order, namefqdn) - } groups[namefqdn] = append(groups[namefqdn], rec) } - return order, groups + return groups } // GetAllDependencies concatinates all dependencies of all records. -func (recs Records) GetAllDependencies() []string { - var dependencies []string +func (recs Records) GetAllDependencies() []Dependency { + var dependencies []Dependency for _, rec := range recs { dependencies = append(dependencies, rec.GetDependencies()...) } return dependencies } - -// PostProcessRecords does any post-processing of the downloaded DNS records. -// Deprecated. zonerecords.CorrectZoneRecords() calls Downcase directly. -func PostProcessRecords(recs []*RecordConfig) { - Downcase(recs) -} - -// Downcase converts all labels and targets to lowercase in a list of RecordConfig. -func Downcase(recs []*RecordConfig) { - for _, r := range recs { - if r.IsModernType() { - continue - } - - r.Name = strings.ToLower(r.Name) - r.NameFQDN = strings.ToLower(r.NameFQDN) - switch r.Type { // #rtype_variations - case "AKAMAICDN", "AKAMAITLC", "ALIAS", "AAAA", "ANAME", "CNAME", "DNAME", "DS", "DNSKEY", "MX", "NS", "NAPTR", "SMIMEA", "PTR", "SRV", "TLSA", "AZURE_ALIAS": - // Target is case insensitive. Downcase it. - r.target = strings.ToLower(r.target) - // BUGFIX(tlim): isn't ALIAS in the wrong case statement? - case "A", "CAA", "CLOUDFLAREAPI_SINGLE_REDIRECT", "CF_REDIRECT", "CF_TEMP_REDIRECT", "CF_WORKER_ROUTE", "DHCID", "IMPORT_TRANSFORM", "LOC", "OPENPGPKEY", "SSHFP", "TXT", "ADGUARDHOME_A_PASSTHROUGH", "ADGUARDHOME_AAAA_PASSTHROUGH": - // Do nothing. (IP address or case sensitive target) - case "SOA": - if r.target != "DEFAULT_NOT_SET." { - r.target = strings.ToLower(r.target) // .target stores the Ns - } - if r.SoaMbox != "DEFAULT_NOT_SET." { - r.SoaMbox = strings.ToLower(r.SoaMbox) - } - default: - // TODO: we'd like to panic here, but custom record types complicate things. - } - } -} - -// CanonicalizeTargets turns Targets into FQDNs. -func CanonicalizeTargets(recs []*RecordConfig, origin string) { - originFQDN := origin + "." - - for _, r := range recs { - - if r.IsModernType() { - continue - } - - switch r.Type { // #rtype_variations - case "ALIAS", "ANAME", "CNAME", "DNAME", "DS", "DNSKEY", "MX", "NS", "NAPTR", "PTR", "SRV": - // Target is a hostname that might be a shortname. Turn it into a FQDN. - r.target = dnsutilv1.AddOrigin(r.target, originFQDN) - case "A", "AKAMAICDN", "AKAMAITLC", "CAA", "DHCID", "CLOUDFLAREAPI_SINGLE_REDIRECT", "CF_REDIRECT", "CF_TEMP_REDIRECT", "CF_WORKER_ROUTE", "HTTPS", "IMPORT_TRANSFORM", "LOC", "OPENPGPKEY", "SMIMEA", "SSHFP", "SVCB", "TLSA", "TXT", "ADGUARDHOME_A_PASSTHROUGH", "ADGUARDHOME_AAAA_PASSTHROUGH": - // Do nothing. - case "SOA": - if r.target != "DEFAULT_NOT_SET." { - r.target = dnsutilv1.AddOrigin(r.target, originFQDN) // .target stores the Ns - } - if r.SoaMbox != "DEFAULT_NOT_SET." { - r.SoaMbox = dnsutilv1.AddOrigin(r.SoaMbox, originFQDN) - } - default: - // TODO: we'd like to panic here, but custom record types complicate things. - } - } -} diff --git a/models/record_astype.go b/models/record_astype.go new file mode 100644 index 0000000000..96a62cf4f4 --- /dev/null +++ b/models/record_astype.go @@ -0,0 +1,408 @@ +// Code generated by astype_generate.go; DO NOT EDIT. + +package models + +import ( + dnsrdatav2 "codeberg.org/miekg/dns/rdata" + privatetypesrdata "github.com/DNSControl/dnscontrol/v5/pkg/privatetypes/rdata" +) + +func (rc *RecordConfig) AsA() dnsrdatav2.A { + return rc.GetRDATA().(dnsrdatav2.A) +} + +func (rc *RecordConfig) AsAAAA() dnsrdatav2.AAAA { + return rc.GetRDATA().(dnsrdatav2.AAAA) +} + +func (rc *RecordConfig) AsADGUARDHOMEAAAAPASSTHROUGH() privatetypesrdata.ADGUARDHOMEAAAAPASSTHROUGH { + return rc.GetRDATA().(privatetypesrdata.ADGUARDHOMEAAAAPASSTHROUGH) +} + +func (rc *RecordConfig) AsADGUARDHOMEAPASSTHROUGH() privatetypesrdata.ADGUARDHOMEAPASSTHROUGH { + return rc.GetRDATA().(privatetypesrdata.ADGUARDHOMEAPASSTHROUGH) +} + +func (rc *RecordConfig) AsAFSDB() dnsrdatav2.AFSDB { + return rc.GetRDATA().(dnsrdatav2.AFSDB) +} + +func (rc *RecordConfig) AsAKAMAICDN() privatetypesrdata.AKAMAICDN { + return rc.GetRDATA().(privatetypesrdata.AKAMAICDN) +} + +func (rc *RecordConfig) AsAKAMAITLC() privatetypesrdata.AKAMAITLC { + return rc.GetRDATA().(privatetypesrdata.AKAMAITLC) +} + +func (rc *RecordConfig) AsALIAS() privatetypesrdata.ALIAS { + return rc.GetRDATA().(privatetypesrdata.ALIAS) +} + +func (rc *RecordConfig) AsAVC() dnsrdatav2.TXT { + return rc.GetRDATA().(dnsrdatav2.TXT) +} + +func (rc *RecordConfig) AsAZUREALIAS() privatetypesrdata.AZUREALIAS { + return rc.GetRDATA().(privatetypesrdata.AZUREALIAS) +} + +func (rc *RecordConfig) AsBUNNYDNSPZ() privatetypesrdata.BUNNYDNSPZ { + return rc.GetRDATA().(privatetypesrdata.BUNNYDNSPZ) +} + +func (rc *RecordConfig) AsBUNNYDNSRDR() privatetypesrdata.BUNNYDNSRDR { + return rc.GetRDATA().(privatetypesrdata.BUNNYDNSRDR) +} + +func (rc *RecordConfig) AsCAA() dnsrdatav2.CAA { + return rc.GetRDATA().(dnsrdatav2.CAA) +} + +func (rc *RecordConfig) AsCDNSKEY() dnsrdatav2.DNSKEY { + return rc.GetRDATA().(dnsrdatav2.DNSKEY) +} + +func (rc *RecordConfig) AsCDS() dnsrdatav2.DS { + return rc.GetRDATA().(dnsrdatav2.DS) +} + +func (rc *RecordConfig) AsCERT() dnsrdatav2.CERT { + return rc.GetRDATA().(dnsrdatav2.CERT) +} + +func (rc *RecordConfig) AsCFWORKERROUTE() privatetypesrdata.CFWORKERROUTE { + return rc.GetRDATA().(privatetypesrdata.CFWORKERROUTE) +} + +func (rc *RecordConfig) AsCLA() dnsrdatav2.TXT { + return rc.GetRDATA().(dnsrdatav2.TXT) +} + +func (rc *RecordConfig) AsCLOUDFLAREAPISINGLEREDIRECT() privatetypesrdata.CLOUDFLAREAPISINGLEREDIRECT { + return rc.GetRDATA().(privatetypesrdata.CLOUDFLAREAPISINGLEREDIRECT) +} + +func (rc *RecordConfig) AsCLOUDNSWR() privatetypesrdata.CLOUDNSWR { + return rc.GetRDATA().(privatetypesrdata.CLOUDNSWR) +} + +func (rc *RecordConfig) AsCNAME() dnsrdatav2.CNAME { + return rc.GetRDATA().(dnsrdatav2.CNAME) +} + +func (rc *RecordConfig) AsCSYNC() dnsrdatav2.CSYNC { + return rc.GetRDATA().(dnsrdatav2.CSYNC) +} + +func (rc *RecordConfig) AsDELEG() dnsrdatav2.DELEG { + return rc.GetRDATA().(dnsrdatav2.DELEG) +} + +func (rc *RecordConfig) AsDELEGPARAM() dnsrdatav2.DELEG { + return rc.GetRDATA().(dnsrdatav2.DELEG) +} + +func (rc *RecordConfig) AsDHCID() dnsrdatav2.DHCID { + return rc.GetRDATA().(dnsrdatav2.DHCID) +} + +func (rc *RecordConfig) AsDLV() dnsrdatav2.DS { + return rc.GetRDATA().(dnsrdatav2.DS) +} + +func (rc *RecordConfig) AsDNAME() dnsrdatav2.DNAME { + return rc.GetRDATA().(dnsrdatav2.DNAME) +} + +func (rc *RecordConfig) AsDNSKEY() dnsrdatav2.DNSKEY { + return rc.GetRDATA().(dnsrdatav2.DNSKEY) +} + +func (rc *RecordConfig) AsDS() dnsrdatav2.DS { + return rc.GetRDATA().(dnsrdatav2.DS) +} + +func (rc *RecordConfig) AsDSYNC() dnsrdatav2.DSYNC { + return rc.GetRDATA().(dnsrdatav2.DSYNC) +} + +func (rc *RecordConfig) AsEID() dnsrdatav2.EID { + return rc.GetRDATA().(dnsrdatav2.EID) +} + +func (rc *RecordConfig) AsEUI48() dnsrdatav2.EUI48 { + return rc.GetRDATA().(dnsrdatav2.EUI48) +} + +func (rc *RecordConfig) AsEUI64() dnsrdatav2.EUI64 { + return rc.GetRDATA().(dnsrdatav2.EUI64) +} + +func (rc *RecordConfig) AsFRAME() privatetypesrdata.FRAME { + return rc.GetRDATA().(privatetypesrdata.FRAME) +} + +func (rc *RecordConfig) AsGID() dnsrdatav2.GID { + return rc.GetRDATA().(dnsrdatav2.GID) +} + +func (rc *RecordConfig) AsGPOS() dnsrdatav2.GPOS { + return rc.GetRDATA().(dnsrdatav2.GPOS) +} + +func (rc *RecordConfig) AsHINFO() dnsrdatav2.HINFO { + return rc.GetRDATA().(dnsrdatav2.HINFO) +} + +func (rc *RecordConfig) AsHIP() dnsrdatav2.HIP { + return rc.GetRDATA().(dnsrdatav2.HIP) +} + +func (rc *RecordConfig) AsHTTPS() dnsrdatav2.SVCB { + return rc.GetRDATA().(dnsrdatav2.SVCB) +} + +func (rc *RecordConfig) AsIMPORTTRANSFORM() privatetypesrdata.IMPORTTRANSFORM { + return rc.GetRDATA().(privatetypesrdata.IMPORTTRANSFORM) +} + +func (rc *RecordConfig) AsIPN() dnsrdatav2.IPN { + return rc.GetRDATA().(dnsrdatav2.IPN) +} + +func (rc *RecordConfig) AsISDN() dnsrdatav2.ISDN { + return rc.GetRDATA().(dnsrdatav2.ISDN) +} + +func (rc *RecordConfig) AsKEY() dnsrdatav2.DNSKEY { + return rc.GetRDATA().(dnsrdatav2.DNSKEY) +} + +func (rc *RecordConfig) AsKX() dnsrdatav2.KX { + return rc.GetRDATA().(dnsrdatav2.KX) +} + +func (rc *RecordConfig) AsL32() dnsrdatav2.L32 { + return rc.GetRDATA().(dnsrdatav2.L32) +} + +func (rc *RecordConfig) AsL64() dnsrdatav2.L64 { + return rc.GetRDATA().(dnsrdatav2.L64) +} + +func (rc *RecordConfig) AsLOC() dnsrdatav2.LOC { + return rc.GetRDATA().(dnsrdatav2.LOC) +} + +func (rc *RecordConfig) AsLP() dnsrdatav2.LP { + return rc.GetRDATA().(dnsrdatav2.LP) +} + +func (rc *RecordConfig) AsLUA() privatetypesrdata.LUA { + return rc.GetRDATA().(privatetypesrdata.LUA) +} + +func (rc *RecordConfig) AsMB() dnsrdatav2.MB { + return rc.GetRDATA().(dnsrdatav2.MB) +} + +func (rc *RecordConfig) AsMD() dnsrdatav2.MD { + return rc.GetRDATA().(dnsrdatav2.MD) +} + +func (rc *RecordConfig) AsMF() dnsrdatav2.MF { + return rc.GetRDATA().(dnsrdatav2.MF) +} + +func (rc *RecordConfig) AsMG() dnsrdatav2.MG { + return rc.GetRDATA().(dnsrdatav2.MG) +} + +func (rc *RecordConfig) AsMIKROTIKFORWARDER() privatetypesrdata.MIKROTIKFORWARDER { + return rc.GetRDATA().(privatetypesrdata.MIKROTIKFORWARDER) +} + +func (rc *RecordConfig) AsMIKROTIKFWD() privatetypesrdata.MIKROTIKFWD { + return rc.GetRDATA().(privatetypesrdata.MIKROTIKFWD) +} + +func (rc *RecordConfig) AsMINFO() dnsrdatav2.MINFO { + return rc.GetRDATA().(dnsrdatav2.MINFO) +} + +func (rc *RecordConfig) AsMR() dnsrdatav2.MR { + return rc.GetRDATA().(dnsrdatav2.MR) +} + +func (rc *RecordConfig) AsMX() dnsrdatav2.MX { + return rc.GetRDATA().(dnsrdatav2.MX) +} + +func (rc *RecordConfig) AsNAPTR() dnsrdatav2.NAPTR { + return rc.GetRDATA().(dnsrdatav2.NAPTR) +} + +func (rc *RecordConfig) AsNID() dnsrdatav2.NID { + return rc.GetRDATA().(dnsrdatav2.NID) +} + +func (rc *RecordConfig) AsNIMLOC() dnsrdatav2.NIMLOC { + return rc.GetRDATA().(dnsrdatav2.NIMLOC) +} + +func (rc *RecordConfig) AsNINFO() dnsrdatav2.NINFO { + return rc.GetRDATA().(dnsrdatav2.NINFO) +} + +func (rc *RecordConfig) AsNS() dnsrdatav2.NS { + return rc.GetRDATA().(dnsrdatav2.NS) +} + +func (rc *RecordConfig) AsNSAPPTR() dnsrdatav2.NSAPPTR { + return rc.GetRDATA().(dnsrdatav2.NSAPPTR) +} + +func (rc *RecordConfig) AsNSEC() dnsrdatav2.NSEC { + return rc.GetRDATA().(dnsrdatav2.NSEC) +} + +func (rc *RecordConfig) AsNSEC3() dnsrdatav2.NSEC3 { + return rc.GetRDATA().(dnsrdatav2.NSEC3) +} + +func (rc *RecordConfig) AsNSEC3PARAM() dnsrdatav2.NSEC3PARAM { + return rc.GetRDATA().(dnsrdatav2.NSEC3PARAM) +} + +func (rc *RecordConfig) AsNULL() dnsrdatav2.NULL { + return rc.GetRDATA().(dnsrdatav2.NULL) +} + +func (rc *RecordConfig) AsNXT() dnsrdatav2.NSEC { + return rc.GetRDATA().(dnsrdatav2.NSEC) +} + +func (rc *RecordConfig) AsOPENPGPKEY() dnsrdatav2.OPENPGPKEY { + return rc.GetRDATA().(dnsrdatav2.OPENPGPKEY) +} + +func (rc *RecordConfig) AsPORKBUNURLFWD() privatetypesrdata.PORKBUNURLFWD { + return rc.GetRDATA().(privatetypesrdata.PORKBUNURLFWD) +} + +func (rc *RecordConfig) AsPTR() dnsrdatav2.PTR { + return rc.GetRDATA().(dnsrdatav2.PTR) +} + +func (rc *RecordConfig) AsPX() dnsrdatav2.PX { + return rc.GetRDATA().(dnsrdatav2.PX) +} + +func (rc *RecordConfig) AsR53ALIAS() privatetypesrdata.R53ALIAS { + return rc.GetRDATA().(privatetypesrdata.R53ALIAS) +} + +func (rc *RecordConfig) AsRESINFO() dnsrdatav2.TXT { + return rc.GetRDATA().(dnsrdatav2.TXT) +} + +func (rc *RecordConfig) AsRKEY() dnsrdatav2.RKEY { + return rc.GetRDATA().(dnsrdatav2.RKEY) +} + +func (rc *RecordConfig) AsRP() dnsrdatav2.RP { + return rc.GetRDATA().(dnsrdatav2.RP) +} + +func (rc *RecordConfig) AsRRSIG() dnsrdatav2.RRSIG { + return rc.GetRDATA().(dnsrdatav2.RRSIG) +} + +func (rc *RecordConfig) AsRT() dnsrdatav2.RT { + return rc.GetRDATA().(dnsrdatav2.RT) +} + +func (rc *RecordConfig) AsSIG() dnsrdatav2.RRSIG { + return rc.GetRDATA().(dnsrdatav2.RRSIG) +} + +func (rc *RecordConfig) AsSMIMEA() dnsrdatav2.SMIMEA { + return rc.GetRDATA().(dnsrdatav2.SMIMEA) +} + +func (rc *RecordConfig) AsSOA() dnsrdatav2.SOA { + return rc.GetRDATA().(dnsrdatav2.SOA) +} + +func (rc *RecordConfig) AsSPF() dnsrdatav2.TXT { + return rc.GetRDATA().(dnsrdatav2.TXT) +} + +func (rc *RecordConfig) AsSRV() dnsrdatav2.SRV { + return rc.GetRDATA().(dnsrdatav2.SRV) +} + +func (rc *RecordConfig) AsSSHFP() dnsrdatav2.SSHFP { + return rc.GetRDATA().(dnsrdatav2.SSHFP) +} + +func (rc *RecordConfig) AsSVCB() dnsrdatav2.SVCB { + return rc.GetRDATA().(dnsrdatav2.SVCB) +} + +func (rc *RecordConfig) AsTA() dnsrdatav2.TA { + return rc.GetRDATA().(dnsrdatav2.TA) +} + +func (rc *RecordConfig) AsTALINK() dnsrdatav2.TALINK { + return rc.GetRDATA().(dnsrdatav2.TALINK) +} + +func (rc *RecordConfig) AsTKEY() dnsrdatav2.TKEY { + return rc.GetRDATA().(dnsrdatav2.TKEY) +} + +func (rc *RecordConfig) AsTLSA() dnsrdatav2.TLSA { + return rc.GetRDATA().(dnsrdatav2.TLSA) +} + +func (rc *RecordConfig) AsTSIG() dnsrdatav2.TSIG { + return rc.GetRDATA().(dnsrdatav2.TSIG) +} + +func (rc *RecordConfig) AsTXT() dnsrdatav2.TXT { + return rc.GetRDATA().(dnsrdatav2.TXT) +} + +func (rc *RecordConfig) AsUID() dnsrdatav2.UID { + return rc.GetRDATA().(dnsrdatav2.UID) +} + +func (rc *RecordConfig) AsUINFO() dnsrdatav2.UINFO { + return rc.GetRDATA().(dnsrdatav2.UINFO) +} + +func (rc *RecordConfig) AsURI() dnsrdatav2.URI { + return rc.GetRDATA().(dnsrdatav2.URI) +} + +func (rc *RecordConfig) AsURL() privatetypesrdata.URL { + return rc.GetRDATA().(privatetypesrdata.URL) +} + +func (rc *RecordConfig) AsURL301() privatetypesrdata.URL301 { + return rc.GetRDATA().(privatetypesrdata.URL301) +} + +func (rc *RecordConfig) AsWALLET() dnsrdatav2.TXT { + return rc.GetRDATA().(dnsrdatav2.TXT) +} + +func (rc *RecordConfig) AsX25() dnsrdatav2.X25 { + return rc.GetRDATA().(dnsrdatav2.X25) +} + +func (rc *RecordConfig) AsZONEMD() dnsrdatav2.ZONEMD { + return rc.GetRDATA().(dnsrdatav2.ZONEMD) +} diff --git a/models/record_factory.go b/models/record_factory.go new file mode 100644 index 0000000000..1dd1557773 --- /dev/null +++ b/models/record_factory.go @@ -0,0 +1,242 @@ +package models + +import ( + "fmt" + "slices" + "strings" + + dnsv2 "codeberg.org/miekg/dns" + dnsutilv2 "codeberg.org/miekg/dns/dnsutil" + "github.com/DNSControl/dnscontrol/v5/pkg/mustbe" + nrc "github.com/DNSControl/dnscontrol/v5/pkg/nrc" + "github.com/DNSControl/dnscontrol/v5/pkg/privatetypes" + "golang.org/x/net/idna" +) + +// NewRecordConfig constructs a models.NewRecord(). +// +// It may seem odd that this is a method of DomainConfig but it makes sense if +// you consider that a RecordConfig lives in the context of its DomainConfig. +// For example, the need to shorten a FQDN requires knowing the domain's name, +// which is stored in a DomainConfig. +// Behavior can be modified by sending an optional nrc.Flag struct as the last arg. +func (dc *DomainConfig) NewRecordConfig(name string, ttl uint32, typeAny any, args ...any) (*RecordConfig, error) { + mustbe.ValidArgs(args) + typeNum, err := anyToTypeNum(typeAny) + if err != nil { + return nil, err + } + + // if last arg is type nrc.Flags, assign it to isEnabled then remove it from the args array. + var isEnabled nrc.Flags + if len(args) > 0 { + if f, ok := args[len(args)-1].(nrc.Flags); ok { + isEnabled = f + args = slices.Delete(args, len(args)-1, len(args)) + } + } + + // SrvWeirdSplit + if isEnabled.SrvWeirdSplit && len(args) == 2 { + isEnabled.SrvWeirdSplit = false + return dc.NewRecordConfigParse(name, ttl, typeNum, fmt.Sprintf("%d %s", args[0], args[1].(string)), isEnabled) + } + // TargetIsFqdnNoDot + // Passed to downstream functions. + + // TxtDontParse + if isEnabled.TxtDontParse { + panic("NewRecordConfig() incompatible with TxtDontParse") + } + + f, ok := privatetypes.TypeToMakeRDATA[typeNum] + if !ok { + return nil, fmt.Errorf("NewRecordConfig: failed TypeToMakeRDATA[%d] == nil", typeNum) + } + rd, err := f(dc.Name, nil, isEnabled, args...) + if err != nil { + return nil, fmt.Errorf("NewRecordConfig: Failed to create RDATA for type %d: %w", typeNum, err) + } + + return newRecordConfigHelper(dc.Name, name, ttl, typeNum, rd, nil) +} + +// NewRecordConfigParse is like NewRecordConfig but the fields of the record +// come from parsing data which is assumed to be in RFC1038 Zonefile format. +// Behavior can be modified by sending an optional nrc.Flag struct. +func (dc *DomainConfig) NewRecordConfigParse(name string, ttl uint32, typeAny any, data string, rcflag ...nrc.Flags) (*RecordConfig, error) { + typeNum, err := anyToTypeNum(typeAny) + if err != nil { + return nil, err + } + + var isEnabled nrc.Flags + switch len(rcflag) { + case 0: + case 1: + isEnabled = rcflag[0] + default: + panic(fmt.Sprintf("NewRecordConfigParse() called with multiple flags: %v", rcflag)) + } + + // SrvWeirdSplit + if isEnabled.SrvWeirdSplit { + panic("NewRecordConfigParse() incompatible with SrvWeirdSplit") + } + + // TargetIsFqdnNoDot + origin := dc.Name + if isEnabled.TargetIsFqdnNoDot { + origin = "" + } + + // TxtDontParse + if isEnabled.TxtDontParse && typeNum == dnsv2.TypeTXT { + isEnabled.TxtDontParse = false + return dc.NewRecordConfig(name, ttl, typeNum, data, isEnabled) + } + + rd, err := MyNewData(typeNum, data, origin) + if err != nil { + return nil, err + } + return newRecordConfigHelper(dc.Name, name, ttl, typeNum, rd, nil) +} + +// NewRecordConfigForRRv2toRC is like NewRecordConfig but takes an RDATA. It +// should only be used by RRv2toRC. It is not intended for general use. +func (dc *DomainConfig) NewRecordConfigForRRv2toRC(name string, ttl uint32, typeNum uint16, rd dnsv2.RDATA) (*RecordConfig, error) { + return newRecordConfigHelper(dc.Name, name, ttl, typeNum, rd, nil) +} + +// newRecordConfigFromDnsconfigjs is only for use by models.ImportRawRecords(). +// +// This is similar to NewRecordConfig plus: +// * Processes name with the "dot rules" of dnsconfig.js. +// * Processes metadata. +// * Handles the D_EXTEND() "subdomain" concept on both the name and any targets. +// +// subdomain is the D_EXTEND() subdomain this record was declared under ("" if +// none). Relative targets (CNAME/MX/NS/SRV/ALIAS) are canonicalized relative to +// subdomain.zone, while the label is already relative to the zone, so the label +// machinery still uses dc.Name. +func (dc *DomainConfig) newRecordConfigFromDnsconfigjs(name string, ttl uint32, typeNum uint16, args []any, metadata map[string]string, subdomain string) (*RecordConfig, error) { + + targetOrigin := dc.Name + if subdomain != "" { + targetOrigin = subdomain + "." + dc.Name + } + + label, err := dc.LabelFromDnsconfigjs(name, subdomain) + if err != nil { + return nil, err + } + + rd, err := privatetypes.TypeToMakeRDATA[typeNum](targetOrigin, metadata, nrc.Flags{EnforceOneDotPolicy: true}, args...) + if err != nil { + return nil, fmt.Errorf("dnsconfigjs: failed to create RDATA for type %s: %w", dnsutilv2.TypeToString(typeNum), err) + } + + return newRecordConfigHelper(dc.Name, label, ttl, typeNum, rd, metadata) +} + +// newRecordConfigHelper is a helper. if rd != nil, args is ignored. +// All valid RecordConfig structs come through this function. Everything else is questionable. +func newRecordConfigHelper(origin, name string, ttl uint32, typeNum uint16, rd dnsv2.RDATA, metadata map[string]string) (*RecordConfig, error) { + + nameASCII, err := makeLabelName(name) + if err != nil { + return nil, err + } + nameUnicode, err := makeLabelNameUnicode(nameASCII) + if err != nil { + return nil, err + } + nameFQDNASCII := makeLabelNameFQDN(origin, nameASCII) + nameFQDNUnicode, err := makeNameFQDNUnicode(nameFQDNASCII) + if err != nil { + return nil, err + } + + rc := &RecordConfig{ + Type: dnsutilv2.TypeToString(typeNum), + TypeNum: typeNum, + Name: nameASCII, + NameUnicode: nameUnicode, + NameFQDN: nameFQDNASCII, + NameFQDNUnicode: nameFQDNUnicode, + TTL: ttl, + Metadata: metadata, + } + if rc.Metadata == nil { + rc.Metadata = map[string]string{} + } + rc.SetRDATA(rd) + return rc, nil +} + +func anyToTypeNum(a any) (uint16, error) { + switch v := a.(type) { + case uint16: + return v, nil + case int: + return uint16(v), nil + case string: + typeNum, err := dnsutilv2.StringToType(v) + if err == nil { + return typeNum, nil + } else { + return 0, fmt.Errorf("anyToTypeNum(%q) failed: %w", v, err) + } + } + return 0, fmt.Errorf("anyToTypeNum called with unknown type: %T", a) +} + +func makeLabelName(name string) (string, error) { + nameASCII, err := idna.ToASCII(name) + if err != nil { + return "", err + } + nameASCII = strings.ToLower(nameASCII) + + // Avoid pointless duplication. + if nameASCII == name { + return name, nil + } + + return nameASCII, err +} + +func makeLabelNameUnicode(name string) (string, error) { + nameUnicode, err := idna.ToUnicode(name) + if err != nil { + return "", err + } + // Avoid pointless duplication. + if name == nameUnicode { + return name, nil + } + return nameUnicode, nil +} + +func makeLabelNameFQDN(origin, nameASCII string) string { + if nameASCII == "@" { + return origin + } + if strings.HasSuffix(nameASCII, ".") { // only needed by TestWriteZoneFileEach() and may be removed when that's gone. Otherwise this would be a failed assertion. + return nameASCII[:len(nameASCII)-1] + } + return nameASCII + "." + origin +} + +func makeNameFQDNUnicode(nameFQDN string) (string, error) { + nameFQDNUnicode, err := idna.ToUnicode(nameFQDN) + if err != nil { + return "", err + } + // Avoid pointless duplication. + if nameFQDNUnicode == nameFQDN { + return nameFQDN, nil + } + return nameFQDNUnicode, nil +} diff --git a/models/record_label.go b/models/record_label.go new file mode 100644 index 0000000000..04f8ce38ec --- /dev/null +++ b/models/record_label.go @@ -0,0 +1,213 @@ +package models + +import ( + "errors" + "fmt" + "regexp" + "strings" + + "github.com/DNSControl/dnscontrol/v5/pkg/nameutil" + "golang.org/x/net/idna" +) + +// subdomainExcludedTypes lists the record types whose labels are NOT rewritten +// when declared under a D_EXTEND() subdomain. This mirrors the exclusion list +// in the legacy recordBuilder (pkg/js/helpers.js). +var subdomainExcludedTypes = map[string]bool{ + "CLOUDFLAREAPI_SINGLE_REDIRECT": true, + "CF_WORKER_ROUTE": true, // Probably works either way. Test to find out. + "ADGUARDHOME_A_PASSTHROUGH": true, + "ADGUARDHOME_AAAA_PASSTHROUGH": true, + "MIKROTIK_FWD": true, + "MIKROTIK_NXDOMAIN": true, + "MIKROTIK_FORWARDER": true, +} + +// 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. +// This is legacy code that will go away when everything uses models.NewRecordConfig*() functions. +func (rc *RecordConfig) SetLabelFromFQDN(fqdn, origin string) { + // Assertions that make sure the function is being used correctly: + if strings.HasSuffix(origin, ".") { + panic(fmt.Errorf("origin (%s) is not supposed to end with a dot", origin)) + } + if strings.HasSuffix(fqdn, "..") { + panic(fmt.Errorf("fqdn (%s) is not supposed to end with double dots", origin)) + } + + // Trim off a trailing dot. + fqdn = strings.TrimSuffix(fqdn, ".") + + fqdn = strings.ToLower(fqdn) + origin = strings.ToLower(origin) + rc.Name = nameutil.ToShort(fqdn, origin) + rc.NameFQDN = fqdn +} + +var ipv4LabelRe = regexp.MustCompile(`^\d+\.\d+\.\d+\.\d+$`) + +// LabelFromShort takes a label and prepares it for use in a RecordConfig. +// name is a "shortname" ("foo", not "foo.example.com"). +// name is assumed to be ASCII, not Unicode (which is what most APIs return). +// If name == "", "@" is returned. +func (dc *DomainConfig) LabelFromShort(name string) string { + if len(name) > 0 && name[len(name)-1] == '.' { + fmt.Printf("ERROR: LabelFromShort(%v) called WRONG. Maybe you want LabelFromFQDNWithDot?\n", name) + } + + if name == "" { + return "@" + } + return strings.ToLower(name) +} + +// LabelFromFQDNNoDot takes a label and prepares it for use in a RecordConfig. +// Name is a FQDN without a dot ("foo.example.com"). +// Name is assumed to be ASCII, not Unicode (which is what most APIs return). +// Name is assumed to end with the zone name (which is what most APIs return). +func (dc *DomainConfig) LabelFromFQDNNoDot(name string) string { + if name == "" { + return "@" + } + if name == "@" { + return name + } + if strings.HasSuffix(name, ".") { + fmt.Printf("ERROR: LabelFromFQDNNoDot(%v) called WRONG. Maybe you want LabelFromFQDNWithDot?\n", name) + } + + newName := strings.ToLower(name) + + if before, found := strings.CutSuffix(newName, "."+dc.Name); found { + return before + } + if newName == dc.Name { + return "@" + } + + // These other possibilities all indicate the function was called wrong. + fmt.Printf("ERROR: LabelFromFQDNNoDot(%v) called WRONG\n", name) + if newName == "" { + return "@" + } + return newName +} + +// LabelFromFQDNWithDot takes a label and prepares it for use in a RecordConfig. +// Name is a FQDN with a dot ("foo.example.com."). +// Name is assumed to be ASCII, not Unicode (which is what most APIs return). +// Name is assumed to end with the zone name (which is what most APIs return). +func (dc *DomainConfig) LabelFromFQDNWithDot(name string) string { + if name == "" { + fmt.Printf("ERROR: LabelFromFQDNWithDot(%v) called WRONG. Maybe you want LabelFromShort?\n", name) + return "IMPOSSIBLE" + } + if !strings.HasSuffix(name, ".") { + fmt.Printf("ERROR: LabelFromFQDNWithDot(%v) called WRONG. Maybe you want LabelFromFQDNNoDot?\n", name) + } + + newName := strings.ToLower(name) + + if before, found := strings.CutSuffix(newName, "."+dc.Name+"."); found { + return before + } + if newName == dc.Name+"." { + return "@" + } + + // These other possibilities all indicate the function was called wrong. + fmt.Printf("ERROR: LabelFromFQDNWithDot(%v) called on WRONG domain (%q)\n", name, dc.Name) + if newName == "" { + return "@" + } + return newName +} + +// LabelFromDnsconfigjs processes labels from `dnsconfig.js`. +// +// nameRaw can be any string that is acceptable in dnsconfig.js, including "@", "foo", "foo.bar", "foo.bar.baz.", etc. +// +// subdomainASCII must already be in IDNA (punycode, lowercase) form; the caller +// converts and memoizes it (see DNSConfig.ImportRawRecords), since the same +// subdomain is shared by every record in a D_EXTEND block. +// +// It enforces the "single dot" rule. +// +// It applies D_EXTEND() subdomain label rewriting. +// +// The returned label is relative to the zone (dc.Name). +func (dc *DomainConfig) LabelFromDnsconfigjs(rawLabel, subdomainASCII string) (string, error) { + if subdomainASCII == "" { + return dc.labelFromDnsconfigjsHelper(rawLabel) + } + + // Convert the label to ASCII (post-IDNA). "@" is preserved as-is. + labelASCII := rawLabel + if rawLabel != "@" { + var err error + labelASCII, err = idna.ToASCII(rawLabel) + if err != nil { + return "", fmt.Errorf("label %q rejected by IDNA: %w", rawLabel, err) + } + labelASCII = strings.ToLower(labelASCII) + } + + // All branches below operate on post-IDNA strings. + switch { + case labelASCII == "@": + // @ sub -> sub + return subdomainASCII, nil + case ipv4LabelRe.MatchString(labelASCII): + // 1.2.3.4 sub -> 1.2.3.4 (leave it alone) + return labelASCII, nil + case strings.HasSuffix(dc.Name, ".ip6.arpa"): + return subdomainASCII, nil + case strings.HasSuffix(labelASCII, ".in-addr.arpa"): + // 4.3.2.1.in-addr.arpa -> 4.3 (strip the subdomain suffix) + if strings.HasSuffix(labelASCII, subdomainASCII) { + return labelASCII[:len(labelASCII)-len(subdomainASCII)-1], nil + } + return labelASCII, nil + default: + // one two -> one.two + return labelASCII + "." + subdomainASCII, nil + } +} + +// labelFromDnsconfigjsHelper implements LabelFromDnsconfigjs's case when D_EXTEND() is not in play. +func (dc *DomainConfig) labelFromDnsconfigjsHelper(nameRaw string) (string, error) { + + name := nameRaw + + if name == "" { + return "", errors.New(`label "" is invalid. Use "@" when a label is at the root (apex) of the zone`) + } + if name == "@" { + return name, nil + } + + // Normalize to ASCII and Unicode + nameASCII, err := idna.ToASCII(name) + if err != nil { + return "", fmt.Errorf("label %q rejected by IDNA: %w", name, err) + } + nameASCII = strings.ToLower(nameASCII) + if nameASCII == name { + nameASCII = name // re-use memory + } + + // Strip the zone. + if nameASCII == dc.Name+"." { + return "@", nil + } + if before, found := strings.CutSuffix(nameASCII, "."+dc.Name+"."); found { + return before, nil + } + + if strings.HasSuffix(nameASCII, ".") { + return "", fmt.Errorf("label %q is not in domain %q", name, dc.Name) + } + + return nameASCII, nil +} diff --git a/models/record_label_test.go b/models/record_label_test.go new file mode 100644 index 0000000000..9403e0dd08 --- /dev/null +++ b/models/record_label_test.go @@ -0,0 +1,32 @@ +package models_test + +import ( + "testing" + + "github.com/DNSControl/dnscontrol/v5/models" +) + +func TestDomainConfig_LabelFromFQDNNoDot(t *testing.T) { + tests := []struct { + tname string // description of this test case + domainname string + name string + want string + }{ + {"b", "foo.com", "foo.com", "@"}, + {"a", "foo.com", "bar.foo.com", "bar"}, + {"a", "foo.com", "bat.bar.foo.com", "bat.bar"}, + } + for _, tt := range tests { + t.Run(tt.tname, func(t *testing.T) { + dc, err := models.NewDomainConfig(tt.domainname) + if err != nil { + t.Fatalf("could not construct receiver type: %v", err) + } + got := dc.LabelFromFQDNNoDot(tt.name) + if got != tt.want { + t.Errorf("LabelFromFQDNNoDot(%q) = %v, want %v", tt.name, got, tt.want) + } + }) + } +} diff --git a/models/record_maketestdata.go b/models/record_maketestdata.go new file mode 100644 index 0000000000..0962a41964 --- /dev/null +++ b/models/record_maketestdata.go @@ -0,0 +1,63 @@ +package models + +import ( + "fmt" + "testing" + + "github.com/DNSControl/dnscontrol/v5/pkg/mustbe" +) + +// AddTestRC is a convenience function that uses +// models.NewRecordConfig() to create a models.RecordConfig and adds it to +// a models.DomainConfig. It is for use in unit tests. +// It panics on error. +// It returns a pointer to the newly-created RecordConfig, and adds it to rc.Records. +// If this is not a test, consider dc.AddRecordConfig(). +func (dc *DomainConfig) AddTestRC(t *testing.T, label string, ttl uint32, typeNum uint16, args ...any) *RecordConfig { + mustbe.ValidArgs(args) + rc, err := dc.NewRecordConfig(label, ttl, typeNum, args...) + if err != nil { + fmt.Printf("dc.NewRecordConfig() returned %v", err) + t.FailNow() + } + dc.AddRecordConfig(rc) + return rc +} + +// AddTestRCParse is a convenience function that uses +// models.NewRecordConfigParse() to create a models.RecordConfig and adds it to +// a models.DomainConfig. It is for use in unit tests. +// It panics on error. +// It returns a pointer to the newly-created RecordConfig, and adds it to rc.Records. +// If this is not a test, consider dc.AddRecordConfig(). +// It returns a pointer to the newly-created RecordConfig, and adds it to rc.Records. +func (dc *DomainConfig) AddTestRCParse(label string, ttl uint32, typeNum uint16, contents string) *RecordConfig { + rc, err := dc.NewRecordConfigParse(label, ttl, typeNum, contents) + if err != nil { + panic(fmt.Sprintf("dc.NewRecordConfigParse() returned %v", err)) + } + dc.AddRecordConfig(rc) + return rc +} + +// MustNewRecordConfig is like models.NewRecordConfig but panics if initialization fails. +// It is intended for use in variable initializations in unit tests. +// Before using this, consider using models.AddTestRC() first. +func (dc *DomainConfig) MustNewRecordConfig(name string, ttl uint32, typeAny any, args ...any) *RecordConfig { + rc, err := dc.NewRecordConfig(name, ttl, typeAny, args...) + if err != nil { + panic(err) + } + return rc +} + +// MustNewRecordConfigParse is like NewRecordConfigParse but panics if initialization fails. +// It is intended for use in variable initializations in unit tests. +// Before using this, consider using models.AddTestRCParse() first. +func (dc *DomainConfig) MustNewRecordConfigParse(name string, ttl uint32, typeAny any, data string) *RecordConfig { + rc, err := dc.NewRecordConfigParse(name, ttl, typeAny, data) + if err != nil { + panic(err) + } + return rc +} diff --git a/models/record_switch_benchmark_test.go b/models/record_switch_benchmark_test.go new file mode 100644 index 0000000000..bb67af7cf5 --- /dev/null +++ b/models/record_switch_benchmark_test.go @@ -0,0 +1,123 @@ +package models + +import ( + "net/netip" + "testing" + + dnsv2 "codeberg.org/miekg/dns" + dnsrdatav2 "codeberg.org/miekg/dns/rdata" +) + +var recordSwitchBenchmarkSink uint64 + +//go:noinline +func dispatchByTypeNum(rc *RecordConfig) uint64 { + switch rc.TypeNum { + case dnsv2.TypeA: + f := rc.AsA() + return uint64(dnsv2.TypeA) + uint64(f.Addr.BitLen()) + case dnsv2.TypeAAAA: + f := rc.AsAAAA() + return uint64(dnsv2.TypeAAAA) + uint64(f.Addr.BitLen()) + case dnsv2.TypeCNAME: + f := rc.AsCNAME() + return uint64(dnsv2.TypeCNAME) + uint64(len(f.Target)) + case dnsv2.TypeMX: + f := rc.AsMX() + return uint64(dnsv2.TypeMX) + uint64(f.Preference) + uint64(len(f.Mx)) + case dnsv2.TypeNS: + f := rc.AsNS() + return uint64(dnsv2.TypeNS) + uint64(len(f.Ns)) + case dnsv2.TypeSRV: + f := rc.AsSRV() + return uint64(dnsv2.TypeSRV) + uint64(f.Priority) + uint64(f.Weight) + uint64(f.Port) + uint64(len(f.Target)) + case dnsv2.TypeTXT: + f := rc.AsTXT() + return uint64(dnsv2.TypeTXT) + uint64(len(f.Txt[0])) + case dnsv2.TypeCAA: + f := rc.AsCAA() + return uint64(dnsv2.TypeCAA) + uint64(f.Flag) + uint64(len(f.Tag)) + uint64(len(f.Value)) + default: + return 0 + } +} + +//go:noinline +func dispatchByRDATAType(rc *RecordConfig) uint64 { + switch f := rc.GetRDATA().(type) { + case dnsrdatav2.A: + return uint64(dnsv2.TypeA) + uint64(f.Addr.BitLen()) + case dnsrdatav2.AAAA: + return uint64(dnsv2.TypeAAAA) + uint64(f.Addr.BitLen()) + case dnsrdatav2.CNAME: + return uint64(dnsv2.TypeCNAME) + uint64(len(f.Target)) + case dnsrdatav2.MX: + return uint64(dnsv2.TypeMX) + uint64(f.Preference) + uint64(len(f.Mx)) + case dnsrdatav2.NS: + return uint64(dnsv2.TypeNS) + uint64(len(f.Ns)) + case dnsrdatav2.SRV: + return uint64(dnsv2.TypeSRV) + uint64(f.Priority) + uint64(f.Weight) + uint64(f.Port) + uint64(len(f.Target)) + case dnsrdatav2.TXT: + return uint64(dnsv2.TypeTXT) + uint64(len(f.Txt[0])) + case dnsrdatav2.CAA: + return uint64(dnsv2.TypeCAA) + uint64(f.Flag) + uint64(len(f.Tag)) + uint64(len(f.Value)) + default: + return 0 + } +} + +func BenchmarkRecordConfigSwitchDispatch(b *testing.B) { + records := Records{ + {TypeNum: dnsv2.TypeA, rdata: dnsrdatav2.A{Addr: netip.MustParseAddr("192.0.2.1")}}, + {TypeNum: dnsv2.TypeAAAA, rdata: dnsrdatav2.AAAA{Addr: netip.MustParseAddr("2001:db8::1")}}, + {TypeNum: dnsv2.TypeCNAME, rdata: dnsrdatav2.CNAME{Target: "target.example."}}, + {TypeNum: dnsv2.TypeMX, rdata: dnsrdatav2.MX{Preference: 10, Mx: "mx.example."}}, + {TypeNum: dnsv2.TypeNS, rdata: dnsrdatav2.NS{Ns: "ns.example."}}, + {TypeNum: dnsv2.TypeSRV, rdata: dnsrdatav2.SRV{Priority: 10, Weight: 20, Port: 443, Target: "service.example."}}, + {TypeNum: dnsv2.TypeTXT, rdata: dnsrdatav2.TXT{Txt: []string{"benchmark"}}}, + {TypeNum: dnsv2.TypeCAA, rdata: dnsrdatav2.CAA{Tag: "issue", Value: "ca.example"}}, + } + defaultRecord := Records{ + {TypeNum: dnsv2.TypePTR, rdata: dnsrdatav2.PTR{}}, + } + + benchmarks := []struct { + name string + records Records + }{ + {name: "single", records: records[:1]}, + {name: "mixed", records: records}, + {name: "default", records: defaultRecord}, + } + + for _, benchmark := range benchmarks { + for _, rc := range benchmark.records { + if got, want := dispatchByRDATAType(rc), dispatchByTypeNum(rc); got != want { + b.Fatalf("dispatch results differ for type %d: RDATA=%d TypeNum=%d", rc.TypeNum, got, want) + } + } + + mask := len(benchmark.records) - 1 + b.Run(benchmark.name+"/TypeNum", func(b *testing.B) { + b.ReportAllocs() + var sum uint64 + i := 0 + for b.Loop() { + sum += dispatchByTypeNum(benchmark.records[i&mask]) + i++ + } + recordSwitchBenchmarkSink = sum + }) + + b.Run(benchmark.name+"/RDATAType", func(b *testing.B) { + b.ReportAllocs() + var sum uint64 + i := 0 + for b.Loop() { + sum += dispatchByRDATAType(benchmark.records[i&mask]) + i++ + } + recordSwitchBenchmarkSink = sum + }) + } +} diff --git a/models/record_test.go b/models/record_test.go index 1c27f07eed..fc3803d5ab 100644 --- a/models/record_test.go +++ b/models/record_test.go @@ -3,18 +3,71 @@ package models import ( "reflect" "testing" + + dnsv2 "codeberg.org/miekg/dns" + "github.com/DNSControl/dnscontrol/v5/pkg/privatetypes" ) -func TestHasRecordTypeName(t *testing.T) { - x := &RecordConfig{ - Type: "A", - Name: "@", +// TestR53AliasTargetSurvivesRDATAUpdate verifies the provider-side mutation +// pattern: copy the typed RDATA, update it, and store it with SetRDATA. +func TestR53AliasTargetSurvivesRDATAUpdate(t *testing.T) { + const origin = "example.com" + const wantTarget = "kyle.example.com." + + dc := MustNewDomainConfig(origin) + rc, err := dc.NewRecordConfig("kenny", 300, "R53_ALIAS", "A", wantTarget, "false") + if err != nil { + t.Fatalf("NewRecordConfig: %v", err) + } + + if got := rc.AsR53ALIAS().Target; got != wantTarget { + t.Fatalf("target after construction = %q, want %q", got, wantTarget) + } + + // Simulate Route53 filling in the zone ID. + rd := rc.AsR53ALIAS() + rd.ZoneID = "Z0389923" + rc.SetRDATA(rd) + + if got := rc.AsR53ALIAS().Target; got != wantTarget { + t.Errorf("target after SetRDATA = %q, want %q", got, wantTarget) + } + if got := rc.AsR53ALIAS().ZoneID; got != "Z0389923" { + t.Errorf("zone ID after SetRDATA = %q, want %q", got, "Z0389923") } +} + +// TestAliasToCnameChangeType reproduces the bug where converting an ALIAS to a +// CNAME via ChangeType() (as CLOUDFLAREAPI and other flattening providers do) +// panicked ("FixUp: .RDATA is nil for type CNAME") and/or lost the target. +func TestAliasToCnameChangeType(t *testing.T) { + const origin = "example.com" + const wantTarget = "foo.example.com." + + dc := MustNewDomainConfig(origin) + rc, err := dc.NewRecordConfig("@", 300, "ALIAS", wantTarget) + if err != nil { + t.Fatalf("NewRecordConfig: %v", err) + } + + // A provider converts the apex ALIAS into a CNAME (CNAME flattening). + rc.ChangeTypeToCNAME(dc, rc.AsALIAS().Target) + + if rc.GetRDATA() == nil { + t.Fatal("RDATA is nil after FixRD") + } + if got := rc.AsCNAME().Target; got != wantTarget { + t.Errorf("CNAME target = %q, want %q", got, wantTarget) + } +} + +func TestHasRecordTypeName(t *testing.T) { + dc := MustNewDomainConfig("example.com") recs := Records{} if recs.HasRecordTypeName("A", "@") { t.Errorf("%v: expected (%v) got (%v)\n", recs, false, true) } - recs = append(recs, x) + recs = append(recs, dc.MustNewRecordConfig("@", 0, dnsv2.TypeA, "1.2.3.4")) if !recs.HasRecordTypeName("A", "@") { t.Errorf("%v: expected (%v) got (%v)\n", recs, true, false) } @@ -24,25 +77,22 @@ func TestHasRecordTypeName(t *testing.T) { } func TestKey(t *testing.T) { + dc := MustNewDomainConfig("example.com") tests := []struct { - rc RecordConfig + rc *RecordConfig expected RecordKey }{ { - RecordConfig{Type: "A", NameFQDN: "example.com"}, + dc.MustNewRecordConfig("@", 0, dnsv2.TypeA, "1.2.3.4"), RecordKey{Type: "A", NameFQDN: "example.com"}, }, { - RecordConfig{Type: "R53_ALIAS", NameFQDN: "example.com"}, - RecordKey{Type: "R53_ALIAS", NameFQDN: "example.com"}, - }, - { - RecordConfig{Type: "R53_ALIAS", NameFQDN: "example.com", R53Alias: map[string]string{"foo": "bar"}}, - RecordKey{Type: "R53_ALIAS", NameFQDN: "example.com"}, + dc.MustNewRecordConfig("@", 0, privatetypes.TypeR53ALIAS, "AAAA", ".", true, ""), + RecordKey{Type: "R53_ALIAS_AAAA", NameFQDN: "example.com"}, }, { - RecordConfig{Type: "R53_ALIAS", NameFQDN: "example.com", R53Alias: map[string]string{"type": "AAAA"}}, - RecordKey{Type: "R53_ALIAS_AAAA", NameFQDN: "example.com"}, + dc.MustNewRecordConfig("@", 0, privatetypes.TypeAZUREALIAS, "CNAME", "foo.com"), + RecordKey{Type: "AZURE_ALIAS_CNAME", NameFQDN: "example.com"}, }, } for i, test := range tests { @@ -55,42 +105,13 @@ func TestKey(t *testing.T) { func TestRecordConfig_Copy(t *testing.T) { type fields struct { - Type string - Name string - SubDomain string - NameFQDN string - target string - TTL uint32 - Metadata map[string]string - MxPreference uint16 - SrvPriority uint16 - SrvWeight uint16 - SrvPort uint16 - CaaTag string - CaaFlag uint8 - DsKeyTag uint16 - DsAlgorithm uint8 - DsDigestType uint8 - DsDigest string - NaptrOrder uint16 - NaptrPreference uint16 - NaptrFlags string - NaptrService string - NaptrRegexp string - SshfpAlgorithm uint8 - SshfpFingerprint uint8 - SoaMbox string - SoaSerial uint32 - SoaRefresh uint32 - SoaRetry uint32 - SoaExpire uint32 - SoaMinttl uint32 - TlsaUsage uint8 - TlsaSelector uint8 - TlsaMatchingType uint8 - R53Alias map[string]string - AzureAlias map[string]string - Original any + Type string + Name string + SubDomain string + NameFQDN string + TTL uint32 + Metadata map[string]string + Original any } tests := []struct { name string @@ -101,122 +122,34 @@ func TestRecordConfig_Copy(t *testing.T) { { name: "only", fields: fields{ - Type: "type", - Name: "name", - SubDomain: "sub", - NameFQDN: "namef", - target: "targette", - TTL: 12345, - Metadata: map[string]string{"me": "ah", "da": "ta"}, - MxPreference: 123, - SrvPriority: 223, - SrvWeight: 345, - SrvPort: 456, - CaaTag: "caata", - CaaFlag: 100, - DsKeyTag: 12341, - DsAlgorithm: 99, - DsDigestType: 98, - DsDigest: "dsdig", - NaptrOrder: 10000, - NaptrPreference: 12220, - NaptrFlags: "naptrfl", - NaptrService: "naptrser", - NaptrRegexp: "naptrreg", - SshfpAlgorithm: 4, - SshfpFingerprint: 5, - SoaMbox: "soambox", - SoaSerial: 456789, - SoaRefresh: 192000, - SoaRetry: 293293, - SoaExpire: 3434343, - SoaMinttl: 34234324, - TlsaUsage: 1, - TlsaSelector: 2, - TlsaMatchingType: 3, - R53Alias: map[string]string{"a": "eh", "b": "bee"}, - AzureAlias: map[string]string{"az": "az", "ure": "your"}, - // Original any, + Type: "type", + Name: "name", + SubDomain: "sub", + NameFQDN: "namef", + TTL: 12345, + Metadata: map[string]string{"me": "ah", "da": "ta"}, }, want: &RecordConfig{ - Type: "type", - Name: "name", - SubDomain: "sub", - NameFQDN: "namef", - target: "targette", - TTL: 12345, - Metadata: map[string]string{"me": "ah", "da": "ta"}, - MxPreference: 123, - SrvPriority: 223, - SrvWeight: 345, - SrvPort: 456, - CaaTag: "caata", - CaaFlag: 100, - DsKeyTag: 12341, - DsAlgorithm: 99, - DsDigestType: 98, - DsDigest: "dsdig", - NaptrOrder: 10000, - NaptrPreference: 12220, - NaptrFlags: "naptrfl", - NaptrService: "naptrser", - NaptrRegexp: "naptrreg", - SshfpAlgorithm: 4, - SshfpFingerprint: 5, - SoaMbox: "soambox", - SoaSerial: 456789, - SoaRefresh: 192000, - SoaRetry: 293293, - SoaExpire: 3434343, - SoaMinttl: 34234324, - TlsaUsage: 1, - TlsaSelector: 2, - TlsaMatchingType: 3, - R53Alias: map[string]string{"a": "eh", "b": "bee"}, - AzureAlias: map[string]string{"az": "az", "ure": "your"}, - // Original any, + Type: "type", + Name: "name", + SubDomain: "sub", + NameFQDN: "namef", + // target: "targette", + TTL: 12345, + Metadata: map[string]string{"me": "ah", "da": "ta"}, }, }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { rc := &RecordConfig{ - Type: tt.fields.Type, - Name: tt.fields.Name, - SubDomain: tt.fields.SubDomain, - NameFQDN: tt.fields.NameFQDN, - target: tt.fields.target, - TTL: tt.fields.TTL, - Metadata: tt.fields.Metadata, - MxPreference: tt.fields.MxPreference, - SrvPriority: tt.fields.SrvPriority, - SrvWeight: tt.fields.SrvWeight, - SrvPort: tt.fields.SrvPort, - CaaTag: tt.fields.CaaTag, - CaaFlag: tt.fields.CaaFlag, - DsKeyTag: tt.fields.DsKeyTag, - DsAlgorithm: tt.fields.DsAlgorithm, - DsDigestType: tt.fields.DsDigestType, - DsDigest: tt.fields.DsDigest, - NaptrOrder: tt.fields.NaptrOrder, - NaptrPreference: tt.fields.NaptrPreference, - NaptrFlags: tt.fields.NaptrFlags, - NaptrService: tt.fields.NaptrService, - NaptrRegexp: tt.fields.NaptrRegexp, - SshfpAlgorithm: tt.fields.SshfpAlgorithm, - SshfpFingerprint: tt.fields.SshfpFingerprint, - SoaMbox: tt.fields.SoaMbox, - SoaSerial: tt.fields.SoaSerial, - SoaRefresh: tt.fields.SoaRefresh, - SoaRetry: tt.fields.SoaRetry, - SoaExpire: tt.fields.SoaExpire, - SoaMinttl: tt.fields.SoaMinttl, - TlsaUsage: tt.fields.TlsaUsage, - TlsaSelector: tt.fields.TlsaSelector, - TlsaMatchingType: tt.fields.TlsaMatchingType, - R53Alias: tt.fields.R53Alias, - AzureAlias: tt.fields.AzureAlias, - Original: tt.fields.Original, + Type: tt.fields.Type, + Name: tt.fields.Name, + SubDomain: tt.fields.SubDomain, + NameFQDN: tt.fields.NameFQDN, + TTL: tt.fields.TTL, + Metadata: tt.fields.Metadata, + Original: tt.fields.Original, } got, err := rc.Copy() if (err != nil) != tt.wantErr { @@ -260,3 +193,46 @@ func TestFixPosition(t *testing.T) { }) } } + +func Test_makeLabelNameFQDN(t *testing.T) { + tests := []struct { + tname string // description of this test case + // Named input parameters for target function. + origin string + name string + want string + }{ + {"a", "bosun.org", "@", "bosun.org"}, + {"b", "bosun.org", "foo", "foo.bosun.org"}, + {"c", "bosun.org", "bosun.org.", "bosun.org"}, + {"d", "bosun.org", "foo.bosun.org.", "foo.bosun.org"}, + } + for _, tt := range tests { + t.Run(tt.tname, func(t *testing.T) { + got := makeLabelNameFQDN(tt.origin, tt.name) + if got != tt.want { + t.Errorf("makeNameFQDN(%q) = %v, want %v", tt.name, got, tt.want) + } + }) + } +} + +func Test_makeLabelNameUnicode(t *testing.T) { + tests := []struct { + tname string // description of this test case + // Named input parameters for target function. + name string + want string + }{ + {"a", "foo.com", "foo.com"}, + {"b", "xn--mnchen-3ya.com", "münchen.com"}, + } + for _, tt := range tests { + t.Run(tt.tname, func(t *testing.T) { + got, _ := makeLabelNameUnicode(tt.name) + if got != tt.want { + t.Errorf("makeNameUnicode(%q) = %v, want %v", tt.name, got, tt.want) + } + }) + } +} diff --git a/models/recordtype.go b/models/recordtype.go index 1340a64177..35d41e0f22 100644 --- a/models/recordtype.go +++ b/models/recordtype.go @@ -1,14 +1,24 @@ package models -// ChangeType converts rc to an rc of type newType. This is only needed when -// converting from one type to another. Do not use this when initializing a new -// record. -// -// Typically this is used to convert an ALIAS to a CNAME, or SPF to TXT. Using -// this function future-proofs the code since eventually such changes will -// require extra steps. -func (rc *RecordConfig) ChangeType(newType string, _ string) { +import ( + "fmt" - rc.Type = newType + dnsv2 "codeberg.org/miekg/dns" + "github.com/DNSControl/dnscontrol/v5/pkg/nrc" +) +// ChangeTypeToCNAME changes rc into a CNAME pointing at target. target will be +// passed to mustbe.TargetHost() to assure it is (or convert it to) a FQDN+".", +// canonicalized to ASCII, and ToLower. +func (rc *RecordConfig) ChangeTypeToCNAME(dc *DomainConfig, target string) { + // Change the Type/TypeNum + rc.Type = "CNAME" + rc.TypeNum = dnsv2.TypeCNAME + + // Store the new RDATA: + rd, err := MakeCNAME(dc.Name, nil, nrc.Flags{}, target) + if err != nil { + panic(fmt.Sprintf("failed ChangeTypeToCNAME: err=%s", err)) // Should not happen. + } + rc.SetRDATA(rd) } diff --git a/models/stutter.go b/models/stutter.go new file mode 100644 index 0000000000..4e5b7f8489 --- /dev/null +++ b/models/stutter.go @@ -0,0 +1,34 @@ +package models + +import ( + "fmt" + "strings" +) + +// isReverseZone reports whether zoneName is an IPv4 or IPv6 reverse-DNS zone. +func isReverseZone(zoneName string) bool { + return strings.HasSuffix(zoneName, ".in-addr.arpa") || strings.HasSuffix(zoneName, ".ip6.arpa") +} + +func doesStutter(name, origin string) bool { + // TODO(tlim): MAYBE: Never return true if last char is "."? + // TODO(tlim): Panic if called with name == ""? + if name == "@" { + return false + } + // Return true if name is the origin (should be "@") or ends in the origin. + return name == origin || strings.HasSuffix(name, "."+origin) +} + +func stutterError(rc *RecordConfig, domain string) error { + label := rc.Name + shortname := strings.TrimSuffix(label, "."+domain) + return fmt.Errorf( + `%s The target name "%s.%s." is an error (repeats the domain). Possible fixes: Replace %q with %q or %q or add DISABLE_REPEATED_DOMAIN_CHECK to this record to override`, + rc.FilePos, + label, domain, + label, + shortname, + label+".", + ) +} diff --git a/pkg/rtypecontrol/import_test.go b/models/stutter_test.go similarity index 68% rename from pkg/rtypecontrol/import_test.go rename to models/stutter_test.go index 50256ce1ab..b51ece398b 100644 --- a/pkg/rtypecontrol/import_test.go +++ b/models/stutter_test.go @@ -1,18 +1,13 @@ -package rtypecontrol +package models import "testing" -func Test_stutters(t *testing.T) { +func Test_doesStutter(t *testing.T) { tests := []struct { name string rName string want bool }{ - { - name: "@ symbol should not stutter", - rName: "@", - want: false, - }, { name: "exact domain match should stutter", rName: "example.com", @@ -24,34 +19,39 @@ func Test_stutters(t *testing.T) { want: true, }, { - name: "simple subdomain should not stutter", - rName: "www", + name: "nested subdomain should stutter", + rName: "api.staging.example.com", + want: true, + }, + { + name: "@ symbol should NOT stutter", + rName: "@", want: false, }, { - name: "partial match without dot should not stutter", - rName: "testexample.com", + name: "different domain should NOT stutter", + rName: "example.org", want: false, }, { - name: "empty name should not stutter", - rName: "", + name: "simple subdomain should NOT stutter", + rName: "www", want: false, }, { - name: "nested subdomain should stutter", - rName: "api.staging.example.com", - want: true, + name: "similar domain should NOT stutter", + rName: "testexample.com", + want: false, }, { - name: "different domain should not stutter", - rName: "example.org", + name: "empty name should NOT stutter", + rName: "", want: false, }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { - if got := stutters(tt.rName, "example.com"); got != tt.want { + if got := doesStutter(tt.rName, "example.com"); got != tt.want { t.Errorf("stutters(%q, %q) = %v, want %v", tt.rName, "example.com", got, tt.want) } }) diff --git a/models/t_caa.go b/models/t_caa.go deleted file mode 100644 index 968ded148f..0000000000 --- a/models/t_caa.go +++ /dev/null @@ -1,52 +0,0 @@ -package models - -import ( - "fmt" - "slices" - "strconv" -) - -// SetTargetCAA sets the CAA fields. -func (rc *RecordConfig) SetTargetCAA(flag uint8, tag string, target string) error { - rc.CaaTag = tag - rc.CaaFlag = flag - if err := rc.SetTarget(target); err != nil { - return err - } - if rc.Type == "" { - rc.Type = "CAA" - } - if rc.Type != "CAA" { - panic("assertion failed: SetTargetCAA called when .Type is not CAA") - } - - // Per: https://www.iana.org/assignments/pkix-parameters/pkix-parameters.xhtml#caa-properties excluding reserved tags - allowedTags := []string{"issue", "issuewild", "iodef", "contactemail", "contactphone", "issuemail", "issuevmc"} - if !slices.Contains(allowedTags, tag) { - return fmt.Errorf("CAA tag (%v) is not one of the valid types", tag) - } - - return nil -} - -// SetTargetCAAStrings is like SetTargetCAA but accepts strings. -func (rc *RecordConfig) SetTargetCAAStrings(flag, tag, target string) error { - i64flag, err := strconv.ParseUint(flag, 10, 8) - if err != nil { - return fmt.Errorf("CAA flag does not fit in 8 bits: %w", err) - } - return rc.SetTargetCAA(uint8(i64flag), tag, target) -} - -// SetTargetCAAString is like SetTargetCAA but accepts one big string. -// Ex: `0 issue "letsencrypt.org"`. -func (rc *RecordConfig) SetTargetCAAString(s string) error { - part, err := ParseQuotedFields(s) - if err != nil { - return err - } - if len(part) != 3 { - return fmt.Errorf("CAA value does not contain 3 fields: (%#v)", s) - } - return rc.SetTargetCAAStrings(part[0], part[1], part[2]) -} diff --git a/models/t_dnskey.go b/models/t_dnskey.go deleted file mode 100644 index 4f2be60ff1..0000000000 --- a/models/t_dnskey.go +++ /dev/null @@ -1,52 +0,0 @@ -package models - -import ( - "strconv" - "strings" - - "github.com/pkg/errors" -) - -// SetTargetDNSKEY sets the DNSKEY fields. -func (rc *RecordConfig) SetTargetDNSKEY(flags uint16, protocol, algorithm uint8, publicKey string) error { - rc.DnskeyFlags = flags - rc.DnskeyProtocol = protocol - rc.DnskeyAlgorithm = algorithm - rc.DnskeyPublicKey = publicKey - - if rc.Type == "" { - rc.Type = "DNSKEY" - } - if rc.Type != "DNSKEY" { - panic("assertion failed: SetTargetDNSKEY called when .Type is not DNSKEY") - } - - return nil -} - -// SetTargetDNSKEYStrings is like SetTargetDNSKEY but accepts strings. -func (rc *RecordConfig) SetTargetDNSKEYStrings(flags, protocol, algorithm, publicKey string) error { - u16flags, err := strconv.ParseUint(flags, 10, 16) - if err != nil { - return errors.Wrap(err, "DNSKEY Flags can't fit in 16 bits") - } - u8protocol, err := strconv.ParseUint(protocol, 10, 8) - if err != nil { - return errors.Wrap(err, "DNSKEY Protocol can't fit in 8 bits") - } - u8algorithm, err := strconv.ParseUint(algorithm, 10, 8) - if err != nil { - return errors.Wrap(err, "DNSKEY Algorithm can't fit in 8 bits") - } - - return rc.SetTargetDNSKEY(uint16(u16flags), uint8(u8protocol), uint8(u8algorithm), publicKey) -} - -// SetTargetDNSKEYString is like SetTargetDNSKEY but accepts one big string. -func (rc *RecordConfig) SetTargetDNSKEYString(s string) error { - part := strings.Fields(s) - if len(part) != 4 { - return errors.Errorf("DNSKEY value does not contain 4 fieldnskey: (%#v)", s) - } - return rc.SetTargetDNSKEYStrings(part[0], part[1], part[2], part[3]) -} diff --git a/models/t_ds.go b/models/t_ds.go deleted file mode 100644 index 38553ed835..0000000000 --- a/models/t_ds.go +++ /dev/null @@ -1,52 +0,0 @@ -package models - -import ( - "strconv" - "strings" - - "github.com/pkg/errors" -) - -// SetTargetDS sets the DS fields. -func (rc *RecordConfig) SetTargetDS(keytag uint16, algorithm, digesttype uint8, digest string) error { - rc.DsKeyTag = keytag - rc.DsAlgorithm = algorithm - rc.DsDigestType = digesttype - rc.DsDigest = digest - - if rc.Type == "" { - rc.Type = "DS" - } - if rc.Type != "DS" { - panic("assertion failed: SetTargetDS called when .Type is not DS") - } - - return nil -} - -// SetTargetDSStrings is like SetTargetDS but accepts strings. -func (rc *RecordConfig) SetTargetDSStrings(keytag, algorithm, digesttype, digest string) error { - u16keytag, err := strconv.ParseUint(keytag, 10, 16) - if err != nil { - return errors.Wrap(err, "DS KeyTag can't fit in 16 bits") - } - u8algorithm, err := strconv.ParseUint(algorithm, 10, 8) - if err != nil { - return errors.Wrap(err, "DS Algorithm can't fit in 8 bits") - } - u8digesttype, err := strconv.ParseUint(digesttype, 10, 8) - if err != nil { - return errors.Wrap(err, "DS DigestType can't fit in 8 bits") - } - - return rc.SetTargetDS(uint16(u16keytag), uint8(u8algorithm), uint8(u8digesttype), digest) -} - -// SetTargetDSString is like SetTargetDS but accepts one big string. -func (rc *RecordConfig) SetTargetDSString(s string) error { - part := strings.Fields(s) - if len(part) != 4 { - return errors.Errorf("DS value does not contain 4 fields: (%#v)", s) - } - return rc.SetTargetDSStrings(part[0], part[1], part[2], part[3]) -} diff --git a/models/t_loc.go b/models/t_loc.go index 86fd8f9872..8bd5efc671 100644 --- a/models/t_loc.go +++ b/models/t_loc.go @@ -1,216 +1,25 @@ package models import ( - "fmt" "math" - "strings" - dnsv1 "github.com/miekg/dns" + dnsv2 "codeberg.org/miekg/dns" ) -// SetTargetLOC sets the LOC fields from the rr.LOC type properties. -func (rc *RecordConfig) SetTargetLOC(ver uint8, lat uint32, lon uint32, alt uint32, siz uint8, hzp uint8, vtp uint8) error { - rc.LocVersion = ver - rc.LocLatitude = lat - rc.LocLongitude = lon - rc.LocAltitude = alt - rc.LocSize = siz - rc.LocHorizPre = hzp - rc.LocVertPre = vtp - - if rc.Type == "" { - rc.Type = "LOC" - } - if rc.Type != "LOC" { - panic("assertion failed: SetTargetLOC called when .Type is not LOC") - } - return nil -} - -// SetLOCParams is an intermediate function which passes the 12 input parameters -// for further processing to the LOC native 7 input binary format: -// LocVersion (0), LocLatitude, LocLongitude, LocAltitude, LocSize, LocVertPre, LocHorizPre. -func (rc *RecordConfig) SetLOCParams(d1 uint8, m1 uint8, s1 float32, ns string, - d2 uint8, m2 uint8, s2 float32, ew string, al float32, sz float32, hp float32, vp float32, -) error { - err := rc.calculateLOCFields(d1, m1, s1, ns, d2, m2, s2, ew, al, sz, hp, vp) - - return err -} - -// SetTargetLOCString is like SetTargetLOC but accepts one big string and origin -// Normally this is used when we receive a record string from provider records -// because e.g. the provider API passed rc.PopulateFromString(). -func (rc *RecordConfig) SetTargetLOCString(origin string, contents string) error { - // This is where text from provider records ingresses into the target field. - // Fill the other fields derived from the TEXT here. LOC is special, and - // needs more math. - // We have to re-invent the wheel because the miekg dns library gives no - // access to the objects properties, and internally the object is represented - // by the dns.LOC format 💩 - - // Build a string with which to init the rr.LOC object: - str := fmt.Sprintf("%s. LOC %s\n", origin, contents) - loc, err := dnsv1.NewRR(str) - if err != nil { - return fmt.Errorf("can't parse LOC data: %w", err) - } - // We 'normalize' the record thru rr.LOC, to get defaults for absent properties. - - loctext := loc.String() - loctext = strings.TrimSpace(strings.Split(loctext, "LOC")[1]) - - err = rc.extractLOCFieldsFromStringInput(loctext) - if err != nil { - return fmt.Errorf("can't extractLOCFieldsFromStringInput from LOC data: %w", err) - } - rc.target = loctext - if rc.Type == "" { - rc.Type = "LOC" - } - if rc.Type != "LOC" { - panic("assertion failed: SetTargetLOC called when .Type is not LOC") - } - return nil -} - -// extractLOCFieldsFromStringInput is a helper to split an input string to -// the 12 variable inputs of integers and strings. -func (rc *RecordConfig) extractLOCFieldsFromStringInput(input string) error { - var d1, m1, d2, m2 uint8 - var al float32 - var s1, s2 float32 - var ns, ew string - var sz, hp, vp float32 - - _, err := fmt.Sscanf(input+"~", "%d %d %f %s %d %d %f %s %fm %fm %fm %fm~", - &d1, &m1, &s1, &ns, &d2, &m2, &s2, &ew, &al, &sz, &hp, &vp) - if err != nil { - return fmt.Errorf("extractLOCFieldsFromStringInput: can't unpack LOC text input data: %w", err) - } - // fmt.Printf("\ngot: %d %d %g %s %d %d %g %s %0.2fm %0.2fm %0.2fm %0.2fm \n", d1, m1, s1, ns, d2, m2, s2, ew, al, sz, hp, vp) - - return rc.calculateLOCFields(d1, m1, s1, ns, d2, m2, s2, ew, al, sz, hp, vp) -} - -// calculateLOCFields converts from 12 user inputs to the LOC 7 binary fields. -func (rc *RecordConfig) calculateLOCFields(d1 uint8, m1 uint8, s1 float32, ns string, - d2 uint8, m2 uint8, s2 float32, ew string, al float32, sz float32, hp float32, vp float32, -) error { - // Crazy hairy shit happens here. - // We already got the useful "string" version earlier. ¯\_(ツ)_/¯ code golf... - lat := uint32(d1)*dnsv1.LOC_DEGREES + uint32(m1)*dnsv1.LOC_HOURS + uint32(s1*1000) - lon := uint32(d2)*dnsv1.LOC_DEGREES + uint32(m2)*dnsv1.LOC_HOURS + uint32(s2*1000) - if strings.ToUpper(ns) == "N" { - rc.LocLatitude = dnsv1.LOC_EQUATOR + lat - } else { // "S" - rc.LocLatitude = dnsv1.LOC_EQUATOR - lat - } - if strings.ToUpper(ew) == "E" { - rc.LocLongitude = dnsv1.LOC_PRIMEMERIDIAN + lon - } else { // "W" - rc.LocLongitude = dnsv1.LOC_PRIMEMERIDIAN - lon - } - // Altitude - altitude := (float64(al) + dnsv1.LOC_ALTITUDEBASE) * 100 - clampedAltitude := math.Min(math.Max(0, altitude), float64(math.MaxUint32)) - rc.LocAltitude = uint32(math.Round(clampedAltitude)) - - var err error - // Size - rc.LocSize, err = getENotationInt(sz) - if err != nil { - return err - } - // Horizontal Precision - rc.LocHorizPre, err = getENotationInt(hp) - if err != nil { - return err - } - // Vertical Precision - rc.LocVertPre, err = getENotationInt(vp) - if err != nil { - return err - } - // if hp != 0 { - // } else { - // rc.LocHorizPre = 22 // 1e6 10,000m default - // } - // if vp != 0 { - // } else { - // rc.LocVertPre = 19 // 1e3 10m default - // } - - return nil -} - -// getENotationInt produces a mantissa_exponent 4bits:4bits into a uint8. -func getENotationInt(x float32) (uint8, error) { - /* - 9000000000cm = 9e9 == 153 (9^4 + 9) or 9<<4 + 9 - 800000000cm = 8e8 == 136 (8^4 + 8) or 8<<4 + 8 - 70000000cm = 7e7 == 119 (7^4 + 7) or 7<<4 + 7 - 6000000cm = 6e6 == 102 (6^4 + 6) or 6<<4 + 6 - 1000000cm = 1e6 == 22 (1^4 + 6) or 1<<4 + 6 - 500000cm = 5e5 == 85 (5^4 + 5) or 5<<4 + 5 - 40000cm = 4e4 == 68 (4^4 + 4) or 4<<4 + 4 - 3000cm = 3e3 == 51 (3^4 + 3) or 3<<4 + 3 - 1000cm = 1e3 == 19 (1^4 + 3) or 1<<4 + 1 - 200cm = 2e2 == 34 (2^4 + 2) or 2<<4 + 2 - 100cm = 1e2 == 18 (1^4 + 2) or 1<<4 + 2 - 10cm = 1e1 == 17 (1^4 + 1) or 1<<4 + 1 - 1cm = 1e0 == 16 (1^4 + 0) or 0<<4 + 0 - 0cm = 0e0 == 0 - */ - if x == 0 { - return 0, nil // both mantissa and exponent will be zero - } - - // get cm value - num := float64(x) * 100 - - // Get exponent (base 10) - exp := int(math.Floor(math.Log10(num))) - - // Normalize the mantissa - mantissa := num / math.Pow(10, float64(exp)) - - // Adjust mantissa and exponent to fit into 4-bit ranges (0-15) - for mantissa < 1 && exp > 0 { - mantissa *= 10 - exp-- - } - - // Truncate the mantissa (integer value) and ensure it's within 4 bits - mantissaInt := min(int(math.Floor(mantissa)), 9) // Cap mantissa at 9 - - // Ensure exponent is within 4 bits - if exp < 0 { - exp = 0 // Cap negative exponents at 0 - } else if exp > 9 { - exp = 9 // Cap exponent at 9 - } - - // Pack mantissa and exponent into a single uint8 - packedValue := uint8((mantissaInt << 4) | (exp & 0x0F)) - - return packedValue, nil -} - // ReverseLatitude takes the packed latitude and returns the hemisphere, degrees, minutes, and seconds. func ReverseLatitude(lat uint32) (string, uint8, uint8, float64) { var hemisphere string - if lat >= dnsv1.LOC_EQUATOR { + if lat >= dnsv2.LOCEquator { hemisphere = "N" - lat = lat - dnsv1.LOC_EQUATOR + lat = lat - dnsv2.LOCEquator } else { hemisphere = "S" - lat = dnsv1.LOC_EQUATOR - lat + lat = dnsv2.LOCEquator - lat } - degrees := uint8(lat / dnsv1.LOC_DEGREES) - lat -= uint32(degrees) * dnsv1.LOC_DEGREES - minutes := uint8(lat / dnsv1.LOC_HOURS) - lat -= uint32(minutes) * dnsv1.LOC_HOURS + degrees := uint8(lat / dnsv2.LOCDegrees) + lat -= uint32(degrees) * dnsv2.LOCDegrees + minutes := uint8(lat / dnsv2.LOCHours) + lat -= uint32(minutes) * dnsv2.LOCHours seconds := float64(lat) / 1000 return hemisphere, degrees, minutes, seconds @@ -219,17 +28,17 @@ func ReverseLatitude(lat uint32) (string, uint8, uint8, float64) { // ReverseLongitude takes the packed longitude and returns the hemisphere, degrees, minutes, and seconds. func ReverseLongitude(lon uint32) (string, uint8, uint8, float64) { var hemisphere string - if lon >= dnsv1.LOC_PRIMEMERIDIAN { + if lon >= dnsv2.LOCPrimemeridian { hemisphere = "E" - lon = lon - dnsv1.LOC_PRIMEMERIDIAN + lon = lon - dnsv2.LOCPrimemeridian } else { hemisphere = "W" - lon = dnsv1.LOC_PRIMEMERIDIAN - lon + lon = dnsv2.LOCPrimemeridian - lon } - degrees := uint8(lon / dnsv1.LOC_DEGREES) - lon -= uint32(degrees) * dnsv1.LOC_DEGREES - minutes := uint8(lon / dnsv1.LOC_HOURS) - lon -= uint32(minutes) * dnsv1.LOC_HOURS + degrees := uint8(lon / dnsv2.LOCDegrees) + lon -= uint32(degrees) * dnsv2.LOCDegrees + minutes := uint8(lon / dnsv2.LOCHours) + lon -= uint32(minutes) * dnsv2.LOCHours seconds := float64(lon) / 1000 return hemisphere, degrees, minutes, seconds diff --git a/models/t_mx.go b/models/t_mx.go deleted file mode 100644 index 174d98cf75..0000000000 --- a/models/t_mx.go +++ /dev/null @@ -1,40 +0,0 @@ -package models - -import ( - "fmt" - "strconv" - "strings" -) - -// SetTargetMX sets the MX fields. -func (rc *RecordConfig) SetTargetMX(pref uint16, target string) error { - rc.MxPreference = pref - if err := rc.SetTarget(target); err != nil { - return err - } - if rc.Type == "" { - rc.Type = "MX" - } - if rc.Type != "MX" { - panic("assertion failed: SetTargetMX called when .Type is not MX") - } - return nil -} - -// SetTargetMXStrings is like SetTargetMX but accepts strings. -func (rc *RecordConfig) SetTargetMXStrings(pref, target string) error { - u64pref, err := strconv.ParseUint(pref, 10, 16) - if err != nil { - return fmt.Errorf("can't parse MX data: %w", err) - } - return rc.SetTargetMX(uint16(u64pref), target) -} - -// SetTargetMXString is like SetTargetMX but accepts one big string. -func (rc *RecordConfig) SetTargetMXString(s string) error { - part := strings.Fields(s) - if len(part) != 2 { - return fmt.Errorf("MX value does not contain 2 fields: (%#v)", s) - } - return rc.SetTargetMXStrings(part[0], part[1]) -} diff --git a/models/t_naptr.go b/models/t_naptr.go deleted file mode 100644 index ed1a21b75f..0000000000 --- a/models/t_naptr.go +++ /dev/null @@ -1,53 +0,0 @@ -package models - -import ( - "fmt" - "strconv" - "strings" -) - -// SetTargetNAPTR sets the NAPTR fields. -func (rc *RecordConfig) SetTargetNAPTR(order uint16, preference uint16, flags string, service string, regexp string, target string) error { - if target == "" { - target = "." - } - rc.NaptrOrder = order - rc.NaptrPreference = preference - rc.NaptrFlags = flags - rc.NaptrService = service - rc.NaptrRegexp = regexp - if err := rc.SetTarget(target); err != nil { - return err - } - - if rc.Type == "" { - rc.Type = "NAPTR" - } - if rc.Type != "NAPTR" { - panic("assertion failed: SetTargetNAPTR called when .Type is not NAPTR") - } - - return nil -} - -// SetTargetNAPTRStrings is like SetTargetNAPTR but accepts strings. -func (rc *RecordConfig) SetTargetNAPTRStrings(order, preference, flags string, service string, regexp string, target string) error { - i64order, err := strconv.ParseUint(order, 10, 16) - if err != nil { - return fmt.Errorf("NAPTR order does not fit in 16 bits: %w", err) - } - i64preference, err := strconv.ParseUint(preference, 10, 16) - if err != nil { - return fmt.Errorf("NAPTR preference does not fit in 16 bits: %w", err) - } - return rc.SetTargetNAPTR(uint16(i64order), uint16(i64preference), flags, service, regexp, target) -} - -// SetTargetNAPTRString is like SetTargetNAPTR but accepts one big string. -func (rc *RecordConfig) SetTargetNAPTRString(s string) error { - part := strings.Fields(s) - if len(part) != 6 { - return fmt.Errorf("NAPTR value does not contain 6 fields: (%#v)", s) - } - return rc.SetTargetNAPTRStrings(part[0], part[1], StripQuotes(part[2]), StripQuotes(part[3]), StripQuotes(part[4]), StripQuotes(part[5])) -} diff --git a/models/t_parse.go b/models/t_parse.go deleted file mode 100644 index c2fd9ed74c..0000000000 --- a/models/t_parse.go +++ /dev/null @@ -1,230 +0,0 @@ -package models - -import ( - "fmt" - "net/netip" -) - -// PopulateFromStringFunc populates a RecordConfig by parsing a common RFC1035-like format. -// -// rtype: the resource record type (rtype) -// contents: a string that contains all parameters of the record's rdata (see below) -// txtFn: If rtype == "TXT", this function is used to parse contents, or nil if no parsing is needed. -// -// The "contents" field is the format used in RFC1035 zonefiles. It is the text -// after the rtype. For example, in the line: foo IN MX 10 mx.example.com. -// contents stores everything after the "MX" (not including the space). -// -// Typical values for txtFn include: -// -// nil: no parsing required. -// txtutil.ParseQuoted: Parse via Tom's interpretation of RFC1035. -// txtutil.ParseCombined: Backwards compatible with Parse via miekg's interpretation of RFC1035. -// -// Many providers deliver record data in this format or something close to it. -// This function is provided to reduce the amount of duplicate code across -// providers. If a particular rtype is not handled as a particular provider -// expects, simply handle it beforehand as a special case. -// -// Example 1: Normal use. -// -// rtype := FILL_IN_RTYPE -// rc := &models.RecordConfig{Type: rtype, TTL: FILL_IN_TTL} -// rc.SetLabelFromFQDN(FILL_IN_NAME, origin) -// rc.Original = FILL_IN_ORIGINAL // The raw data received from provider (if needed later) -// if err = rc.PopulateFromStringFunc(rtype, target, origin, nil); err != nil { -// return nil, fmt.Errorf("unparsable record type=%q received from PROVDER_NAME: %w", rtype, err) -// } -// return rc, nil -// -// Example 2: Use your own MX parser. -// -// rtype := FILL_IN_RTYPE -// rc := &models.RecordConfig{Type: rtype, TTL: FILL_IN_TTL} -// rc.SetLabelFromFQDN(FILL_IN_NAME, origin) -// rc.Original = FILL_IN_ORIGINAL // The raw data received from provider (if needed later) -// switch rtype { -// case "MX": -// // MX priority in a separate field. -// err = rc.SetTargetMX(cr.Priority, target) -// default: -// err = rc.PopulateFromString(rtype, target, origin) -// } -// if err != nil { -// return nil, fmt.Errorf("unparsable record type=%q received from PROVDER_NAME: %w", rtype, err) -// } -// return rc, nil -func (rc *RecordConfig) PopulateFromStringFunc(rtype, contents, origin string, txtFn func(s string) (string, error)) error { - if rc.Type != "" && rc.Type != rtype { - return fmt.Errorf("assertion failed: rtype already set (%s) (%s)", rtype, rc.Type) - } - - switch rc.Type = rtype; rtype { // #rtype_variations - case "A": - ip, err := netip.ParseAddr(contents) - if err != nil || !ip.Is4() { - return fmt.Errorf("invalid IP in A record: %s", contents) - } - return rc.SetTargetIP(ip) // Reformat to canonical form. - case "AAAA": - ip, err := netip.ParseAddr(contents) - if err != nil || !ip.Is6() { - return fmt.Errorf("invalid IP in AAAA record: %s", contents) - } - return rc.SetTargetIP(ip) // Reformat to canonical form. - case "AKAMAICDN", "AKAMAITLC", "ALIAS", "ANAME", "CNAME", "NS", "PTR": - return rc.SetTarget(contents) - case "CAA": - return rc.SetTargetCAAString(contents) - case "DS": - return rc.SetTargetDSString(contents) - case "DNSKEY": - return rc.SetTargetDNSKEYString(contents) - case "DHCID": - return rc.SetTarget(contents) - case "DNAME": - return rc.SetTarget(contents) - case "LOC": - return rc.SetTargetLOCString(origin, contents) - case "MX": - return rc.SetTargetMXString(contents) - case "NAPTR": - return rc.SetTargetNAPTRString(contents) - case "OPENPGPKEY": - return rc.SetTarget(contents) - case "SMIMEA": - return rc.SetTargetSMIMEAString(contents) - case "SOA": - return rc.SetTargetSOAString(contents) - case "SPF", "TXT": - if txtFn == nil { - return rc.SetTargetTXT(contents) - } - t, err := txtFn(contents) - if err != nil { - return fmt.Errorf("invalid TXT record: %s", contents) - } - return rc.SetTargetTXT(t) - case "LUA": - luaType, payload := ParseLuaContent(contents) - rc.LuaRType = luaType - if txtFn != nil { - value, err := txtFn(payload) - if err != nil { - return fmt.Errorf("invalid LUA record: %s", contents) - } - return rc.SetTargetTXT(value) - } - value, err := DecodeLuaPayload(payload) - if err != nil { - return fmt.Errorf("invalid LUA record: %s", contents) - } - return rc.SetTargetTXT(value) - case "SRV": - return rc.SetTargetSRVString(contents) - case "SSHFP": - return rc.SetTargetSSHFPString(contents) - case "SVCB", "HTTPS": - return rc.SetTargetSVCBString(origin, contents) - case "TLSA": - return rc.SetTargetTLSAString(contents) - default: - // return fmt.Errorf("unknown rtype (%s) when parsing (%s) domain=(%s)", rtype, contents, origin) - return MakeUnknown(rc, rtype, contents, origin) - } -} - -// PopulateFromString populates a RecordConfig given a type and string. Many -// providers give all the parameters of a resource record in one big string. -// This helper function lets you not re-invent the wheel. -// -// NOTE: You almost always want to special-case TXT records. Every provider -// seems to quote them differently. -// -// Recommended calling convention: Process the exceptions first, then use the -// PopulateFromString function for everything else. -// -// rtype := FILL_IN_TYPE -// var err error -// rc := &models.RecordConfig{Type: rtype} -// rc.SetLabelFromFQDN(FILL_IN_NAME, origin) -// rc.TTL = uint32(FILL_IN_TTL) -// rc.Original = FILL_IN_ORIGINAL // The raw data received from provider (if needed later) -// switch rtype { -// case "MX": -// // MX priority in a separate field. -// err = rc.SetTargetMX(cr.Priority, target) -// case "TXT": -// // TXT records are stored verbatim; no quoting/escaping to parse. -// err = rc.SetTargetTXT(target) -// default: -// err = rc.PopulateFromString(rtype, target, origin) -// } -// if err != nil { -// return nil, fmt.Errorf("unparsable record type=%q received from PROVDER_NAME: %w", rtype, err) -// } -// return rc, nil -func (rc *RecordConfig) PopulateFromString(rtype, contents, origin string) error { - if rc.Type != "" && rc.Type != rtype { - panic(fmt.Errorf("assertion failed: rtype already set (%s) (%s)", rtype, rc.Type)) - } - switch rc.Type = rtype; rtype { // #rtype_variations - case "A": - ip, err := netip.ParseAddr(contents) - if err != nil || !ip.Is4() { - return fmt.Errorf("invalid IP in A record: %s", contents) - } - return rc.SetTargetIP(ip) // Reformat to canonical form. - case "AAAA": - ip, err := netip.ParseAddr(contents) - if err != nil || !ip.Is6() { - return fmt.Errorf("invalid IP in AAAA record: %s", contents) - } - return rc.SetTargetIP(ip) // Reformat to canonical form. - case "AKAMAICDN", "AKAMAITLC", "ALIAS", "ANAME", "CNAME", "NS", "PTR": - return rc.SetTarget(contents) - case "CAA": - return rc.SetTargetCAAString(contents) - case "DS": - return rc.SetTargetDSString(contents) - case "DNSKEY": - return rc.SetTargetDNSKEYString(contents) - case "DHCID": - return rc.SetTarget(contents) - case "DNAME": - return rc.SetTarget(contents) - case "LOC": - return rc.SetTargetLOCString(origin, contents) - case "MX": - return rc.SetTargetMXString(contents) - case "NAPTR": - return rc.SetTargetNAPTRString(contents) - case "OPENPGPKEY": - return rc.SetTarget(contents) - case "SMIMEA": - return rc.SetTargetSMIMEAString(contents) - case "SOA": - return rc.SetTargetSOAString(contents) - case "SPF", "TXT": - return rc.SetTargetTXTs(ParseQuotedTxt(contents)) - case "LUA": - luaType, payload := ParseLuaContent(contents) - rc.LuaRType = luaType - value, err := DecodeLuaPayload(payload) - if err != nil { - return fmt.Errorf("invalid LUA record: %s", contents) - } - return rc.SetTargetTXT(value) - case "SRV": - return rc.SetTargetSRVString(contents) - case "SSHFP": - return rc.SetTargetSSHFPString(contents) - case "SVCB", "HTTPS": - return rc.SetTargetSVCBString(origin, contents) - case "TLSA": - return rc.SetTargetTLSAString(contents) - default: - return fmt.Errorf("unknown rtype (%s) when parsing (%s) domain=(%s)", - rtype, contents, origin) - } -} diff --git a/models/t_smimea.go b/models/t_smimea.go deleted file mode 100644 index 2aa8508809..0000000000 --- a/models/t_smimea.go +++ /dev/null @@ -1,46 +0,0 @@ -package models - -import ( - "fmt" - "strconv" - "strings" -) - -// SetTargetSMIMEA sets the SMIMEA fields. -func (rc *RecordConfig) SetTargetSMIMEA(usage, selector, matchingtype uint8, target string) error { - rc.SmimeaUsage = usage - rc.SmimeaSelector = selector - rc.SmimeaMatchingType = matchingtype - if err := rc.SetTarget(target); err != nil { - return err - } - if rc.Type == "" { - rc.Type = "SMIMEA" - } - if rc.Type != "SMIMEA" { - panic("assertion failed: SetTargetSMIMEA called when .Type is not SMIMEA") - } - return nil -} - -// SetTargetSMIMEAStrings is like SetTargetSMIMEA but accepts strings. -func (rc *RecordConfig) SetTargetSMIMEAStrings(usage, selector, matchingtype, target string) (err error) { - var i64usage, i64selector, i64matchingtype uint64 - if i64usage, err = strconv.ParseUint(usage, 10, 8); err == nil { - if i64selector, err = strconv.ParseUint(selector, 10, 8); err == nil { - if i64matchingtype, err = strconv.ParseUint(matchingtype, 10, 8); err == nil { - return rc.SetTargetSMIMEA(uint8(i64usage), uint8(i64selector), uint8(i64matchingtype), target) - } - } - } - return fmt.Errorf("SMIMEA has value that won't fit in field: %w", err) -} - -// SetTargetSMIMEAString is like SetTargetSMIMEA but accepts one big string. -func (rc *RecordConfig) SetTargetSMIMEAString(s string) error { - part := strings.Fields(s) - if len(part) != 4 { - return fmt.Errorf("SMIMEA value does not contain 4 fields: (%#v)", s) - } - return rc.SetTargetSMIMEAStrings(part[0], part[1], part[2], part[3]) -} diff --git a/models/t_soa.go b/models/t_soa.go deleted file mode 100644 index 053cad4e5e..0000000000 --- a/models/t_soa.go +++ /dev/null @@ -1,80 +0,0 @@ -package models - -import ( - "fmt" - "strconv" - "strings" -) - -/* - -Providers are not expected to support this record. - -Most providers do not support SOA records. They generate them -dynamically behind the scenes. Providers like BIND (which is -software, not SaaS), must handle SOA records and emulate the dynamic -work that providers do. - -*/ - -// SetTargetSOA sets the SOA fields. -func (rc *RecordConfig) SetTargetSOA(ns, mbox string, serial, refresh, retry, expire, minttl uint32) error { - // The NS field is stored as the .Target - if err := rc.SetTarget(ns); err != nil { - return err - } - rc.SoaMbox = mbox - rc.SoaSerial = serial - rc.SoaRefresh = refresh - rc.SoaRetry = retry - rc.SoaExpire = expire - rc.SoaMinttl = minttl - - if rc.Type == "" { - rc.Type = "SOA" - } - if rc.Type != "SOA" { - panic("assertion failed: SetTargetSOA called when .Type is not SOA") - } - - return nil -} - -// SetTargetSOAStrings is like SetTargetSOA but accepts strings. -func (rc *RecordConfig) SetTargetSOAStrings(ns, mbox, serial, refresh, retry, expire, minttl string) error { - u32serial, err := strconv.ParseUint(serial, 10, 32) - if err != nil { - return fmt.Errorf("SOA serial '%v' is invalid: %w", serial, err) - } - - u32refresh, err := strconv.ParseUint(refresh, 10, 32) - if err != nil { - return fmt.Errorf("SOA refresh '%v' is invalid: %w", refresh, err) - } - - u32retry, err := strconv.ParseUint(retry, 10, 32) - if err != nil { - return fmt.Errorf("SOA retry '%v' is invalid: %w", retry, err) - } - - u32expire, err := strconv.ParseUint(expire, 10, 32) - if err != nil { - return fmt.Errorf("SOA expire '%v' is invalid: %w", expire, err) - } - - u32minttl, err := strconv.ParseUint(minttl, 10, 32) - if err != nil { - return fmt.Errorf("SOA minttl '%v' is invalid: %w", minttl, err) - } - - return rc.SetTargetSOA(ns, mbox, uint32(u32serial), uint32(u32refresh), uint32(u32retry), uint32(u32expire), uint32(u32minttl)) -} - -// SetTargetSOAString is like SetTargetSOA but accepts one big string. -func (rc *RecordConfig) SetTargetSOAString(s string) error { - part := strings.Fields(s) - if len(part) != 7 { - return fmt.Errorf("SOA value does not contain 7 fields: (%#v)", s) - } - return rc.SetTargetSOAStrings(part[0], part[1], part[2], part[3], part[4], part[5], part[6]) -} diff --git a/models/t_srv.go b/models/t_srv.go deleted file mode 100644 index f335e772c3..0000000000 --- a/models/t_srv.go +++ /dev/null @@ -1,69 +0,0 @@ -package models - -import ( - "fmt" - "strconv" - "strings" -) - -// SetTargetSRV sets the SRV fields. -func (rc *RecordConfig) SetTargetSRV(priority, weight, port uint16, target string) error { - rc.SrvPriority = priority - rc.SrvWeight = weight - rc.SrvPort = port - if err := rc.SetTarget(target); err != nil { - return err - } - if rc.Type == "" { - rc.Type = "SRV" - } - if rc.Type != "SRV" { - panic("assertion failed: SetTargetSRV called when .Type is not SRV") - } - return nil -} - -// setTargetSRVIntAndStrings is like SetTargetSRV but accepts priority as an int, the other parameters as strings. -func (rc *RecordConfig) setTargetSRVIntAndStrings(priority uint16, weight, port, target string) (err error) { - var i64weight, i64port uint64 - if i64weight, err = strconv.ParseUint(weight, 10, 16); err == nil { - if i64port, err = strconv.ParseUint(port, 10, 16); err == nil { - return rc.SetTargetSRV(priority, uint16(i64weight), uint16(i64port), target) - } - } - return fmt.Errorf("SRV value too big for uint16: %w", err) -} - -// SetTargetSRVStrings is like SetTargetSRV but accepts all parameters as strings. -func (rc *RecordConfig) SetTargetSRVStrings(priority, weight, port, target string) (err error) { - var i64priority uint64 - if i64priority, err = strconv.ParseUint(priority, 10, 16); err == nil { - return rc.setTargetSRVIntAndStrings(uint16(i64priority), weight, port, target) - } - return fmt.Errorf("SRV value too big for uint16: %w", err) -} - -// SetTargetSRVPriorityString is like SetTargetSRV but accepts priority as an -// uint16 and the rest of the values joined in a string that needs to be parsed. -// This is a helper function that comes in handy when a provider re-uses the MX preference -// field as the SRV priority. -func (rc *RecordConfig) SetTargetSRVPriorityString(priority uint16, s string) error { - part := strings.Fields(s) - switch len(part) { - case 3: - return rc.setTargetSRVIntAndStrings(priority, part[0], part[1], part[2]) - case 2: - return rc.setTargetSRVIntAndStrings(priority, part[0], part[1], ".") - default: - return fmt.Errorf("SRV value does not contain 3 fields: (%#v)", s) - } -} - -// SetTargetSRVString is like SetTargetSRV but accepts one big string to be parsed. -func (rc *RecordConfig) SetTargetSRVString(s string) error { - part := strings.Fields(s) - if len(part) != 4 { - return fmt.Errorf("SRV value does not contain 4 fields: (%#v)", s) - } - return rc.SetTargetSRVStrings(part[0], part[1], part[2], part[3]) -} diff --git a/models/t_sshfp.go b/models/t_sshfp.go deleted file mode 100644 index 3331814c7f..0000000000 --- a/models/t_sshfp.go +++ /dev/null @@ -1,53 +0,0 @@ -package models - -import ( - "fmt" - "strconv" - "strings" -) - -// SetTargetSSHFP sets the SSHFP fields. -func (rc *RecordConfig) SetTargetSSHFP(algorithm uint8, fingerprint uint8, target string) error { - rc.SshfpAlgorithm = algorithm - rc.SshfpFingerprint = fingerprint - if err := rc.SetTarget(target); err != nil { - return err - } - if rc.Type == "" { - rc.Type = "SSHFP" - } - if rc.Type != "SSHFP" { - panic("assertion failed: SetTargetSSHFP called when .Type is not SSHFP") - } - - if algorithm < 1 && algorithm > 4 { - return fmt.Errorf("SSHFP algorithm (%v) is not one of 1, 2, 3 or 4", algorithm) - } - if fingerprint < 1 && fingerprint > 2 { - return fmt.Errorf("SSHFP fingerprint (%v) is not one of 1 or 2", fingerprint) - } - - return nil -} - -// SetTargetSSHFPStrings is like SetTargetSSHFP but accepts strings. -func (rc *RecordConfig) SetTargetSSHFPStrings(algorithm, fingerprint, target string) error { - i64algorithm, err := strconv.ParseUint(algorithm, 10, 8) - if err != nil { - return fmt.Errorf("SSHFP algorithm does not fit in 8 bits: %w", err) - } - i64fingerprint, err := strconv.ParseUint(fingerprint, 10, 8) - if err != nil { - return fmt.Errorf("SSHFP fingerprint does not fit in 8 bits: %w", err) - } - return rc.SetTargetSSHFP(uint8(i64algorithm), uint8(i64fingerprint), target) -} - -// SetTargetSSHFPString is like SetTargetSSHFP but accepts one big string. -func (rc *RecordConfig) SetTargetSSHFPString(s string) error { - part := strings.Fields(s) - if len(part) != 3 { - return fmt.Errorf("SSHFP value does not contain 3 fields: (%#v)", s) - } - return rc.SetTargetSSHFPStrings(part[0], part[1], StripQuotes(part[2])) -} diff --git a/models/t_svcb.go b/models/t_svcb.go index e8d9b853e1..d6593bf788 100644 --- a/models/t_svcb.go +++ b/models/t_svcb.go @@ -1,53 +1,149 @@ package models import ( + "bytes" "fmt" "strings" - dnsv1 "github.com/miekg/dns" + dnsv2 "codeberg.org/miekg/dns" + svcbv2 "codeberg.org/miekg/dns/svcb" ) -func (rc *RecordConfig) targetCombinedSVCBRaw() string { - if rc.SvcParams == "" { - return fmt.Sprintf("%d %s", rc.SvcPriority, rc.target) +// stringToSvcbv2Values converts a string to a SVCB value list. +// TODO(tlim): THIS NEEDS A UNIT TEST! +func stringToSvcbv2Values(origin string, contents string) ([]svcbv2.Pair, error) { + fields := strings.Fields(contents) + + var result []svcbv2.Pair + + for _, field := range fields { + keyValue := strings.SplitN(field, "=", 2) + if len(keyValue) != 2 { + return nil, fmt.Errorf("invalid svcb.Pair: %q", field) + } + + // Make the pair. + pairFn := svcbv2.KeyToPair(svcbv2.StringToKey(keyValue[0])) + pair := pairFn() + + // Strip the value of any quotes: + v := keyValue[1] + if len(v) >= 2 && v[0] == '"' && v[len(v)-1] == '"' { // Strip quotes if present + v = v[1 : len(v)-1] + } + + // Parse it: + err := svcbv2.Parse(pair, v, origin) + if err != nil { + return nil, err + } + + result = append(result, pair) } - return fmt.Sprintf("%d %s %s", rc.SvcPriority, rc.target, rc.SvcParams) + return result, nil } -// SetTargetSVCB sets the SVCB fields. -func (rc *RecordConfig) SetTargetSVCB(priority uint16, target string, params []dnsv1.SVCBKeyValue) error { - rc.SvcPriority = priority - if err := rc.SetTarget(target); err != nil { - return err +// Svcbv2ValueToString converts a SVCB value list to a string. +// Typical usage: models.Svcbv2ValueToString(rc.AsHTTPS().Value) +// Does NOT generate quotes around values in key=value pairs. +func Svcbv2ValueToString(pairs []svcbv2.Pair) string { + var sb strings.Builder + for i, p := range pairs { + if i > 0 { + sb.WriteString(" ") + } + knum := svcbv2.PairToKey(p) + k := svcbv2.KeyToString(knum) + fmt.Fprintf(&sb, "%s=%s", k, p.String()) } - paramsStr := []string{} - for _, kv := range params { - paramsStr = append(paramsStr, fmt.Sprintf("%s=%s", kv.Key(), kv.String())) + return sb.String() +} + +// SVCBHydrateDesiredEchIgnore finds any ECH=IGNORE parameters (stored as +// ECH=1000) and substitute the existing ECH value instead. +func SVCBHydrateDesiredEchIgnore(existing, desired Records) { + cache := map[string][]byte{} + + // Gather the ECH= values from "existing" + for _, rec := range existing { + if rec.TypeNum == dnsv2.TypeSVCB || rec.TypeNum == dnsv2.TypeHTTPS { + k := svcbEncKey(rec) + v := svcbEncValue(rec) + if len(v) == 0 { + continue + } + cache[k] = v + } } - rc.SvcParams = strings.Join(paramsStr, " ") - if rc.Type == "" { - rc.Type = "SVCB" + // svcbDumpCache(cache) + + // Find any ECH=1000 values from "desired" and replace them. + for _, rec := range desired { + if rec.TypeNum == dnsv2.TypeSVCB || rec.TypeNum == dnsv2.TypeHTTPS { + k := svcbEncKey(rec) + if _, ok := cache[k]; ok { + // if eValue, ok := cache[k]; ok { + rd := rec.AsSVCB() + desiredPairs := rd.Value + newPairs, found := svcbReplaceIGNOREWithData(desiredPairs, cache, rec) + if found { + rd.Value = newPairs + rec.SetRDATA(rd) + } + } + } } - if rc.Type != "SVCB" && rc.Type != "HTTPS" { - panic("assertion failed: SetTargetSVCB called when .Type is not SVCB or HTTPS") +} + +func svcbEncKey(rec *RecordConfig) string { + rd := rec.AsSVCB() + return fmt.Sprintf("%s:%v", rec.NameFQDN, rd.Priority) +} + +func svcbEncValue(rec *RecordConfig) []byte { + rd := rec.AsSVCB() + for _, pair := range rd.Value { + kNum := svcbv2.PairToKey(pair) + if kNum != svcbv2.KeyEchConfig { + continue + } + return pair.(*svcbv2.ECHCONFIG).ECH } return nil } -// SetTargetSVCBString is like SetTargetSVCB but accepts one big string and the origin so parsing can be done using miekg/dns. -func (rc *RecordConfig) SetTargetSVCBString(origin, contents string) error { - if rc.Type == "" { - rc.Type = "SVCB" - } - record, err := dnsv1.NewRR(fmt.Sprintf("%s. %s %s", origin, rc.Type, contents)) - if err != nil { - return fmt.Errorf("could not parse SVCB record: %w", err) - } - switch r := record.(type) { - case *dnsv1.HTTPS: - return rc.SetTargetSVCB(r.Priority, r.Target, r.Value) - case *dnsv1.SVCB: - return rc.SetTargetSVCB(r.Priority, r.Target, r.Value) +// func svcbDumpCache(cache map[string][]byte) { +// if len(cache) > 0 { +// fmt.Printf("\n##### SVCB Ech Cache:\n") +// for k, v := range cache { +// fmt.Printf("##### CACHE k=%q v=%q\n", k, base64.StdEncoding.EncodeToString(v)) +// } +// fmt.Printf("#####\n\n") +// } +// } + +// svcbReplaceIGNOREWithData searches through pairs for an ECH value == the magic number ("1000"). +func svcbReplaceIGNOREWithData(pairs []svcbv2.Pair, cache map[string][]byte, rec *RecordConfig) ([]svcbv2.Pair, bool) { + var result []svcbv2.Pair + found := false + + for _, p := range pairs { + switch v := p.(type) { + case *svcbv2.ECHCONFIG: + if bytes.Equal(v.ECH, []byte{215, 77, 52}) { // "1000" + found = true + ech := p.(*svcbv2.ECHCONFIG) + ech.ECH = cache[svcbEncKey(rec)] + result = append(result, ech) + } else { + result = append(result, p) + } + + default: + result = append(result, p) + } } - return nil + rec.generateComparableV3() + + return result, found } diff --git a/models/t_svcb_test.go b/models/t_svcb_test.go new file mode 100644 index 0000000000..51cb23ac75 --- /dev/null +++ b/models/t_svcb_test.go @@ -0,0 +1,39 @@ +package models_test + +import ( + "fmt" + "strings" + "testing" + + dnsv2 "codeberg.org/miekg/dns" + dnsrdatav2 "codeberg.org/miekg/dns/rdata" + "github.com/DNSControl/dnscontrol/v5/models" +) + +func TestSvcbv2ValueToString(t *testing.T) { + tests := []struct { + input string + }{ + {"0 test.com. "}, + {"1 test.com. port=80"}, + {"1 test.com. alpn=h2 port=99"}, + {"3 example.com. alpn=h2,h3 port=999"}, + {"3 example.com. alpn=h2,h3 port=999 ech=some+base64+encoded+value///"}, + {"3 example.com. alpn=h2 port=80 ech=another+base64+encoded+value"}, + {"3 yetanother.com. alpn=h2 port=80 ech=another+base64+encoded+value"}, + {"3 example.com. alpn=h2,h3 port=999"}, + {"1 . "}, + {"2 . alpn=h3,h2 port=443 ipv4hint=123.123.123.123 ipv6hint=dead::beaf"}, + } + + for i, tt := range tests { + t.Run(fmt.Sprintf("%d", i), func(t *testing.T) { + rd, _ := dnsv2.NewData(dnsv2.TypeSVCB, tt.input, "example.com") + want := strings.TrimSpace(tt.input[strings.Index(tt.input, ". ")+2:]) + got := models.Svcbv2ValueToString(rd.(dnsrdatav2.SVCB).Value) + if got != want { + t.Errorf("Svcbv2ValueToString() = %q, want %q", got, want) + } + }) + } +} diff --git a/models/t_tlsa.go b/models/t_tlsa.go deleted file mode 100644 index eaf38ae659..0000000000 --- a/models/t_tlsa.go +++ /dev/null @@ -1,46 +0,0 @@ -package models - -import ( - "fmt" - "strconv" - "strings" -) - -// SetTargetTLSA sets the TLSA fields. -func (rc *RecordConfig) SetTargetTLSA(usage, selector, matchingtype uint8, target string) error { - rc.TlsaUsage = usage - rc.TlsaSelector = selector - rc.TlsaMatchingType = matchingtype - if err := rc.SetTarget(target); err != nil { - return err - } - if rc.Type == "" { - rc.Type = "TLSA" - } - if rc.Type != "TLSA" { - panic("assertion failed: SetTargetTLSA called when .Type is not TLSA") - } - return nil -} - -// SetTargetTLSAStrings is like SetTargetTLSA but accepts strings. -func (rc *RecordConfig) SetTargetTLSAStrings(usage, selector, matchingtype, target string) (err error) { - var i64usage, i64selector, i64matchingtype uint64 - if i64usage, err = strconv.ParseUint(usage, 10, 8); err == nil { - if i64selector, err = strconv.ParseUint(selector, 10, 8); err == nil { - if i64matchingtype, err = strconv.ParseUint(matchingtype, 10, 8); err == nil { - return rc.SetTargetTLSA(uint8(i64usage), uint8(i64selector), uint8(i64matchingtype), target) - } - } - } - return fmt.Errorf("TLSA has value that won't fit in field: %w", err) -} - -// SetTargetTLSAString is like SetTargetTLSA but accepts one big string. -func (rc *RecordConfig) SetTargetTLSAString(s string) error { - part := strings.Fields(s) - if len(part) != 4 { - return fmt.Errorf("TLSA value does not contain 4 fields: (%#v)", s) - } - return rc.SetTargetTLSAStrings(part[0], part[1], part[2], part[3]) -} diff --git a/models/t_txt.go b/models/t_txt.go index 2005f6e2bc..7e7e9b9c2f 100644 --- a/models/t_txt.go +++ b/models/t_txt.go @@ -1,38 +1,21 @@ package models import ( + "fmt" + "log" + "os" "strings" "unicode" - "github.com/DNSControl/dnscontrol/v4/pkg/txtutil" + dnsv2 "codeberg.org/miekg/dns" + dnsrdatav2 "codeberg.org/miekg/dns/rdata" + "github.com/DNSControl/dnscontrol/v5/pkg/nrc" + privatetypesrdata "github.com/DNSControl/dnscontrol/v5/pkg/privatetypes/rdata" + "github.com/DNSControl/dnscontrol/v5/pkg/txtutil" ) /* -Sadly many providers handle TXT records in strange and unexpeected -ways. DNSControl has to handle all of them. Over the years we've -tried many things. This explain the current state of the code. - -DNSControl stores the TXT record target as a single string of any length. -Providers take care of any splitting, excaping, or quoting. - -NOTE: Older versions of DNSControl stored the TXT record as -represented by the provider, which could be a single string, a series -of smaller strings, or a single string that is quoted/escaped. This -created tons of edge-cases and other distractions. - -If a provider doesn't support certain characters in a TXT record, use -the providers/$PROVIDER/auditrecords.go file to indicate this. -DNSControl uses this information to warn users of unsupporrted input, -and to skip related integration tests. - -There are 2 ways to create a TXT record: - SetTargetTXT(): Create from a string. - SetTargetTXTs(): Create from an array of strings that need to be joined. - -There are 2 ways to get the value (target) of a TXT record: - GetTargetTXTJoined(): Returns one big string - GetTargetTXTSegmented(): Returns an array 255-octet segments. - +For notes on how TXT records are handled, see documentation/developer-info/cookbook.md */ // HasFormatIdenticalToTXT returns if a RecordConfig has a format which is @@ -43,44 +26,118 @@ func (rc *RecordConfig) HasFormatIdenticalToTXT() bool { } // SetTargetTXT sets the TXT fields when there is 1 string. +// +// LUA records reuse the TXT accessors (their payload is a TXT-format string). +// When .Type is "LUA", preserve its emitted record type while replacing the +// payload in its RDATA. func (rc *RecordConfig) SetTargetTXT(s string) error { - if rc.Type == "" { - rc.Type = "TXT" - } else if !rc.HasFormatIdenticalToTXT() { - panic("assertion failed: SetTargetTXT called when .Type is not TXT or compatible type") + if rc.Type == "LUA" { + rd := rc.AsLUA() + rd.LuaPayload = s + rc.SetRDATA(rd) + return nil + } + return legacySetTargetArgsTXT(rc, s) +} + +func legacySetTargetArgsTXT(rc *RecordConfig, args ...any) error { + + rc.TypeNum = dnsv2.TypeTXT + rc.Type = "TXT" + + if rc.Metadata == nil { + rc.Metadata = map[string]string{} } - return rc.SetTarget(s) + rd, err := MakeTXT("", nil, nrc.Flags{}, args...) + if err != nil { + log.Fatalf("legacySetTargetArgs: Failed to create RDATA for type %s: %+v", rc.Type, err) + } + rc.SetRDATA(rd) + + return nil } -// SetTargetTXTs sets the TXT fields when there are many strings. They are stored concatenated. +// SetTargetTXTs joins the supplied TXT fields and stores canonical 255-octet segments. func (rc *RecordConfig) SetTargetTXTs(s []string) error { return rc.SetTargetTXT(strings.Join(s, "")) } +// TXTJoined returns all the character-strings in a TXT RDATA as one string. +// FIXME(tlim): Unexport. +func TXTJoined(rd dnsrdatav2.TXT) string { + return strings.Join(rd.Txt, "") +} + +// TXTSegmented returns a TXT RDATA in DNSControl's canonical form: the +// character-strings are joined and then split into 255-octet segments. Empty +// input is represented by one empty segment. +// FIXME(tlim): Unexport. +func TXTSegmented(rd dnsrdatav2.TXT) []string { + return splitChunks(TXTJoined(rd), 255) +} + +// txtProperlySegmented returns true the TXT segments are properly segmented. +// - There must be at least one segment. +// - If there is one segment, it may be empty. It must be 255 octets or less. +// - If there is more than 1 segment, all but the last must be exactly 255 +// octets. The last segment must be 255 octets or less but can not be empty. +func txtProperlySegmented(txts []string) bool { + if len(txts) == 0 { + return false + } + if len(txts) == 1 { + return len(txts[0]) <= 255 + } + for i := 0; i < len(txts)-1; i++ { + if len(txts[i]) != 255 { + return false + } + } + last := txts[len(txts)-1] + return len(last) > 0 && len(last) <= 255 +} + +// txtPayload returns the record's TXT payload as one string. It supports both +// TXT rdata and LUA rdata (whose payload is TXT-format). +func (rc *RecordConfig) txtPayload() string { + switch rd := rc.GetRDATA().(type) { + case dnsrdatav2.TXT: + return TXTJoined(rd) + case privatetypesrdata.LUA: + return rd.LuaPayload + } + return "" +} + // GetTargetTXTJoined returns the TXT target as one string. func (rc *RecordConfig) GetTargetTXTJoined() string { - return rc.target + return rc.txtPayload() } // GetTargetTXTSegmented returns the TXT target as 255-octet segments, with the remainder in the last segment. func (rc *RecordConfig) GetTargetTXTSegmented() []string { - return splitChunks(rc.target, 255) + if rd, ok := rc.rdata.(dnsrdatav2.TXT); ok { + if !txtProperlySegmented(rd.Txt) { + fmt.Fprintf(os.Stderr, "WARNING: GetTargetTXTSegmented: TXT record not properly segmented. Someone is not using SetRDATA? txt=%+v\n", rd.Txt) + return splitChunks(rc.txtPayload(), 255) + } + return rd.Txt + } + return splitChunks(rc.txtPayload(), 255) } // GetTargetTXTSegmentCount returns the number of 255-octet segments required to store TXT target. func (rc *RecordConfig) GetTargetTXTSegmentCount() int { - total := len(rc.target) - segs := total / 255 // integer division, decimals are truncated - if (total % 255) > 0 { - return segs + 1 - } - return segs + return len(rc.GetTargetTXTSegmented()) } func splitChunks(buf string, lim int) []string { if len(buf) == 0 { - return nil + return []string{""} + } + if len(buf) <= lim { + return []string{buf} } var chunk string diff --git a/models/t_txt_test.go b/models/t_txt_test.go new file mode 100644 index 0000000000..dc9162304b --- /dev/null +++ b/models/t_txt_test.go @@ -0,0 +1,171 @@ +package models + +import ( + "slices" + "strings" + "testing" + + dnsv2 "codeberg.org/miekg/dns" + dnsrdatav2 "codeberg.org/miekg/dns/rdata" +) + +func testTXTRecord(t *testing.T, value string) *RecordConfig { + t.Helper() + dc := MustNewDomainConfig("example.com") + rc := dc.MustNewRecordConfig("foo", 0, dnsv2.TypeTXT, value) + return rc +} + +func TestTXTJoined(t *testing.T) { + tests := []struct { + name string + txt []string + want string + }{ + {name: "no segments", txt: []string{}, want: ""}, + {name: "one segment", txt: []string{"one"}, want: "one"}, + {name: "one empty segment", txt: []string{""}, want: ""}, + {name: "multiple segments", txt: []string{"one", "", "two"}, want: "onetwo"}, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + rd := dnsrdatav2.TXT{Txt: tt.txt} + if got := TXTJoined(rd); got != tt.want { + t.Fatalf("TXTJoined() = %q, want %q", got, tt.want) + } + }) + } +} + +func TestTXTSegmented(t *testing.T) { + payload := strings.Repeat("a", 254) + "bc" + tests := []struct { + name string + txt []string + want []string + }{ + {name: "no segments", txt: []string{}, want: []string{""}}, + {name: "one segment", txt: []string{"one"}, want: []string{"one"}}, + { + name: "removes empty segments and resegments", + txt: []string{"", payload[:100], "", payload[100:]}, + want: []string{payload[:255], payload[255:]}, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + got := TXTSegmented(dnsrdatav2.TXT{Txt: tt.txt}) + if !slices.Equal(got, tt.want) { + t.Fatalf("TXTSegmented() = %#v, want %#v", got, tt.want) + } + }) + } +} + +func TestRecordConfigGetTargetTXTJoined(t *testing.T) { + tests := []struct { + name string + value string + }{ + {name: "empty", value: ""}, + {name: "one segment", value: "one"}, + {name: "multiple segments", value: strings.Repeat("a", 255) + "b"}, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + rc := testTXTRecord(t, tt.value) + if got := rc.GetTargetTXTJoined(); got != tt.value { + t.Fatalf("GetTargetTXTJoined() = %q, want %q", got, tt.value) + } + }) + } +} + +func TestRecordConfigGetTargetTXTSegmented(t *testing.T) { + tests := []struct { + name string + value string + want []string + }{ + {name: "empty", value: "", want: []string{""}}, + {name: "one segment", value: "one", want: []string{"one"}}, + {name: "multiple segments", value: strings.Repeat("a", 255) + "b", want: []string{strings.Repeat("a", 255), "b"}}, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + rc := testTXTRecord(t, tt.value) + got := rc.GetTargetTXTSegmented() + if !slices.Equal(got, tt.want) { + t.Fatalf("GetTargetTXTSegmented() = %#v, want %#v", got, tt.want) + } + }) + } +} + +func TestRecordConfigSetTargetTXT(t *testing.T) { + tests := []struct { + name string + value string + want []string + }{ + {name: "empty", value: "", want: []string{""}}, + {name: "one segment", value: "one", want: []string{"one"}}, + {name: "multiple segments", value: strings.Repeat("x", 256), want: []string{strings.Repeat("x", 255), "x"}}, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + rc := testTXTRecord(t, tt.value) + rd := rc.AsTXT() + if !slices.Equal(rd.Txt, tt.want) { + t.Fatalf("SetTargetTXT stored %#v, want %#v", rd.Txt, tt.want) + } + }) + } +} + +func TestRecordConfigGetTargetFieldTXT(t *testing.T) { + tests := []struct { + name string + value string + }{ + {name: "empty", value: ""}, + {name: "one segment", value: "joined target"}, + {name: "multiple segments", value: strings.Repeat("a", 256)}, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + rc := testTXTRecord(t, tt.value) + if got, want := strings.Join(rc.GetTargetTXTSegmented(), ""), rc.GetTargetTXTJoined(); got != want { + t.Fatalf("GetTargetTXTSegmented() = %q, want %q", got, want) + } + }) + } +} + +func TestRecordConfigGetTargetIPTXT(t *testing.T) { + rc := testTXTRecord(t, "not an IP") + defer func() { + if recover() == nil { + t.Fatal("GetTargetIP() did not panic for TXT") + } + }() + rc.GetTargetIP() +} + +// func equalStrings(a, b []string) bool { +// if len(a) != len(b) { +// return false +// } +// for i := range a { +// if a[i] != b[i] { +// return false +// } +// } +// return true +// } diff --git a/models/target.go b/models/target.go index f8bf108a53..4ab4ec96c0 100644 --- a/models/target.go +++ b/models/target.go @@ -3,223 +3,68 @@ package models import ( "fmt" "net/netip" - "strings" - "github.com/DNSControl/dnscontrol/v4/pkg/txtutil" - dnsv1 "github.com/miekg/dns" + dnsv2 "codeberg.org/miekg/dns" + dnsrdatav2 "codeberg.org/miekg/dns/rdata" + "github.com/DNSControl/dnscontrol/v5/pkg/nrc" ) -/* .target is kind of a mess. -If an rType has more than one field, one field goes in .target and the remaining are stored in bespoke fields. -Not the best design, but we're stuck with it until we re-do RecordConfig, possibly using generics. -*/ - -// 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. +// GetTargetField returns the "target" field. That is, the field in RDATA that is a hostname. +// We hard-code certain types and others we guess by picking the last field in the struct. +// NOTE: Deprecated. No new code should use this. Get the field you need instead. func (rc *RecordConfig) GetTargetField() string { - return rc.target -} - -// GetTargetIP returns the net.IP stored in .target. -func (rc *RecordConfig) GetTargetIP() netip.Addr { - if rc.Type != "A" && rc.Type != "AAAA" { - panic(fmt.Errorf("GetTargetIP called on an inappropriate rtype (%s)", rc.Type)) - } - ip, _ := netip.ParseAddr(rc.target) - return ip -} - -// 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" || rc.Type == "LUA" { - 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 := dnsv1.StringToType[rc.Type]; !ok { - switch rc.Type { // #rtype_variations - case "LUA": - return rc.luaCombined() - case "R53_ALIAS": - // Differentiate between multiple R53_ALIASs on the same label. - 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"]) - case "AKAMAITLC": - return fmt.Sprintf("%s %s", rc.AnswerType, rc.target) - default: - // Just return the target. - return rc.target - } - } - - // Everything else switch rc.Type { - case "UNKNOWN": - return fmt.Sprintf("rtype=%s rdata=%s", rc.UnknownTypeName, rc.target) 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) - } - - return rc.zoneFileQuoted() -} - -// zoneFileQuoted returns the rData as would be quoted in a zonefile. -func (rc *RecordConfig) zoneFileQuoted() string { - // We cheat by converting to a dns.RR and use the String() function. - // This combines all the data for us, and even does proper quoting. - // Sadly String() always includes a header, which we must strip out. - // TODO(tlim): Request the dns project add a function that returns - // the string without the header. - if rc.Type == "NAPTR" && rc.GetTargetField() == "" { - rc.MustSetTarget(".") - } - rr := rc.ToRR() - 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") - } - return full[len(header):] -} - -func (rc *RecordConfig) luaCombined() string { - rtype := rc.luaTypeUpper() - payload := rc.target - if rtype == "" { - return payload - } - payload = txtutil.EncodeQuoted(payload) - if payload == "" { - return rtype - } - return fmt.Sprintf("%s %s", rtype, payload) -} - -func (rc *RecordConfig) luaTypeUpper() string { - if rc.LuaRType == "" { - return "" - } - return strings.ToUpper(rc.LuaRType) -} - -// GetTargetRFC1035Quoted returns the target as it would be in an -// RFC1035-style zonefile. -// Do not use this function if RecordConfig might be a pseudo-rtype -// such as R53_ALIAS. Use GetTargetCombined() instead. -func (rc *RecordConfig) GetTargetRFC1035Quoted() string { - return rc.zoneFileQuoted() -} - -// GetTargetDebug returns a string with the various fields spelled out. -func (rc *RecordConfig) GetTargetDebug() string { - target := rc.target - //if rc.Type == "TXT" { - if rc.HasFormatIdenticalToTXT() { - 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", "OPENPGPKEY", "PTR", "TXT": - // Nothing special. - case "LUA": - content += " luartype=" + rc.luaTypeUpper() - case "AZURE_ALIAS": - content += " type=" + rc.AzureAlias["type"] - case "CAA": - content += fmt.Sprintf(" caatag=%s caaflag=%d", rc.CaaTag, rc.CaaFlag) - case "DS": - content += fmt.Sprintf(" ds_algorithm=%d ds_keytag=%d ds_digesttype=%d ds_digest=%s", rc.DsAlgorithm, rc.DsKeyTag, rc.DsDigestType, rc.DsDigest) - case "DNSKEY": - content += fmt.Sprintf(" dnskey_flags=%d dnskey_protocol=%d dnskey_algorithm=%d dnskey_publickey=%s", rc.DnskeyFlags, rc.DnskeyProtocol, rc.DnskeyAlgorithm, rc.DnskeyPublicKey) - case "MX": - content += fmt.Sprintf(" pref=%d", rc.MxPreference) - 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) + return rc.GetTargetTXTJoined() case "R53_ALIAS": - 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 "SMIMEA": - content += fmt.Sprintf(" smimeausage=%d smimeaselector=%d smimeamatchingtype=%d", rc.SmimeaUsage, rc.SmimeaSelector, rc.SmimeaMatchingType) - 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": - content += fmt.Sprintf(" srvpriority=%d srvweight=%d srvport=%d", rc.SrvPriority, rc.SrvWeight, rc.SrvPort) - case "SSHFP": - content += fmt.Sprintf(" sshfpalgorithm=%d sshfpfingerprint=%d", rc.SshfpAlgorithm, rc.SshfpFingerprint) - case "SVCB", "HTTPS": - // HTTPS is only a special subform of the SVCB Record - content += fmt.Sprintf(" priority=%d params=%v", rc.SvcPriority, rc.SvcParams) - case "TLSA": - content += fmt.Sprintf(" tlsausage=%d tlsaselector=%d tlsamatchingtype=%d", rc.TlsaUsage, rc.TlsaSelector, rc.TlsaMatchingType) - default: - panic(fmt.Errorf("rc.String rtype %v unimplemented", rc.Type)) - // We panic so that we quickly find any switch statements - // that have not been updated for a new RR type. + // R53_ALIAS's target (DNSName) is not the last field of the RDATA. + return rc.AsR53ALIAS().Target } - for k, v := range rc.Metadata { - content += fmt.Sprintf(" %s=%s", k, v) - } - return content -} -// GetTargetJS returns the target as a JavaScript literal, as documented in -// documentation/language-reference/domain-modifiers/*.md. Each parameter is -// quoted, unless it is an integer or boolean. We can't use GetTargetCombined() -// because it is not designed for JavaScript and may include unquoted -// parameters, which would break the JavaScript. Instead, we must quote each -// parameter separately. This doesn't support all types and needs to be improved. -// FIXME(tlim): This duplicates code in commands/getZones.go:formatDsl(). -// -// We should extract the common logic into a function they can both use. -func (rc *RecordConfig) GetTargetJS() string { - if rc.Type == "TXT" || rc.Type == "LUA" { - return fmt.Sprintf("%q", rc.target) + // Return the last field. Not perfect, but good enough until we get rid of this function. + fx, err := RDtoFieldsStrings(rc.GetRDATA()) + if err != nil { + return rc.GetRDATA().String() } - switch rc.Type { - case "A", "AAAA", "AKAMAICDN", "CNAME", "DHCID", "NS", "OPENPGPKEY", "PTR": - return fmt.Sprintf("%q", rc.target) - case "SOA": - // SOA(ns, mbox, refresh, retry, expire, minttl) - return fmt.Sprintf("%q, %q, %d, %d, %d, %d", rc.target, rc.SoaMbox, rc.SoaRefresh, rc.SoaRetry, rc.SoaExpire, rc.SoaMinttl) - case "SRV": - // SRV(priority, weight, port, target) - return fmt.Sprintf("%d, %d, %d, %q", rc.SrvPriority, rc.SrvWeight, rc.SrvPort, rc.target) - default: - return fmt.Sprintf("%q", rc.GetTargetCombined()) + if len(fx) == 0 { + return "" } + return fx[len(fx)-1] } -// SetTarget sets the target, assuming that the rtype is appropriate. -func (rc *RecordConfig) SetTarget(target string) error { - rc.target = target - return nil -} - -// MustSetTarget is like SetTarget, but panics if an error occurs. -// It should only be used in _test.go files and in the init() function. -func (rc *RecordConfig) MustSetTarget(target string) { - if err := rc.SetTarget(target); err != nil { - panic(err) +// GetTargetIP returns the net.IP stored in .target. +// NOTE: Deprecated. No new code should use this. Use rc.AsA().Addr or rc.AsAAAA().Addr. +func (rc *RecordConfig) GetTargetIP() netip.Addr { + switch f := rc.GetRDATA().(type) { + case dnsrdatav2.A: + return f.Addr + case dnsrdatav2.AAAA: + return f.Addr } + panic(fmt.Sprintf("wrong type GetTargetIP(%T)", rc.GetRDATA())) } // SetTargetIP sets the target to an IP, verifying this is an appropriate rtype. +// NOTE: Deprecated. No new code should use this. func (rc *RecordConfig) SetTargetIP(ip netip.Addr) error { // TODO(tlim): Verify the rtype is appropriate for an IP. - return rc.SetTarget(ip.String()) + //return rc.SetTarget(ip.String()) + switch rc.TypeNum { + case dnsv2.TypeA: + rd, err := MakeA("", nil, nrc.Flags{}, ip) + if err != nil { + return err + } + rc.SetRDATA(rd) + return nil + case dnsv2.TypeAAAA: + rd, err := MakeAAAA("", nil, nrc.Flags{}, ip) + if err != nil { + return err + } + rc.SetRDATA(rd) + return nil + } + return fmt.Errorf("invalid IP %v", ip) } diff --git a/models/unknown.go b/models/unknown.go index a4128d638c..f1790047c4 100644 --- a/models/unknown.go +++ b/models/unknown.go @@ -4,7 +4,6 @@ package models func MakeUnknown(rc *RecordConfig, rtype string, contents string, origin string) error { rc.Type = "UNKNOWN" rc.UnknownTypeName = rtype - rc.target = contents return nil } diff --git a/pkg/diff/diff.go b/pkg/diff/diff.go deleted file mode 100644 index 0c657c9578..0000000000 --- a/pkg/diff/diff.go +++ /dev/null @@ -1,44 +0,0 @@ -package diff - -import ( - "fmt" - - "github.com/DNSControl/dnscontrol/v4/models" - "github.com/fatih/color" -) - -// Correlation stores a difference between two records. -type Correlation struct { - d *differ - Existing *models.RecordConfig - Desired *models.RecordConfig -} - -// Changeset stores many Correlation. -type Changeset []Correlation - -// Differ is an interface for computing the difference between two zones. -type Differ interface { - // IncrementalDiff performs a diff on a record-by-record basis, and returns a sets for which records need to be created, deleted, or modified. - IncrementalDiff(existing []*models.RecordConfig) (reportMsgs []string, create, toDelete, modify Changeset, actualChangeCount int, err error) - // ChangedGroups performs a diff more appropriate for providers with a "RecordSet" model, where all records with the same name and type are grouped. - // Individual record changes are often not useful in such scenarios. Instead we return a map of record keys to a list of change descriptions within that group. - ChangedGroups(existing []*models.RecordConfig) (map[models.RecordKey][]string, []string, int, error) -} - -type differ struct{} - -// get normalized content for record. target, ttl, mxprio, and specified metadata. -func (d *differ) content(r *models.RecordConfig) string { - return fmt.Sprintf("%s ttl=%d", r.ToComparableNoTTL(), r.TTL) -} - -func (c Correlation) String() string { - if c.Existing == nil { - return color.GreenString("+ CREATE %s %s %s", c.Desired.Type, c.Desired.GetLabelFQDN(), c.d.content(c.Desired)) - } - if c.Desired == nil { - return color.RedString("- DELETE %s %s %s", c.Existing.Type, c.Existing.GetLabelFQDN(), c.d.content(c.Existing)) - } - return color.YellowString("± MODIFY %s %s: (%s) -> (%s)", c.Existing.Type, c.Existing.GetLabelFQDN(), c.d.content(c.Existing), c.d.content(c.Desired)) -} diff --git a/pkg/diff/diff2compat.go b/pkg/diff/diff2compat.go deleted file mode 100644 index c7725994f2..0000000000 --- a/pkg/diff/diff2compat.go +++ /dev/null @@ -1,103 +0,0 @@ -package diff - -import ( - "fmt" - - "github.com/DNSControl/dnscontrol/v4/models" - "github.com/DNSControl/dnscontrol/v4/pkg/diff2" -) - -// 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. -// -// To use this simply change New() to NewCompat(). If that doesn't -// 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") - } - - return &differCompat{ - dc: dc, - } -} - -// differCompat meets the Differ interface but provides its service -// using pkg/diff2 instead of pkg/diff. -type differCompat struct { - dc *models.DomainConfig -} - -// IncrementalDiff usees pkg/diff2 to generate output compatible with systems -// still using NewCompat(). -func (d *differCompat) IncrementalDiff(existing []*models.RecordConfig) (reportMsgs []string, toCreate, toDelete, toModify Changeset, actualChangeCount int, err error) { - instructions, actualChangeCount, err := diff2.ByRecord(existing, d.dc, nil) - if err != nil { - return nil, nil, nil, nil, 0, err - } - - if len(d.dc.EnsureAbsent) != 0 { - reportMsgs = append(reportMsgs, "WARNING: This provider does not reliably support ENSURE_ABSENT") - } - if d.dc.KeepUnknown { - reportMsgs = append(reportMsgs, "WARNING: This provider does not reliably support NO_PURGE") - } - if len(d.dc.Unmanaged) != 0 { - reportMsgs = append(reportMsgs, "WARNING: This provider does not reliably support IGNORE() and friends") - } - if d.dc.UnmanagedUnsafe { - reportMsgs = append(reportMsgs, "WARNING: This provider does not reliably support DISABLE_IGNORE_SAFETY_CHECK") - } - - for _, inst := range instructions { - cor := Correlation{} - switch inst.Type { - case diff2.REPORT: - reportMsgs = append(reportMsgs, inst.Msgs...) - case diff2.CREATE: - cor.Desired = inst.New[0] - toCreate = append(toCreate, cor) - case diff2.CHANGE: - cor.Existing = inst.Old[0] - cor.Desired = inst.New[0] - toModify = append(toModify, cor) - case diff2.DELETE: - cor.Existing = inst.Old[0] - toDelete = append(toDelete, cor) - default: - panic(fmt.Sprintf("unhandled inst.Type %s", inst.Type)) - } - } - - 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}) - } - return -} - -// ChangedGroups provides the same results as IncrementalDiff but grouped by key. -func (d *differCompat) ChangedGroups(existing []*models.RecordConfig) (map[models.RecordKey][]string, []string, int, error) { - changedKeys := map[models.RecordKey][]string{} - toReport, toCreate, toDelete, toModify, actualChangeCount, err := d.IncrementalDiff(existing) - if err != nil { - return nil, nil, 0, err - } - for _, c := range toCreate { - changedKeys[c.Desired.Key()] = append(changedKeys[c.Desired.Key()], c.String()) - } - for _, d := range toDelete { - changedKeys[d.Existing.Key()] = append(changedKeys[d.Existing.Key()], d.String()) - } - for _, m := range toModify { - changedKeys[m.Desired.Key()] = append(changedKeys[m.Desired.Key()], m.String()) - } - return changedKeys, toReport, actualChangeCount, nil -} diff --git a/pkg/diff2/analyze.go b/pkg/diff2/analyze.go index 93fd4ee1f7..9ceff61425 100644 --- a/pkg/diff2/analyze.go +++ b/pkg/diff2/analyze.go @@ -2,11 +2,10 @@ package diff2 import ( "fmt" - "regexp" "sort" "strings" - "github.com/DNSControl/dnscontrol/v4/models" + "github.com/DNSControl/dnscontrol/v5/models" "github.com/fatih/color" ) @@ -75,7 +74,7 @@ func analyzeByLabel(cc *CompareConfig) (ChangeList, int) { if len(accMsgs) == 0 { // Nothing changed. } else if len(accDesired) == 0 { // No new records at the label? This must be a delete. instructions = append(instructions, mkDelete(label, "", accMsgs, accExisting)) - } else if len(accExisting) == 0 { // No old records at the label? This must be a change. + } else if len(accExisting) == 0 { // No old records at the label? This must be a create. c := mkAdd(label, "", accMsgs, accDesired) c.MsgsByKey = msgsByKey instructions = append(instructions, c) @@ -232,19 +231,20 @@ func humanDiff(a, b targetConfig) string { // FUTURE(tlim): Records like MX and SRV should have more clever output. // For example if only the MX priority changes, show just that. + // FUTURE(tlim): If the data but NOT the TTLs are different, omit the TTLs. + if a.comparableNoTTL != b.comparableNoTTL { // The recorddata is different: - return fmt.Sprintf("(%s) -> (%s)", a.comparableFull, b.comparableFull) + //return fmt.Sprintf("(%s) -> (%s)", a.comparableFull, b.comparableFull) + return fmt.Sprintf("(%s ttl=%d) -> (%s ttl=%d)", a.rec.GetRDATA().String(), a.rec.TTL, b.rec.GetRDATA().String(), b.rec.TTL) } // Just the TTLs are different: return fmt.Sprintf("ttl=(%d->%d) %s", a.rec.TTL, b.rec.TTL, - a.comparableNoTTL) + a.rec.GetRDATA().String()) } -var echRe = regexp.MustCompile(`ech="?([\w+/=]+)"?`) - // diffTargets is the real workhorse of the diff2 system. All the setup has been complete, // now we can find the differences between two zones. func diffTargets(existing, desired []targetConfig) ChangeList { @@ -255,37 +255,13 @@ func diffTargets(existing, desired []targetConfig) ChangeList { return nil } - echs := make(map[string]string) - for _, v := range existing { - matches := echRe.FindStringSubmatch(v.rec.SvcParams) - if len(matches) == 2 { - echs[v.rec.NameFQDN] = matches[1] - } - } - for i, v := range desired { - if strings.Contains(v.rec.SvcParams, "ech=IGNORE") { - var unquoted, quoted string - if _, ok := echs[v.rec.NameFQDN]; ok { - unquoted = fmt.Sprintf("ech=%s", echs[v.rec.NameFQDN]) - quoted = fmt.Sprintf("ech=%s", echs[v.rec.NameFQDN]) - } else { - unquoted = "" - quoted = "" - } - v.rec.SvcParams = echRe.ReplaceAllString(v.rec.SvcParams, unquoted) - v.comparableFull = echRe.ReplaceAllString(v.comparableFull, quoted) - v.comparableNoTTL = echRe.ReplaceAllString(v.comparableNoTTL, quoted) - } - desired[i] = v - } - var instructions ChangeList // remove the exact matches. existing, desired = removeCommon(existing, desired) // At this point the exact matches are removed. However there may be - // records that have the same GetTargetCombined() but different + // records that have the same .String() but different // TTLs. existing, desired, newChanges := findTTLChanges(existing, desired) @@ -300,7 +276,6 @@ func diffTargets(existing, desired []targetConfig) ChangeList { for i := range mi { er := existing[i].rec dr := desired[i].rec - m := color.YellowString("± MODIFY %s %s %s", dr.NameFQDN, dr.Type, humanDiff(existing[i], desired[i])) mkc := mkChange(dr.NameFQDN, dr.Type, []string{m}, models.Records{er}, models.Records{dr}) diff --git a/pkg/diff2/analyze_test.go b/pkg/diff2/analyze_test.go index 59db66a120..39df26a76d 100644 --- a/pkg/diff2/analyze_test.go +++ b/pkg/diff2/analyze_test.go @@ -7,7 +7,8 @@ import ( "strings" "testing" - "github.com/DNSControl/dnscontrol/v4/models" + dnsutilv2 "codeberg.org/miekg/dns/dnsutil" + "github.com/DNSControl/dnscontrol/v5/models" "github.com/fatih/color" "github.com/kylelemons/godebug/diff" ) @@ -32,10 +33,10 @@ func (c Change) String() string { fmt.Fprint(b, " Hints=OnlyTTL\n", c.Key) } if len(c.Old) != 0 { - fmt.Fprintf(b, " old=%v\n", c.Old) + fmt.Fprintf(b, " old=%v\n", c.Old.StringEach()) } if len(c.New) != 0 { - fmt.Fprintf(b, " new=%v\n", c.New) + fmt.Fprintf(b, " new=%v\n", c.New.StringEach()) } fmt.Fprintf(b, " msg=%q\n", c.Msgs) @@ -57,13 +58,13 @@ func (cl ChangeList) String() string { // Make sample data func makeRec(label, rtype, content string) *models.RecordConfig { - origin := "f.com" - r := models.RecordConfig{TTL: 300} - r.SetLabel(label, origin) - if err := r.PopulateFromString(rtype, content, origin); err != nil { - panic(err) + dc := models.MustNewDomainConfig("f.com") + typeNum, err := dnsutilv2.StringToType(rtype) + if err != nil { + panic(fmt.Sprintf("BUG: makeRec does not support %q", rtype)) } - return &r + rec := dc.AddTestRCParse(dc.LabelFromShort(label), 300, typeNum, content) + return rec } func makeRecTTL(label, rtype, content string, ttl uint32) *models.RecordConfig { @@ -536,8 +537,6 @@ ChangeList: len=11 }, } for _, tt := range tests { - models.CanonicalizeTargets(tt.args.existing, tt.args.origin) - models.CanonicalizeTargets(tt.args.desired, tt.args.origin) // Each "analyze*()" should return the same msgs, but a different ChangeList. // Sadly the analyze*() functions are destructive to the CompareConfig struct. @@ -578,7 +577,6 @@ func coalesce(a string, b string) string { func mkTargetConfig(x ...*models.RecordConfig) []targetConfig { var tc []targetConfig - models.CanonicalizeTargets(x, "f.com") for _, r := range x { ct, cf := mkCompareBlobs(r, nil) tc = append(tc, targetConfig{ diff --git a/pkg/diff2/compareconfig.go b/pkg/diff2/compareconfig.go index 1153d5feb5..ce84eab134 100644 --- a/pkg/diff2/compareconfig.go +++ b/pkg/diff2/compareconfig.go @@ -4,8 +4,8 @@ import ( "fmt" "sort" - "github.com/DNSControl/dnscontrol/v4/models" - "github.com/DNSControl/dnscontrol/v4/pkg/prettyzone" + "github.com/DNSControl/dnscontrol/v5/models" + "github.com/DNSControl/dnscontrol/v5/pkg/prettyzone" ) /* @@ -77,8 +77,8 @@ type labelConfig struct { type rTypeConfig struct { rType string // The rType for all records in this group (A, CNAME, etc) // The records stored as lists: - existingRecs []*models.RecordConfig - desiredRecs []*models.RecordConfig + existingRecs models.Records + desiredRecs models.Records // The records stored as compareable/rec tuples: existingTargets []targetConfig desiredTargets []targetConfig @@ -104,6 +104,9 @@ func NewCompareConfig(origin string, existing, desired models.Records, compFn Co keyMap: map[models.RecordKey]bool{}, } cc.addRecords(existing, true) // Must be called first so that CNAME manipulations happen in the correct order. + models.SVCBHydrateDesiredEchIgnore(existing, desired) + // It is a layering violation to post-process SVCB records here but I can't + // find a better place to do it. cc.addRecords(desired, false) cc.verifyCNAMEAssertions() sort.Slice(cc.ldata, func(i, j int) bool { @@ -170,8 +173,10 @@ func (cc *CompareConfig) verifyCNAMEAssertions() { // Generate a string that can be used to compare this record to others // for equality. func mkCompareBlobs(rc *models.RecordConfig, f func(*models.RecordConfig) string) (string, string) { - // Start with the comparable string - comp := rc.ToComparableNoTTL() + comp := rc.ComparableV3 + if comp == "" { + panic(fmt.Sprintf("mkCompareBlobs: record %s IN %s %s has empty ComparableV3", rc.NameFQDN, rc.Type, rc.GetRDATA().String())) + } // If the custom function exists, add its output if f != nil { @@ -200,6 +205,12 @@ func (cc *CompareConfig) addRecords(recs models.Records, storeInExisting bool) { z := prettyzone.PrettySort(recs, cc.origin, 0, nil) for _, rec := range z.Records { + if rec.ComparableV3 == "" { + panic(fmt.Sprintf("addRecord: should not happen: Cv3 is blank: %v", rec)) + // We panic because we have eliminated all places where the .ComparableV3 + // doesn't get fixed. If we're wrong, we want to know about it. + } + key := rec.Key() label := key.NameFQDN rtype := key.Type diff --git a/pkg/diff2/compareconfig_test.go b/pkg/diff2/compareconfig_test.go index 09a6fdcec2..87fdacd902 100644 --- a/pkg/diff2/compareconfig_test.go +++ b/pkg/diff2/compareconfig_test.go @@ -6,7 +6,7 @@ import ( "strings" "testing" - "github.com/DNSControl/dnscontrol/v4/models" + "github.com/DNSControl/dnscontrol/v5/models" "github.com/kylelemons/godebug/diff" ) @@ -31,8 +31,8 @@ func (cc *CompareConfig) String() string { } fmt.Fprintf(b, "labelMap: len=%d %v\n", len(cc.labelMap), cc.labelMap) fmt.Fprintf(b, "keyMap: len=%d %v\n", len(cc.keyMap), cc.keyMap) - fmt.Fprintf(b, "existing: %q\n", cc.existing) - fmt.Fprintf(b, "desired: %q\n", cc.desired) + fmt.Fprintf(b, "existing: %q\n", cc.existing.StringEach()) + fmt.Fprintf(b, "desired: %q\n", cc.desired.StringEach()) fmt.Fprintf(b, "origin: %v\n", cc.origin) fmt.Fprintf(b, "compFn: %v\n", cc.compareableFunc) @@ -226,9 +226,6 @@ compFn: for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { - models.CanonicalizeTargets(tt.args.desired, "f.com") - models.CanonicalizeTargets(tt.args.existing, "f.com") - cc := NewCompareConfig(tt.args.origin, tt.args.existing, tt.args.desired, tt.args.compFn) got := strings.TrimSpace(cc.String()) tt.want = strings.TrimSpace(tt.want) diff --git a/pkg/diff2/diff2.go b/pkg/diff2/diff2.go index bec6fbbb20..c2ffb53f2f 100644 --- a/pkg/diff2/diff2.go +++ b/pkg/diff2/diff2.go @@ -9,8 +9,8 @@ import ( "fmt" "strings" - "github.com/DNSControl/dnscontrol/v4/models" - "github.com/DNSControl/dnscontrol/v4/pkg/dnsgraph" + "github.com/DNSControl/dnscontrol/v5/models" + "github.com/DNSControl/dnscontrol/v5/pkg/dnsgraph" ) // Verb indicates the Change's type (create, delete, etc.) @@ -64,24 +64,53 @@ func (c Change) GetDependencies() []dnsgraph.Dependency { var dependencies []dnsgraph.Dependency if c.Type == CHANGE || c.Type == DELETE { - dependencies = append(dependencies, dnsgraph.CreateDependencies(c.Old.GetAllDependencies(), dnsgraph.BackwardDependency)...) + dependencies = append(dependencies, toGraphDependencies(c.Old.GetAllDependencies(), dnsgraph.BackwardDependency)...) } if c.Type == CHANGE || c.Type == CREATE { - dependencies = append(dependencies, dnsgraph.CreateDependencies(c.New.GetAllDependencies(), dnsgraph.ForwardDependency)...) + dependencies = append(dependencies, toGraphDependencies(c.New.GetAllDependencies(), dnsgraph.ForwardDependency)...) } return dependencies } +// toGraphDependencies converts model.Dependency dependencies into +// graph.Dependency dependencies, tagging each with the given direction and +// preserving any OnlyType filter. +func toGraphDependencies(deps []models.Dependency, direction dnsgraph.DependencyType) []dnsgraph.Dependency { + result := make([]dnsgraph.Dependency, 0, len(deps)) + for _, dep := range deps { + result = append(result, dnsgraph.Dependency{ + NameFQDN: dep.NameFQDN, + Type: direction, + OnlyType: dep.OnlyType, + }) + } + return result +} + +// GetRecordType returns the DNS record type of the change, used to satisfy +// dnsgraph Dependency.OnlyType filters. Change.Key.Type is only populated for +// ByRecordSet, so fall back to the records themselves. +func (c Change) GetRecordType() string { + if len(c.New) > 0 { + return c.New[0].Type + } + if len(c.Old) > 0 { + return c.Old[0].Type + } + return c.Key.Type +} + /* General instructions: -Every provider updates their zones in one of three granularities: record, recordset, label, or zone. +Every provider updates their zones in one of four granularities: record, recordset, label, or zone. Identify which your provider is, and use the appropriate "By*" call. (ByZone is different, see its documentation.) changes, err := diff2.ByRecord(existing, dc, nil) //changes, err := diff2.ByRecordSet(existing, dc, nil) //changes, err := diff2.ByLabel(existing, dc, nil) + // diff2.ByZone's boilerplate is different. See ByZone. if err != nil { return nil, err } @@ -146,7 +175,7 @@ func (c *Change) CreateCorrectionWithMessage(msg string, correctionFunction func // record, if A records are added, changed, or removed, the API takes // www.example.com, A, and a list of all the desired IP addresses. // -// Examples include: AZURE_DNS, GCORE, NS1, ROUTE53. +// Examples include: AZURE_DNS, GCORE, NS1, ROUTE53, VULTR. func ByRecordSet(existing models.Records, dc *models.DomainConfig, compFunc ComparableFunc) (ChangeList, int, error) { return byHelper(analyzeByRecordSet, existing, dc, compFunc) } @@ -174,7 +203,7 @@ func ByLabel(existing models.Records, dc *models.DomainConfig, compFunc Comparab // A change always has exactly 1 old and 1 new: .Old[0] and .New[0] // A delete always has exactly 1 old: .Old[0] // -// Examples include: CLOUDFLAREAPI, HEDNS, INWX, MSDNS, OVH, PORKBUN, VULTR. +// Examples include: CLOUDFLAREAPI, HEDNS, INWX, MSDNS, OVH, PORKBUN. func ByRecord(existing models.Records, dc *models.DomainConfig, compFunc ComparableFunc) (ChangeList, int, error) { return byHelper(analyzeByRecord, existing, dc, compFunc) } diff --git a/pkg/diff2/dsordering_test.go b/pkg/diff2/dsordering_test.go new file mode 100644 index 0000000000..e67195e2da --- /dev/null +++ b/pkg/diff2/dsordering_test.go @@ -0,0 +1,105 @@ +package diff2 + +import ( + "testing" + + "github.com/DNSControl/dnscontrol/v5/models" +) + +// newRC is a small helper for building records in these tests. +func newRC(dc *models.DomainConfig, label, typ string, args ...any) *models.RecordConfig { + rc, err := dc.NewRecordConfig(label, 300, typ, args...) + if err != nil { + panic(err) + } + return rc +} + +// deleteThenCreateTypes returns the record types of the DELETE instructions +// followed by the record types of the CREATE instructions, in emitted order. +func changeTypesByVerb(changes ChangeList, verb Verb) []string { + var out []string + for _, c := range changes { + if c.Type != verb { + continue + } + switch verb { + case DELETE: + out = append(out, c.Old[0].Type) + default: + out = append(out, c.New[0].Type) + } + } + return out +} + +// TestDSNSOrdering verifies the DS<->NS dependency ordering. A DS delegation +// signs the NS at the same label, so: +// - on create, the NS must be created before the DS, and +// - on delete, the DS must be deleted before the NS. +// +// Multiple DS records at one label must NOT depend on each other (which would +// otherwise create a false circular dependency and leave them unordered). +func TestDSNSOrdering(t *testing.T) { + dsDigest := "da39a3ee5e6b4b0d3255bfef95601890afd80709" + dsDigest2 := "ee02c885b5b4ed64899f2d43eb2b8e6619bdb50c" + + t.Run("delete DS before NS", func(t *testing.T) { + dc := models.MustNewDomainConfig("example.com") + existing := models.Records{ + newRC(dc, "child", "NS", "ns1.example.net."), + newRC(dc, "child", "DS", uint16(1), uint8(13), uint8(1), dsDigest), + newRC(dc, "child", "DS", uint16(2), uint8(13), uint8(1), dsDigest2), + } + dc.Records = models.Records{} + + changes, _, err := ByRecord(existing, dc, nil) + if err != nil { + t.Fatal(err) + } + order := changeTypesByVerb(changes, DELETE) + assertBefore(t, order, "DS", "NS") + }) + + t.Run("create NS before DS", func(t *testing.T) { + dc := models.MustNewDomainConfig("example.com") + dc.Records = models.Records{ + newRC(dc, "child", "NS", "ns1.example.net."), + newRC(dc, "child", "DS", uint16(1), uint8(13), uint8(1), dsDigest), + newRC(dc, "child", "DS", uint16(2), uint8(13), uint8(1), dsDigest2), + } + + changes, _, err := ByRecord(nil, dc, nil) + if err != nil { + t.Fatal(err) + } + order := changeTypesByVerb(changes, CREATE) + assertBefore(t, order, "NS", "DS") + }) +} + +// assertBefore fails if any occurrence of "after" precedes an occurrence of +// "before" in order. It also requires that both types are present. +func assertBefore(t *testing.T, order []string, before, after string) { + t.Helper() + lastBefore, firstAfter := -1, -1 + for i, typ := range order { + switch typ { + case before: + lastBefore = i + case after: + if firstAfter == -1 { + firstAfter = i + } + } + } + if lastBefore == -1 { + t.Fatalf("no %s record found in order %v", before, order) + } + if firstAfter == -1 { + t.Fatalf("no %s record found in order %v", after, order) + } + if lastBefore > firstAfter { + t.Errorf("expected all %s before all %s, got order %v", before, after, order) + } +} diff --git a/pkg/diff2/externaldns.go b/pkg/diff2/externaldns.go index 72ba61249d..dae68e0174 100644 --- a/pkg/diff2/externaldns.go +++ b/pkg/diff2/externaldns.go @@ -16,7 +16,7 @@ package diff2 import ( "strings" - "github.com/DNSControl/dnscontrol/v4/models" + "github.com/DNSControl/dnscontrol/v5/models" ) const ( @@ -33,7 +33,7 @@ type externalDNSManagedRecord struct { // isExternalDNSTxtRecord checks if a TXT record is an external-dns ownership record. // It returns true and the managed record info if it is, false otherwise. // customPrefix is an optional prefix that external-dns was configured with (e.g., "extdns-"). -func isExternalDNSTxtRecord(rec *models.RecordConfig, domain string, customPrefix string) (bool, *externalDNSManagedRecord) { +func isExternalDNSTxtRecord(rec *models.RecordConfig, _ string, customPrefix string) (bool, *externalDNSManagedRecord) { if rec.Type != "TXT" { return false, nil } diff --git a/pkg/diff2/externaldns_test.go b/pkg/diff2/externaldns_test.go index 0f270f8f08..7f1c6b6fd4 100644 --- a/pkg/diff2/externaldns_test.go +++ b/pkg/diff2/externaldns_test.go @@ -3,20 +3,15 @@ package diff2 import ( "testing" - "github.com/DNSControl/dnscontrol/v4/models" + "github.com/DNSControl/dnscontrol/v5/models" ) func makeTestRecord(name, rtype, target, domain string) *models.RecordConfig { - rc := &models.RecordConfig{ - Type: rtype, - } - rc.SetLabel(name, domain) + dc := models.MustNewDomainConfig(domain) if rtype == "TXT" { - rc.SetTargetTXT(target) - } else { - rc.SetTarget(target) + return dc.MustNewRecordConfig(dc.LabelFromShort(name), 0, rtype, target) } - return rc + return dc.MustNewRecordConfigParse(dc.LabelFromShort(name), 0, rtype, target) } func TestIsExternalDNSTxtRecord(t *testing.T) { @@ -206,7 +201,7 @@ func TestFindExternalDNSManagedRecords(t *testing.T) { // Non-external-dns records makeTestRecord("static", "A", "1.2.3.4", domain), makeTestRecord("@", "TXT", "v=spf1 -all", domain), - makeTestRecord("@", "MX", "mail.example.com.", domain), + makeTestRecord("@", "MX", "10 mail.example.com.", domain), } managed := findExternalDNSManagedRecords(existing, domain, "") @@ -490,7 +485,7 @@ func TestGetExternalDNSIgnoredRecords_PeriodFormatApex(t *testing.T) { makeTestRecord("extdns-aaaa", "TXT", "heritage=external-dns,external-dns/owner=k3s-cluster", domain), makeTestRecord("@", "AAAA", "::1", domain), // Non-external-dns apex records (should not be ignored) - makeTestRecord("@", "MX", "mail.example.com.", domain), + makeTestRecord("@", "MX", "10 mail.example.com.", domain), makeTestRecord("@", "TXT", "v=spf1 -all", domain), } diff --git a/pkg/diff2/handsoff.go b/pkg/diff2/handsoff.go index 6d2a2b8925..f37720b916 100644 --- a/pkg/diff2/handsoff.go +++ b/pkg/diff2/handsoff.go @@ -9,8 +9,8 @@ import ( "fmt" "strings" - "github.com/DNSControl/dnscontrol/v4/models" - "github.com/DNSControl/dnscontrol/v4/pkg/printer" + "github.com/DNSControl/dnscontrol/v5/models" + "github.com/DNSControl/dnscontrol/v5/pkg/printer" "github.com/gobwas/glob" ) @@ -71,7 +71,7 @@ Here is how we intend to implement these features: * Take the list of existing records. If any match one of the IGNORE glob patterns, add it to the "ignored list". * If any item on the "ignored list" is also in "desired" (match on - label:rtype), output a warning (defeault) or declare an error (if + label:rtype), detail an error (default) or output a warning (if DISABLE_IGNORE_SAFETY_CHECK is true). * When we're done, add the "ignore list" records to desired. @@ -151,7 +151,7 @@ func handsoff( if len(conflicts) != 0 { msgs = append(msgs, fmt.Sprintf("%d records that are both IGNORE*()'d and not ignored:", len(conflicts))) for _, r := range conflicts { - msgs = append(msgs, fmt.Sprintf(" %s %s %s", r.GetLabelFQDN(), r.Type, r.GetTargetCombined())) + msgs = append(msgs, fmt.Sprintf(" %s %s %s", r.GetLabelFQDN(), r.Type, r.GetRDATA().String())) } if !unmanagedSafely { return nil, nil, errors.New(strings.Join(msgs, "\n") + @@ -166,7 +166,7 @@ func handsoff( if len(externalDNSConflicts) != 0 { msgs = append(msgs, fmt.Sprintf("WARNING: %d records are defined in your config but also managed by external-dns:", len(externalDNSConflicts))) for _, r := range externalDNSConflicts { - msgs = append(msgs, fmt.Sprintf(" %s %s %s", r.GetLabelFQDN(), r.Type, r.GetTargetCombined())) + msgs = append(msgs, fmt.Sprintf(" %s %s %s", r.GetLabelFQDN(), r.Type, r.GetRDATA().String())) } msgs = append(msgs, "Consider removing these from your config or from external-dns to avoid conflicts.") } @@ -194,7 +194,7 @@ func reportSkips(recs models.Records, full bool) []string { } for _, r := range recs[:last] { - msgs = append(msgs, fmt.Sprintf(` %s("%s.", %s),`, r.Type, r.GetLabelFQDN(), r.GetTargetJS())) + msgs = append(msgs, fmt.Sprintf(` %s("%s.", %s),`, r.Type, r.GetLabelFQDN(), r.GetRDATA().String())) } if shorten && printer.MaxReport != 0 { msgs = append(msgs, fmt.Sprintf(" ...and %d more... (use --full to show all)", len(recs)-printer.MaxReport)) @@ -281,7 +281,6 @@ func compileUnmanagedConfigs(configs []*models.UnmanagedConfig) error { // matchAny returns true if rec matches any of the uconfigs. func matchAny(uconfigs []*models.UnmanagedConfig, rec *models.RecordConfig) bool { - // fmt.Printf("DEBUG: matchAny(%s, %q, %q, %q)\n", models.DebugUnmanagedConfig(uconfigs), rec.NameFQDN, rec.Type, rec.GetTargetField()) for _, uc := range uconfigs { if matchLabel(uc.LabelGlob, rec.GetLabel()) && matchType(uc.RTypeMap, rec.Type) && diff --git a/pkg/diff2/handsoff_test.go b/pkg/diff2/handsoff_test.go index 2ca7fd9528..33cfaba4d4 100644 --- a/pkg/diff2/handsoff_test.go +++ b/pkg/diff2/handsoff_test.go @@ -5,25 +5,26 @@ import ( "strings" "testing" - "github.com/DNSControl/dnscontrol/v4/models" - "github.com/DNSControl/dnscontrol/v4/pkg/dnsrr" - "github.com/DNSControl/dnscontrol/v4/pkg/js" - dnsv1 "github.com/miekg/dns" + dnsv2 "codeberg.org/miekg/dns" + "github.com/DNSControl/dnscontrol/v5/models" + "github.com/DNSControl/dnscontrol/v5/pkg/dnsrr" + "github.com/DNSControl/dnscontrol/v5/pkg/js" testifyrequire "github.com/stretchr/testify/require" ) // parseZoneContents is copied verbatim from providers/bind/bindProvider.go // because import cycles and... tests shouldn't depend on huge modules. -func parseZoneContents(content string, zoneName string, zonefileName string) (models.Records, error) { - zp := dnsv1.NewZoneParser(strings.NewReader(content), zoneName, zonefileName) +func parseZoneContents(content string, dc *models.DomainConfig, zonefileName string) (models.Records, error) { + zoneName := dc.Name + zp := dnsv2.NewZoneParser(strings.NewReader(content), zoneName, zonefileName) foundRecords := models.Records{} for rr, ok := zp.Next(); ok; rr, ok = zp.Next() { - rec, err := dnsrr.RRtoRCTxtBug(rr, zoneName) + rec, err := dnsrr.RRv2toRC(dc, rr) if err != nil { return nil, err } - foundRecords = append(foundRecords, &rec) + foundRecords = append(foundRecords, rec) } if err := zp.Err(); err != nil { @@ -39,7 +40,7 @@ func showRecs(recs models.Records) string { result.WriteString(" ") result.WriteString(rec.Type) result.WriteString(" ") - result.WriteString(rec.GetTargetCombined()) + result.WriteString(rec.GetRDATA().String()) result.WriteString("\n") } return result.String() @@ -47,8 +48,9 @@ func showRecs(recs models.Records) string { func handsoffHelper(t *testing.T, existingZone, desiredJs string, noPurge bool, resultWanted string) { t.Helper() + dc1 := models.MustNewDomainConfig("f.com") - existing, err := parseZoneContents(existingZone, "f.com", "no_file_name") + existing, err := parseZoneContents(existingZone, dc1, "no_file_name") if err != nil { t.Fatal(err) } diff --git a/pkg/diff2/ordering.go b/pkg/diff2/ordering.go index e0d4679c05..38496bf232 100644 --- a/pkg/diff2/ordering.go +++ b/pkg/diff2/ordering.go @@ -3,8 +3,8 @@ package diff2 import ( "log" - "github.com/DNSControl/dnscontrol/v4/pkg/dnsgraph" - "github.com/DNSControl/dnscontrol/v4/pkg/dnssort" + "github.com/DNSControl/dnscontrol/v5/pkg/dnsgraph" + "github.com/DNSControl/dnscontrol/v5/pkg/dnssort" ) func orderByDependencies(changes ChangeList) ChangeList { diff --git a/pkg/dnsgraph/dependencies.go b/pkg/dnsgraph/dependencies.go deleted file mode 100644 index fb5794e7d2..0000000000 --- a/pkg/dnsgraph/dependencies.go +++ /dev/null @@ -1,12 +0,0 @@ -package dnsgraph - -// CreateDependencies creates a dependency list from a list of FQDNs and a DepenendyType. -func CreateDependencies(dependencyFQDNs []string, dependencyType DependencyType) []Dependency { - var dependencies []Dependency - - for _, dependency := range dependencyFQDNs { - dependencies = append(dependencies, Dependency{NameFQDN: dependency, Type: dependencyType}) - } - - return dependencies -} diff --git a/pkg/dnsgraph/dnsgraph.go b/pkg/dnsgraph/dnsgraph.go index 9e3bccdf5f..3b3e15910f 100644 --- a/pkg/dnsgraph/dnsgraph.go +++ b/pkg/dnsgraph/dnsgraph.go @@ -1,6 +1,6 @@ package dnsgraph -import "github.com/DNSControl/dnscontrol/v4/pkg/dnstree" +import "github.com/DNSControl/dnscontrol/v5/pkg/dnstree" type edgeDirection uint8 @@ -99,6 +99,13 @@ func (graph *Graph[T]) AddEdge(sourceNode *Node[T], dependency Dependency) { continue } + // A type-restricted dependency only links to destination nodes of the + // requested record type (e.g. a DS depends on the NS at its label, not + // on sibling DS records). + if dependency.OnlyType != "" && destinationNode.Data.GetRecordType() != dependency.OnlyType { + continue + } + if sourceNode.Edges.Contains(destinationNode, OutgoingEdge) { continue } @@ -130,7 +137,7 @@ func (nodes dnsGraphNodes[T]) RemoveNode(toRemove *Node[T]) dnsGraphNodes[T] { return newNodes } -// RemoveNode removes a node from a graph. +// RemoveNode removes a node edges. func (edges Edges[T]) RemoveNode(toRemove *Node[T]) Edges[T] { var newEdges Edges[T] diff --git a/pkg/dnsgraph/dnsgraph_test.go b/pkg/dnsgraph/dnsgraph_test.go index 3974666ac8..09136f4bbf 100644 --- a/pkg/dnsgraph/dnsgraph_test.go +++ b/pkg/dnsgraph/dnsgraph_test.go @@ -3,8 +3,8 @@ package dnsgraph_test import ( "testing" - "github.com/DNSControl/dnscontrol/v4/pkg/dnsgraph" - "github.com/DNSControl/dnscontrol/v4/pkg/dnsgraph/testutils" + "github.com/DNSControl/dnscontrol/v5/pkg/dnsgraph" + "github.com/DNSControl/dnscontrol/v5/pkg/dnsgraph/testutils" "github.com/stretchr/testify/assert" ) diff --git a/pkg/dnsgraph/graphable.go b/pkg/dnsgraph/graphable.go index 280b86c0ab..5e29a55c6e 100644 --- a/pkg/dnsgraph/graphable.go +++ b/pkg/dnsgraph/graphable.go @@ -24,12 +24,26 @@ const ( type Dependency struct { NameFQDN string Type DependencyType + // CNAME would generate Dependency{NameFQDN: target, OnlyType: ""} + // because the dependency is on the target. + // + // However a DS's dependency is on its own label, not the target. + // A DS needs to specify that the dependency is on the NS record at the same label. + // Therefore a DS record returns Dependency{NameFQDN: label, OnlyType: "NS"} + // to indicate that the dependency is only for NS records. + // If OnlyType were "", a DS would also depend on the *other* DS records at its + // label; with two or more DS there, they'd depend on each other and dnsgraph + // reports a cycle. + OnlyType string } // Graphable is an interface for things that can be in a graph. type Graphable interface { GetType() NodeType GetName() string + // GetRecordType returns the DNS record type (e.g. "NS", "DS") of the node. + // It is used to satisfy Dependency.OnlyType filters. + GetRecordType() string GetDependencies() []Dependency } diff --git a/pkg/dnsgraph/testutils/stubrecords.go b/pkg/dnsgraph/testutils/stubrecords.go index f902d4f1dc..773b4f0136 100644 --- a/pkg/dnsgraph/testutils/stubrecords.go +++ b/pkg/dnsgraph/testutils/stubrecords.go @@ -1,12 +1,13 @@ package testutils -import "github.com/DNSControl/dnscontrol/v4/pkg/dnsgraph" +import "github.com/DNSControl/dnscontrol/v5/pkg/dnsgraph" // StubRecord stub. type StubRecord struct { NameFQDN string Dependencies []dnsgraph.Dependency Type dnsgraph.NodeType + RecordType string } // GetType stub. @@ -19,6 +20,11 @@ func (record StubRecord) GetName() string { return record.NameFQDN } +// GetRecordType stub. +func (record StubRecord) GetRecordType() string { + return record.RecordType +} + // GetDependencies stub. func (record StubRecord) GetDependencies() []dnsgraph.Dependency { return record.Dependencies diff --git a/pkg/dnsrr/dnsrr.go b/pkg/dnsrr/dnsrr.go index a7181c88f1..7374026a6d 100644 --- a/pkg/dnsrr/dnsrr.go +++ b/pkg/dnsrr/dnsrr.go @@ -4,104 +4,41 @@ import ( "fmt" "strings" - "github.com/DNSControl/dnscontrol/v4/models" - "github.com/DNSControl/dnscontrol/v4/pkg/domaintags" - "github.com/DNSControl/dnscontrol/v4/pkg/rtypecontrol" - "github.com/DNSControl/dnscontrol/v4/pkg/rtypeinfo" - dnsv1 "github.com/miekg/dns" + dnsv2 "codeberg.org/miekg/dns" + dnsrdatav2 "codeberg.org/miekg/dns/rdata" + "github.com/DNSControl/dnscontrol/v5/models" + "github.com/DNSControl/dnscontrol/v5/pkg/nrc" ) -// RRtoRC converts dns.RR to models.RecordConfig. -func RRtoRC(rr dnsv1.RR, origin string) (models.RecordConfig, error) { - return helperRRtoRC(rr, origin, false) -} - -// RRtoRCTxtBug converts dns.RR to models.RecordConfig. Compensates for the backslash bug in github.com/miekg/dns/issues/1384. -func RRtoRCTxtBug(rr dnsv1.RR, origin string) (models.RecordConfig, error) { - return helperRRtoRC(rr, origin, true) -} - -// helperRRtoRC converts dns.RR to models.RecordConfig. If fixBug is true, replaces `\\` to `\` in TXT records to compensate for github.com/miekg/dns/issues/1384. -func helperRRtoRC(rr dnsv1.RR, origin string, fixBug bool) (models.RecordConfig, error) { - // Convert's dns.RR into DNSControl's models.RecordConfig struct. +// RRv2toRC converts dnsv2.RR to models.RecordConfig. It assumes: +// - The header.Name is a fully qualified domain name (FQDN) with a trailing dot. +// - The fields in the RDATA are already in the correct format (e.g., IDNA for domain names), FQDN+"." for targets. +func RRv2toRC(dc *models.DomainConfig, rr dnsv2.RR) (*models.RecordConfig, error) { + // Convert's dnsv2.RR into DNSControl's models.RecordConfig struct. header := rr.Header() - ty := dnsv1.TypeToString[header.Rrtype] + ttl := header.TTL + typeNum := dnsv2.RRToType(rr) + rd := rr.Data() - if rtypeinfo.IsModernType(ty) { - switch v := rr.(type) { - default: - rec, err := rtypecontrol.NewRecordConfigFromStruct(strings.TrimSuffix(header.Name, origin), header.Ttl, dnsv1.TypeToString[header.Rrtype], v, domaintags.MakeDomainNameVarieties(origin)) - return *rec, err - } - } - - rc := new(models.RecordConfig) - rc.Type = dnsv1.TypeToString[header.Rrtype] - rc.TTL = header.Ttl - rc.Original = rr - rc.SetLabelFromFQDN(strings.TrimSuffix(header.Name, "."), origin) var err error - switch v := rr.(type) { // #rtype_variations - case *dnsv1.A: - err = rc.SetTarget(v.A.String()) - case *dnsv1.AAAA: - err = rc.SetTarget(v.AAAA.String()) - case *dnsv1.CAA: - err = rc.SetTargetCAA(v.Flag, v.Tag, v.Value) - case *dnsv1.CNAME: - err = rc.SetTarget(v.Target) - case *dnsv1.DHCID: - err = rc.SetTarget(v.Digest) - case *dnsv1.DNAME: - err = rc.SetTarget(v.Target) - case *dnsv1.DS: - panic("DS should be handled as modern type") - case *dnsv1.DNSKEY: - err = rc.SetTargetDNSKEY(v.Flags, v.Protocol, v.Algorithm, v.PublicKey) - case *dnsv1.HTTPS: - err = rc.SetTargetSVCB(v.Priority, v.Target, v.Value) - case *dnsv1.LOC: - err = rc.SetTargetLOC(v.Version, v.Latitude, v.Longitude, v.Altitude, v.Size, v.HorizPre, v.VertPre) - case *dnsv1.MX: - err = rc.SetTargetMX(v.Preference, v.Mx) - case *dnsv1.NAPTR: - err = rc.SetTargetNAPTR(v.Order, v.Preference, v.Flags, v.Service, v.Regexp, v.Replacement) - case *dnsv1.OPENPGPKEY: - err = rc.SetTarget(v.PublicKey) - case *dnsv1.NS: - err = rc.SetTarget(v.Ns) - case *dnsv1.PTR: - err = rc.SetTarget(v.Ptr) - case *dnsv1.RP: - panic("RP should be handled as modern type") - case *dnsv1.SMIMEA: - err = rc.SetTargetSMIMEA(v.Usage, v.Selector, v.MatchingType, v.Certificate) - case *dnsv1.SOA: - err = rc.SetTargetSOA(v.Ns, v.Mbox, v.Serial, v.Refresh, v.Retry, v.Expire, v.Minttl) - case *dnsv1.SRV: - err = rc.SetTargetSRV(v.Priority, v.Weight, v.Port, v.Target) - case *dnsv1.SSHFP: - err = rc.SetTargetSSHFP(v.Algorithm, v.Type, v.FingerPrint) - case *dnsv1.SVCB: - err = rc.SetTargetSVCB(v.Priority, v.Target, v.Value) - case *dnsv1.TLSA: - err = rc.SetTargetTLSA(v.Usage, v.Selector, v.MatchingType, v.Certificate) - case *dnsv1.TXT: - if fixBug { - t := strings.Join(v.Txt, "") - te := t - te = strings.ReplaceAll(te, `\\`, `\`) - te = strings.ReplaceAll(te, `\"`, `"`) - err = rc.SetTargetTXT(te) - } else { - err = rc.SetTargetTXTs(v.Txt) + switch v := rd.(type) { + case dnsrdatav2.TXT: + // DNSControl stores a TXT value as a single string, so join the + // parser's 255-octet chunks. The patched dns library (codeberg.org/miekg/dns) + // unescapes backslashes correctly, so no further fix-up is needed + rd = dnsrdatav2.TXT{Txt: []string{strings.Join(v.Txt, "")}} + case dnsrdatav2.TLSA: + // TLSA is a special case because we need to normalize the certificate data to uppercase. + rd, err = models.MakeTLSA(dc.Name, nil, nrc.Flags{}, v.Usage, v.Selector, v.MatchingType, v.Certificate) + if err != nil { + return nil, fmt.Errorf("error creating TLSA record: %w", err) } - default: - return *rc, fmt.Errorf("rrToRecord: Unimplemented zone record type=%s (%v)", rc.Type, rr) } + + rec, err := dc.NewRecordConfigForRRv2toRC(dc.LabelFromFQDNWithDot(header.Name), ttl, typeNum, rd) if err != nil { - return *rc, fmt.Errorf("unparsable record received: %w", err) + return nil, fmt.Errorf("error creating record config: %w", err) } - return *rc, nil + return rec, nil } diff --git a/pkg/dnsrr/v1v2.go b/pkg/dnsrr/v1v2.go deleted file mode 100644 index e499469621..0000000000 --- a/pkg/dnsrr/v1v2.go +++ /dev/null @@ -1,32 +0,0 @@ -package dnsrr - -import ( - dnsv2 "codeberg.org/miekg/dns" - dnsv1 "github.com/miekg/dns" -) - -// RRv1tov2 converts github.com/miekg/dns (v1) RR to codeberg.org/miekg/dns (v2) RR. -// Typically used in providers that still use v1. -// Note: this function is not efficient. It converts via string representation. -// Use it until you are able to convert to v2 fully. -// Note: Panics on error. -func RRv1tov2(rrv1 dnsv1.RR) dnsv2.RR { - rrv2, err := dnsv2.New(rrv1.String()) - if err != nil { - panic("Failed to convert RR to v2: " + err.Error()) - } - return rrv2 -} - -// RRv2tov1 converts codeberg.org/miekg/dns (v2) RR to github.com/miekg/dns (v1) RR. -// Typically used in providers that still use v1. -// Note: this function is not efficient. It converts via string representation. -// Use it until you are able to convert to v1 fully. -// Note: Panics on error. -func RRv2tov1(rrv2 dnsv2.RR) dnsv1.RR { - rrv1, err := dnsv1.NewRR(rrv2.String()) - if err != nil { - panic("Failed to convert RR to v1: " + err.Error()) - } - return rrv1 -} diff --git a/pkg/dnssort/graphsort.go b/pkg/dnssort/graphsort.go index 70c57f3d76..544b12f473 100644 --- a/pkg/dnssort/graphsort.go +++ b/pkg/dnssort/graphsort.go @@ -1,6 +1,6 @@ package dnssort -import "github.com/DNSControl/dnscontrol/v4/pkg/dnsgraph" +import "github.com/DNSControl/dnscontrol/v5/pkg/dnsgraph" // SortUsingGraph sorts changes based on their dependencies using a directed graph. // Most changes have dependencies on other changes. @@ -22,8 +22,8 @@ func SortUsingGraph[T dnsgraph.Graphable](records []T) SortResult[T] { sortState := createDirectedSortState(records) for sortState.hasWork() { + sortState.hasResolvedLastRound = false for _, node := range sortState.graph.All { - sortState.hasResolvedLastRound = false if hasUnmetDependencies(node) { continue diff --git a/pkg/dnssort/graphsort_test.go b/pkg/dnssort/graphsort_test.go index 6d3b187b55..a6e783fb6e 100644 --- a/pkg/dnssort/graphsort_test.go +++ b/pkg/dnssort/graphsort_test.go @@ -3,9 +3,9 @@ package dnssort_test import ( "testing" - "github.com/DNSControl/dnscontrol/v4/pkg/dnsgraph" - "github.com/DNSControl/dnscontrol/v4/pkg/dnsgraph/testutils" - "github.com/DNSControl/dnscontrol/v4/pkg/dnssort" + "github.com/DNSControl/dnscontrol/v5/pkg/dnsgraph" + "github.com/DNSControl/dnscontrol/v5/pkg/dnsgraph/testutils" + "github.com/DNSControl/dnscontrol/v5/pkg/dnssort" ) func Test_graphsort(t *testing.T) { @@ -37,6 +37,22 @@ func Test_graphsort(t *testing.T) { ), ) + t.Run("Multi-round dependency chain resolves when tail is last", + executeGraphSort( + []testutils.StubRecord{ + {NameFQDN: "d.example.com", Dependencies: []dnsgraph.Dependency{{Type: dnsgraph.ForwardDependency, NameFQDN: "e.example.com"}}}, + {NameFQDN: "e.example.com", Dependencies: []dnsgraph.Dependency{}}, + {NameFQDN: "l.example.com", Dependencies: []dnsgraph.Dependency{{Type: dnsgraph.ForwardDependency, NameFQDN: "d.example.com"}}}, + }, + []string{ + "e.example.com", + "d.example.com", + "l.example.com", + }, + []string{}, + ), + ) + t.Run("Use wildcards", executeGraphSort( []testutils.StubRecord{ diff --git a/pkg/dnssort/result.go b/pkg/dnssort/result.go index d731c7f738..551964680b 100644 --- a/pkg/dnssort/result.go +++ b/pkg/dnssort/result.go @@ -1,6 +1,6 @@ package dnssort -import "github.com/DNSControl/dnscontrol/v4/pkg/dnsgraph" +import "github.com/DNSControl/dnscontrol/v5/pkg/dnsgraph" // SortResult is the result of a sort function. type SortResult[T dnsgraph.Graphable] struct { diff --git a/pkg/dnstree/dnstree.go b/pkg/dnstree/dnstree.go index 8de204e106..18ffa449c0 100644 --- a/pkg/dnstree/dnstree.go +++ b/pkg/dnstree/dnstree.go @@ -1,6 +1,7 @@ package dnstree import ( + "slices" "strings" ) @@ -70,8 +71,8 @@ func (tree *DomainTree[T]) Get(fqdn string) T { var mostSpecificNode *domainNode[T] ptr := (*domainNode[T])(tree) - for iX := len(domainParts) - 1; iX >= 0; iX-- { - node, ok := ptr.Children[domainParts[iX]] + for _, domainPart := range slices.Backward(domainParts) { + node, ok := ptr.Children[domainPart] if !ok { if mostSpecificNode != nil { return mostSpecificNode.data @@ -104,8 +105,8 @@ func (tree *DomainTree[T]) Has(fqdn string) bool { var mostSpecificNode *domainNode[T] ptr := (*domainNode[T])(tree) - for iX := len(domainParts) - 1; iX >= 0; iX-- { - node, ok := ptr.Children[domainParts[iX]] + for _, domainPart := range slices.Backward(domainParts) { + node, ok := ptr.Children[domainPart] if !ok { return mostSpecificNode != nil } diff --git a/pkg/dnstree/dnstree_test.go b/pkg/dnstree/dnstree_test.go index 733341bf24..3b1f518bbb 100644 --- a/pkg/dnstree/dnstree_test.go +++ b/pkg/dnstree/dnstree_test.go @@ -3,7 +3,7 @@ package dnstree_test import ( "testing" - "github.com/DNSControl/dnscontrol/v4/pkg/dnstree" + "github.com/DNSControl/dnscontrol/v5/pkg/dnstree" ) func Test_domaintree(t *testing.T) { diff --git a/pkg/domaintags/domaintags.go b/pkg/domaintags/domaintags.go index 7c5365c40d..2e5091981a 100644 --- a/pkg/domaintags/domaintags.go +++ b/pkg/domaintags/domaintags.go @@ -54,7 +54,6 @@ func MakeDomainNameVarieties(n string) *DomainNameVarieties { nameASCII = strings.ToLower(nameASCII) // Avoid pointless duplication. if strings.HasPrefix(n, nameASCII) { - // Avoid pointless duplication. nameASCII = n[0:len(nameASCII)] } } diff --git a/pkg/domaintags/idn.go b/pkg/domaintags/idn.go index da79003d4d..c94236445e 100644 --- a/pkg/domaintags/idn.go +++ b/pkg/domaintags/idn.go @@ -22,18 +22,3 @@ func EfficientToASCII(name string) string { } return nameIDN } - -// EfficientToUnicode converts a domain name to its Unicode representation -// using IDNA, on error returns the original name, and avoids allocating new -// memory when possible. -func EfficientToUnicode(name string) string { - nameUnicode, err := idna.ToUnicode(name) - if err != nil { - return name // Fallback to raw name on error. - } - // Avoid pointless duplication. - if nameUnicode == name { - return name - } - return nameUnicode -} diff --git a/pkg/domaintags/idn_test.go b/pkg/domaintags/idn_test.go new file mode 100644 index 0000000000..34be872496 --- /dev/null +++ b/pkg/domaintags/idn_test.go @@ -0,0 +1,28 @@ +package domaintags_test + +import ( + "testing" + + "github.com/DNSControl/dnscontrol/v5/pkg/domaintags" +) + +func TestEfficientToASCII(t *testing.T) { + tests := []struct { + name string // description of this test case + // Named input parameters for target function. + iname string + want string + }{ + {name: "simple", iname: `foo`, want: `foo`}, + {name: "case", iname: `SIMPLE`, want: `simple`}, + {name: "mixed", iname: `SIMекамплеPLE`, want: `xn--simple-5nf3bb2cml3b`}, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + got := domaintags.EfficientToASCII(tt.iname) + if got != tt.want { + t.Errorf("EfficientToASCII(%q) = %q, want %q", tt.iname, got, tt.want) + } + }) + } +} diff --git a/pkg/js/hash.go b/pkg/js/hash.go index 7639449eab..c3b7c13ca3 100644 --- a/pkg/js/hash.go +++ b/pkg/js/hash.go @@ -17,8 +17,7 @@ func hashFunc(call otto.FunctionCall) otto.Value { } algorithm := call.Argument(0).String() // The algorithm to use for hashing value := call.Argument(1).String() // The value to hash - //lint:ignore SA4006 work around bug in staticcheck. This value is needed if the switch statement follows the default path. - result := otto.Value{} //nolint:staticcheck + result := otto.Value{} // fmt.Printf("%s\n", value) switch algorithm { diff --git a/pkg/js/helpers.js b/pkg/js/helpers.js index ec120dcc3d..079b90b007 100644 --- a/pkg/js/helpers.js +++ b/pkg/js/helpers.js @@ -39,7 +39,9 @@ function initialize() { function _isDomain(d) { return ( - _.isArray(d.nameservers) && _.isArray(d.records) && _.isString(d.name) + _.isArray(d.nameservers) && + _.isArray(d.rawrecords) && + _.isString(d.name) ); } @@ -110,14 +112,11 @@ function newDomain(name, registrar) { subdomain: '', registrar: registrar, meta: {}, - records: [], rawrecords: [], recordsabsent: [], dnsProviders: {}, defaultTTL: 0, nameservers: [], - ignored_names: [], - ignored_targets: [], unmanaged: [], }; } @@ -183,7 +182,10 @@ function INCLUDE(name) { ); } return function (d) { - d.records.push.apply(d.records, domain.obj.records); + // New-style record types live in rawrecords (processed in Go), so they + // must be copied too. Each domain re-serializes these objects to its own + // IR, so sharing the references here is safe. + d.rawrecords.push.apply(d.rawrecords, domain.obj.rawrecords); }; } @@ -304,6 +306,13 @@ function DefaultTTL(v) { function makeCAAFlag(value) { return function (record) { record.caaflag |= value; + if (!_.isObject(record.meta)) { + record.meta = {}; + } + // Store as a string: meta values cross to Go as strings (see + // mergeMetas), otherwise a numeric value would be mangled (e.g. into + // "%!s(float64=128)"). + record.meta['caaflag'] = record.caaflag.toString(); }; } @@ -322,57 +331,45 @@ function DnsProvider(name, nsCount) { }; } -// A(name,ip, recordModifiers...) -var A = recordBuilder('A'); - -// AAAA(name,ip, recordModifiers...) -var AAAA = recordBuilder('AAAA'); - -// AKAMAICDN(name, target, recordModifiers...) -var AKAMAICDN = recordBuilder('AKAMAICDN'); - -// AKAMAITLC(name, answer_type, target, recordModifiers...) -var AKAMAITLC = recordBuilder('AKAMAITLC', { - args: [ - ['name', _.isString], - [ - 'answer_type', - function (value) { - return ( - _.isString(value) && - ['DUAL', 'A', 'AAAA'].indexOf(value) !== -1 - ); - }, - ], - ['target', _.isString], - ], - transform: function (record, args, modifier) { - record.name = args.name; - record.answer_type = args.answer_type; - record.target = args.target; - }, -}); - -// ALIAS(name,target, recordModifiers...) -var ALIAS = recordBuilder('ALIAS'); +// // AKAMAITLC(name, answer_type, target, recordModifiers...) +// var AKAMAITLC = recordBuilder('AKAMAITLC', { +// args: [ +// ['name', _.isString], +// [ +// 'answer_type', +// function (value) { +// return ( +// _.isString(value) && +// ['DUAL', 'A', 'AAAA'].indexOf(value) !== -1 +// ); +// }, +// ], +// ['target', _.isString], +// ], +// transform: function (record, args, modifier) { +// record.name = args.name; +// record.answer_type = args.answer_type; +// record.target = args.target; +// }, +// }); // AZURE_ALIAS(name, type, target, recordModifiers...) -var AZURE_ALIAS = recordBuilder('AZURE_ALIAS', { - args: [ - ['name', _.isString], - ['type', validateAzureAliasType], - ['target', _.isString], - ], - transform: function (record, args, modifier) { - record.name = args.name; - record.target = args.target; - if (_.isObject(record.azure_alias)) { - record.azure_alias['type'] = args.type; - } else { - record.azure_alias = { type: args.type }; - } - }, -}); +// var AZURE_ALIAS = recordBuilder('AZURE_ALIAS', { +// args: [ +// ['name', _.isString], +// ['type', validateAzureAliasType], +// ['target', _.isString], +// ], +// transform: function (record, args, modifier) { +// record.name = args.name; +// record.target = args.target; +// if (_.isObject(record.azure_alias)) { +// record.azure_alias['type'] = args.type; +// } else { +// record.azure_alias = { type: args.type }; +// } +// }, +// }); function validateAzureAliasType(value) { if (!_.isString(value)) { @@ -381,38 +378,17 @@ function validateAzureAliasType(value) { return ['A', 'AAAA', 'CNAME'].indexOf(value) !== -1; } -// R53_ALIAS(name, target, type, recordModifiers...) -var R53_ALIAS = recordBuilder('R53_ALIAS', { - args: [ - ['name', _.isString], - ['type', validateR53AliasType], - ['target', _.isString], - ], - transform: function (record, args, modifiers) { - record.name = args.name; - 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, - evaluate_target_health: 'false', - }; - } - }, -}); - // R53_ZONE(zone_id) function R53_ZONE(zone_id) { return function (r) { if (_isDomain(r)) { r.meta.zone_id = zone_id; + //console.debug("R53_Opt store zoneid in domainmeta", zone_id); } else if (_.isObject(r.r53_alias)) { r.r53_alias['zone_id'] = zone_id; + //console.debug("R53_Opt store zoneid in recordr53alias", zone_id); } else { + //console.debug("R53_Opt MAKE zoneid in recordr53alias", zone_id); r.r53_alias = { zone_id: zone_id }; } }; @@ -429,6 +405,24 @@ function R53_EVALUATE_TARGET_HEALTH(enabled) { }; } +function r53AliasOptions(record, processedArgs, processedMetas) { + // The args are [label, aliasType, target, evaluate_target_health, zone_id]. + var replacement = [ + processedArgs[0], + processedArgs[1], + processedArgs[2], + '', + '', + ]; + + if (_.isObject(record.r53_alias)) { + replacement[3] = record.r53_alias['evaluate_target_health'] || 'false'; + replacement[4] = record.r53_alias['zone_id'] || ''; + } + + return replacement; +} + // R53_WEIGHT(weight, set_identifier) configures Route 53 weighted routing. // weight: integer 0-255, set_identifier: unique string within the weighted group. function R53_WEIGHT(weight, set_identifier) { @@ -486,245 +480,9 @@ function validateR53AliasType(value) { ); } -// CAA(name,tag,value, recordModifiers...) -var CAA = recordBuilder('CAA', { - // TODO(tlim): It should be an error if value is not 0 or 128. - args: [ - ['name', _.isString], - ['tag', _.isString], - ['value', _.isString], - ], - transform: function (record, args, modifiers) { - record.name = args.name; - record.caatag = args.tag; - record.target = args.value; - }, - modifierNumber: function (record, value) { - record.caaflags |= value; - }, -}); - -// CNAME(name,target, recordModifiers...) -var CNAME = recordBuilder('CNAME'); - -// DHCID(name,target, recordModifiers...) -var DHCID = recordBuilder('DHCID'); - -// DNAME(name,target, recordModifiers...) -var DNAME = recordBuilder('DNAME'); - -// DNSKEY(name, flags, protocol, algorithm, publickey) -var DNSKEY = recordBuilder('DNSKEY', { - args: [ - ['name', _.isString], - ['flags', _.isNumber], - ['protocol', _.isNumber], - ['algorithm', _.isNumber], - ['publickey', _.isString], - ], - transform: function (record, args, modifiers) { - record.name = args.name; - record.dnskeyflags = args.flags; - record.dnskeyprotocol = args.protocol; - record.dnskeyalgorithm = args.algorithm; - record.dnskeypublickey = args.publickey; - record.target = args.target; - }, -}); - -// name, priority, target, params -var HTTPS = recordBuilder('HTTPS', { - args: [ - ['name', _.isString], - ['priority', _.isNumber], - ['target', _.isString], - ['params', _.isString], - ], - transform: function (record, args, modifiers) { - record.name = args.name; - record.svcpriority = args.priority; - record.target = args.target; - record.svcparams = args.params; - }, -}); - -// PTR(name,target, recordModifiers...) -var PTR = recordBuilder('PTR'); - -// NAPTR(name,order,preference,flags,service,regexp,target, recordModifiers...) -var NAPTR = recordBuilder('NAPTR', { - args: [ - ['name', _.isString], - ['order', _.isNumber], - ['preference', _.isNumber], - ['flags', _.isString], - ['service', _.isString], - ['regexp', _.isString], - ['target', _.isString], - ], - transform: function (record, args, modifiers) { - record.name = args.name; - record.naptrorder = args.order; - record.naptrpreference = args.preference; - record.naptrflags = args.flags; - record.naptrservice = args.service; - record.naptrregexp = args.regexp; - record.target = args.target; - }, -}); - -// OPENPGPKEY(name,target, recordModifiers...) -var OPENPGPKEY = recordBuilder('OPENPGPKEY'); - -// name, usage, selector, matchingtype, certificate -var SMIMEA = recordBuilder('SMIMEA', { - args: [ - ['name', _.isString], - ['usage', _.isNumber], - ['selector', _.isNumber], - ['matchingtype', _.isNumber], - ['target', _.isString], // recordBuilder needs a "target" argument - ], - transform: function (record, args, modifiers) { - record.name = args.name + '._smimecert'; - record.smimeausage = args.usage; - record.smimeaselector = args.selector; - record.smimeamatchingtype = args.matchingtype; - record.target = args.target; - }, -}); - -// SOA(name,ns,mbox,refresh,retry,expire,minimum, recordModifiers...) -var SOA = recordBuilder('SOA', { - args: [ - ['name', _.isString], - ['target', _.isString], - ['mbox', _.isString], - ['refresh', _.isNumber], - ['retry', _.isNumber], - ['expire', _.isNumber], - ['minttl', _.isNumber], - ], - transform: function (record, args, modifiers) { - record.name = args.name; - record.target = args.target; - record.soambox = args.mbox; - record.soarefresh = args.refresh; - record.soaretry = args.retry; - record.soaexpire = args.expire; - record.soaminttl = args.minttl; - }, -}); - -// SRV(name,priority,weight,port,target, recordModifiers...) -var SRV = recordBuilder('SRV', { - args: [ - ['name', _.isString], - ['priority', _.isNumber], - ['weight', _.isNumber], - ['port', _.isNumber], - ['target', _.isString], - ], - transform: function (record, args, modifiers) { - record.name = args.name; - record.srvpriority = args.priority; - record.srvweight = args.weight; - record.srvport = args.port; - record.target = args.target; - }, -}); - -// SSHFP(name,algorithm,type,value, recordModifiers...) -var SSHFP = recordBuilder('SSHFP', { - args: [ - ['name', _.isString], - ['algorithm', _.isNumber], - ['fingerprint', _.isNumber], - ['value', _.isString], - ], - transform: function (record, args, modifiers) { - record.name = args.name; - record.sshfpalgorithm = args.algorithm; - record.sshfpfingerprint = args.fingerprint; - record.target = args.value; - }, -}); - -// name, priority, target, params -var SVCB = recordBuilder('SVCB', { - args: [ - ['name', _.isString], - ['priority', _.isNumber], - ['target', _.isString], - ['params', _.isString], - ], - transform: function (record, args, modifiers) { - record.name = args.name; - record.svcpriority = args.priority; - record.target = args.target; - record.svcparams = args.params; - }, -}); - -// name, usage, selector, matchingtype, certificate -var TLSA = recordBuilder('TLSA', { - args: [ - ['name', _.isString], - ['usage', _.isNumber], - ['selector', _.isNumber], - ['matchingtype', _.isNumber], - ['target', _.isString], // recordBuilder needs a "target" argument - ], - transform: function (record, args, modifiers) { - record.name = args.name; - record.tlsausage = args.usage; - record.tlsaselector = args.selector; - record.tlsamatchingtype = args.matchingtype; - record.target = args.target; - }, -}); - -function isStringOrArray(x) { - return _.isString(x) || _.isArray(x); -} - // AUTOSPLIT is deprecated. It is now a no-op. var AUTOSPLIT = {}; -// TXT(name,target, recordModifiers...) -var TXT = recordBuilder('TXT', { - args: [ - ['name', _.isString], - ['target', isStringOrArray], - ], - transform: function (record, args, modifiers) { - record.name = args.name; - // Store the strings from the user verbatim. - if (_.isString(args.target)) { - record.target = args.target; - } else { - record.target = args.target.join(''); - } - }, -}); - -var LUA = recordBuilder('LUA', { - args: [ - ['name', _.isString], - ['rtype', _.isString], - ['target', isStringOrArray], - ], - transform: function (record, args, modifiers) { - record.name = args.name; - record.luartype = args.rtype.toUpperCase(); - if (_.isString(args.target)) { - record.target = args.target; - } else { - record.target = args.target.join(''); - } - }, -}); - // Parses coordinates of the form 41°24'12.2"N 2°10'26.5"E function parseDMSCoordinatesString(inputString) { var lat = inputString.match(/(-?\d+).(\d+).([\d\.]+).?\ ?([NS])/); @@ -945,31 +703,6 @@ function locDMSBuilder(record, args) { record.locvertpre = getENotationInt(args.vp); } -// LOC(name,d1,m1,s1,ns,d2,m2,s2,ew,alt,siz,hp,vp, recordModifiers...) -var LOC = recordBuilder('LOC', { - args: [ - ['name', _.isString], //i.e. subdomain - ['d1', _.isNumber], // N/S degrees - ['m1', _.isNumber], // N/S minutes - ['s1', _.isNumber], // N/S seconds - ['ns', _.isString], // N/S - ['d2', _.isNumber], // E/W degrees - ['m2', _.isNumber], // E/W minutes - ['s2', _.isNumber], // E/W seconds - ['ew', _.isString], // E/W - ['alt', _.isNumber], // altitude - ['siz', _.isNumber], // size/precision - ['hp', _.isNumber], // horizontal precision - ['vp', _.isNumber], // vertical precision - ], - transform: function (record, args, modifiers) { - validateIntegers(args); - - record = locStringBuilder(record, args); - record = locDMSBuilder(record, args); - }, -}); - // Post-validation function for LOC that checks if degrees and minutes are integers function validateIntegers(args) { if (args.d1 % 1 !== 0) { @@ -1036,23 +769,6 @@ function ConvertDDToDMS(D, longitude) { }; } -// MX(name,priority,target, recordModifiers...) -var MX = recordBuilder('MX', { - args: [ - ['name', _.isString], - ['priority', _.isNumber], - ['target', _.isString], - ], - transform: function (record, args, modifiers) { - record.name = args.name; - record.mxpreference = args.priority; - record.target = args.target; - }, -}); - -// NS(name,target, recordModifiers...) -var NS = recordBuilder('NS'); - // NAMESERVER(name,target) function NAMESERVER(name) { if (arguments.length != 1) { @@ -1152,32 +868,30 @@ function IGNORE_TARGET(target, rType) { } // IMPORT_TRANSFORM(translation_table, domain, ttl) -var IMPORT_TRANSFORM = recordBuilder('IMPORT_TRANSFORM', { - args: [['translation_table'], ['domain'], ['ttl', _.isNumber]], - transform: function (record, args, modifiers) { - record.name = '@'; - record.target = args.domain; - record.meta['transform_table'] = format_tt(args.translation_table); - record.ttl = args.ttl; - }, -}); +function importTransformOptions(record, processedArgs) { + return [ + processedArgs[0], + processedArgs[1], + processedArgs[3], + processedArgs.length === 5 ? processedArgs[4] : '', + processedArgs[2], + ]; +} + +var importTransformRawBuilder = rawrecordBuilder( + 'IMPORT_TRANSFORM', + true, + importTransformOptions +); +function importTransformBuilder(translation_table) { + arguments[0] = format_tt(translation_table); + return importTransformRawBuilder.apply(null, arguments); +} + +var IMPORT_TRANSFORM = importTransformBuilder; // IMPORT_TRANSFORM_STRIP(translation_table, domain, ttl, suffixstrip) -var IMPORT_TRANSFORM_STRIP = recordBuilder('IMPORT_TRANSFORM', { - args: [ - ['translation_table'], - ['domain'], - ['ttl', _.isNumber], - ['suffixstrip'], - ], - transform: function (record, args, modifiers) { - record.name = '@'; - record.target = args.domain; - record.meta['transform_table'] = format_tt(args.translation_table); - record.ttl = args.ttl; - record.meta['transform_suffixstrip'] = args.suffixstrip; - }, -}); +var IMPORT_TRANSFORM_STRIP = importTransformBuilder; // PURGE() function PURGE(d) { @@ -1256,213 +970,6 @@ function getModifiers(args, start) { return mods; } -/** - * Record type builder - * @param {string} type Record type - * @param {string} opts.args[][0] Argument name - * @param {function=} opts.args[][1] Optional validator - * @param {function=} opts.transform Function to apply arguments to record. - * Take (record, args, modifier) as arguments. Any modifiers will be - * applied before this function. It should mutate the given record. - * @param {function=} opts.applyModifier Function to apply modifiers to the record - */ -function recordBuilder(type, opts) { - opts = _.defaults({}, opts, { - args: [['name', _.isString], ['target']], - - transform: function (record, args, modifiers) { - // record will have modifiers already applied - // args will be an object for parameters defined - record.name = args.name; - if (_.isNumber(args.target)) { - record.target = num2dot(args.target); - } else { - record.target = args.target; - } - }, - - applyModifier: function (record, modifiers) { - for (var i = 0; i < modifiers.length; i++) { - var mod = modifiers[i]; - - if (_.isFunction(mod)) { - mod(record); - } else if (_.isObject(mod)) { - // convert transforms to strings - if (mod.transform && _.isArray(mod.transform)) { - mod.transform = format_tt(mod.transform); - } - _.extend(record.meta, mod); - } else { - throw 'ERROR: Unknown modifier type'; - } - } - }, - }); - - return function () { - var parsedArgs = {}; - var modifiers = []; - - if (arguments.length < opts.args.length) { - var argumentsList = opts.args - .map(function (item) { - return item[0]; - }) - .join(', '); - throw ( - type + - ' record requires ' + - opts.args.length + - ' arguments (' + - argumentsList + - '). Only ' + - arguments.length + - ' were supplied' - ); - return; - } - - // collect arguments - for (var i = 0; i < opts.args.length; i++) { - var argDefinition = opts.args[i]; - var value = arguments[i]; - if (argDefinition.length > 1) { - // run validator if supplied - if (!argDefinition[1](value)) { - throw ( - type + - ' record ' + - argDefinition[0] + - ' argument validation failed' - ); - } - } - parsedArgs[argDefinition[0]] = value; - } - - // collect modifiers - for (var i = opts.args.length; i < arguments.length; i++) { - modifiers.push(arguments[i]); - } - - // Record which line called this record type. - // NB(tlim): Hopefully we can find a better way to do this in the - // future. Right now we're faking that there was an error just to parse - // out the line number. That's inefficient but I can't find anything better. - // This will certainly break if we change to a different Javascript interpreter. - // Hopefully any other interpreter will have a better way to do this. - var positionLines = new Error().stack.split('\n'); - var position = positionLines[positionLines.length - 2]; - - return function (d) { - var record = { - type: type, - meta: {}, - ttl: d.defaultTTL, - filepos: position, - }; - - opts.applyModifier(record, modifiers); - opts.transform(record, parsedArgs, modifiers); - - // Handle D_EXTEND() with subdomains. - // Fix the labels. (Fixing targets is done in pkg/normalize/validate.go) - if ( - d.subdomain && - record.type != 'CF_SINGLE_REDIRECT' && - record.type != 'CF_WORKER_ROUTE' && - record.type != 'ADGUARDHOME_A_PASSTHROUGH' && - record.type != 'ADGUARDHOME_AAAA_PASSTHROUGH' && - record.type != 'MIKROTIK_FWD' && - record.type != 'MIKROTIK_NXDOMAIN' && - record.type != 'MIKROTIK_FORWARDER' - ) { - record.subdomain = d.subdomain; - - // @ sub dom -> sub sub - // one two dom -> one.two - // 4.3.2.1.in-addr.arpa 4.3 -> 4.3 2.1.in-addr.arpa - // 1.2.3.4 sub -> 1.2.3.4 sub - - if (record.name == '@') { - record.name = d.subdomain; - } else if (record.name.match(/^\d+\.\d+\.\d+\.\d+$/)) { - // leave it alone - } else if (d.name.endsWith('.ip6.arpa')) { - record.name = d.subdomain; - d.subdomain = undefined; - } else if (record.name.endsWith('.in-addr.arpa')) { - if (record.name.endsWith(d.subdomain)) { - record.name = record.name.slice( - 0, - -d.subdomain.length - 1 - ); - } - } else { - record.name = record.name + '.' + d.subdomain; - } - } - - // Now we finally have the record. If it is a normal record, we add - // it to "records". If it is an ENSURE_ABSENT record, we add it to - // the ensure_absent list. - if (record.ensure_absent) { - d.recordsabsent.push(record); - } else { - d.records.push(record); - } - - return record; - }; - }; -} - -/** - * @deprecated - */ -function addRecord(d, type, name, target, mods) { - // if target is number, assume ip address. convert it. - if (_.isNumber(target)) { - target = num2dot(target); - } - var rec = { - type: type, - name: name, - target: target, - ttl: d.defaultTTL, - priority: 0, - meta: {}, - }; - // for each modifier, decide based on type: - // - Function: call is with the record as the argument - // - Object: merge it into the metadata - // - Number: IF MX record assume it is priority - if (mods) { - for (var i = 0; i < mods.length; i++) { - var m = mods[i]; - if (_.isFunction(m)) { - m(rec); - } else if (_.isObject(m)) { - // convert transforms to strings - if (m.transform && _.isArray(m.transform)) { - m.transform = format_tt(m.transform); - } - _.extend(rec.meta, m); - _.extend(rec.meta, m); - } else { - console.log( - 'WARNING: Modifier type unsupported:', - typeof m, - '(Skipping!)' - ); - } - } - } - d.records.push(rec); - return rec; -} - // ip conversion functions from http://stackoverflow.com/a/8105740/121660 // via http://javascript.about.com/library/blipconvert.htm function IP(dot) { @@ -1549,68 +1056,6 @@ function GIDINET_PREMIUM_NS() { ]; } -// CUSTOM, PROVIDER SPECIFIC RECORD TYPES - -function _validateCloudflareRedirect(value) { - if (!_.isString(value)) { - return false; - } - return value.indexOf(',') === -1; -} - -var CF_WORKER_ROUTE = recordBuilder('CF_WORKER_ROUTE', { - args: [ - ['pattern', _validateCloudflareRedirect], - ['script', _validateCloudflareRedirect], - ], - transform: function (record, args, modifiers) { - record.name = '@'; - record.target = args.pattern + ',' + args.script; - }, -}); - -var ADGUARDHOME_A_PASSTHROUGH = recordBuilder('ADGUARDHOME_A_PASSTHROUGH'); - -var ADGUARDHOME_AAAA_PASSTHROUGH = recordBuilder( - 'ADGUARDHOME_AAAA_PASSTHROUGH' -); - -var URL = recordBuilder('URL'); -var URL301 = recordBuilder('URL301'); -var FRAME = recordBuilder('FRAME'); -var CLOUDNS_WR = recordBuilder('CLOUDNS_WR'); -/** - * @deprecated Please use URL or URL301 instead - */ -var PORKBUN_URLFWD = recordBuilder('PORKBUN_URLFWD'); -var BUNNY_DNS_RDR = recordBuilder('BUNNY_DNS_RDR'); - -// MIKROTIK_FWD(name, target, modifiers...) -// RouterOS conditional DNS forwarding entry. -var MIKROTIK_FWD = recordBuilder('MIKROTIK_FWD'); - -// MIKROTIK_NXDOMAIN(name, modifiers...) -// RouterOS NXDOMAIN entry — returns NXDOMAIN for matching queries (DNS blackholing). -var MIKROTIK_NXDOMAIN = recordBuilder('MIKROTIK_NXDOMAIN', { - args: [['name', _.isString]], - transform: function (record, args, modifiers) { - record.name = args.name; - record.target = 'NXDOMAIN'; - }, -}); - -// MIKROTIK_FORWARDER(name, dns_servers, modifiers...) -// RouterOS named DNS forwarder (/ip/dns/forwarders). -// Use in the synthetic zone "_forwarders.mikrotik". -var MIKROTIK_FORWARDER = recordBuilder('MIKROTIK_FORWARDER'); - -var BUNNY_DNS_PZ = recordBuilder('BUNNY_DNS_PZ', { - args: [['name', _.isString], ['pullZoneId']], - transform: function (record, args, modifiers) { - record.name = args.name; - record.target = String(args.pullZoneId); - }, -}); // LOC_BUILDER_DD takes an object: // label: The DNS label for the LOC record. (default: '@') // x: Decimal X coordinate. @@ -2571,10 +2016,13 @@ var DISABLE_REPEATED_DOMAIN_CHECK = { skip_fqdn_check: 'true' }; // Javascript knowledge, and allows us to use the testing platform build into // Go. -function rawrecordBuilder(type) { +function rawrecordBuilder(type, noLabel, optionalsFn) { return function () { - // Copy the raw args: var rawArgs = []; + if (noLabel !== undefined && noLabel) { + rawArgs.push('@'); + } + // Copy the raw args locally. for (var i = 0; i < arguments.length; i++) { rawArgs.push(arguments[i]); } @@ -2609,16 +2057,55 @@ function rawrecordBuilder(type) { var r = rawArgs[i]; if (_.isFunction(r)) { r(record); + } else if (_.isArray(r)) { + // An array argument (e.g. TXT("n", ["a", "b"])) is a set of + // string segments; join them into a single argument, + // mirroring the legacy recordBuilder. Arrays are never + // metadata, so this must be checked before _.isObject() + // (which is true for arrays). + processedArgs.push(r.join('')); } else if (_.isObject(r)) { + // Convert a transform array to its encoded string form + // (see format_tt), mirroring the legacy recordBuilder. + // Otherwise the array crosses to Go as an unparseable + // string and IP() numbers are never converted to dotted + // decimal. + if (r.transform && _.isArray(r.transform)) { + r.transform = format_tt(r.transform); + } processedMetas.push(r); } else { processedArgs.push(r); } } + + // Grab meta data that is OptionalsFields + if (optionalsFn !== undefined) { + //console.debug("FOO", optionalsFn) + processedArgs = optionalsFn( + record, + processedArgs, + processedMetas + ); + } + + // Modifier functions (e.g. CAA_CRITICAL) may have written to + // record.meta. Capture that so it propagates to Go as a meta; + // otherwise it would be silently dropped. + if (_.isObject(record.meta) && !_.isEmpty(record.meta)) { + processedMetas.push(record.meta); + } + // Store the processed args. record.args = processedArgs; record.metas = processedMetas; + // Capture the D_EXTEND() subdomain (per-record, at push time). + // d.subdomain is domain-level mutable state that each D_EXTEND() + // call overwrites, so it must be snapshotted here. The label + // rewriting itself is done in Go (models.ImportRawRecords). + record.subdomain = d.subdomain; + // Add this raw record to the list of records. d.rawrecords.push(record); @@ -2629,8 +2116,53 @@ function rawrecordBuilder(type) { // PLEASE KEEP THIS LIST ALPHABETICAL! -var CF_REDIRECT = rawrecordBuilder('CF_REDIRECT'); -var CF_SINGLE_REDIRECT = rawrecordBuilder('CLOUDFLAREAPI_SINGLE_REDIRECT'); -var CF_TEMP_REDIRECT = rawrecordBuilder('CF_TEMP_REDIRECT'); +var A = rawrecordBuilder('A'); +var AAAA = rawrecordBuilder('AAAA'); +var ADGUARDHOME_AAAA_PASSTHROUGH = rawrecordBuilder( + 'ADGUARDHOME_AAAA_PASSTHROUGH' +); +var ADGUARDHOME_A_PASSTHROUGH = rawrecordBuilder('ADGUARDHOME_A_PASSTHROUGH'); +var AKAMAICDN = rawrecordBuilder('AKAMAICDN'); +var AKAMAITLC = rawrecordBuilder('AKAMAITLC'); +var ALIAS = rawrecordBuilder('ALIAS'); +var AZURE_ALIAS = rawrecordBuilder('AZURE_ALIAS'); +var BUNNY_DNS_PZ = rawrecordBuilder('BUNNY_DNS_PZ'); +var BUNNY_DNS_RDR = rawrecordBuilder('BUNNY_DNS_RDR'); +var CAA = rawrecordBuilder('CAA'); +var CF_REDIRECT = rawrecordBuilder('CF_REDIRECT', true); +var CF_SINGLE_REDIRECT = rawrecordBuilder( + 'CLOUDFLAREAPI_SINGLE_REDIRECT', + true +); +var CF_TEMP_REDIRECT = rawrecordBuilder('CF_TEMP_REDIRECT', true); +var CF_WORKER_ROUTE = rawrecordBuilder('CF_WORKER_ROUTE', true); +var CLOUDNS_WR = rawrecordBuilder('CLOUDNS_WR'); +var CNAME = rawrecordBuilder('CNAME'); +var DHCID = rawrecordBuilder('DHCID'); +var DNAME = rawrecordBuilder('DNAME'); +var DNSKEY = rawrecordBuilder('DNSKEY'); var DS = rawrecordBuilder('DS'); +var FRAME = rawrecordBuilder('FRAME'); +var HTTPS = rawrecordBuilder('HTTPS'); +var LOC = rawrecordBuilder('LOC'); +var LUA = rawrecordBuilder('LUA'); +var MIKROTIK_FORWARDER = rawrecordBuilder('MIKROTIK_FORWARDER'); +var MIKROTIK_FWD = rawrecordBuilder('MIKROTIK_FWD'); +var MIKROTIK_NXDOMAIN = rawrecordBuilder('MIKROTIK_NXDOMAIN'); +var MX = rawrecordBuilder('MX'); +var NAPTR = rawrecordBuilder('NAPTR'); +var NS = rawrecordBuilder('NS'); +var OPENPGPKEY = rawrecordBuilder('OPENPGPKEY'); +var PORKBUN_URLFWD = rawrecordBuilder('PORKBUN_URLFWD'); +var PTR = rawrecordBuilder('PTR'); +var R53_ALIAS = rawrecordBuilder('R53_ALIAS', false, r53AliasOptions); var RP = rawrecordBuilder('RP'); +var SMIMEA = rawrecordBuilder('SMIMEA'); +var SOA = rawrecordBuilder('SOA'); +var SRV = rawrecordBuilder('SRV'); +var SSHFP = rawrecordBuilder('SSHFP'); +var SVCB = rawrecordBuilder('SVCB'); +var TLSA = rawrecordBuilder('TLSA'); +var TXT = rawrecordBuilder('TXT'); +var URL = rawrecordBuilder('URL'); +var URL301 = rawrecordBuilder('URL301'); diff --git a/pkg/js/import.go b/pkg/js/import.go new file mode 100644 index 0000000000..e15bcabfc1 --- /dev/null +++ b/pkg/js/import.go @@ -0,0 +1,11 @@ +package js + +// func stutters(name, domain string) bool { +// if name == "@" { +// return false +// } +// if name == domain || strings.HasSuffix(name, "."+domain) { +// return true +// } +// return false +// } diff --git a/pkg/js/js.go b/pkg/js/js.go index 9f42015348..67687e91de 100644 --- a/pkg/js/js.go +++ b/pkg/js/js.go @@ -9,13 +9,12 @@ import ( "path/filepath" "strings" - "github.com/DNSControl/dnscontrol/v4/models" - "github.com/DNSControl/dnscontrol/v4/pkg/printer" - "github.com/DNSControl/dnscontrol/v4/pkg/rfc4183" - "github.com/DNSControl/dnscontrol/v4/pkg/rtypecontrol" - "github.com/DNSControl/dnscontrol/v4/pkg/transform" - "github.com/robertkrimen/otto" // load underscore js into vm by default - _ "github.com/robertkrimen/otto/underscore" // required by otto + "github.com/DNSControl/dnscontrol/v5/models" + "github.com/DNSControl/dnscontrol/v5/pkg/printer" + "github.com/DNSControl/dnscontrol/v5/pkg/rfc4183" + "github.com/DNSControl/dnscontrol/v5/pkg/transform" + "github.com/robertkrimen/otto" // required by otto + _ "github.com/robertkrimen/otto/underscore" // load underscore js into vm by default "github.com/xddxdd/ottoext/fetch" "github.com/xddxdd/ottoext/loop" "github.com/xddxdd/ottoext/promise" @@ -121,13 +120,18 @@ func ExecuteJavascriptString(script []byte, devMode bool, variables map[string]s return nil, err } + // dc.Name and related fields are not populated when the DomainConfig is created from dnsconfig.js. We need to populate them here. + // This includes IDN processing, setting up Tags, stripping the "!tag" from .Name, and more. + for _, dc := range conf.Domains { + dc.PopulateNamesFromRaw(dc.Name) + } + err = conf.PostProcess() if err != nil { return nil, err } - // No need to call FixLegacyDC here. These records were created from dnsconfig.js, not from a provider. - if err := rtypecontrol.ImportRawRecords(conf.Domains); err != nil { + if err := conf.ImportRawRecords(); err != nil { return nil, err } diff --git a/pkg/js/js_test.go b/pkg/js/js_test.go index e11cfb1b58..69bbcfd040 100644 --- a/pkg/js/js_test.go +++ b/pkg/js/js_test.go @@ -10,12 +10,11 @@ import ( "testing" "unicode" - "github.com/DNSControl/dnscontrol/v4/models" - "github.com/DNSControl/dnscontrol/v4/pkg/normalize" - "github.com/DNSControl/dnscontrol/v4/pkg/prettyzone" - "github.com/DNSControl/dnscontrol/v4/pkg/providers" - _ "github.com/DNSControl/dnscontrol/v4/pkg/providers/_all" - _ "github.com/DNSControl/dnscontrol/v4/pkg/rtype" + "github.com/DNSControl/dnscontrol/v5/models" + "github.com/DNSControl/dnscontrol/v5/pkg/normalize" + "github.com/DNSControl/dnscontrol/v5/pkg/prettyzone" + "github.com/DNSControl/dnscontrol/v5/pkg/providers" + _ "github.com/DNSControl/dnscontrol/v5/pkg/providers/_all" testifyrequire "github.com/stretchr/testify/require" ) @@ -106,7 +105,7 @@ func TestParsedFiles(t *testing.T) { if err := os.WriteFile(expectedFile+".ACTUAL", []byte(as), 0o644); err != nil { t.Fatal(err) } - testifyrequire.JSONEqf(t, es, as, "EXPECTING %q = \n```\n%s\n```", expectedFile, as) + testifyrequire.JSONEqf(t, es, as, "ACTUAL %q = \n```\n%s\n```", expectedFile+".ACTUAL", as) // For each domain, if there is a zone file, test against it: @@ -118,9 +117,9 @@ func TestParsedFiles(t *testing.T) { } else { zoneFile = filepath.Join(testDir, testName, dc.Name+".zone") } - //fmt.Printf("DEBUG: zonefile = %q\n", zoneFile) expectedZone, err := os.ReadFile(zoneFile) if err != nil { + //fmt.Printf("DEBUG: No zone file for domain %q (looking for %q)\n", dc.Name, zoneFile) continue } dCount++ @@ -141,7 +140,7 @@ func TestParsedFiles(t *testing.T) { t.Fatal(err) } } - testifyrequire.Equal(t, es, as, "EXPECTING %q =\n```\n%s```", zoneFile, as) + testifyrequire.Equal(t, es, as, "2EXPECTING %q =\n```\n%s```", zoneFile, as) } if dCount > 0 && (len(conf.Domains) != dCount) { t.Fatal(fmt.Errorf("only %d of %d domains in %q have zonefiles", dCount, len(conf.Domains), name)) diff --git a/pkg/js/parse_tests/001-basic.json b/pkg/js/parse_tests/001-basic.json index 1d266c9a36..42b13f6c41 100644 --- a/pkg/js/parse_tests/001-basic.json +++ b/pkg/js/parse_tests/001-basic.json @@ -10,19 +10,19 @@ "dnsProviders": { "Cloudflare": -1 }, - "meta": { - "dnscontrol_nameraw": "foo.com", - "dnscontrol_nameunicode": "foo.com", - "dnscontrol_uniquename": "foo.com" - }, "name": "foo.com", "records": [ { + "comparablev3": "1.2.3.4", "filepos": "[line:5:5]", "name": "@", - "target": "1.2.3.4", + "name_unicode": "@", + "rdata": { + "Addr": "1.2.3.4" + }, "ttl": 300, - "type": "A" + "type": "A", + "typenum": 1 } ], "registrar": "Third-Party", diff --git a/pkg/js/parse_tests/002-ttl.json b/pkg/js/parse_tests/002-ttl.json index a950b994c6..ee8a453faa 100644 --- a/pkg/js/parse_tests/002-ttl.json +++ b/pkg/js/parse_tests/002-ttl.json @@ -10,19 +10,19 @@ "dnsProviders": { "Cloudflare": -1 }, - "meta": { - "dnscontrol_nameraw": "foo.com", - "dnscontrol_nameunicode": "foo.com", - "dnscontrol_uniquename": "foo.com" - }, "name": "foo.com", "records": [ { + "comparablev3": "1.2.3.4", "filepos": "[line:5:5]", "name": "@", - "target": "1.2.3.4", + "name_unicode": "@", + "rdata": { + "Addr": "1.2.3.4" + }, "ttl": 42, - "type": "A" + "type": "A", + "typenum": 1 } ], "registrar": "Third-Party", diff --git a/pkg/js/parse_tests/003-meta.json b/pkg/js/parse_tests/003-meta.json index 8082144791..9cabdca2fb 100644 --- a/pkg/js/parse_tests/003-meta.json +++ b/pkg/js/parse_tests/003-meta.json @@ -3,22 +3,22 @@ "domains": [ { "dnsProviders": {}, - "meta": { - "dnscontrol_nameraw": "foo.com", - "dnscontrol_nameunicode": "foo.com", - "dnscontrol_uniquename": "foo.com" - }, "name": "foo.com", "records": [ { + "comparablev3": "1.2.3.4", "filepos": "[line:4:5]", "meta": { "cloudflare_proxy": "ON" }, "name": "@", - "target": "1.2.3.4", + "name_unicode": "@", + "rdata": { + "Addr": "1.2.3.4" + }, "ttl": 300, - "type": "A" + "type": "A", + "typenum": 1 } ], "registrar": "Cloudflare", diff --git a/pkg/js/parse_tests/004-ips.json b/pkg/js/parse_tests/004-ips.json index 660a4f674b..c9cb6874e4 100644 --- a/pkg/js/parse_tests/004-ips.json +++ b/pkg/js/parse_tests/004-ips.json @@ -10,33 +10,43 @@ "dnsProviders": { "Cloudflare": 0 }, - "meta": { - "dnscontrol_nameraw": "foo.com", - "dnscontrol_nameunicode": "foo.com", - "dnscontrol_uniquename": "foo.com" - }, "name": "foo.com", "records": [ { + "comparablev3": "1.2.3.4", "filepos": "[line:7:5]", "name": "@", - "target": "1.2.3.4", + "name_unicode": "@", + "rdata": { + "Addr": "1.2.3.4" + }, "ttl": 300, - "type": "A" + "type": "A", + "typenum": 1 }, { + "comparablev3": "1.2.3.5", "filepos": "[line:8:5]", "name": "p1", - "target": "1.2.3.5", + "name_unicode": "p1", + "rdata": { + "Addr": "1.2.3.5" + }, "ttl": 300, - "type": "A" + "type": "A", + "typenum": 1 }, { + "comparablev3": "1.2.4.3", "filepos": "[line:9:5]", "name": "p255", - "target": "1.2.4.3", + "name_unicode": "p255", + "rdata": { + "Addr": "1.2.4.3" + }, "ttl": 300, - "type": "A" + "type": "A", + "typenum": 1 } ], "registrar": "Third-Party", diff --git a/pkg/js/parse_tests/005-ignored-records.json b/pkg/js/parse_tests/005-ignored-records.json index ba4c5a4a82..2e3e6c76b1 100644 --- a/pkg/js/parse_tests/005-ignored-records.json +++ b/pkg/js/parse_tests/005-ignored-records.json @@ -3,11 +3,6 @@ "domains": [ { "dnsProviders": {}, - "meta": { - "dnscontrol_nameraw": "foo.com", - "dnscontrol_nameunicode": "foo.com", - "dnscontrol_uniquename": "foo.com" - }, "name": "foo.com", "records": [], "registrar": "none", @@ -57,11 +52,6 @@ }, { "dnsProviders": {}, - "meta": { - "dnscontrol_nameraw": "diff2.com", - "dnscontrol_nameunicode": "diff2.com", - "dnscontrol_uniquename": "diff2.com" - }, "name": "diff2.com", "records": [], "registrar": "none", diff --git a/pkg/js/parse_tests/006-transforms.json b/pkg/js/parse_tests/006-transforms.json index d151bec171..8503276a63 100644 --- a/pkg/js/parse_tests/006-transforms.json +++ b/pkg/js/parse_tests/006-transforms.json @@ -10,42 +10,52 @@ "dnsProviders": { "Cloudflare": -1 }, - "meta": { - "dnscontrol_nameraw": "foo.com", - "dnscontrol_nameunicode": "foo.com", - "dnscontrol_uniquename": "foo.com" - }, "name": "foo.com", "records": [ { + "comparablev3": "3.3.3.3", "filepos": "[line:18:5]", "meta": { "transform": "0.0.0.0 ~ 1.1.1.0 ~ 2.2.2.2 ~ ; 1.1.1.1 ~ 2.2.2.2 ~ ~ 3.3.3.3,4.4.4.4,5.5.5.5" }, "name": "@", - "target": "3.3.3.3", + "name_unicode": "@", + "rdata": { + "Addr": "3.3.3.3" + }, "ttl": 300, - "type": "A" + "type": "A", + "typenum": 1 }, { + "comparablev3": "4.4.4.4", "filepos": "[line:18:5]", "meta": { "transform": "0.0.0.0 ~ 1.1.1.0 ~ 2.2.2.2 ~ ; 1.1.1.1 ~ 2.2.2.2 ~ ~ 3.3.3.3,4.4.4.4,5.5.5.5" }, "name": "@", - "target": "4.4.4.4", + "name_unicode": "@", + "rdata": { + "Addr": "4.4.4.4" + }, "ttl": 300, - "type": "A" + "type": "A", + "typenum": 1 }, { + "comparablev3": "5.5.5.5", "filepos": "[line:18:5]", "meta": { "transform": "0.0.0.0 ~ 1.1.1.0 ~ 2.2.2.2 ~ ; 1.1.1.1 ~ 2.2.2.2 ~ ~ 3.3.3.3,4.4.4.4,5.5.5.5" }, "name": "@", - "target": "5.5.5.5", + "name_unicode": "@", + "rdata": { + "Addr": "5.5.5.5" + }, "ttl": 300, - "type": "A" + "type": "A", + "typenum": 1 } ], "registrar": "Third-Party", diff --git a/pkg/js/parse_tests/007-importTransformTTL.json b/pkg/js/parse_tests/007-importTransformTTL.json index d0152bd21d..b73a64263b 100644 --- a/pkg/js/parse_tests/007-importTransformTTL.json +++ b/pkg/js/parse_tests/007-importTransformTTL.json @@ -3,26 +3,31 @@ "domains": [ { "dnsProviders": {}, - "meta": { - "dnscontrol_nameraw": "foo1.com", - "dnscontrol_nameunicode": "foo1.com", - "dnscontrol_uniquename": "foo1.com" - }, "name": "foo1.com", "records": [ { + "comparablev3": "1.1.1.1", "filepos": "[line:2:5]", "name": "bar", - "target": "1.1.1.1", + "name_unicode": "bar", + "rdata": { + "Addr": "1.1.1.1" + }, "ttl": 300, - "type": "A" + "type": "A", + "typenum": 1 }, { + "comparablev3": "5.5.5.5", "filepos": "[line:3:5]", "name": "foo", - "target": "5.5.5.5", + "name_unicode": "foo", + "rdata": { + "Addr": "5.5.5.5" + }, "ttl": 300, - "type": "A" + "type": "A", + "typenum": 1 } ], "registrar": "reg", @@ -30,26 +35,31 @@ }, { "dnsProviders": {}, - "meta": { - "dnscontrol_nameraw": "inny", - "dnscontrol_nameunicode": "inny", - "dnscontrol_uniquename": "inny" - }, "name": "inny", "records": [ { + "comparablev3": "4.4.4.101", "filepos": "[line:2:5]", "name": "bar.foo1.com", - "target": "4.4.4.101", + "name_unicode": "bar", + "rdata": { + "Addr": "4.4.4.101" + }, "ttl": 60, - "type": "A" + "type": "A", + "typenum": 1 }, { + "comparablev3": "6.6.6.3", "filepos": "[line:3:5]", "name": "foo.foo1.com", - "target": "6.6.6.3", + "name_unicode": "foo", + "rdata": { + "Addr": "6.6.6.3" + }, "ttl": 60, - "type": "A" + "type": "A", + "typenum": 1 } ], "registrar": "reg", @@ -57,26 +67,31 @@ }, { "dnsProviders": {}, - "meta": { - "dnscontrol_nameraw": "com.inny", - "dnscontrol_nameunicode": "com.inny", - "dnscontrol_uniquename": "com.inny" - }, "name": "com.inny", "records": [ { + "comparablev3": "1.1.1.1", "filepos": "[line:2:5]", "name": "bar.foo1", - "target": "1.1.1.1", + "name_unicode": "bar", + "rdata": { + "Addr": "1.1.1.1" + }, "ttl": 99, - "type": "A" + "type": "A", + "typenum": 1 }, { + "comparablev3": "7.7.7.7", "filepos": "[line:3:5]", "name": "foo.foo1", - "target": "7.7.7.7", + "name_unicode": "foo", + "rdata": { + "Addr": "7.7.7.7" + }, "ttl": 99, - "type": "A" + "type": "A", + "typenum": 1 } ], "registrar": "reg", diff --git a/pkg/js/parse_tests/008-import.json b/pkg/js/parse_tests/008-import.json index 43488083f7..4e857da3f2 100644 --- a/pkg/js/parse_tests/008-import.json +++ b/pkg/js/parse_tests/008-import.json @@ -3,19 +3,19 @@ "domains": [ { "dnsProviders": {}, - "meta": { - "dnscontrol_nameraw": "foo.com", - "dnscontrol_nameunicode": "foo.com", - "dnscontrol_uniquename": "foo.com" - }, "name": "foo.com", "records": [ { + "comparablev3": "1.2.3.4", "filepos": "[line:1:1]", "name": "@", - "target": "1.2.3.4", + "name_unicode": "@", + "rdata": { + "Addr": "1.2.3.4" + }, "ttl": 300, - "type": "A" + "type": "A", + "typenum": 1 } ], "registrar": "none", diff --git a/pkg/js/parse_tests/009-reverse.json b/pkg/js/parse_tests/009-reverse.json index a071dd058c..c4b60712c0 100644 --- a/pkg/js/parse_tests/009-reverse.json +++ b/pkg/js/parse_tests/009-reverse.json @@ -3,11 +3,6 @@ "domains": [ { "dnsProviders": {}, - "meta": { - "dnscontrol_nameraw": "2.1.in-addr.arpa", - "dnscontrol_nameunicode": "2.1.in-addr.arpa", - "dnscontrol_uniquename": "2.1.in-addr.arpa" - }, "name": "2.1.in-addr.arpa", "records": [], "registrar": "none", diff --git a/pkg/js/parse_tests/010-alias.json b/pkg/js/parse_tests/010-alias.json index ff42158b29..e30309624a 100644 --- a/pkg/js/parse_tests/010-alias.json +++ b/pkg/js/parse_tests/010-alias.json @@ -3,19 +3,19 @@ "domains": [ { "dnsProviders": {}, - "meta": { - "dnscontrol_nameraw": "foo.com", - "dnscontrol_nameunicode": "foo.com", - "dnscontrol_uniquename": "foo.com" - }, "name": "foo.com", "records": [ { + "comparablev3": "foo.com.", "filepos": "[line:2:5]", "name": "@", - "target": "foo.com.", + "name_unicode": "@", + "rdata": { + "Target": "foo.com." + }, "ttl": 300, - "type": "ALIAS" + "type": "ALIAS", + "typenum": 65285 } ], "registrar": "none", diff --git a/pkg/js/parse_tests/011-cfRedirect.json b/pkg/js/parse_tests/011-cfRedirect.json index 666c76ec79..a21052ad7c 100644 --- a/pkg/js/parse_tests/011-cfRedirect.json +++ b/pkg/js/parse_tests/011-cfRedirect.json @@ -3,48 +3,41 @@ "domains": [ { "dnsProviders": {}, - "meta": { - "dnscontrol_nameraw": "foo.com", - "dnscontrol_nameunicode": "foo.com", - "dnscontrol_uniquename": "foo.com" - }, "name": "foo.com", "records": [ { - "comparable": "name=(301,test1.foo.com,https://goo.com/$1) code=(301) when=(http.host eq \"test1.foo.com\" and http.request.uri.path eq \"/\") then=(concat(\"https://goo.com\", http.request.uri.path))", - "fields": { - "code": 301, - "sr_display": "name=(301,test1.foo.com,https://goo.com/$1) code=(301) when=(http.host eq \"test1.foo.com\" and http.request.uri.path eq \"/\") then=(concat(\"https://goo.com\", http.request.uri.path))", - "sr_name": "301,test1.foo.com,https://goo.com/$1", - "sr_then": "concat(\"https://goo.com\", http.request.uri.path)", - "sr_when": "http.host eq \"test1.foo.com\" and http.request.uri.path eq \"/\"" - }, + "comparablev3": "\"301,test1.foo.com,https://goo.com/$1\" 301 \"http.host eq \\\"test1.foo.com\\\" and http.request.uri.path eq \\\"/\\\"\" \"concat(\\\"https://goo.com\\\", http.request.uri.path)\"", "filepos": "[line:2:5]", "name": "@", - "name_raw": "@", "name_unicode": "@", - "target": "name=(301,test1.foo.com,https://goo.com/$1) code=(301) when=(http.host eq \"test1.foo.com\" and http.request.uri.path eq \"/\") then=(concat(\"https://goo.com\", http.request.uri.path))", + "rdata": { + "Code": 301, + "RT_SRRRulesetID": "", + "RT_SRRRulesetRuleID": "", + "SRName": "301,test1.foo.com,https://goo.com/$1", + "SRThen": "concat(\"https://goo.com\", http.request.uri.path)", + "SRWhen": "http.host eq \"test1.foo.com\" and http.request.uri.path eq \"/\"" + }, "ttl": 1, "type": "CLOUDFLAREAPI_SINGLE_REDIRECT", - "zonfefilepartial": "name=(301,test1.foo.com,https://goo.com/$1) code=(301) when=(http.host eq \"test1.foo.com\" and http.request.uri.path eq \"/\") then=(concat(\"https://goo.com\", http.request.uri.path))" + "typenum": 65289 }, { - "comparable": "name=(302,test2.foo.com,https://goo.com/$1) code=(302) when=(http.host eq \"test2.foo.com\" and http.request.uri.path eq \"/\") then=(concat(\"https://goo.com\", http.request.uri.path))", - "fields": { - "code": 302, - "sr_display": "name=(302,test2.foo.com,https://goo.com/$1) code=(302) when=(http.host eq \"test2.foo.com\" and http.request.uri.path eq \"/\") then=(concat(\"https://goo.com\", http.request.uri.path))", - "sr_name": "302,test2.foo.com,https://goo.com/$1", - "sr_then": "concat(\"https://goo.com\", http.request.uri.path)", - "sr_when": "http.host eq \"test2.foo.com\" and http.request.uri.path eq \"/\"" - }, + "comparablev3": "\"302,test2.foo.com,https://goo.com/$1\" 302 \"http.host eq \\\"test2.foo.com\\\" and http.request.uri.path eq \\\"/\\\"\" \"concat(\\\"https://goo.com\\\", http.request.uri.path)\"", "filepos": "[line:3:5]", "name": "@", - "name_raw": "@", "name_unicode": "@", - "target": "name=(302,test2.foo.com,https://goo.com/$1) code=(302) when=(http.host eq \"test2.foo.com\" and http.request.uri.path eq \"/\") then=(concat(\"https://goo.com\", http.request.uri.path))", + "rdata": { + "Code": 302, + "RT_SRRRulesetID": "", + "RT_SRRRulesetRuleID": "", + "SRName": "302,test2.foo.com,https://goo.com/$1", + "SRThen": "concat(\"https://goo.com\", http.request.uri.path)", + "SRWhen": "http.host eq \"test2.foo.com\" and http.request.uri.path eq \"/\"" + }, "ttl": 1, "type": "CLOUDFLAREAPI_SINGLE_REDIRECT", - "zonfefilepartial": "name=(302,test2.foo.com,https://goo.com/$1) code=(302) when=(http.host eq \"test2.foo.com\" and http.request.uri.path eq \"/\") then=(concat(\"https://goo.com\", http.request.uri.path))" + "typenum": 65289 } ], "registrar": "none", diff --git a/pkg/js/parse_tests/011-cfRedirect/foo.com.zone b/pkg/js/parse_tests/011-cfRedirect/foo.com.zone index d3da3e157e..a066dd6e49 100644 --- a/pkg/js/parse_tests/011-cfRedirect/foo.com.zone +++ b/pkg/js/parse_tests/011-cfRedirect/foo.com.zone @@ -1,3 +1,3 @@ $TTL 300 -;@ 1 IN CLOUDFLAREAPI_SINGLE_REDIRECT name=(301,test1.foo.com,https://goo.com/$1) code=(301) when=(http.host eq "test1.foo.com" and http.request.uri.path eq "/") then=(concat("https://goo.com", http.request.uri.path)) -;@ 1 IN CLOUDFLAREAPI_SINGLE_REDIRECT name=(302,test2.foo.com,https://goo.com/$1) code=(302) when=(http.host eq "test2.foo.com" and http.request.uri.path eq "/") then=(concat("https://goo.com", http.request.uri.path)) +@ 1 IN CLOUDFLAREAPI_SINGLE_REDIRECT "301,test1.foo.com,https://goo.com/$1" 301 "http.host eq \"test1.foo.com\" and http.request.uri.path eq \"/\"" "concat(\"https://goo.com\", http.request.uri.path)" + 1 IN CLOUDFLAREAPI_SINGLE_REDIRECT "302,test2.foo.com,https://goo.com/$1" 302 "http.host eq \"test2.foo.com\" and http.request.uri.path eq \"/\"" "concat(\"https://goo.com\", http.request.uri.path)" diff --git a/pkg/js/parse_tests/012-duration.json b/pkg/js/parse_tests/012-duration.json index 4060e4672e..290aba5ad3 100644 --- a/pkg/js/parse_tests/012-duration.json +++ b/pkg/js/parse_tests/012-duration.json @@ -3,47 +3,67 @@ "domains": [ { "dnsProviders": {}, - "meta": { - "dnscontrol_nameraw": "foo.com", - "dnscontrol_nameunicode": "foo.com", - "dnscontrol_uniquename": "foo.com" - }, "name": "foo.com", "records": [ { + "comparablev3": "1.2.3.4", "filepos": "[line:2:5]", "name": "@", - "target": "1.2.3.4", + "name_unicode": "@", + "rdata": { + "Addr": "1.2.3.4" + }, "ttl": 300, - "type": "A" + "type": "A", + "typenum": 1 }, { + "comparablev3": "1.2.3.5", "filepos": "[line:3:5]", "name": "a", - "target": "1.2.3.5", + "name_unicode": "a", + "rdata": { + "Addr": "1.2.3.5" + }, "ttl": 300, - "type": "A" + "type": "A", + "typenum": 1 }, { + "comparablev3": "1.2.3.6", "filepos": "[line:4:5]", "name": "b", - "target": "1.2.3.6", + "name_unicode": "b", + "rdata": { + "Addr": "1.2.3.6" + }, "ttl": 180, - "type": "A" + "type": "A", + "typenum": 1 }, { + "comparablev3": "1.2.3.7", "filepos": "[line:5:5]", "name": "c", - "target": "1.2.3.7", + "name_unicode": "c", + "rdata": { + "Addr": "1.2.3.7" + }, "ttl": 10800, - "type": "A" + "type": "A", + "typenum": 1 }, { + "comparablev3": "1.2.3.8", "filepos": "[line:6:5]", "name": "d", - "target": "1.2.3.8", + "name_unicode": "d", + "rdata": { + "Addr": "1.2.3.8" + }, "ttl": 259200, - "type": "A" + "type": "A", + "typenum": 1 } ], "registrar": "none", diff --git a/pkg/js/parse_tests/013-mx.json b/pkg/js/parse_tests/013-mx.json index dfbddec2c8..2ce36759cd 100644 --- a/pkg/js/parse_tests/013-mx.json +++ b/pkg/js/parse_tests/013-mx.json @@ -3,20 +3,20 @@ "domains": [ { "dnsProviders": {}, - "meta": { - "dnscontrol_nameraw": "foo.com", - "dnscontrol_nameunicode": "foo.com", - "dnscontrol_uniquename": "foo.com" - }, "name": "foo.com", "records": [ { + "comparablev3": "15 foo.com.", "filepos": "[line:2:5]", - "mxpreference": 15, "name": "@", - "target": "foo.com.", + "name_unicode": "@", + "rdata": { + "Mx": "foo.com.", + "Preference": 15 + }, "ttl": 300, - "type": "MX" + "type": "MX", + "typenum": 15 } ], "registrar": "none", diff --git a/pkg/js/parse_tests/014-caa.json b/pkg/js/parse_tests/014-caa.json index 3be264cc87..f3003169ec 100644 --- a/pkg/js/parse_tests/014-caa.json +++ b/pkg/js/parse_tests/014-caa.json @@ -3,54 +3,83 @@ "domains": [ { "dnsProviders": {}, - "meta": { - "dnscontrol_nameraw": "foo.com", - "dnscontrol_nameunicode": "foo.com", - "dnscontrol_uniquename": "foo.com" - }, "name": "foo.com", "records": [ { - "caaflag": 128, - "caatag": "iodef", + "comparablev3": "128 iodef \"https://example.com\"", "filepos": "[line:12:5]", + "meta": { + "caaflag": "128" + }, "name": "@", - "target": "https://example.com", + "name_unicode": "@", + "rdata": { + "Flag": 128, + "Tag": "iodef", + "Value": "https://example.com" + }, "ttl": 300, - "type": "CAA" + "type": "CAA", + "typenum": 257 }, { - "caaflag": 128, - "caatag": "iodef", + "comparablev3": "128 iodef \"mailto:test@example.com\"", "filepos": "[line:8:5]", + "meta": { + "caaflag": "128" + }, "name": "@", - "target": "mailto:test@example.com", + "name_unicode": "@", + "rdata": { + "Flag": 128, + "Tag": "iodef", + "Value": "mailto:test@example.com" + }, "ttl": 300, - "type": "CAA" + "type": "CAA", + "typenum": 257 }, { - "caatag": "iodef", + "comparablev3": "0 iodef \"http://example.com\"", "filepos": "[line:10:5]", "name": "@", - "target": "http://example.com", + "name_unicode": "@", + "rdata": { + "Flag": 0, + "Tag": "iodef", + "Value": "http://example.com" + }, "ttl": 300, - "type": "CAA" + "type": "CAA", + "typenum": 257 }, { - "caatag": "issue", + "comparablev3": "0 issue \"letsencrypt.org\"", "filepos": "[line:3:5]", "name": "@", - "target": "letsencrypt.org", + "name_unicode": "@", + "rdata": { + "Flag": 0, + "Tag": "issue", + "Value": "letsencrypt.org" + }, "ttl": 300, - "type": "CAA" + "type": "CAA", + "typenum": 257 }, { - "caatag": "issuewild", + "comparablev3": "0 issuewild \";\"", "filepos": "[line:5:5]", "name": "@", - "target": ";", + "name_unicode": "@", + "rdata": { + "Flag": 0, + "Tag": "issuewild", + "Value": ";" + }, "ttl": 300, - "type": "CAA" + "type": "CAA", + "typenum": 257 } ], "registrar": "none", diff --git a/pkg/js/parse_tests/015-tlsa.json b/pkg/js/parse_tests/015-tlsa.json index 47c87b00f6..9eac4885bd 100644 --- a/pkg/js/parse_tests/015-tlsa.json +++ b/pkg/js/parse_tests/015-tlsa.json @@ -3,22 +3,22 @@ "domains": [ { "dnsProviders": {}, - "meta": { - "dnscontrol_nameraw": "foo.com", - "dnscontrol_nameunicode": "foo.com", - "dnscontrol_uniquename": "foo.com" - }, "name": "foo.com", "records": [ { + "comparablev3": "3 1 1 MDFIYTQ3MTLJODBINMZLOTEXYJA5MWE3YZA1MTI0YJY0ZWVLY2U5NJRLMDLJMDU4ZWY4ZJK4MDVKYWNHNTQ2YIAGLQO=", "filepos": "[line:2:5]", "name": "_443._tcp", - "target": "mdfiytq3mtljodbinmzlotexyja5mwe3yza1mti0yjy0zwvly2u5njrlmdljmdu4zwy4zjk4mdvkywnhntq2yiaglqo=", - "tlsamatchingtype": 1, - "tlsaselector": 1, - "tlsausage": 3, + "name_unicode": "_443._tcp", + "rdata": { + "Certificate": "MDFIYTQ3MTLJODBINMZLOTEXYJA5MWE3YZA1MTI0YJY0ZWVLY2U5NJRLMDLJMDU4ZWY4ZJK4MDVKYWNHNTQ2YIAGLQO=", + "MatchingType": 1, + "Selector": 1, + "Usage": 3 + }, "ttl": 300, - "type": "TLSA" + "type": "TLSA", + "typenum": 52 } ], "registrar": "none", diff --git a/pkg/js/parse_tests/015-tlsa/foo.com.zone b/pkg/js/parse_tests/015-tlsa/foo.com.zone index 9e872198f1..c428190785 100644 --- a/pkg/js/parse_tests/015-tlsa/foo.com.zone +++ b/pkg/js/parse_tests/015-tlsa/foo.com.zone @@ -1,2 +1,2 @@ $TTL 300 -_443._tcp IN TLSA 3 1 1 mdfiytq3mtljodbinmzlotexyja5mwe3yza1mti0yjy0zwvly2u5njrlmdljmdu4zwy4zjk4mdvkywnhntq2yiaglqo= +_443._tcp IN TLSA 3 1 1 MDFIYTQ3MTLJODBINMZLOTEXYJA5MWE3YZA1MTI0YJY0ZWVLY2U5NJRLMDLJMDU4ZWY4ZJK4MDVKYWNHNTQ2YIAGLQO= diff --git a/pkg/js/parse_tests/017-txt.json b/pkg/js/parse_tests/017-txt.json index 43b108ca05..e213b48b3d 100644 --- a/pkg/js/parse_tests/017-txt.json +++ b/pkg/js/parse_tests/017-txt.json @@ -3,47 +3,77 @@ "domains": [ { "dnsProviders": {}, - "meta": { - "dnscontrol_nameraw": "foo.com", - "dnscontrol_nameunicode": "foo.com", - "dnscontrol_uniquename": "foo.com" - }, "name": "foo.com", "records": [ { + "comparablev3": "\"simple\"", "filepos": "[line:2:5]", "name": "a", - "target": "simple", + "name_unicode": "a", + "rdata": { + "Txt": [ + "simple" + ] + }, "ttl": 300, - "type": "TXT" + "type": "TXT", + "typenum": 16 }, { + "comparablev3": "\"ws at end \"", "filepos": "[line:3:5]", "name": "b", - "target": "ws at end ", + "name_unicode": "b", + "rdata": { + "Txt": [ + "ws at end " + ] + }, "ttl": 300, - "type": "TXT" + "type": "TXT", + "typenum": 16 }, { + "comparablev3": "\"one\"", "filepos": "[line:4:5]", "name": "c", - "target": "one", + "name_unicode": "c", + "rdata": { + "Txt": [ + "one" + ] + }, "ttl": 300, - "type": "TXT" + "type": "TXT", + "typenum": 16 }, { + "comparablev3": "\"bonieclyde\"", "filepos": "[line:5:5]", "name": "d", - "target": "bonieclyde", + "name_unicode": "d", + "rdata": { + "Txt": [ + "bonieclyde" + ] + }, "ttl": 300, - "type": "TXT" + "type": "TXT", + "typenum": 16 }, { + "comparablev3": "\"strawwoodbrick\"", "filepos": "[line:6:5]", "name": "e", - "target": "strawwoodbrick", + "name_unicode": "e", + "rdata": { + "Txt": [ + "strawwoodbrick" + ] + }, "ttl": 300, - "type": "TXT" + "type": "TXT", + "typenum": 16 } ], "registrar": "none", diff --git a/pkg/js/parse_tests/018-dkim.json b/pkg/js/parse_tests/018-dkim.json index 869ad9dbe7..ffac35b7ba 100644 --- a/pkg/js/parse_tests/018-dkim.json +++ b/pkg/js/parse_tests/018-dkim.json @@ -3,19 +3,22 @@ "domains": [ { "dnsProviders": {}, - "meta": { - "dnscontrol_nameraw": "foo.com", - "dnscontrol_nameunicode": "foo.com", - "dnscontrol_uniquename": "foo.com" - }, "name": "foo.com", "records": [ { + "comparablev3": "\"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;\"", "filepos": "[line:2:5]", "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;", + "name_unicode": "dkimtest2", + "rdata": { + "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;" + ] + }, "ttl": 300, - "type": "TXT" + "type": "TXT", + "typenum": 16 } ], "registrar": "none", diff --git a/pkg/js/parse_tests/019-r53-alias.js b/pkg/js/parse_tests/019-r53-alias.js index 53b880efe3..dc999bc1d4 100644 --- a/pkg/js/parse_tests/019-r53-alias.js +++ b/pkg/js/parse_tests/019-r53-alias.js @@ -3,6 +3,7 @@ D("foo.com", "none", 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("aevaltargethealthtest2", "A", "foo.com.", R53_EVALUATE_TARGET_HEALTH(false)), R53_ALIAS("aaaatest", "AAAA", "foo.com."), R53_ALIAS("aaaatest", "AAAA", "foo.com.", R53_ZONE("ERERTFGFGF")), R53_ALIAS("cnametest", "CNAME", "foo.com."), @@ -17,5 +18,8 @@ D("foo.com", "none", R53_ALIAS("tlsatest", "TLSA", "foo.com."), R53_ALIAS("sshfptest", "SSHFP", "foo.com."), R53_ALIAS("svcbtest", "SVCB", "foo.com."), - R53_ALIAS("httpstest", "HTTPS", "foo.com.") + R53_ALIAS("httpstest", "HTTPS", "foo.com."), + // Non-apex (out-of-zone) targets. GitHub issue https://github.com/DNSControl/dnscontrol/issues/4796 + R53_ALIAS("cftest", "A", "d111111abcdef8.cloudfront.net."), + R53_ALIAS("cfzonetest", "A", "d222222abcdef8.cloudfront.net.", R53_ZONE("Z2FDTNDATAQYW2")) ); diff --git a/pkg/js/parse_tests/019-r53-alias.json b/pkg/js/parse_tests/019-r53-alias.json index 482663e3f6..fcb15740d7 100644 --- a/pkg/js/parse_tests/019-r53-alias.json +++ b/pkg/js/parse_tests/019-r53-alias.json @@ -3,280 +3,403 @@ "domains": [ { "dnsProviders": {}, - "meta": { - "dnscontrol_nameraw": "foo.com", - "dnscontrol_nameunicode": "foo.com", - "dnscontrol_uniquename": "foo.com" - }, "name": "foo.com", "records": [ { - "filepos": "[line:6:5]", + "comparablev3": "AAAA foo.com. \"\" \"\"", + "filepos": "[line:7:5]", "meta": { "orig_custom_type": "R53_ALIAS" }, "name": "aaaatest", - "r53_alias": { - "evaluate_target_health": "false", - "type": "AAAA" + "name_unicode": "aaaatest", + "rdata": { + "AliasType": "AAAA", + "EvalTargetHealth": "", + "Target": "foo.com.", + "ZoneID": "" }, - "target": "foo.com.", "ttl": 300, - "type": "R53_ALIAS" + "type": "R53_ALIAS", + "typenum": 65298 }, { - "filepos": "[line:7:5]", + "comparablev3": "AAAA foo.com. false ERERTFGFGF", + "filepos": "[line:8:5]", "meta": { "orig_custom_type": "R53_ALIAS" }, "name": "aaaatest", - "r53_alias": { - "evaluate_target_health": "false", - "type": "AAAA", - "zone_id": "ERERTFGFGF" + "name_unicode": "aaaatest", + "rdata": { + "AliasType": "AAAA", + "EvalTargetHealth": "false", + "Target": "foo.com.", + "ZoneID": "ERERTFGFGF" }, - "target": "foo.com.", "ttl": 300, - "type": "R53_ALIAS" + "type": "R53_ALIAS", + "typenum": 65298 }, { + "comparablev3": "A foo.com. true \"\"", "filepos": "[line:5:5]", "meta": { "orig_custom_type": "R53_ALIAS" }, "name": "aevaltargethealthtest", - "r53_alias": { - "evaluate_target_health": "true", - "type": "A" + "name_unicode": "aevaltargethealthtest", + "rdata": { + "AliasType": "A", + "EvalTargetHealth": "true", + "Target": "foo.com.", + "ZoneID": "" }, - "target": "foo.com.", "ttl": 300, - "type": "R53_ALIAS" + "type": "R53_ALIAS", + "typenum": 65298 }, { + "comparablev3": "A foo.com. false \"\"", + "filepos": "[line:6:5]", + "meta": { + "orig_custom_type": "R53_ALIAS" + }, + "name": "aevaltargethealthtest2", + "name_unicode": "aevaltargethealthtest2", + "rdata": { + "AliasType": "A", + "EvalTargetHealth": "false", + "Target": "foo.com.", + "ZoneID": "" + }, + "ttl": 300, + "type": "R53_ALIAS", + "typenum": 65298 + }, + { + "comparablev3": "A foo.com. \"\" \"\"", "filepos": "[line:3:5]", "meta": { "orig_custom_type": "R53_ALIAS" }, "name": "atest", - "r53_alias": { - "evaluate_target_health": "false", - "type": "A" + "name_unicode": "atest", + "rdata": { + "AliasType": "A", + "EvalTargetHealth": "", + "Target": "foo.com.", + "ZoneID": "" }, - "target": "foo.com.", "ttl": 300, - "type": "R53_ALIAS" + "type": "R53_ALIAS", + "typenum": 65298 }, { + "comparablev3": "A foo.com. false Z2FTEDLFRTF", "filepos": "[line:4:5]", "meta": { "orig_custom_type": "R53_ALIAS" }, "name": "atest", - "r53_alias": { - "evaluate_target_health": "false", - "type": "A", - "zone_id": "Z2FTEDLFRTF" + "name_unicode": "atest", + "rdata": { + "AliasType": "A", + "EvalTargetHealth": "false", + "Target": "foo.com.", + "ZoneID": "Z2FTEDLFRTF" }, - "target": "foo.com.", "ttl": 300, - "type": "R53_ALIAS" + "type": "R53_ALIAS", + "typenum": 65298 }, { - "filepos": "[line:13:5]", + "comparablev3": "CAA foo.com. \"\" \"\"", + "filepos": "[line:14:5]", "meta": { "orig_custom_type": "R53_ALIAS" }, "name": "caatest", - "r53_alias": { - "evaluate_target_health": "false", - "type": "CAA" + "name_unicode": "caatest", + "rdata": { + "AliasType": "CAA", + "EvalTargetHealth": "", + "Target": "foo.com.", + "ZoneID": "" }, - "target": "foo.com.", "ttl": 300, - "type": "R53_ALIAS" + "type": "R53_ALIAS", + "typenum": 65298 }, { - "filepos": "[line:8:5]", + "comparablev3": "A d111111abcdef8.cloudfront.net. \"\" \"\"", + "filepos": "[line:23:5]", + "meta": { + "orig_custom_type": "R53_ALIAS" + }, + "name": "cftest", + "name_unicode": "cftest", + "rdata": { + "AliasType": "A", + "EvalTargetHealth": "", + "Target": "d111111abcdef8.cloudfront.net.", + "ZoneID": "" + }, + "ttl": 300, + "type": "R53_ALIAS", + "typenum": 65298 + }, + { + "comparablev3": "A d222222abcdef8.cloudfront.net. false Z2FDTNDATAQYW2", + "filepos": "[line:24:5]", + "meta": { + "orig_custom_type": "R53_ALIAS" + }, + "name": "cfzonetest", + "name_unicode": "cfzonetest", + "rdata": { + "AliasType": "A", + "EvalTargetHealth": "false", + "Target": "d222222abcdef8.cloudfront.net.", + "ZoneID": "Z2FDTNDATAQYW2" + }, + "ttl": 300, + "type": "R53_ALIAS", + "typenum": 65298 + }, + { + "comparablev3": "CNAME foo.com. \"\" \"\"", + "filepos": "[line:9:5]", "meta": { "orig_custom_type": "R53_ALIAS" }, "name": "cnametest", - "r53_alias": { - "evaluate_target_health": "false", - "type": "CNAME" + "name_unicode": "cnametest", + "rdata": { + "AliasType": "CNAME", + "EvalTargetHealth": "", + "Target": "foo.com.", + "ZoneID": "" }, - "target": "foo.com.", "ttl": 300, - "type": "R53_ALIAS" + "type": "R53_ALIAS", + "typenum": 65298 }, { - "filepos": "[line:16:5]", + "comparablev3": "DS foo.com. \"\" \"\"", + "filepos": "[line:17:5]", "meta": { "orig_custom_type": "R53_ALIAS" }, "name": "dstest", - "r53_alias": { - "evaluate_target_health": "false", - "type": "DS" + "name_unicode": "dstest", + "rdata": { + "AliasType": "DS", + "EvalTargetHealth": "", + "Target": "foo.com.", + "ZoneID": "" }, - "target": "foo.com.", "ttl": 300, - "type": "R53_ALIAS" + "type": "R53_ALIAS", + "typenum": 65298 }, { - "filepos": "[line:20:5]", + "comparablev3": "HTTPS foo.com. \"\" \"\"", + "filepos": "[line:21:5]", "meta": { "orig_custom_type": "R53_ALIAS" }, "name": "httpstest", - "r53_alias": { - "evaluate_target_health": "false", - "type": "HTTPS" + "name_unicode": "httpstest", + "rdata": { + "AliasType": "HTTPS", + "EvalTargetHealth": "", + "Target": "foo.com.", + "ZoneID": "" }, - "target": "foo.com.", "ttl": 300, - "type": "R53_ALIAS" + "type": "R53_ALIAS", + "typenum": 65298 }, { + "comparablev3": "MX foo.com. \"\" \"\"", "filepos": "[line:2:5]", "meta": { "orig_custom_type": "R53_ALIAS" }, "name": "mxtest", - "r53_alias": { - "evaluate_target_health": "false", - "type": "MX" + "name_unicode": "mxtest", + "rdata": { + "AliasType": "MX", + "EvalTargetHealth": "", + "Target": "foo.com.", + "ZoneID": "" }, - "target": "foo.com.", "ttl": 300, - "type": "R53_ALIAS" + "type": "R53_ALIAS", + "typenum": 65298 }, { - "filepos": "[line:14:5]", + "comparablev3": "NAPTR foo.com. \"\" \"\"", + "filepos": "[line:15:5]", "meta": { "orig_custom_type": "R53_ALIAS" }, "name": "naptrtest", - "r53_alias": { - "evaluate_target_health": "false", - "type": "NAPTR" + "name_unicode": "naptrtest", + "rdata": { + "AliasType": "NAPTR", + "EvalTargetHealth": "", + "Target": "foo.com.", + "ZoneID": "" }, - "target": "foo.com.", "ttl": 300, - "type": "R53_ALIAS" + "type": "R53_ALIAS", + "typenum": 65298 }, { - "filepos": "[line:9:5]", + "comparablev3": "PTR foo.com. \"\" \"\"", + "filepos": "[line:10:5]", "meta": { "orig_custom_type": "R53_ALIAS" }, "name": "ptrtest", - "r53_alias": { - "evaluate_target_health": "false", - "type": "PTR" + "name_unicode": "ptrtest", + "rdata": { + "AliasType": "PTR", + "EvalTargetHealth": "", + "Target": "foo.com.", + "ZoneID": "" }, - "target": "foo.com.", "ttl": 300, - "type": "R53_ALIAS" + "type": "R53_ALIAS", + "typenum": 65298 }, { - "filepos": "[line:15:5]", + "comparablev3": "SOA foo.com. \"\" \"\"", + "filepos": "[line:16:5]", "meta": { "orig_custom_type": "R53_ALIAS" }, "name": "soatest", - "r53_alias": { - "evaluate_target_health": "false", - "type": "SOA" + "name_unicode": "soatest", + "rdata": { + "AliasType": "SOA", + "EvalTargetHealth": "", + "Target": "foo.com.", + "ZoneID": "" }, - "target": "foo.com.", "ttl": 300, - "type": "R53_ALIAS" + "type": "R53_ALIAS", + "typenum": 65298 }, { - "filepos": "[line:12:5]", + "comparablev3": "SPF foo.com. \"\" \"\"", + "filepos": "[line:13:5]", "meta": { "orig_custom_type": "R53_ALIAS" }, "name": "spftest", - "r53_alias": { - "evaluate_target_health": "false", - "type": "SPF" + "name_unicode": "spftest", + "rdata": { + "AliasType": "SPF", + "EvalTargetHealth": "", + "Target": "foo.com.", + "ZoneID": "" }, - "target": "foo.com.", "ttl": 300, - "type": "R53_ALIAS" + "type": "R53_ALIAS", + "typenum": 65298 }, { - "filepos": "[line:11:5]", + "comparablev3": "SRV foo.com. \"\" \"\"", + "filepos": "[line:12:5]", "meta": { "orig_custom_type": "R53_ALIAS" }, "name": "srvtest", - "r53_alias": { - "evaluate_target_health": "false", - "type": "SRV" + "name_unicode": "srvtest", + "rdata": { + "AliasType": "SRV", + "EvalTargetHealth": "", + "Target": "foo.com.", + "ZoneID": "" }, - "target": "foo.com.", "ttl": 300, - "type": "R53_ALIAS" + "type": "R53_ALIAS", + "typenum": 65298 }, { - "filepos": "[line:18:5]", + "comparablev3": "SSHFP foo.com. \"\" \"\"", + "filepos": "[line:19:5]", "meta": { "orig_custom_type": "R53_ALIAS" }, "name": "sshfptest", - "r53_alias": { - "evaluate_target_health": "false", - "type": "SSHFP" + "name_unicode": "sshfptest", + "rdata": { + "AliasType": "SSHFP", + "EvalTargetHealth": "", + "Target": "foo.com.", + "ZoneID": "" }, - "target": "foo.com.", "ttl": 300, - "type": "R53_ALIAS" + "type": "R53_ALIAS", + "typenum": 65298 }, { - "filepos": "[line:19:5]", + "comparablev3": "SVCB foo.com. \"\" \"\"", + "filepos": "[line:20:5]", "meta": { "orig_custom_type": "R53_ALIAS" }, "name": "svcbtest", - "r53_alias": { - "evaluate_target_health": "false", - "type": "SVCB" + "name_unicode": "svcbtest", + "rdata": { + "AliasType": "SVCB", + "EvalTargetHealth": "", + "Target": "foo.com.", + "ZoneID": "" }, - "target": "foo.com.", "ttl": 300, - "type": "R53_ALIAS" + "type": "R53_ALIAS", + "typenum": 65298 }, { - "filepos": "[line:17:5]", + "comparablev3": "TLSA foo.com. \"\" \"\"", + "filepos": "[line:18:5]", "meta": { "orig_custom_type": "R53_ALIAS" }, "name": "tlsatest", - "r53_alias": { - "evaluate_target_health": "false", - "type": "TLSA" + "name_unicode": "tlsatest", + "rdata": { + "AliasType": "TLSA", + "EvalTargetHealth": "", + "Target": "foo.com.", + "ZoneID": "" }, - "target": "foo.com.", "ttl": 300, - "type": "R53_ALIAS" + "type": "R53_ALIAS", + "typenum": 65298 }, { - "filepos": "[line:10:5]", + "comparablev3": "TXT foo.com. \"\" \"\"", + "filepos": "[line:11:5]", "meta": { "orig_custom_type": "R53_ALIAS" }, "name": "txttest", - "r53_alias": { - "evaluate_target_health": "false", - "type": "TXT" + "name_unicode": "txttest", + "rdata": { + "AliasType": "TXT", + "EvalTargetHealth": "", + "Target": "foo.com.", + "ZoneID": "" }, - "target": "foo.com.", "ttl": 300, - "type": "R53_ALIAS" + "type": "R53_ALIAS", + "typenum": 65298 } ], "registrar": "none", diff --git a/pkg/js/parse_tests/020-complexRequire.json b/pkg/js/parse_tests/020-complexRequire.json index fe066d5379..c0063a66c1 100644 --- a/pkg/js/parse_tests/020-complexRequire.json +++ b/pkg/js/parse_tests/020-complexRequire.json @@ -3,47 +3,67 @@ "domains": [ { "dnsProviders": {}, - "meta": { - "dnscontrol_nameraw": "sortfoo.com", - "dnscontrol_nameunicode": "sortfoo.com", - "dnscontrol_uniquename": "sortfoo.com" - }, "name": "sortfoo.com", "records": [ { + "comparablev3": "1.2.3.4", "filepos": "[line:1:1]", "name": "@", - "target": "1.2.3.4", + "name_unicode": "@", + "rdata": { + "Addr": "1.2.3.4" + }, "ttl": 300, - "type": "A" + "type": "A", + "typenum": 1 }, { + "comparablev3": "foo.com.", "filepos": "[line:1:1]", "name": "a", - "target": "foo.com.", + "name_unicode": "a", + "rdata": { + "Target": "foo.com." + }, "ttl": 300, - "type": "CNAME" + "type": "CNAME", + "typenum": 5 }, { + "comparablev3": "foo.com.", "filepos": "[line:1:1]", "name": "b", - "target": "foo.com.", + "name_unicode": "b", + "rdata": { + "Target": "foo.com." + }, "ttl": 300, - "type": "CNAME" + "type": "CNAME", + "typenum": 5 }, { + "comparablev3": "foo.com.", "filepos": "[line:1:1]", "name": "c", - "target": "foo.com.", + "name_unicode": "c", + "rdata": { + "Target": "foo.com." + }, "ttl": 300, - "type": "CNAME" + "type": "CNAME", + "typenum": 5 }, { + "comparablev3": "foo.com.", "filepos": "[line:1:1]", "name": "d", - "target": "foo.com.", + "name_unicode": "d", + "rdata": { + "Target": "foo.com." + }, "ttl": 300, - "type": "CNAME" + "type": "CNAME", + "typenum": 5 } ], "registrar": "none", diff --git a/pkg/js/parse_tests/021-srv.json b/pkg/js/parse_tests/021-srv.json index 117b64dfd7..2fbb5bcfc6 100644 --- a/pkg/js/parse_tests/021-srv.json +++ b/pkg/js/parse_tests/021-srv.json @@ -3,60 +3,82 @@ "domains": [ { "dnsProviders": {}, - "meta": { - "dnscontrol_nameraw": "foo.com", - "dnscontrol_nameunicode": "foo.com", - "dnscontrol_uniquename": "foo.com" - }, "name": "foo.com", "records": [ { + "comparablev3": "0 0 1 zeros.foo.com.", "filepos": "[line:6:5]", "name": "_ntp._udp", - "srvport": 1, - "target": "zeros.foo.com.", + "name_unicode": "_ntp._udp", + "rdata": { + "Port": 1, + "Priority": 0, + "Target": "zeros.foo.com.", + "Weight": 0 + }, "ttl": 300, - "type": "SRV" + "type": "SRV", + "typenum": 33 }, { + "comparablev3": "1 100 123 one.foo.com.", "filepos": "[line:2:5]", "name": "_ntp._udp", - "srvport": 123, - "srvpriority": 1, - "srvweight": 100, - "target": "one.foo.com.", + "name_unicode": "_ntp._udp", + "rdata": { + "Port": 123, + "Priority": 1, + "Target": "one.foo.com.", + "Weight": 100 + }, "ttl": 300, - "type": "SRV" + "type": "SRV", + "typenum": 33 }, { + "comparablev3": "2 100 123 two.foo.com.", "filepos": "[line:3:5]", "name": "_ntp._udp", - "srvport": 123, - "srvpriority": 2, - "srvweight": 100, - "target": "two.foo.com.", + "name_unicode": "_ntp._udp", + "rdata": { + "Port": 123, + "Priority": 2, + "Target": "two.foo.com.", + "Weight": 100 + }, "ttl": 300, - "type": "SRV" + "type": "SRV", + "typenum": 33 }, { + "comparablev3": "3 100 123 localhost.foo.com.", "filepos": "[line:4:5]", "name": "_ntp._udp", - "srvport": 123, - "srvpriority": 3, - "srvweight": 100, - "target": "localhost.foo.com.", + "name_unicode": "_ntp._udp", + "rdata": { + "Port": 123, + "Priority": 3, + "Target": "localhost.foo.com.", + "Weight": 100 + }, "ttl": 300, - "type": "SRV" + "type": "SRV", + "typenum": 33 }, { + "comparablev3": "4 100 123 three.example.com.", "filepos": "[line:5:5]", "name": "_ntp._udp", - "srvport": 123, - "srvpriority": 4, - "srvweight": 100, - "target": "three.example.com.", + "name_unicode": "_ntp._udp", + "rdata": { + "Port": 123, + "Priority": 4, + "Target": "three.example.com.", + "Weight": 100 + }, "ttl": 300, - "type": "SRV" + "type": "SRV", + "typenum": 33 } ], "registrar": "none", diff --git a/pkg/js/parse_tests/022-sshfp.json b/pkg/js/parse_tests/022-sshfp.json index 5ab4dd798c..a365f8a67d 100644 --- a/pkg/js/parse_tests/022-sshfp.json +++ b/pkg/js/parse_tests/022-sshfp.json @@ -3,84 +3,119 @@ "domains": [ { "dnsProviders": {}, - "meta": { - "dnscontrol_nameraw": "foo.com", - "dnscontrol_nameunicode": "foo.com", - "dnscontrol_uniquename": "foo.com" - }, "name": "foo.com", "records": [ { + "comparablev3": "1 1 66C7D5540B7D75A1FB4C84FEBFA178AD99BDD67C", "filepos": "[line:2:5]", "name": "@", - "sshfpalgorithm": 1, - "sshfpfingerprint": 1, - "target": "66c7d5540b7d75a1fb4c84febfa178ad99bdd67c", + "name_unicode": "@", + "rdata": { + "Algorithm": 1, + "FingerPrint": "66C7D5540B7D75A1FB4C84FEBFA178AD99BDD67C", + "Type": 1 + }, "ttl": 300, - "type": "SSHFP" + "type": "SSHFP", + "typenum": 44 }, { + "comparablev3": "1 2 745A635BC46A397A5C4F21D437483005BCC40D7511FF15FBFAFE913A081559BC", "filepos": "[line:3:5]", "name": "@", - "sshfpalgorithm": 1, - "sshfpfingerprint": 2, - "target": "745a635bc46a397a5c4f21d437483005bcc40d7511ff15fbfafe913a081559bc", + "name_unicode": "@", + "rdata": { + "Algorithm": 1, + "FingerPrint": "745A635BC46A397A5C4F21D437483005BCC40D7511FF15FBFAFE913A081559BC", + "Type": 2 + }, "ttl": 300, - "type": "SSHFP" + "type": "SSHFP", + "typenum": 44 }, { + "comparablev3": "2 1 66C7D5540B7D75A1FB4C84FEBFA178AD99BDD67C", "filepos": "[line:4:5]", "name": "@", - "sshfpalgorithm": 2, - "sshfpfingerprint": 1, - "target": "66c7d5540b7d75a1fb4c84febfa178ad99bdd67c", + "name_unicode": "@", + "rdata": { + "Algorithm": 2, + "FingerPrint": "66C7D5540B7D75A1FB4C84FEBFA178AD99BDD67C", + "Type": 1 + }, "ttl": 300, - "type": "SSHFP" + "type": "SSHFP", + "typenum": 44 }, { + "comparablev3": "2 2 745A635BC46A397A5C4F21D437483005BCC40D7511FF15FBFAFE913A081559BC", "filepos": "[line:5:5]", "name": "@", - "sshfpalgorithm": 2, - "sshfpfingerprint": 2, - "target": "745a635bc46a397a5c4f21d437483005bcc40d7511ff15fbfafe913a081559bc", + "name_unicode": "@", + "rdata": { + "Algorithm": 2, + "FingerPrint": "745A635BC46A397A5C4F21D437483005BCC40D7511FF15FBFAFE913A081559BC", + "Type": 2 + }, "ttl": 300, - "type": "SSHFP" + "type": "SSHFP", + "typenum": 44 }, { + "comparablev3": "3 1 66C7D5540B7D75A1FB4C84FEBFA178AD99BDD67C", "filepos": "[line:6:5]", "name": "@", - "sshfpalgorithm": 3, - "sshfpfingerprint": 1, - "target": "66c7d5540b7d75a1fb4c84febfa178ad99bdd67c", + "name_unicode": "@", + "rdata": { + "Algorithm": 3, + "FingerPrint": "66C7D5540B7D75A1FB4C84FEBFA178AD99BDD67C", + "Type": 1 + }, "ttl": 300, - "type": "SSHFP" + "type": "SSHFP", + "typenum": 44 }, { + "comparablev3": "3 2 745A635BC46A397A5C4F21D437483005BCC40D7511FF15FBFAFE913A081559BC", "filepos": "[line:7:5]", "name": "@", - "sshfpalgorithm": 3, - "sshfpfingerprint": 2, - "target": "745a635bc46a397a5c4f21d437483005bcc40d7511ff15fbfafe913a081559bc", + "name_unicode": "@", + "rdata": { + "Algorithm": 3, + "FingerPrint": "745A635BC46A397A5C4F21D437483005BCC40D7511FF15FBFAFE913A081559BC", + "Type": 2 + }, "ttl": 300, - "type": "SSHFP" + "type": "SSHFP", + "typenum": 44 }, { + "comparablev3": "4 1 66C7D5540B7D75A1FB4C84FEBFA178AD99BDD67C", "filepos": "[line:8:5]", "name": "@", - "sshfpalgorithm": 4, - "sshfpfingerprint": 1, - "target": "66c7d5540b7d75a1fb4c84febfa178ad99bdd67c", + "name_unicode": "@", + "rdata": { + "Algorithm": 4, + "FingerPrint": "66C7D5540B7D75A1FB4C84FEBFA178AD99BDD67C", + "Type": 1 + }, "ttl": 300, - "type": "SSHFP" + "type": "SSHFP", + "typenum": 44 }, { + "comparablev3": "4 2 745A635BC46A397A5C4F21D437483005BCC40D7511FF15FBFAFE913A081559BC", "filepos": "[line:9:5]", "name": "@", - "sshfpalgorithm": 4, - "sshfpfingerprint": 2, - "target": "745a635bc46a397a5c4f21d437483005bcc40d7511ff15fbfafe913a081559bc", + "name_unicode": "@", + "rdata": { + "Algorithm": 4, + "FingerPrint": "745A635BC46A397A5C4F21D437483005BCC40D7511FF15FBFAFE913A081559BC", + "Type": 2 + }, "ttl": 300, - "type": "SSHFP" + "type": "SSHFP", + "typenum": 44 } ], "registrar": "none", diff --git a/pkg/js/parse_tests/023-ignored-glob-records.json b/pkg/js/parse_tests/023-ignored-glob-records.json index b7210c2b7a..3f1af40335 100644 --- a/pkg/js/parse_tests/023-ignored-glob-records.json +++ b/pkg/js/parse_tests/023-ignored-glob-records.json @@ -3,11 +3,6 @@ "domains": [ { "dnsProviders": {}, - "meta": { - "dnscontrol_nameraw": "foo.com", - "dnscontrol_nameunicode": "foo.com", - "dnscontrol_uniquename": "foo.com" - }, "name": "foo.com", "records": [], "registrar": "none", diff --git a/pkg/js/parse_tests/024-json-import.json b/pkg/js/parse_tests/024-json-import.json index 32b952ad64..1955deab71 100644 --- a/pkg/js/parse_tests/024-json-import.json +++ b/pkg/js/parse_tests/024-json-import.json @@ -3,19 +3,19 @@ "domains": [ { "dnsProviders": {}, - "meta": { - "dnscontrol_nameraw": "foo.com", - "dnscontrol_nameunicode": "foo.com", - "dnscontrol_uniquename": "foo.com" - }, "name": "foo.com", "records": [ { + "comparablev3": "1.1.1.1", "filepos": "[line:7:5]", "name": "@", - "target": "1.1.1.1", + "name_unicode": "@", + "rdata": { + "Addr": "1.1.1.1" + }, "ttl": 300, - "type": "A" + "type": "A", + "typenum": 1 } ], "registrar": "none", diff --git a/pkg/js/parse_tests/025-autodnssec.json b/pkg/js/parse_tests/025-autodnssec.json index fe709bbfa2..e992b81022 100644 --- a/pkg/js/parse_tests/025-autodnssec.json +++ b/pkg/js/parse_tests/025-autodnssec.json @@ -3,11 +3,6 @@ "domains": [ { "dnsProviders": {}, - "meta": { - "dnscontrol_nameraw": "nothing.com", - "dnscontrol_nameunicode": "nothing.com", - "dnscontrol_uniquename": "nothing.com" - }, "name": "nothing.com", "records": [], "registrar": "none", @@ -16,11 +11,6 @@ { "auto_dnssec": "on", "dnsProviders": {}, - "meta": { - "dnscontrol_nameraw": "with.com", - "dnscontrol_nameunicode": "with.com", - "dnscontrol_uniquename": "with.com" - }, "name": "with.com", "records": [], "registrar": "none", @@ -29,11 +19,6 @@ { "auto_dnssec": "off", "dnsProviders": {}, - "meta": { - "dnscontrol_nameraw": "without.com", - "dnscontrol_nameunicode": "without.com", - "dnscontrol_uniquename": "without.com" - }, "name": "without.com", "records": [], "registrar": "none", diff --git a/pkg/js/parse_tests/026-azure-alias.json b/pkg/js/parse_tests/026-azure-alias.json index deac14eae8..d2fd251225 100644 --- a/pkg/js/parse_tests/026-azure-alias.json +++ b/pkg/js/parse_tests/026-azure-alias.json @@ -3,51 +3,55 @@ "domains": [ { "dnsProviders": {}, - "meta": { - "dnscontrol_nameraw": "foo.com", - "dnscontrol_nameunicode": "foo.com", - "dnscontrol_uniquename": "foo.com" - }, "name": "foo.com", "records": [ { - "azure_alias": { - "type": "AAAA" - }, + "comparablev3": "AAAA foo.com.", "filepos": "[line:3:5]", "meta": { "orig_custom_type": "AZURE_ALIAS" }, "name": "aaaatest", - "target": "foo.com.", + "name_unicode": "aaaatest", + "rdata": { + "AliasType": "AAAA", + "Target": "foo.com." + }, "ttl": 300, - "type": "AZURE_ALIAS" + "type": "AZURE_ALIAS", + "typenum": 65286 }, { - "azure_alias": { - "type": "A" - }, + "comparablev3": "A foo.com.", "filepos": "[line:2:5]", "meta": { "orig_custom_type": "AZURE_ALIAS" }, "name": "atest", - "target": "foo.com.", + "name_unicode": "atest", + "rdata": { + "AliasType": "A", + "Target": "foo.com." + }, "ttl": 300, - "type": "AZURE_ALIAS" + "type": "AZURE_ALIAS", + "typenum": 65286 }, { - "azure_alias": { - "type": "CNAME" - }, + "comparablev3": "CNAME foo.com.", "filepos": "[line:4:5]", "meta": { "orig_custom_type": "AZURE_ALIAS" }, "name": "cnametest", - "target": "foo.com.", + "name_unicode": "cnametest", + "rdata": { + "AliasType": "CNAME", + "Target": "foo.com." + }, "ttl": 300, - "type": "AZURE_ALIAS" + "type": "AZURE_ALIAS", + "typenum": 65286 } ], "registrar": "none", diff --git a/pkg/js/parse_tests/027-ds.json b/pkg/js/parse_tests/027-ds.json index 2f18443134..f36c3ddf01 100644 --- a/pkg/js/parse_tests/027-ds.json +++ b/pkg/js/parse_tests/027-ds.json @@ -3,68 +3,37 @@ "domains": [ { "dnsProviders": {}, - "meta": { - "dnscontrol_nameraw": "foo.com", - "dnscontrol_nameunicode": "foo.com", - "dnscontrol_uniquename": "foo.com" - }, "name": "foo.com", "records": [ { - "comparable": "1 1 1 FFFF", - "dsalgorithm": 1, - "dsdigest": "FFFF", - "dsdigesttype": 1, - "dskeytag": 1, - "fields": { + "comparablev3": "1 1 1 FFFF", + "filepos": "[line:3:5]", + "name": "@", + "name_unicode": "@", + "rdata": { "Algorithm": 1, "Digest": "FFFF", "DigestType": 1, - "Hdr": { - "Class": 1, - "Name": "foo.com.", - "Rdlength": 0, - "Rrtype": 43, - "Ttl": 300 - }, "KeyTag": 1 }, - "filepos": "[line:3:5]", - "name": "@", - "name_raw": "@", - "name_unicode": "@", - "target": "", "ttl": 300, "type": "DS", - "zonfefilepartial": "1 1 1 FFFF" + "typenum": 43 }, { - "comparable": "1000 13 2 AABBCCDDEEFF", - "dsalgorithm": 13, - "dsdigest": "AABBCCDDEEFF", - "dsdigesttype": 2, - "dskeytag": 1000, - "fields": { + "comparablev3": "1000 13 2 AABBCCDDEEFF", + "filepos": "[line:2:5]", + "name": "@", + "name_unicode": "@", + "rdata": { "Algorithm": 13, "Digest": "AABBCCDDEEFF", "DigestType": 2, - "Hdr": { - "Class": 1, - "Name": "foo.com.", - "Rdlength": 0, - "Rrtype": 43, - "Ttl": 300 - }, "KeyTag": 1000 }, - "filepos": "[line:2:5]", - "name": "@", - "name_raw": "@", - "name_unicode": "@", - "target": "", "ttl": 300, "type": "DS", - "zonfefilepartial": "1000 13 2 AABBCCDDEEFF" + "typenum": 43 } ], "registrar": "none", diff --git a/pkg/js/parse_tests/028-dextend.json b/pkg/js/parse_tests/028-dextend.json index 35eb5bbcdf..59ef5e061f 100644 --- a/pkg/js/parse_tests/028-dextend.json +++ b/pkg/js/parse_tests/028-dextend.json @@ -10,26 +10,31 @@ "dnsProviders": { "Cloudflare": -1 }, - "meta": { - "dnscontrol_nameraw": "foo.com", - "dnscontrol_nameunicode": "foo.com", - "dnscontrol_uniquename": "foo.com" - }, "name": "foo.com", "records": [ { + "comparablev3": "10.1.1.1", "filepos": "[line:6:5]", "name": "@", - "target": "10.1.1.1", + "name_unicode": "@", + "rdata": { + "Addr": "10.1.1.1" + }, "ttl": 300, - "type": "A" + "type": "A", + "typenum": 1 }, { + "comparablev3": "10.2.2.2", "filepos": "[line:7:5]", "name": "www", - "target": "10.2.2.2", + "name_unicode": "www", + "rdata": { + "Addr": "10.2.2.2" + }, "ttl": 300, - "type": "A" + "type": "A", + "typenum": 1 } ], "registrar": "Third-Party", @@ -39,26 +44,31 @@ "dnsProviders": { "Cloudflare": -1 }, - "meta": { - "dnscontrol_nameraw": "bar.foo.com", - "dnscontrol_nameunicode": "bar.foo.com", - "dnscontrol_uniquename": "bar.foo.com" - }, "name": "bar.foo.com", "records": [ { + "comparablev3": "10.3.3.3", "filepos": "[line:10:5]", "name": "@", - "target": "10.3.3.3", + "name_unicode": "@", + "rdata": { + "Addr": "10.3.3.3" + }, "ttl": 300, - "type": "A" + "type": "A", + "typenum": 1 }, { + "comparablev3": "10.4.4.4", "filepos": "[line:11:5]", "name": "www", - "target": "10.4.4.4", + "name_unicode": "www", + "rdata": { + "Addr": "10.4.4.4" + }, "ttl": 300, - "type": "A" + "type": "A", + "typenum": 1 } ], "registrar": "Third-Party", @@ -68,40 +78,55 @@ "dnsProviders": { "Cloudflare": -1 }, - "meta": { - "dnscontrol_nameraw": "foo.edu", - "dnscontrol_nameunicode": "foo.edu", - "dnscontrol_uniquename": "foo.edu" - }, "name": "foo.edu", "records": [ { + "comparablev3": "10.5.5.5", "filepos": "[line:16:5]", "name": "@", - "target": "10.5.5.5", + "name_unicode": "@", + "rdata": { + "Addr": "10.5.5.5" + }, "ttl": 300, - "type": "A" + "type": "A", + "typenum": 1 }, { + "comparablev3": "10.7.7.7", "filepos": "[line:20:5]", "name": "more1", - "target": "10.7.7.7", + "name_unicode": "more1", + "rdata": { + "Addr": "10.7.7.7" + }, "ttl": 300, - "type": "A" + "type": "A", + "typenum": 1 }, { + "comparablev3": "10.8.8.8", "filepos": "[line:21:5]", "name": "more2", - "target": "10.8.8.8", + "name_unicode": "more2", + "rdata": { + "Addr": "10.8.8.8" + }, "ttl": 300, - "type": "A" + "type": "A", + "typenum": 1 }, { + "comparablev3": "10.6.6.6", "filepos": "[line:17:5]", "name": "www", - "target": "10.6.6.6", + "name_unicode": "www", + "rdata": { + "Addr": "10.6.6.6" + }, "ttl": 300, - "type": "A" + "type": "A", + "typenum": 1 } ], "registrar": "Third-Party", diff --git a/pkg/js/parse_tests/029-dextendsub.json b/pkg/js/parse_tests/029-dextendsub.json index 21e23f1ef3..2127cea141 100644 --- a/pkg/js/parse_tests/029-dextendsub.json +++ b/pkg/js/parse_tests/029-dextendsub.json @@ -10,58 +10,83 @@ "dnsProviders": { "Cloudflare": -1 }, - "meta": { - "dnscontrol_nameraw": "foo.net", - "dnscontrol_nameunicode": "foo.net", - "dnscontrol_uniquename": "foo.net" - }, "name": "foo.net", "records": [ { + "comparablev3": "10.1.1.1", "filepos": "[line:7:5]", "name": "@", - "target": "10.1.1.1", + "name_unicode": "@", + "rdata": { + "Addr": "10.1.1.1" + }, "ttl": 300, - "type": "A" + "type": "A", + "typenum": 1 }, { + "comparablev3": "10.3.3.3", "filepos": "[line:11:5]", "name": "bar", + "name_unicode": "bar", + "rdata": { + "Addr": "10.3.3.3" + }, "subdomain": "bar", - "target": "10.3.3.3", "ttl": 300, - "type": "A" + "type": "A", + "typenum": 1 }, { + "comparablev3": "10.4.4.4", "filepos": "[line:12:5]", "name": "www.bar", + "name_unicode": "www.bar", + "rdata": { + "Addr": "10.4.4.4" + }, "subdomain": "bar", - "target": "10.4.4.4", "ttl": 300, - "type": "A" + "type": "A", + "typenum": 1 }, { + "comparablev3": "10.25.25.25", "filepos": "[line:70:5]", "name": "a.long.path.of.sub.domains", + "name_unicode": "a.long.path.of.sub.domains", + "rdata": { + "Addr": "10.25.25.25" + }, "subdomain": "a.long.path.of.sub.domains", - "target": "10.25.25.25", "ttl": 300, - "type": "A" + "type": "A", + "typenum": 1 }, { + "comparablev3": "10.26.26.26", "filepos": "[line:71:5]", "name": "www.a.long.path.of.sub.domains", + "name_unicode": "www.a.long.path.of.sub.domains", + "rdata": { + "Addr": "10.26.26.26" + }, "subdomain": "a.long.path.of.sub.domains", - "target": "10.26.26.26", "ttl": 300, - "type": "A" + "type": "A", + "typenum": 1 }, { + "comparablev3": "10.2.2.2", "filepos": "[line:8:5]", "name": "www", - "target": "10.2.2.2", + "name_unicode": "www", + "rdata": { + "Addr": "10.2.2.2" + }, "ttl": 300, - "type": "A" + "type": "A", + "typenum": 1 } ], "registrar": "Third-Party", @@ -71,33 +96,43 @@ "dnsProviders": { "Cloudflare": -1 }, - "meta": { - "dnscontrol_nameraw": "foo.tld", - "dnscontrol_nameunicode": "foo.tld", - "dnscontrol_uniquename": "foo.tld" - }, "name": "foo.tld", "records": [ { + "comparablev3": "20.5.5.5", "filepos": "[line:18:5]", "name": "@", - "target": "20.5.5.5", + "name_unicode": "@", + "rdata": { + "Addr": "20.5.5.5" + }, "ttl": 300, - "type": "A" + "type": "A", + "typenum": 1 }, { + "comparablev3": "20.10.10.10", "filepos": "[line:30:5]", "name": "a", - "target": "20.10.10.10", + "name_unicode": "a", + "rdata": { + "Addr": "20.10.10.10" + }, "ttl": 300, - "type": "A" + "type": "A", + "typenum": 1 }, { + "comparablev3": "20.6.6.6", "filepos": "[line:19:5]", "name": "www", - "target": "20.6.6.6", + "name_unicode": "www", + "rdata": { + "Addr": "20.6.6.6" + }, "ttl": 300, - "type": "A" + "type": "A", + "typenum": 1 } ], "registrar": "Third-Party", @@ -107,33 +142,43 @@ "dnsProviders": { "Cloudflare": -1 }, - "meta": { - "dnscontrol_nameraw": "bar.foo.tld", - "dnscontrol_nameunicode": "bar.foo.tld", - "dnscontrol_uniquename": "bar.foo.tld" - }, "name": "bar.foo.tld", "records": [ { + "comparablev3": "30.7.7.7", "filepos": "[line:23:5]", "name": "@", - "target": "30.7.7.7", + "name_unicode": "@", + "rdata": { + "Addr": "30.7.7.7" + }, "ttl": 300, - "type": "A" + "type": "A", + "typenum": 1 }, { + "comparablev3": "30.9.9.9", "filepos": "[line:27:5]", "name": "a", - "target": "30.9.9.9", + "name_unicode": "a", + "rdata": { + "Addr": "30.9.9.9" + }, "ttl": 300, - "type": "A" + "type": "A", + "typenum": 1 }, { + "comparablev3": "30.8.8.8", "filepos": "[line:24:5]", "name": "www", - "target": "30.8.8.8", + "name_unicode": "www", + "rdata": { + "Addr": "30.8.8.8" + }, "ttl": 300, - "type": "A" + "type": "A", + "typenum": 1 } ], "registrar": "Third-Party", @@ -143,42 +188,57 @@ "dnsProviders": { "Cloudflare": -1 }, - "meta": { - "dnscontrol_nameraw": "foo.help", - "dnscontrol_nameunicode": "foo.help", - "dnscontrol_uniquename": "foo.help" - }, "name": "foo.help", "records": [ { + "comparablev3": "40.12.12.12", "filepos": "[line:36:5]", "name": "@", - "target": "40.12.12.12", + "name_unicode": "@", + "rdata": { + "Addr": "40.12.12.12" + }, "ttl": 300, - "type": "A" + "type": "A", + "typenum": 1 }, { + "comparablev3": "40.17.17.17", "filepos": "[line:49:5]", "name": "morty", + "name_unicode": "morty", + "rdata": { + "Addr": "40.17.17.17" + }, "subdomain": "morty", - "target": "40.17.17.17", "ttl": 300, - "type": "A" + "type": "A", + "typenum": 1 }, { + "comparablev3": "40.18.18.18", "filepos": "[line:50:5]", "name": "www.morty", + "name_unicode": "www.morty", + "rdata": { + "Addr": "40.18.18.18" + }, "subdomain": "morty", - "target": "40.18.18.18", "ttl": 300, - "type": "A" + "type": "A", + "typenum": 1 }, { + "comparablev3": "40.12.12.12", "filepos": "[line:37:5]", "name": "www", - "target": "40.12.12.12", + "name_unicode": "www", + "rdata": { + "Addr": "40.12.12.12" + }, "ttl": 300, - "type": "A" + "type": "A", + "typenum": 1 } ], "registrar": "Third-Party", @@ -188,42 +248,57 @@ "dnsProviders": { "Cloudflare": -1 }, - "meta": { - "dnscontrol_nameraw": "bar.foo.help", - "dnscontrol_nameunicode": "bar.foo.help", - "dnscontrol_uniquename": "bar.foo.help" - }, "name": "bar.foo.help", "records": [ { + "comparablev3": "50.13.13.13", "filepos": "[line:41:5]", "name": "@", - "target": "50.13.13.13", + "name_unicode": "@", + "rdata": { + "Addr": "50.13.13.13" + }, "ttl": 300, - "type": "A" + "type": "A", + "typenum": 1 }, { + "comparablev3": "50.14.14.14", "filepos": "[line:42:5]", "name": "www", - "target": "50.14.14.14", + "name_unicode": "www", + "rdata": { + "Addr": "50.14.14.14" + }, "ttl": 300, - "type": "A" + "type": "A", + "typenum": 1 }, { + "comparablev3": "50.15.15.15", "filepos": "[line:45:5]", "name": "zip", + "name_unicode": "zip", + "rdata": { + "Addr": "50.15.15.15" + }, "subdomain": "zip", - "target": "50.15.15.15", "ttl": 300, - "type": "A" + "type": "A", + "typenum": 1 }, { + "comparablev3": "50.16.16.16", "filepos": "[line:46:5]", "name": "www.zip", + "name_unicode": "www.zip", + "rdata": { + "Addr": "50.16.16.16" + }, "subdomain": "zip", - "target": "50.16.16.16", "ttl": 300, - "type": "A" + "type": "A", + "typenum": 1 } ], "registrar": "Third-Party", @@ -233,58 +308,83 @@ "dnsProviders": { "Cloudflare": -1 }, - "meta": { - "dnscontrol_nameraw": "foo.here", - "dnscontrol_nameunicode": "foo.here", - "dnscontrol_uniquename": "foo.here" - }, "name": "foo.here", "records": [ { + "comparablev3": "60.19.19.19", "filepos": "[line:56:5]", "name": "@", - "target": "60.19.19.19", + "name_unicode": "@", + "rdata": { + "Addr": "60.19.19.19" + }, "ttl": 300, - "type": "A" + "type": "A", + "typenum": 1 }, { + "comparablev3": "60.21.21.21", "filepos": "[line:60:5]", "name": "bar", + "name_unicode": "bar", + "rdata": { + "Addr": "60.21.21.21" + }, "subdomain": "bar", - "target": "60.21.21.21", "ttl": 300, - "type": "A" + "type": "A", + "typenum": 1 }, { + "comparablev3": "60.23.23.23", "filepos": "[line:64:5]", "name": "baz.bar", + "name_unicode": "baz.bar", + "rdata": { + "Addr": "60.23.23.23" + }, "subdomain": "baz.bar", - "target": "60.23.23.23", "ttl": 300, - "type": "A" + "type": "A", + "typenum": 1 }, { + "comparablev3": "60.24.24.24", "filepos": "[line:65:5]", "name": "www.baz.bar", + "name_unicode": "www.baz.bar", + "rdata": { + "Addr": "60.24.24.24" + }, "subdomain": "baz.bar", - "target": "60.24.24.24", "ttl": 300, - "type": "A" + "type": "A", + "typenum": 1 }, { + "comparablev3": "60.22.22.22", "filepos": "[line:61:5]", "name": "www.bar", + "name_unicode": "www.bar", + "rdata": { + "Addr": "60.22.22.22" + }, "subdomain": "bar", - "target": "60.22.22.22", "ttl": 300, - "type": "A" + "type": "A", + "typenum": 1 }, { + "comparablev3": "60.20.20.20", "filepos": "[line:57:5]", "name": "www", - "target": "60.20.20.20", + "name_unicode": "www", + "rdata": { + "Addr": "60.20.20.20" + }, "ttl": 300, - "type": "A" + "type": "A", + "typenum": 1 } ], "registrar": "Third-Party", @@ -294,58 +394,83 @@ "dnsProviders": { "Cloudflare": -1 }, - "meta": { - "dnscontrol_nameraw": "example.com", - "dnscontrol_nameunicode": "example.com", - "dnscontrol_uniquename": "example.com" - }, "name": "example.com", "records": [ { + "comparablev3": "10.0.0.1", "filepos": "[line:77:5]", "name": "@", - "target": "10.0.0.1", + "name_unicode": "@", + "rdata": { + "Addr": "10.0.0.1" + }, "ttl": 300, - "type": "A" + "type": "A", + "typenum": 1 }, { - "filepos": "[line:82:5]", - "name": "d\u00fcsseldorf", - "subdomain": "d\u00fcsseldorf", - "target": "10.0.0.3", + "comparablev3": "10.0.0.2", + "filepos": "[line:78:5]", + "name": "www", + "name_unicode": "www", + "rdata": { + "Addr": "10.0.0.2" + }, "ttl": 300, - "type": "A" + "type": "A", + "typenum": 1 }, { - "filepos": "[line:83:5]", - "name": "www.d\u00fcsseldorf", - "subdomain": "d\u00fcsseldorf", - "target": "10.0.0.4", + "comparablev3": "10.0.0.3", + "filepos": "[line:82:5]", + "name": "xn--dsseldorf-q9a", + "name_unicode": "d\u00fcsseldorf", + "rdata": { + "Addr": "10.0.0.3" + }, + "subdomain": "xn--dsseldorf-q9a", "ttl": 300, - "type": "A" + "type": "A", + "typenum": 1 }, { - "filepos": "[line:78:5]", - "name": "www", - "target": "10.0.0.2", + "comparablev3": "10.0.0.4", + "filepos": "[line:83:5]", + "name": "www.xn--dsseldorf-q9a", + "name_unicode": "www.d\u00fcsseldorf", + "rdata": { + "Addr": "10.0.0.4" + }, + "subdomain": "xn--dsseldorf-q9a", "ttl": 300, - "type": "A" + "type": "A", + "typenum": 1 }, { + "comparablev3": "10.0.0.5", "filepos": "[line:87:5]", - "name": "\u00fc", - "subdomain": "\u00fc", - "target": "10.0.0.5", + "name": "xn--tda", + "name_unicode": "\u00fc", + "rdata": { + "Addr": "10.0.0.5" + }, + "subdomain": "xn--tda", "ttl": 300, - "type": "A" + "type": "A", + "typenum": 1 }, { + "comparablev3": "10.0.0.6", "filepos": "[line:88:5]", - "name": "www.\u00fc", - "subdomain": "\u00fc", - "target": "10.0.0.6", - "ttl": 300, - "type": "A" + "name": "www.xn--tda", + "name_unicode": "www.\u00fc", + "rdata": { + "Addr": "10.0.0.6" + }, + "subdomain": "xn--tda", + "ttl": 300, + "type": "A", + "typenum": 1 } ], "registrar": "Third-Party", @@ -355,74 +480,109 @@ "dnsProviders": { "Cloudflare": -1 }, - "meta": { - "dnscontrol_nameraw": "d\u00fcsseldorf.example.net", - "dnscontrol_nameunicode": "d\u00fcsseldorf.example.net", - "dnscontrol_uniquename": "xn--dsseldorf-q9a.example.net" - }, "name": "xn--dsseldorf-q9a.example.net", "records": [ { + "comparablev3": "10.0.0.7", "filepos": "[line:94:5]", "name": "@", - "target": "10.0.0.7", - "ttl": 300, - "type": "A" - }, - { - "filepos": "[line:104:5]", - "name": "d\u00fcsseltal", - "subdomain": "d\u00fcsseltal", - "target": "10.0.0.11", + "name_unicode": "@", + "rdata": { + "Addr": "10.0.0.7" + }, "ttl": 300, - "type": "A" - }, - { - "filepos": "[line:105:5]", - "name": "www.d\u00fcsseltal", - "subdomain": "d\u00fcsseltal", - "target": "10.0.0.12", - "ttl": 300, - "type": "A" + "type": "A", + "typenum": 1 }, { + "comparablev3": "10.0.0.9", "filepos": "[line:99:5]", "name": "subdomain", + "name_unicode": "subdomain", + "rdata": { + "Addr": "10.0.0.9" + }, "subdomain": "subdomain", - "target": "10.0.0.9", "ttl": 300, - "type": "A" + "type": "A", + "typenum": 1 }, { + "comparablev3": "10.0.0.10", "filepos": "[line:100:5]", "name": "www.subdomain", + "name_unicode": "www.subdomain", + "rdata": { + "Addr": "10.0.0.10" + }, "subdomain": "subdomain", - "target": "10.0.0.10", "ttl": 300, - "type": "A" + "type": "A", + "typenum": 1 }, { + "comparablev3": "10.0.0.8", "filepos": "[line:95:5]", "name": "www", - "target": "10.0.0.8", + "name_unicode": "www", + "rdata": { + "Addr": "10.0.0.8" + }, "ttl": 300, - "type": "A" + "type": "A", + "typenum": 1 }, { + "comparablev3": "10.0.0.11", + "filepos": "[line:104:5]", + "name": "xn--dsseltal-65a", + "name_unicode": "d\u00fcsseltal", + "rdata": { + "Addr": "10.0.0.11" + }, + "subdomain": "xn--dsseltal-65a", + "ttl": 300, + "type": "A", + "typenum": 1 + }, + { + "comparablev3": "10.0.0.12", + "filepos": "[line:105:5]", + "name": "www.xn--dsseltal-65a", + "name_unicode": "www.d\u00fcsseltal", + "rdata": { + "Addr": "10.0.0.12" + }, + "subdomain": "xn--dsseltal-65a", + "ttl": 300, + "type": "A", + "typenum": 1 + }, + { + "comparablev3": "10.0.0.13", "filepos": "[line:109:5]", - "name": "\u00fc", - "subdomain": "\u00fc", - "target": "10.0.0.13", + "name": "xn--tda", + "name_unicode": "\u00fc", + "rdata": { + "Addr": "10.0.0.13" + }, + "subdomain": "xn--tda", "ttl": 300, - "type": "A" + "type": "A", + "typenum": 1 }, { + "comparablev3": "10.0.0.14", "filepos": "[line:110:5]", - "name": "www.\u00fc", - "subdomain": "\u00fc", - "target": "10.0.0.14", - "ttl": 300, - "type": "A" + "name": "www.xn--tda", + "name_unicode": "www.\u00fc", + "rdata": { + "Addr": "10.0.0.14" + }, + "subdomain": "xn--tda", + "ttl": 300, + "type": "A", + "typenum": 1 } ], "registrar": "Third-Party", @@ -432,74 +592,109 @@ "dnsProviders": { "Cloudflare": -1 }, - "meta": { - "dnscontrol_nameraw": "\u00fc.example.net", - "dnscontrol_nameunicode": "\u00fc.example.net", - "dnscontrol_uniquename": "xn--tda.example.net" - }, "name": "xn--tda.example.net", "records": [ { + "comparablev3": "10.0.0.15", "filepos": "[line:116:5]", "name": "@", - "target": "10.0.0.15", - "ttl": 300, - "type": "A" - }, - { - "filepos": "[line:126:5]", - "name": "d\u00fcsseldorf", - "subdomain": "d\u00fcsseldorf", - "target": "10.0.0.19", - "ttl": 300, - "type": "A" - }, - { - "filepos": "[line:127:5]", - "name": "www.d\u00fcsseldorf", - "subdomain": "d\u00fcsseldorf", - "target": "10.0.0.20", + "name_unicode": "@", + "rdata": { + "Addr": "10.0.0.15" + }, "ttl": 300, - "type": "A" + "type": "A", + "typenum": 1 }, { + "comparablev3": "10.0.0.17", "filepos": "[line:121:5]", "name": "subdomain", + "name_unicode": "subdomain", + "rdata": { + "Addr": "10.0.0.17" + }, "subdomain": "subdomain", - "target": "10.0.0.17", "ttl": 300, - "type": "A" + "type": "A", + "typenum": 1 }, { + "comparablev3": "10.0.0.18", "filepos": "[line:122:5]", "name": "www.subdomain", + "name_unicode": "www.subdomain", + "rdata": { + "Addr": "10.0.0.18" + }, "subdomain": "subdomain", - "target": "10.0.0.18", "ttl": 300, - "type": "A" + "type": "A", + "typenum": 1 }, { + "comparablev3": "10.0.0.16", "filepos": "[line:117:5]", "name": "www", - "target": "10.0.0.16", + "name_unicode": "www", + "rdata": { + "Addr": "10.0.0.16" + }, + "ttl": 300, + "type": "A", + "typenum": 1 + }, + { + "comparablev3": "10.0.0.19", + "filepos": "[line:126:5]", + "name": "xn--dsseldorf-q9a", + "name_unicode": "d\u00fcsseldorf", + "rdata": { + "Addr": "10.0.0.19" + }, + "subdomain": "xn--dsseldorf-q9a", "ttl": 300, - "type": "A" + "type": "A", + "typenum": 1 }, { + "comparablev3": "10.0.0.20", + "filepos": "[line:127:5]", + "name": "www.xn--dsseldorf-q9a", + "name_unicode": "www.d\u00fcsseldorf", + "rdata": { + "Addr": "10.0.0.20" + }, + "subdomain": "xn--dsseldorf-q9a", + "ttl": 300, + "type": "A", + "typenum": 1 + }, + { + "comparablev3": "10.0.0.21", "filepos": "[line:131:5]", - "name": "\u00fc", - "subdomain": "\u00fc", - "target": "10.0.0.21", + "name": "xn--tda", + "name_unicode": "\u00fc", + "rdata": { + "Addr": "10.0.0.21" + }, + "subdomain": "xn--tda", "ttl": 300, - "type": "A" + "type": "A", + "typenum": 1 }, { + "comparablev3": "10.0.0.22", "filepos": "[line:132:5]", - "name": "www.\u00fc", - "subdomain": "\u00fc", - "target": "10.0.0.22", - "ttl": 300, - "type": "A" + "name": "www.xn--tda", + "name_unicode": "www.\u00fc", + "rdata": { + "Addr": "10.0.0.22" + }, + "subdomain": "xn--tda", + "ttl": 300, + "type": "A", + "typenum": 1 } ], "registrar": "Third-Party", @@ -509,44 +704,59 @@ "dnsProviders": { "Cloudflare": -1 }, - "meta": { - "dnscontrol_nameraw": "example.tld", - "dnscontrol_nameunicode": "example.tld", - "dnscontrol_uniquename": "example.tld" - }, "name": "example.tld", "records": [ { + "comparablev3": "b.sub.example.tld.", "filepos": "[line:138:5]", "name": "a.sub", + "name_unicode": "a.sub", + "rdata": { + "Target": "b.sub.example.tld." + }, "subdomain": "sub", - "target": "b.sub.example.tld.", "ttl": 300, - "type": "CNAME" + "type": "CNAME", + "typenum": 5 }, { + "comparablev3": "sub.example.tld.", "filepos": "[line:139:5]", "name": "b.sub", + "name_unicode": "b.sub", + "rdata": { + "Target": "sub.example.tld." + }, "subdomain": "sub", - "target": "sub.example.tld.", "ttl": 300, - "type": "CNAME" + "type": "CNAME", + "typenum": 5 }, { + "comparablev3": "sub.example.tld.", "filepos": "[line:140:5]", "name": "c.sub", + "name_unicode": "c.sub", + "rdata": { + "Target": "sub.example.tld." + }, "subdomain": "sub", - "target": "sub.example.tld.", "ttl": 300, - "type": "CNAME" + "type": "CNAME", + "typenum": 5 }, { + "comparablev3": "otherdomain.tld.", "filepos": "[line:142:5]", "name": "e.sub", + "name_unicode": "e.sub", + "rdata": { + "Target": "otherdomain.tld." + }, "subdomain": "sub", - "target": "otherdomain.tld.", "ttl": 300, - "type": "CNAME" + "type": "CNAME", + "typenum": 5 } ], "registrar": "Third-Party", diff --git a/pkg/js/parse_tests/029-dextendsub/example.com.zone b/pkg/js/parse_tests/029-dextendsub/example.com.zone index 419d41f0ab..a36d4d8ed6 100644 --- a/pkg/js/parse_tests/029-dextendsub/example.com.zone +++ b/pkg/js/parse_tests/029-dextendsub/example.com.zone @@ -1,7 +1,7 @@ $TTL 300 @ IN A 10.0.0.1 -düsseldorf IN A 10.0.0.3 -www.düsseldorf IN A 10.0.0.4 www IN A 10.0.0.2 -ü IN A 10.0.0.5 -www.ü IN A 10.0.0.6 +xn--dsseldorf-q9a IN A 10.0.0.3 +www.xn--dsseldorf-q9a IN A 10.0.0.4 +xn--tda IN A 10.0.0.5 +www.xn--tda IN A 10.0.0.6 diff --git a/pkg/js/parse_tests/029-dextendsub/xn--dsseldorf-q9a.example.net.zone b/pkg/js/parse_tests/029-dextendsub/xn--dsseldorf-q9a.example.net.zone index 48e9bc2d70..bc497c7f00 100644 --- a/pkg/js/parse_tests/029-dextendsub/xn--dsseldorf-q9a.example.net.zone +++ b/pkg/js/parse_tests/029-dextendsub/xn--dsseldorf-q9a.example.net.zone @@ -1,9 +1,9 @@ $TTL 300 @ IN A 10.0.0.7 -düsseltal IN A 10.0.0.11 -www.düsseltal IN A 10.0.0.12 subdomain IN A 10.0.0.9 www.subdomain IN A 10.0.0.10 www IN A 10.0.0.8 -ü IN A 10.0.0.13 -www.ü IN A 10.0.0.14 +xn--dsseltal-65a IN A 10.0.0.11 +www.xn--dsseltal-65a IN A 10.0.0.12 +xn--tda IN A 10.0.0.13 +www.xn--tda IN A 10.0.0.14 diff --git a/pkg/js/parse_tests/029-dextendsub/xn--tda.example.net.zone b/pkg/js/parse_tests/029-dextendsub/xn--tda.example.net.zone index ca058364a9..9a2736f234 100644 --- a/pkg/js/parse_tests/029-dextendsub/xn--tda.example.net.zone +++ b/pkg/js/parse_tests/029-dextendsub/xn--tda.example.net.zone @@ -1,9 +1,9 @@ $TTL 300 @ IN A 10.0.0.15 -düsseldorf IN A 10.0.0.19 -www.düsseldorf IN A 10.0.0.20 subdomain IN A 10.0.0.17 www.subdomain IN A 10.0.0.18 www IN A 10.0.0.16 -ü IN A 10.0.0.21 -www.ü IN A 10.0.0.22 +xn--dsseldorf-q9a IN A 10.0.0.19 +www.xn--dsseldorf-q9a IN A 10.0.0.20 +xn--tda IN A 10.0.0.21 +www.xn--tda IN A 10.0.0.22 diff --git a/pkg/js/parse_tests/030-dextenddoc.json b/pkg/js/parse_tests/030-dextenddoc.json index 2f3058d2c7..d73b18d33b 100644 --- a/pkg/js/parse_tests/030-dextenddoc.json +++ b/pkg/js/parse_tests/030-dextenddoc.json @@ -10,103 +10,158 @@ "dnsProviders": { "Cloudflare": -1 }, - "meta": { - "dnscontrol_nameraw": "domain.tld", - "dnscontrol_nameunicode": "domain.tld", - "dnscontrol_uniquename": "domain.tld" - }, "name": "domain.tld", "records": [ { + "comparablev3": "127.0.0.1", "filepos": "[line:7:5]", "name": "@", - "target": "127.0.0.1", + "name_unicode": "@", + "rdata": { + "Addr": "127.0.0.1" + }, "ttl": 300, - "type": "A" + "type": "A", + "typenum": 1 }, { + "comparablev3": "b.domain.tld.", "filepos": "[line:9:5]", "name": "a", - "target": "b.domain.tld.", + "name_unicode": "a", + "rdata": { + "Target": "b.domain.tld." + }, "ttl": 300, - "type": "CNAME" + "type": "CNAME", + "typenum": 5 }, { + "comparablev3": "127.0.0.3", "filepos": "[line:12:5]", "name": "aaa", - "target": "127.0.0.3", + "name_unicode": "aaa", + "rdata": { + "Addr": "127.0.0.3" + }, "ttl": 300, - "type": "A" + "type": "A", + "typenum": 1 }, { + "comparablev3": "d.domain.tld.", "filepos": "[line:13:5]", "name": "c", - "target": "d.domain.tld.", + "name_unicode": "c", + "rdata": { + "Target": "d.domain.tld." + }, "ttl": 300, - "type": "CNAME" + "type": "CNAME", + "typenum": 5 }, { + "comparablev3": "127.0.0.7", "filepos": "[line:25:5]", "name": "sub", + "name_unicode": "sub", + "rdata": { + "Addr": "127.0.0.7" + }, "subdomain": "sub", - "target": "127.0.0.7", "ttl": 300, - "type": "A" + "type": "A", + "typenum": 1 }, { + "comparablev3": "127.0.0.4", "filepos": "[line:16:5]", "name": "bbb.sub", + "name_unicode": "bbb.sub", + "rdata": { + "Addr": "127.0.0.4" + }, "subdomain": "sub", - "target": "127.0.0.4", "ttl": 300, - "type": "A" + "type": "A", + "typenum": 1 }, { + "comparablev3": "127.0.0.5", "filepos": "[line:17:5]", "name": "ccc.sub", + "name_unicode": "ccc.sub", + "rdata": { + "Addr": "127.0.0.5" + }, "subdomain": "sub", - "target": "127.0.0.5", "ttl": 300, - "type": "A" + "type": "A", + "typenum": 1 }, { + "comparablev3": "f.sub.domain.tld.", "filepos": "[line:18:5]", "name": "e.sub", + "name_unicode": "e.sub", + "rdata": { + "Target": "f.sub.domain.tld." + }, "subdomain": "sub", - "target": "f.sub.domain.tld.", "ttl": 300, - "type": "CNAME" + "type": "CNAME", + "typenum": 5 }, { + "comparablev3": "j.sub.domain.tld.", "filepos": "[line:26:5]", "name": "i.sub", + "name_unicode": "i.sub", + "rdata": { + "Target": "j.sub.domain.tld." + }, "subdomain": "sub", - "target": "j.sub.domain.tld.", "ttl": 300, - "type": "CNAME" + "type": "CNAME", + "typenum": 5 }, { + "comparablev3": "127.0.0.6", "filepos": "[line:21:5]", "name": "ddd.sub.sub", + "name_unicode": "ddd.sub.sub", + "rdata": { + "Addr": "127.0.0.6" + }, "subdomain": "sub.sub", - "target": "127.0.0.6", "ttl": 300, - "type": "A" + "type": "A", + "typenum": 1 }, { + "comparablev3": "h.sub.sub.domain.tld.", "filepos": "[line:22:5]", "name": "g.sub.sub", + "name_unicode": "g.sub.sub", + "rdata": { + "Target": "h.sub.sub.domain.tld." + }, "subdomain": "sub.sub", - "target": "h.sub.sub.domain.tld.", "ttl": 300, - "type": "CNAME" + "type": "CNAME", + "typenum": 5 }, { + "comparablev3": "127.0.0.2", "filepos": "[line:8:5]", "name": "www", - "target": "127.0.0.2", + "name_unicode": "www", + "rdata": { + "Addr": "127.0.0.2" + }, "ttl": 300, - "type": "A" + "type": "A", + "typenum": 1 } ], "registrar": "Third-Party", diff --git a/pkg/js/parse_tests/031-dextendnames.json b/pkg/js/parse_tests/031-dextendnames.json index 90ffc2ec0e..7f140662b6 100644 --- a/pkg/js/parse_tests/031-dextendnames.json +++ b/pkg/js/parse_tests/031-dextendnames.json @@ -10,102 +10,157 @@ "dnsProviders": { "Cloudflare": -1 }, - "meta": { - "dnscontrol_nameraw": "domain.tld", - "dnscontrol_nameunicode": "domain.tld", - "dnscontrol_uniquename": "domain.tld" - }, "name": "domain.tld", "records": [ { + "comparablev3": "127.0.0.1", "filepos": "[line:7:5]", "name": "@", - "target": "127.0.0.1", + "name_unicode": "@", + "rdata": { + "Addr": "127.0.0.1" + }, "ttl": 300, - "type": "A" + "type": "A", + "typenum": 1 }, { + "comparablev3": "127.0.0.3", "filepos": "[line:21:5]", "name": "@", - "target": "127.0.0.3", + "name_unicode": "@", + "rdata": { + "Addr": "127.0.0.3" + }, "ttl": 300, - "type": "A" + "type": "A", + "typenum": 1 }, { + "comparablev3": "127.0.0.2", "filepos": "[line:8:5]", "name": "a", - "target": "127.0.0.2", + "name_unicode": "a", + "rdata": { + "Addr": "127.0.0.2" + }, "ttl": 300, - "type": "A" + "type": "A", + "typenum": 1 }, { + "comparablev3": "c.domain.tld.", "filepos": "[line:9:5]", "name": "b", - "target": "c.domain.tld.", + "name_unicode": "b", + "rdata": { + "Target": "c.domain.tld." + }, "ttl": 300, - "type": "CNAME" + "type": "CNAME", + "typenum": 5 }, { + "comparablev3": "127.0.0.4", "filepos": "[line:22:5]", "name": "d", - "target": "127.0.0.4", + "name_unicode": "d", + "rdata": { + "Addr": "127.0.0.4" + }, "ttl": 300, - "type": "A" + "type": "A", + "typenum": 1 }, { + "comparablev3": "f.domain.tld.", "filepos": "[line:23:5]", "name": "e", - "target": "f.domain.tld.", + "name_unicode": "e", + "rdata": { + "Target": "f.domain.tld." + }, "ttl": 300, - "type": "CNAME" + "type": "CNAME", + "typenum": 5 }, { + "comparablev3": "127.0.0.7", "filepos": "[line:42:5]", "name": "ssub", + "name_unicode": "ssub", + "rdata": { + "Addr": "127.0.0.7" + }, "subdomain": "ssub", - "target": "127.0.0.7", "ttl": 300, - "type": "A" + "type": "A", + "typenum": 1 }, { + "comparablev3": "127.0.0.8", "filepos": "[line:43:5]", "name": "j.ssub", + "name_unicode": "j.ssub", + "rdata": { + "Addr": "127.0.0.8" + }, "subdomain": "ssub", - "target": "127.0.0.8", "ttl": 300, - "type": "A" + "type": "A", + "typenum": 1 }, { + "comparablev3": "l.ssub.domain.tld.", "filepos": "[line:44:5]", "name": "k.ssub", + "name_unicode": "k.ssub", + "rdata": { + "Target": "l.ssub.domain.tld." + }, "subdomain": "ssub", - "target": "l.ssub.domain.tld.", "ttl": 300, - "type": "CNAME" + "type": "CNAME", + "typenum": 5 }, { + "comparablev3": "127.0.0.5", "filepos": "[line:28:5]", "name": "ub", + "name_unicode": "ub", + "rdata": { + "Addr": "127.0.0.5" + }, "subdomain": "ub", - "target": "127.0.0.5", "ttl": 300, - "type": "A" + "type": "A", + "typenum": 1 }, { + "comparablev3": "127.0.0.6", "filepos": "[line:29:5]", "name": "g.ub", + "name_unicode": "g.ub", + "rdata": { + "Addr": "127.0.0.6" + }, "subdomain": "ub", - "target": "127.0.0.6", "ttl": 300, - "type": "A" + "type": "A", + "typenum": 1 }, { + "comparablev3": "i.ub.domain.tld.", "filepos": "[line:30:5]", "name": "h.ub", + "name_unicode": "h.ub", + "rdata": { + "Target": "i.ub.domain.tld." + }, "subdomain": "ub", - "target": "i.ub.domain.tld.", "ttl": 300, - "type": "CNAME" + "type": "CNAME", + "typenum": 5 } ], "registrar": "Third-Party", @@ -115,54 +170,79 @@ "dnsProviders": { "Cloudflare": -1 }, - "meta": { - "dnscontrol_nameraw": "sub.domain.tld", - "dnscontrol_nameunicode": "sub.domain.tld", - "dnscontrol_uniquename": "sub.domain.tld" - }, "name": "sub.domain.tld", "records": [ { + "comparablev3": "127.0.1.1", "filepos": "[line:13:5]", "name": "@", - "target": "127.0.1.1", + "name_unicode": "@", + "rdata": { + "Addr": "127.0.1.1" + }, "ttl": 300, - "type": "A" + "type": "A", + "typenum": 1 }, { + "comparablev3": "127.0.1.3", "filepos": "[line:35:5]", "name": "@", - "target": "127.0.1.3", + "name_unicode": "@", + "rdata": { + "Addr": "127.0.1.3" + }, "ttl": 300, - "type": "A" + "type": "A", + "typenum": 1 }, { + "comparablev3": "127.0.1.2", "filepos": "[line:14:5]", "name": "aa", - "target": "127.0.1.2", + "name_unicode": "aa", + "rdata": { + "Addr": "127.0.1.2" + }, "ttl": 300, - "type": "A" + "type": "A", + "typenum": 1 }, { + "comparablev3": "cc.sub.domain.tld.", "filepos": "[line:15:5]", "name": "bb", - "target": "cc.sub.domain.tld.", + "name_unicode": "bb", + "rdata": { + "Target": "cc.sub.domain.tld." + }, "ttl": 300, - "type": "CNAME" + "type": "CNAME", + "typenum": 5 }, { + "comparablev3": "127.0.1.4", "filepos": "[line:36:5]", "name": "dd", - "target": "127.0.1.4", + "name_unicode": "dd", + "rdata": { + "Addr": "127.0.1.4" + }, "ttl": 300, - "type": "A" + "type": "A", + "typenum": 1 }, { + "comparablev3": "ff.sub.domain.tld.", "filepos": "[line:37:5]", "name": "ee", - "target": "ff.sub.domain.tld.", + "name_unicode": "ee", + "rdata": { + "Target": "ff.sub.domain.tld." + }, "ttl": 300, - "type": "CNAME" + "type": "CNAME", + "typenum": 5 } ], "registrar": "Third-Party", diff --git a/pkg/js/parse_tests/032-reverseip.json b/pkg/js/parse_tests/032-reverseip.json index 74685784c8..4f72c943c2 100644 --- a/pkg/js/parse_tests/032-reverseip.json +++ b/pkg/js/parse_tests/032-reverseip.json @@ -10,84 +10,124 @@ "dnsProviders": { "bind": -1 }, - "meta": { - "dnscontrol_nameraw": "3.2.1.in-addr.arpa", - "dnscontrol_nameunicode": "3.2.1.in-addr.arpa", - "dnscontrol_uniquename": "3.2.1.in-addr.arpa" - }, "name": "3.2.1.in-addr.arpa", "records": [ { + "comparablev3": "foo.example.com.", "filepos": "[line:7:5]", "name": "1", - "target": "foo.example.com.", + "name_unicode": "1", + "rdata": { + "Ptr": "foo.example.com." + }, "ttl": 300, - "type": "PTR" + "type": "PTR", + "typenum": 12 }, { + "comparablev3": "bar.example.com.", "filepos": "[line:8:5]", "name": "2", - "target": "bar.example.com.", + "name_unicode": "1.2.3.2", + "rdata": { + "Ptr": "bar.example.com." + }, "ttl": 300, - "type": "PTR" + "type": "PTR", + "typenum": 12 }, { + "comparablev3": "baz.example.com.", "filepos": "[line:9:5]", "meta": { "skip_fqdn_check": "true" }, "name": "3", - "target": "baz.example.com.", + "name_unicode": "3.3.2.1.in-addr.arpa", + "rdata": { + "Ptr": "baz.example.com." + }, "ttl": 300, - "type": "PTR" + "type": "PTR", + "typenum": 12 }, { + "comparablev3": "silly.example.com.", "filepos": "[line:14:5]", "name": "4", + "name_unicode": "4", + "rdata": { + "Ptr": "silly.example.com." + }, "subdomain": "4", - "target": "silly.example.com.", "ttl": 300, - "type": "PTR" + "type": "PTR", + "typenum": 12 }, { + "comparablev3": "willy.example.com.", "filepos": "[line:17:5]", "name": "5", + "name_unicode": "1.2.3.5", + "rdata": { + "Ptr": "willy.example.com." + }, "subdomain": "5", - "target": "willy.example.com.", "ttl": 300, - "type": "PTR" + "type": "PTR", + "typenum": 12 }, { + "comparablev3": "billy.example.com.", "filepos": "[line:20:5]", "name": "6", + "name_unicode": "6.3.2.1.in-addr.arpa", + "rdata": { + "Ptr": "billy.example.com." + }, "subdomain": "6", - "target": "billy.example.com.", "ttl": 300, - "type": "PTR" + "type": "PTR", + "typenum": 12 }, { + "comparablev3": "my.example.com.", "filepos": "[line:24:5]", "name": "7", - "target": "my.example.com.", + "name_unicode": "7", + "rdata": { + "Ptr": "my.example.com." + }, "ttl": 300, - "type": "PTR" + "type": "PTR", + "typenum": 12 }, { + "comparablev3": "fair.example.com.", "filepos": "[line:27:5]", "name": "8", - "target": "fair.example.com.", + "name_unicode": "1.2.3.8", + "rdata": { + "Ptr": "fair.example.com." + }, "ttl": 300, - "type": "PTR" + "type": "PTR", + "typenum": 12 }, { + "comparablev3": "lady.example.com.", "filepos": "[line:30:5]", "meta": { "skip_fqdn_check": "true" }, "name": "9", - "target": "lady.example.com.", + "name_unicode": "9.3.2.1.in-addr.arpa", + "rdata": { + "Ptr": "lady.example.com." + }, "ttl": 300, - "type": "PTR" + "type": "PTR", + "typenum": 12 } ], "registrar": "none", diff --git a/pkg/js/parse_tests/033-revextend.json b/pkg/js/parse_tests/033-revextend.json index 614402920f..8f828bae35 100644 --- a/pkg/js/parse_tests/033-revextend.json +++ b/pkg/js/parse_tests/033-revextend.json @@ -10,27 +10,32 @@ "dnsProviders": { "bind": -1 }, - "meta": { - "dnscontrol_nameraw": "8.9.in-addr.arpa", - "dnscontrol_nameunicode": "8.9.in-addr.arpa", - "dnscontrol_uniquename": "8.9.in-addr.arpa" - }, "name": "8.9.in-addr.arpa", "records": [ { + "comparablev3": "ns1.example.com.", "filepos": "[line:8:5]", "name": "1.2", - "target": "ns1.example.com.", + "name_unicode": "1.2.8.9.in-addr.arpa", + "rdata": { + "Ns": "ns1.example.com." + }, "ttl": 300, - "type": "NS" + "type": "NS", + "typenum": 2 }, { + "comparablev3": "ns2.example.org.", "filepos": "[line:11:5]", "name": "6.7", + "name_unicode": "6.7.8.9.in-addr.arpa", + "rdata": { + "Ns": "ns2.example.org." + }, "subdomain": "7", - "target": "ns2.example.org.", "ttl": 300, - "type": "NS" + "type": "NS", + "typenum": 2 } ], "registrar": "none", @@ -40,35 +45,45 @@ "dnsProviders": { "bind": -1 }, - "meta": { - "dnscontrol_nameraw": "example.com", - "dnscontrol_nameunicode": "example.com", - "dnscontrol_uniquename": "example.com" - }, "name": "example.com", "records": [ { + "comparablev3": "ns1.fooexample.com.", "filepos": "[line:17:5]", "name": "foo", - "target": "ns1.fooexample.com.", + "name_unicode": "foo", + "rdata": { + "Ns": "ns1.fooexample.com." + }, "ttl": 300, - "type": "NS" + "type": "NS", + "typenum": 2 }, { + "comparablev3": "ns1.example.com.", "filepos": "[line:20:5]", "name": "more.lego", + "name_unicode": "more.lego", + "rdata": { + "Ns": "ns1.example.com." + }, "subdomain": "lego", - "target": "ns1.example.com.", "ttl": 300, - "type": "NS" + "type": "NS", + "typenum": 2 }, { + "comparablev3": "ns1.lego.example.com.", "filepos": "[line:21:5]", "name": "short.lego", + "name_unicode": "short.lego", + "rdata": { + "Ns": "ns1.lego.example.com." + }, "subdomain": "lego", - "target": "ns1.lego.example.com.", "ttl": 300, - "type": "NS" + "type": "NS", + "typenum": 2 } ], "registrar": "none", diff --git a/pkg/js/parse_tests/034-nameserver-ttl.json b/pkg/js/parse_tests/034-nameserver-ttl.json index 224186569f..4ef58e1d29 100644 --- a/pkg/js/parse_tests/034-nameserver-ttl.json +++ b/pkg/js/parse_tests/034-nameserver-ttl.json @@ -4,9 +4,6 @@ { "dnsProviders": {}, "meta": { - "dnscontrol_nameraw": "foo.com", - "dnscontrol_nameunicode": "foo.com", - "dnscontrol_uniquename": "foo.com", "ns_ttl": "86400" }, "name": "foo.com", @@ -17,9 +14,6 @@ { "dnsProviders": {}, "meta": { - "dnscontrol_nameraw": "bar.com", - "dnscontrol_nameunicode": "bar.com", - "dnscontrol_uniquename": "bar.com", "ns_ttl": "300" }, "name": "bar.com", diff --git a/pkg/js/parse_tests/035-naptr.json b/pkg/js/parse_tests/035-naptr.json index 0ffb0898c2..fcf970a4ce 100644 --- a/pkg/js/parse_tests/035-naptr.json +++ b/pkg/js/parse_tests/035-naptr.json @@ -3,60 +3,75 @@ "domains": [ { "dnsProviders": {}, - "meta": { - "dnscontrol_nameraw": "foo.com", - "dnscontrol_nameunicode": "foo.com", - "dnscontrol_uniquename": "foo.com" - }, "name": "foo.com", "records": [ { + "comparablev3": "100 10 \"U\" \"E2U+sip\" \"!^.*$!sip:customer-service@example.com!\" example", "filepos": "[line:2:5]", "name": "@", - "naptrflags": "U", - "naptrorder": 100, - "naptrpreference": 10, - "naptrregexp": "!^.*$!sip:customer-service@example.com!", - "naptrservice": "E2U+sip", - "target": "example", + "name_unicode": "@", + "rdata": { + "Flags": "U", + "Order": 100, + "Preference": 10, + "Regexp": "!^.*$!sip:customer-service@example.com!", + "Replacement": "example", + "Service": "E2U+sip" + }, "ttl": 300, - "type": "NAPTR" + "type": "NAPTR", + "typenum": 35 }, { + "comparablev3": "102 10 \"U\" \"E2U+email\" \"!^.*$!mailto:information@example.com!\" example", "filepos": "[line:3:5]", "name": "@", - "naptrflags": "U", - "naptrorder": 102, - "naptrpreference": 10, - "naptrregexp": "!^.*$!mailto:information@example.com!", - "naptrservice": "E2U+email", - "target": "example", + "name_unicode": "@", + "rdata": { + "Flags": "U", + "Order": 102, + "Preference": 10, + "Regexp": "!^.*$!mailto:information@example.com!", + "Replacement": "example", + "Service": "E2U+email" + }, "ttl": 300, - "type": "NAPTR" + "type": "NAPTR", + "typenum": 35 }, { + "comparablev3": "103 10 \"U\" \"E2U+email\" \"!^.*$!mailto:information@example.com!\" .", "filepos": "[line:4:5]", "name": "@", - "naptrflags": "U", - "naptrorder": 103, - "naptrpreference": 10, - "naptrregexp": "!^.*$!mailto:information@example.com!", - "naptrservice": "E2U+email", - "target": ".", + "name_unicode": "@", + "rdata": { + "Flags": "U", + "Order": 103, + "Preference": 10, + "Regexp": "!^.*$!mailto:information@example.com!", + "Replacement": ".", + "Service": "E2U+email" + }, "ttl": 300, - "type": "NAPTR" + "type": "NAPTR", + "typenum": 35 }, { + "comparablev3": "104 10 \"U\" \"E2U+email\" \"!^.*$!mailto:information@example.com!\" .", "filepos": "[line:5:5]", "name": "@", - "naptrflags": "U", - "naptrorder": 104, - "naptrpreference": 10, - "naptrregexp": "!^.*$!mailto:information@example.com!", - "naptrservice": "E2U+email", - "target": ".", + "name_unicode": "@", + "rdata": { + "Flags": "U", + "Order": 104, + "Preference": 10, + "Regexp": "!^.*$!mailto:information@example.com!", + "Replacement": ".", + "Service": "E2U+email" + }, "ttl": 300, - "type": "NAPTR" + "type": "NAPTR", + "typenum": 35 } ], "registrar": "none", diff --git a/pkg/js/parse_tests/036-dextendcf.json b/pkg/js/parse_tests/036-dextendcf.json index 9c31e016c2..9769e92b28 100644 --- a/pkg/js/parse_tests/036-dextendcf.json +++ b/pkg/js/parse_tests/036-dextendcf.json @@ -10,82 +10,96 @@ "dnsProviders": { "Cloudflare": -1 }, - "meta": { - "dnscontrol_nameraw": "foo.com", - "dnscontrol_nameunicode": "foo.com", - "dnscontrol_uniquename": "foo.com" - }, "name": "foo.com", "records": [ { + "comparablev3": "test3.foo.com \"test-worker\"", "filepos": "[line:11:5]", "meta": { "orig_custom_type": "CF_WORKER_ROUTE" }, "name": "@", - "target": "test3.foo.com,test-worker", + "name_unicode": "@", + "rdata": { + "Then": "test-worker", + "When": "test3.foo.com" + }, "ttl": 300, - "type": "CF_WORKER_ROUTE" + "type": "CF_WORKER_ROUTE", + "typenum": 65288 }, { - "comparable": "name=(301,test1.foo.com,https://goo.com/$1) code=(301) when=(http.host eq \"test1.foo.com\" and http.request.uri.path eq \"/\") then=(concat(\"https://goo.com\", http.request.uri.path))", - "fields": { - "code": 301, - "sr_display": "name=(301,test1.foo.com,https://goo.com/$1) code=(301) when=(http.host eq \"test1.foo.com\" and http.request.uri.path eq \"/\") then=(concat(\"https://goo.com\", http.request.uri.path))", - "sr_name": "301,test1.foo.com,https://goo.com/$1", - "sr_then": "concat(\"https://goo.com\", http.request.uri.path)", - "sr_when": "http.host eq \"test1.foo.com\" and http.request.uri.path eq \"/\"" - }, + "comparablev3": "\"301,test1.foo.com,https://goo.com/$1\" 301 \"http.host eq \\\"test1.foo.com\\\" and http.request.uri.path eq \\\"/\\\"\" \"concat(\\\"https://goo.com\\\", http.request.uri.path)\"", "filepos": "[line:9:5]", "name": "@", - "name_raw": "@", "name_unicode": "@", - "target": "name=(301,test1.foo.com,https://goo.com/$1) code=(301) when=(http.host eq \"test1.foo.com\" and http.request.uri.path eq \"/\") then=(concat(\"https://goo.com\", http.request.uri.path))", + "rdata": { + "Code": 301, + "RT_SRRRulesetID": "", + "RT_SRRRulesetRuleID": "", + "SRName": "301,test1.foo.com,https://goo.com/$1", + "SRThen": "concat(\"https://goo.com\", http.request.uri.path)", + "SRWhen": "http.host eq \"test1.foo.com\" and http.request.uri.path eq \"/\"" + }, "ttl": 1, "type": "CLOUDFLAREAPI_SINGLE_REDIRECT", - "zonfefilepartial": "name=(301,test1.foo.com,https://goo.com/$1) code=(301) when=(http.host eq \"test1.foo.com\" and http.request.uri.path eq \"/\") then=(concat(\"https://goo.com\", http.request.uri.path))" + "typenum": 65289 }, { - "comparable": "name=(302,test2.foo.com,https://goo.com/$1) code=(302) when=(http.host eq \"test2.foo.com\" and http.request.uri.path eq \"/\") then=(concat(\"https://goo.com\", http.request.uri.path))", - "fields": { - "code": 302, - "sr_display": "name=(302,test2.foo.com,https://goo.com/$1) code=(302) when=(http.host eq \"test2.foo.com\" and http.request.uri.path eq \"/\") then=(concat(\"https://goo.com\", http.request.uri.path))", - "sr_name": "302,test2.foo.com,https://goo.com/$1", - "sr_then": "concat(\"https://goo.com\", http.request.uri.path)", - "sr_when": "http.host eq \"test2.foo.com\" and http.request.uri.path eq \"/\"" - }, + "comparablev3": "\"302,test2.foo.com,https://goo.com/$1\" 302 \"http.host eq \\\"test2.foo.com\\\" and http.request.uri.path eq \\\"/\\\"\" \"concat(\\\"https://goo.com\\\", http.request.uri.path)\"", "filepos": "[line:10:5]", "name": "@", - "name_raw": "@", "name_unicode": "@", - "target": "name=(302,test2.foo.com,https://goo.com/$1) code=(302) when=(http.host eq \"test2.foo.com\" and http.request.uri.path eq \"/\") then=(concat(\"https://goo.com\", http.request.uri.path))", + "rdata": { + "Code": 302, + "RT_SRRRulesetID": "", + "RT_SRRRulesetRuleID": "", + "SRName": "302,test2.foo.com,https://goo.com/$1", + "SRThen": "concat(\"https://goo.com\", http.request.uri.path)", + "SRWhen": "http.host eq \"test2.foo.com\" and http.request.uri.path eq \"/\"" + }, "ttl": 1, "type": "CLOUDFLAREAPI_SINGLE_REDIRECT", - "zonfefilepartial": "name=(302,test2.foo.com,https://goo.com/$1) code=(302) when=(http.host eq \"test2.foo.com\" and http.request.uri.path eq \"/\") then=(concat(\"https://goo.com\", http.request.uri.path))" + "typenum": 65289 }, { + "comparablev3": "10.2.3.1", "filepos": "[line:6:5]", "name": "test1.foo.com.sub", + "name_unicode": "test1.foo.com.sub", + "rdata": { + "Addr": "10.2.3.1" + }, "subdomain": "sub", - "target": "10.2.3.1", "ttl": 300, - "type": "A" + "type": "A", + "typenum": 1 }, { + "comparablev3": "10.2.3.2", "filepos": "[line:7:5]", "name": "test2.foo.com.sub", + "name_unicode": "test2.foo.com.sub", + "rdata": { + "Addr": "10.2.3.2" + }, "subdomain": "sub", - "target": "10.2.3.2", "ttl": 300, - "type": "A" + "type": "A", + "typenum": 1 }, { + "comparablev3": "10.2.3.3", "filepos": "[line:8:5]", "name": "test3.foo.com.sub", + "name_unicode": "test3.foo.com.sub", + "rdata": { + "Addr": "10.2.3.3" + }, "subdomain": "sub", - "target": "10.2.3.3", "ttl": 300, - "type": "A" + "type": "A", + "typenum": 1 } ], "registrar": "Third-Party", diff --git a/pkg/js/parse_tests/036-dextendcf/foo.com.zone b/pkg/js/parse_tests/036-dextendcf/foo.com.zone index 10acd60538..860ae2e5e8 100644 --- a/pkg/js/parse_tests/036-dextendcf/foo.com.zone +++ b/pkg/js/parse_tests/036-dextendcf/foo.com.zone @@ -1,7 +1,7 @@ $TTL 300 -;@ IN CF_WORKER_ROUTE test3.foo.com,test-worker -;@ 1 IN CLOUDFLAREAPI_SINGLE_REDIRECT name=(301,test1.foo.com,https://goo.com/$1) code=(301) when=(http.host eq "test1.foo.com" and http.request.uri.path eq "/") then=(concat("https://goo.com", http.request.uri.path)) -;@ 1 IN CLOUDFLAREAPI_SINGLE_REDIRECT name=(302,test2.foo.com,https://goo.com/$1) code=(302) when=(http.host eq "test2.foo.com" and http.request.uri.path eq "/") then=(concat("https://goo.com", http.request.uri.path)) +@ IN CF_WORKER_ROUTE test3.foo.com "test-worker" + 1 IN CLOUDFLAREAPI_SINGLE_REDIRECT "301,test1.foo.com,https://goo.com/$1" 301 "http.host eq \"test1.foo.com\" and http.request.uri.path eq \"/\"" "concat(\"https://goo.com\", http.request.uri.path)" + 1 IN CLOUDFLAREAPI_SINGLE_REDIRECT "302,test2.foo.com,https://goo.com/$1" 302 "http.host eq \"test2.foo.com\" and http.request.uri.path eq \"/\"" "concat(\"https://goo.com\", http.request.uri.path)" test1.foo.com.sub IN A 10.2.3.1 test2.foo.com.sub IN A 10.2.3.2 test3.foo.com.sub IN A 10.2.3.3 diff --git a/pkg/js/parse_tests/037-splithor.json b/pkg/js/parse_tests/037-splithor.json index 8e854b303b..d97ba7b625 100644 --- a/pkg/js/parse_tests/037-splithor.json +++ b/pkg/js/parse_tests/037-splithor.json @@ -18,26 +18,31 @@ "dnsProviders": { "otherconfig": -1 }, - "meta": { - "dnscontrol_nameraw": "example.com", - "dnscontrol_nameunicode": "example.com", - "dnscontrol_uniquename": "example.com" - }, "name": "example.com", "records": [ { + "comparablev3": "3.3.3.3", "filepos": "[line:7:5]", "name": "main", - "target": "3.3.3.3", + "name_unicode": "main", + "rdata": { + "Addr": "3.3.3.3" + }, "ttl": 300, - "type": "A" + "type": "A", + "typenum": 1 }, { + "comparablev3": "33.33.33.33", "filepos": "[line:19:5]", "name": "www", - "target": "33.33.33.33", + "name_unicode": "www", + "rdata": { + "Addr": "33.33.33.33" + }, "ttl": 300, - "type": "A" + "type": "A", + "typenum": 1 } ], "registrar": "Third-Party", @@ -47,27 +52,31 @@ "dnsProviders": { "Cloudflare": -1 }, - "meta": { - "dnscontrol_nameraw": "example.com", - "dnscontrol_nameunicode": "example.com", - "dnscontrol_tag": "inside", - "dnscontrol_uniquename": "example.com!inside" - }, "name": "example.com", "records": [ { + "comparablev3": "1.1.1.1", "filepos": "[line:11:5]", "name": "main", - "target": "1.1.1.1", + "name_unicode": "main", + "rdata": { + "Addr": "1.1.1.1" + }, "ttl": 300, - "type": "A" + "type": "A", + "typenum": 1 }, { + "comparablev3": "11.11.11.11", "filepos": "[line:23:5]", "name": "main", - "target": "11.11.11.11", + "name_unicode": "main", + "rdata": { + "Addr": "11.11.11.11" + }, "ttl": 300, - "type": "A" + "type": "A", + "typenum": 1 } ], "registrar": "Third-Party", @@ -78,20 +87,19 @@ "dnsProviders": { "bind": -1 }, - "meta": { - "dnscontrol_nameraw": "example.com", - "dnscontrol_nameunicode": "example.com", - "dnscontrol_tag": "outside", - "dnscontrol_uniquename": "example.com!outside" - }, "name": "example.com", "records": [ { + "comparablev3": "8.8.8.8", "filepos": "[line:15:5]", "name": "main", - "target": "8.8.8.8", + "name_unicode": "main", + "rdata": { + "Addr": "8.8.8.8" + }, "ttl": 300, - "type": "A" + "type": "A", + "typenum": 1 } ], "registrar": "Third-Party", @@ -102,26 +110,31 @@ "dnsProviders": { "bind": -1 }, - "meta": { - "dnscontrol_nameraw": "example.net", - "dnscontrol_nameunicode": "example.net", - "dnscontrol_uniquename": "example.net" - }, "name": "example.net", "records": [ { + "comparablev3": "203.0.113.12", "filepos": "[line:31:5]", "name": "main", - "target": "203.0.113.12", + "name_unicode": "main", + "rdata": { + "Addr": "203.0.113.12" + }, "ttl": 300, - "type": "A" + "type": "A", + "typenum": 1 }, { + "comparablev3": "203.0.113.1", "filepos": "[line:27:5]", "name": "www", - "target": "203.0.113.1", + "name_unicode": "www", + "rdata": { + "Addr": "203.0.113.1" + }, "ttl": 300, - "type": "A" + "type": "A", + "typenum": 1 } ], "registrar": "Third-Party", @@ -131,34 +144,43 @@ "dnsProviders": { "Cloudflare": -1 }, - "meta": { - "dnscontrol_nameraw": "example.net", - "dnscontrol_nameunicode": "example.net", - "dnscontrol_tag": "inside", - "dnscontrol_uniquename": "example.net!inside" - }, "name": "example.net", "records": [ { + "comparablev3": "192.0.2.1", "filepos": "[line:36:5]", "name": "main", - "target": "192.0.2.1", + "name_unicode": "main", + "rdata": { + "Addr": "192.0.2.1" + }, "ttl": 300, - "type": "A" + "type": "A", + "typenum": 1 }, { + "comparablev3": "203.0.113.12", "filepos": "[line:31:5]", "name": "main", - "target": "203.0.113.12", + "name_unicode": "main", + "rdata": { + "Addr": "203.0.113.12" + }, "ttl": 300, - "type": "A" + "type": "A", + "typenum": 1 }, { + "comparablev3": "203.0.113.1", "filepos": "[line:27:5]", "name": "www", - "target": "203.0.113.1", + "name_unicode": "www", + "rdata": { + "Addr": "203.0.113.1" + }, "ttl": 300, - "type": "A" + "type": "A", + "typenum": 1 } ], "registrar": "Third-Party", @@ -169,34 +191,43 @@ "dnsProviders": { "bind": -1 }, - "meta": { - "dnscontrol_nameraw": "example.net", - "dnscontrol_nameunicode": "example.net", - "dnscontrol_tag": "outside", - "dnscontrol_uniquename": "example.net!outside" - }, "name": "example.net", "records": [ { + "comparablev3": "203.0.113.1", "filepos": "[line:41:5]", "name": "main", - "target": "203.0.113.1", + "name_unicode": "main", + "rdata": { + "Addr": "203.0.113.1" + }, "ttl": 300, - "type": "A" + "type": "A", + "typenum": 1 }, { + "comparablev3": "203.0.113.12", "filepos": "[line:31:5]", "name": "main", - "target": "203.0.113.12", + "name_unicode": "main", + "rdata": { + "Addr": "203.0.113.12" + }, "ttl": 300, - "type": "A" + "type": "A", + "typenum": 1 }, { + "comparablev3": "203.0.113.1", "filepos": "[line:27:5]", "name": "www", - "target": "203.0.113.1", + "name_unicode": "www", + "rdata": { + "Addr": "203.0.113.1" + }, "ttl": 300, - "type": "A" + "type": "A", + "typenum": 1 } ], "registrar": "Third-Party", @@ -207,26 +238,31 @@ "dnsProviders": { "bind": -1 }, - "meta": { - "dnscontrol_nameraw": "empty.example.net", - "dnscontrol_nameunicode": "empty.example.net", - "dnscontrol_uniquename": "empty.example.net" - }, "name": "empty.example.net", "records": [ { + "comparablev3": "203.0.113.22", "filepos": "[line:49:5]", "name": "main", - "target": "203.0.113.22", + "name_unicode": "main", + "rdata": { + "Addr": "203.0.113.22" + }, "ttl": 300, - "type": "A" + "type": "A", + "typenum": 1 }, { + "comparablev3": "203.0.113.2", "filepos": "[line:45:5]", "name": "www", - "target": "203.0.113.2", + "name_unicode": "www", + "rdata": { + "Addr": "203.0.113.2" + }, "ttl": 300, - "type": "A" + "type": "A", + "typenum": 1 } ], "registrar": "Third-Party", @@ -236,26 +272,31 @@ "dnsProviders": { "bind": -1 }, - "meta": { - "dnscontrol_nameraw": "example-b.net", - "dnscontrol_nameunicode": "example-b.net", - "dnscontrol_uniquename": "example-b.net!" - }, "name": "example-b.net", "records": [ { + "comparablev3": "203.0.113.12", "filepos": "[line:57:5]", "name": "main", - "target": "203.0.113.12", + "name_unicode": "main", + "rdata": { + "Addr": "203.0.113.12" + }, "ttl": 300, - "type": "A" + "type": "A", + "typenum": 1 }, { + "comparablev3": "203.0.113.1", "filepos": "[line:53:5]", "name": "www", - "target": "203.0.113.1", + "name_unicode": "www", + "rdata": { + "Addr": "203.0.113.1" + }, "ttl": 300, - "type": "A" + "type": "A", + "typenum": 1 } ], "registrar": "Third-Party", diff --git a/pkg/js/parse_tests/038-soa.json b/pkg/js/parse_tests/038-soa.json index 5c39df9cb4..c2c37031b4 100644 --- a/pkg/js/parse_tests/038-soa.json +++ b/pkg/js/parse_tests/038-soa.json @@ -3,24 +3,25 @@ "domains": [ { "dnsProviders": {}, - "meta": { - "dnscontrol_nameraw": "foo.com", - "dnscontrol_nameunicode": "foo.com", - "dnscontrol_uniquename": "foo.com" - }, "name": "foo.com", "records": [ { + "comparablev3": "ns1.foo.com. admin.foo.com X 3600 900 604800 86400", "filepos": "[line:2:5]", "name": "@", - "soaexpire": 604800, - "soambox": "admin.foo.com", - "soaminttl": 86400, - "soarefresh": 3600, - "soaretry": 900, - "target": "ns1.foo.com.", + "name_unicode": "@", + "rdata": { + "Expire": 604800, + "Mbox": "admin.foo.com", + "Minttl": 86400, + "Ns": "ns1.foo.com.", + "Refresh": 3600, + "Retry": 900, + "Serial": 0 + }, "ttl": 300, - "type": "SOA" + "type": "SOA", + "typenum": 6 } ], "registrar": "none", diff --git a/pkg/js/parse_tests/039-include.json b/pkg/js/parse_tests/039-include.json index 3e985ff897..acdf061ed8 100644 --- a/pkg/js/parse_tests/039-include.json +++ b/pkg/js/parse_tests/039-include.json @@ -10,20 +10,19 @@ "dnsProviders": { "Cloudflare": -1 }, - "meta": { - "dnscontrol_nameraw": "foo.com", - "dnscontrol_nameunicode": "foo.com", - "dnscontrol_tag": "external", - "dnscontrol_uniquename": "foo.com!external" - }, "name": "foo.com", "records": [ { + "comparablev3": "1.2.3.4", "filepos": "[line:5:5]", "name": "@", - "target": "1.2.3.4", + "name_unicode": "@", + "rdata": { + "Addr": "1.2.3.4" + }, "ttl": 300, - "type": "A" + "type": "A", + "typenum": 1 } ], "registrar": "Third-Party", @@ -34,27 +33,31 @@ "dnsProviders": { "Cloudflare": -1 }, - "meta": { - "dnscontrol_nameraw": "foo.com", - "dnscontrol_nameunicode": "foo.com", - "dnscontrol_tag": "internal", - "dnscontrol_uniquename": "foo.com!internal" - }, "name": "foo.com", "records": [ { + "comparablev3": "1.2.3.4", "filepos": "[line:5:5]", "name": "@", - "target": "1.2.3.4", + "name_unicode": "@", + "rdata": { + "Addr": "1.2.3.4" + }, "ttl": 300, - "type": "A" + "type": "A", + "typenum": 1 }, { + "comparablev3": "127.0.0.1", "filepos": "[line:10:5]", "name": "local", - "target": "127.0.0.1", + "name_unicode": "local", + "rdata": { + "Addr": "127.0.0.1" + }, "ttl": 300, - "type": "A" + "type": "A", + "typenum": 1 } ], "registrar": "Third-Party", diff --git a/pkg/js/parse_tests/040-cfWorkerRoute.json b/pkg/js/parse_tests/040-cfWorkerRoute.json index 82c9e51c8e..0456118b12 100644 --- a/pkg/js/parse_tests/040-cfWorkerRoute.json +++ b/pkg/js/parse_tests/040-cfWorkerRoute.json @@ -3,22 +3,23 @@ "domains": [ { "dnsProviders": {}, - "meta": { - "dnscontrol_nameraw": "foo.com", - "dnscontrol_nameunicode": "foo.com", - "dnscontrol_uniquename": "foo.com" - }, "name": "foo.com", "records": [ { + "comparablev3": "test.foo.com \"test-worker\"", "filepos": "[line:2:5]", "meta": { "orig_custom_type": "CF_WORKER_ROUTE" }, "name": "@", - "target": "test.foo.com,test-worker", + "name_unicode": "@", + "rdata": { + "Then": "test-worker", + "When": "test.foo.com" + }, "ttl": 300, - "type": "CF_WORKER_ROUTE" + "type": "CF_WORKER_ROUTE", + "typenum": 65288 } ], "registrar": "none", diff --git a/pkg/js/parse_tests/040-cfWorkerRoute/foo.com.zone b/pkg/js/parse_tests/040-cfWorkerRoute/foo.com.zone index 2dca479d55..54c67c7ff2 100644 --- a/pkg/js/parse_tests/040-cfWorkerRoute/foo.com.zone +++ b/pkg/js/parse_tests/040-cfWorkerRoute/foo.com.zone @@ -1,2 +1,2 @@ $TTL 300 -;@ IN CF_WORKER_ROUTE test.foo.com,test-worker +@ IN CF_WORKER_ROUTE test.foo.com "test-worker" diff --git a/pkg/js/parse_tests/040-r53-zone.js b/pkg/js/parse_tests/040-r53-zone.js index 5f6b0963c7..de540bcc2b 100644 --- a/pkg/js/parse_tests/040-r53-zone.js +++ b/pkg/js/parse_tests/040-r53-zone.js @@ -3,5 +3,5 @@ D( 'foo.com!internal', 'none', R53_ZONE('Z2FTEDLFRTF'), - R53_ALIAS('atest', 'A', 'foo.com.', R53_ZONE('Z2FTEDLFRTZ')) + R53_ALIAS('atest', 'A', 'foo.com.', R53_ZONE('Z2FTEDLFRTZ')), ); diff --git a/pkg/js/parse_tests/040-r53-zone.json b/pkg/js/parse_tests/040-r53-zone.json index e2eece7e68..444dd64ebd 100644 --- a/pkg/js/parse_tests/040-r53-zone.json +++ b/pkg/js/parse_tests/040-r53-zone.json @@ -4,9 +4,6 @@ { "dnsProviders": {}, "meta": { - "dnscontrol_nameraw": "foo.com", - "dnscontrol_nameunicode": "foo.com", - "dnscontrol_uniquename": "foo.com", "zone_id": "Z2FTEDLFRTZ" }, "name": "foo.com", @@ -17,28 +14,27 @@ { "dnsProviders": {}, "meta": { - "dnscontrol_nameraw": "foo.com", - "dnscontrol_nameunicode": "foo.com", - "dnscontrol_tag": "internal", - "dnscontrol_uniquename": "foo.com!internal", "zone_id": "Z2FTEDLFRTF" }, "name": "foo.com", "records": [ { + "comparablev3": "A foo.com. false Z2FTEDLFRTZ", "filepos": "[line:6:5]", "meta": { "orig_custom_type": "R53_ALIAS" }, "name": "atest", - "r53_alias": { - "evaluate_target_health": "false", - "type": "A", - "zone_id": "Z2FTEDLFRTZ" + "name_unicode": "atest", + "rdata": { + "AliasType": "A", + "EvalTargetHealth": "false", + "Target": "foo.com.", + "ZoneID": "Z2FTEDLFRTZ" }, - "target": "foo.com.", "ttl": 300, - "type": "R53_ALIAS" + "type": "R53_ALIAS", + "typenum": 65298 } ], "registrar": "none", diff --git a/pkg/js/parse_tests/043-safety.json b/pkg/js/parse_tests/043-safety.json index 8c0dccc9fa..fec26c96c4 100644 --- a/pkg/js/parse_tests/043-safety.json +++ b/pkg/js/parse_tests/043-safety.json @@ -3,11 +3,6 @@ "domains": [ { "dnsProviders": {}, - "meta": { - "dnscontrol_nameraw": "unsafe.com", - "dnscontrol_nameunicode": "unsafe.com", - "dnscontrol_uniquename": "unsafe.com" - }, "name": "unsafe.com", "records": [], "registrar": "none", @@ -16,11 +11,6 @@ }, { "dnsProviders": {}, - "meta": { - "dnscontrol_nameraw": "safe.com", - "dnscontrol_nameunicode": "safe.com", - "dnscontrol_uniquename": "safe.com" - }, "name": "safe.com", "records": [], "registrar": "none", diff --git a/pkg/js/parse_tests/044-ensureabsent.json b/pkg/js/parse_tests/044-ensureabsent.json index de0632ecf3..7bd121e311 100644 --- a/pkg/js/parse_tests/044-ensureabsent.json +++ b/pkg/js/parse_tests/044-ensureabsent.json @@ -3,27 +3,31 @@ "domains": [ { "dnsProviders": {}, - "meta": { - "dnscontrol_nameraw": "example.com", - "dnscontrol_nameunicode": "example.com", - "dnscontrol_uniquename": "example.com" - }, "name": "example.com", "records": [ { + "comparablev3": "2.2.2.2", + "filepos": "[line:3:5]", + "name": "helper", + "name_unicode": "helper", + "rdata": { + "Addr": "2.2.2.2" + }, + "ttl": 300, + "type": "A", + "typenum": 1 + }, + { + "comparablev3": "1.1.1.1", "filepos": "[line:2:5]", "name": "normal", - "target": "1.1.1.1", + "name_unicode": "normal", + "rdata": { + "Addr": "1.1.1.1" + }, "ttl": 300, - "type": "A" - } - ], - "recordsabsent": [ - { - "filepos": "[line:3:5]", - "name": "helper", - "target": "2.2.2.2", - "type": "A" + "type": "A", + "typenum": 1 } ], "registrar": "none", diff --git a/pkg/js/parse_tests/045-loc.js b/pkg/js/parse_tests/045-loc.js index 2c5f5f7afc..9c89333fb4 100644 --- a/pkg/js/parse_tests/045-loc.js +++ b/pkg/js/parse_tests/045-loc.js @@ -7,17 +7,17 @@ D("foo.com", "none", LOC("d", 42, 21, 28.764, "N", 71, 0, 51.617, "W", -44, 2000, 0, 0), //42 21 28.764 N 71 00 51.617 W -44m 2000m LOC("d-alt-highest", 42, 21, 28.764, "N", 71, 0, 51.617, "W", 42849672.95, 2000, 0, 0), //42 21 28.764 N 71 00 51.617 W 42849672.95m 2000m LOC("d-alt-lowest", 42, 21, 28.764, "N", 71, 0, 51.617, "W", -100000.00, 2000, 0, 0), //42 21 28.764 N 71 00 51.617 W -100000.00m 2000m - LOC("d-alt-toohigh", 42, 21, 28.764, "N", 71, 0, 51.617, "W", 42849672.96, 2000, 0, 0), //42 21 28.764 N 71 00 51.617 W 42849672.95m 2000m - LOC("d-alt-toolow", 42, 21, 28.764, "N", 71, 0, 51.617, "W", -100000.01, 2000, 0, 0), //42 21 28.764 N 71 00 51.617 W -100000m 2000m + // LOC("d-alt-toohigh", 42, 21, 28.764, "N", 71, 0, 51.617, "W", 42849672.96, 2000, 0, 0), //42 21 28.764 N 71 00 51.617 W 42849672.95m 2000m + // LOC("d-alt-toolow", 42, 21, 28.764, "N", 71, 0, 51.617, "W", -100000.01, 2000, 0, 0), //42 21 28.764 N 71 00 51.617 W -100000m 2000m LOC("d-horizprecision-hi", 42, 21, 28.764, "N", 71, 0, 51.617, "W", 0, 1, 90000000, 0), //42 21 28.764 N 71 00 51.617 W 0m 1m 90000000m 0.00m - LOC("d-horizprecision-toohi", 42, 21, 28.764, "N", 71, 0, 51.617, "W", 0, 1, 98765432, 0), //42 21 28.764 N 71 00 51.617 W 0m 1m 90000000m 0.00m - LOC("d-horizprecision-toolow", 42, 21, 28.764, "N", 71, 0, 51.617, "W", 0, 1, -1, 0), //42 21 28.764 N 71 00 51.617 W 0m 1m 0m 0.00m - LOC("d-size-toohi", 42, 21, 28.764, "N", 71, 0, 51.617, "W", 0, 98765432, 0, 0), //42 21 28.764 N 71 00 51.617 W -44m 2000m - LOC("d-size-toolow", 42, 21, 28.764, "N", 71, 0, 51.617, "W", 0, -1, 0, 0), //42 21 28.764 N 71 00 51.617 W -44m 0m + // LOC("d-horizprecision-toohi", 42, 21, 28.764, "N", 71, 0, 51.617, "W", 0, 1, 98765432, 0), //42 21 28.764 N 71 00 51.617 W 0m 1m 90000000m 0.00m + // LOC("d-horizprecision-toolow", 42, 21, 28.764, "N", 71, 0, 51.617, "W", 0, 1, -1, 0), //42 21 28.764 N 71 00 51.617 W 0m 1m 0m 0.00m + // LOC("d-size-toohi", 42, 21, 28.764, "N", 71, 0, 51.617, "W", 0, 98765432, 0, 0), //42 21 28.764 N 71 00 51.617 W -44m 2000m + // LOC("d-size-toolow", 42, 21, 28.764, "N", 71, 0, 51.617, "W", 0, -1, 0, 0), //42 21 28.764 N 71 00 51.617 W -44m 0m LOC("d-size-hi", 42, 21, 28.764, "N", 71, 0, 51.617, "W", 0, 90000000, 0, 0), //42 21 28.764 N 71 00 51.617 W -44m 90000000m LOC("d-vertprecision-hi", 42, 21, 28.764, "N", 71, 0, 51.617, "W", 0, 1, 0, 90000000), //42 21 28.764 N 71 00 51.617 W 0m 1m 0.00m 90000000m - LOC("d-vertprecision-toohi", 42, 21, 28.764, "N", 71, 0, 51.617, "W", 0, 1, 0, 98765432), //42 21 28.764 N 71 00 51.617 W 0m 1m 0.00m 90000000m - LOC("d-vertprecision-toolow", 42, 21, 28.764, "N", 71, 0, 51.617, "W", 0, 1, 0, -1), //42 21 28.764 N 71 00 51.617 W 0m 1m 0.00m 0m + // LOC("d-vertprecision-toohi", 42, 21, 28.764, "N", 71, 0, 51.617, "W", 0, 1, 0, 98765432), //42 21 28.764 N 71 00 51.617 W 0m 1m 0.00m 90000000m + // LOC("d-vertprecision-toolow", 42, 21, 28.764, "N", 71, 0, 51.617, "W", 0, 1, 0, -1), //42 21 28.764 N 71 00 51.617 W 0m 1m 0.00m 0m // via the Decimal degrees to LOC builder. LOC_BUILDER_DD({ diff --git a/pkg/js/parse_tests/045-loc.json b/pkg/js/parse_tests/045-loc.json index f5d086f7f5..6b234d8df5 100644 --- a/pkg/js/parse_tests/045-loc.json +++ b/pkg/js/parse_tests/045-loc.json @@ -3,331 +3,403 @@ "domains": [ { "dnsProviders": {}, - "meta": { - "dnscontrol_nameraw": "foo.com", - "dnscontrol_nameunicode": "foo.com", - "dnscontrol_uniquename": "foo.com" - }, "name": "foo.com", "records": [ { + "comparablev3": "42 21 54.000 N 71 06 18.000 W -24m 30m 0.00m 0.00m", "filepos": "[line:3:5]", - "localtitude": 9997600, - "loclatitude": 2299997648, - "loclongitude": 1891505648, - "locsize": 51, "name": "@", - "target": "42 21 54 N 71 6 18 W -24m 30m 0m 0m", + "name_unicode": "@", + "rdata": { + "Altitude": 9997600, + "HorizPre": 0, + "Latitude": 2299997648, + "Longitude": 1891505648, + "Size": 51, + "Version": 0, + "VertPre": 0 + }, "ttl": 300, - "type": "LOC" + "type": "LOC", + "typenum": 29 }, { + "comparablev3": "42 21 43.950 N 71 05 6.340 W -24.01m 1m 200m 10m", "filepos": "[line:4:5]", - "localtitude": 9997599, - "lochorizpre": 36, - "loclatitude": 2299987600, - "loclongitude": 1891577304, - "locsize": 18, - "locvertpre": 19, "name": "a", - "target": "42 21 43.952 N 71 5 6.344 W -24.01m 1m 200m 10m", + "name_unicode": "a", + "rdata": { + "Altitude": 9997599, + "HorizPre": 36, + "Latitude": 2299987598, + "Longitude": 1891577308, + "Size": 18, + "Version": 0, + "VertPre": 19 + }, "ttl": 300, - "type": "LOC" + "type": "LOC", + "typenum": 29 }, { + "comparablev3": "52 14 5.000 N 00 08 50.000 E 10.33m 0.00m 0.00m 0.00m", "filepos": "[line:5:5]", - "localtitude": 10001033, - "loclatitude": 2335528648, - "loclongitude": 2148013648, "name": "b", - "target": "52 14 5 N 0 8 50 E 10.33m 0m 0m 0m", + "name_unicode": "b", + "rdata": { + "Altitude": 10001033, + "HorizPre": 0, + "Latitude": 2335528648, + "Longitude": 2148013648, + "Size": 0, + "Version": 0, + "VertPre": 0 + }, "ttl": 300, - "type": "LOC" + "type": "LOC", + "typenum": 29 }, { + "comparablev3": "51 30 3.030 N 00 07 28.650 W 6m 0.00m 0.00m 0.00m", "filepos": "[line:23:5]", - "localtitude": 10000600, - "loclatitude": 2332886681, - "loclongitude": 2147034997, "name": "big-ben", - "target": "51 30 3.033 N 0 7 28.651 W 6m 0m 0m 0m", + "name_unicode": "big-ben", + "rdata": { + "Altitude": 10000600, + "HorizPre": 0, + "Latitude": 2332886678, + "Longitude": 2147034998, + "Size": 0, + "Version": 0, + "VertPre": 0 + }, "ttl": 300, - "type": "LOC" + "type": "LOC", + "typenum": 29 }, { + "comparablev3": "32 07 19.000 S 116 02 25.000 E 10m 0.00m 0.00m 0.00m", "filepos": "[line:6:5]", - "localtitude": 10001000, - "loclatitude": 2031844648, - "loclongitude": 2565228648, "name": "c", - "target": "32 7 19 S 116 2 25 E 10m 0m 0m 0m", + "name_unicode": "c", + "rdata": { + "Altitude": 10001000, + "HorizPre": 0, + "Latitude": 2031844648, + "Longitude": 2565228648, + "Size": 0, + "Version": 0, + "VertPre": 0 + }, "ttl": 300, - "type": "LOC" + "type": "LOC", + "typenum": 29 }, { + "comparablev3": "42 21 28.760 N 71 00 51.620 W -44m 2000m 0.00m 0.00m", "filepos": "[line:7:5]", - "localtitude": 9995600, - "loclatitude": 2299972412, - "loclongitude": 1891832031, - "locsize": 37, "name": "d", - "target": "42 21 28.764 N 71 0 51.617 W -44m 2000m 0m 0m", + "name_unicode": "d", + "rdata": { + "Altitude": 9995600, + "HorizPre": 0, + "Latitude": 2299972408, + "Longitude": 1891832028, + "Size": 37, + "Version": 0, + "VertPre": 0 + }, "ttl": 300, - "type": "LOC" + "type": "LOC", + "typenum": 29 }, { + "comparablev3": "42 21 28.760 N 71 00 51.620 W 42849672.95m 2000m 0.00m 0.00m", "filepos": "[line:8:5]", - "localtitude": 4294967295, - "loclatitude": 2299972412, - "loclongitude": 1891832031, - "locsize": 37, "name": "d-alt-highest", - "target": "42 21 28.764 N 71 0 51.617 W 42849672.95m 2000m 0m 0m", + "name_unicode": "d-alt-highest", + "rdata": { + "Altitude": 4294967295, + "HorizPre": 0, + "Latitude": 2299972408, + "Longitude": 1891832028, + "Size": 37, + "Version": 0, + "VertPre": 0 + }, "ttl": 300, - "type": "LOC" + "type": "LOC", + "typenum": 29 }, { + "comparablev3": "42 21 28.760 N 71 00 51.620 W -100000m 2000m 0.00m 0.00m", "filepos": "[line:9:5]", - "loclatitude": 2299972412, - "loclongitude": 1891832031, - "locsize": 37, "name": "d-alt-lowest", - "target": "42 21 28.764 N 71 0 51.617 W -100000m 2000m 0m 0m", + "name_unicode": "d-alt-lowest", + "rdata": { + "Altitude": 0, + "HorizPre": 0, + "Latitude": 2299972408, + "Longitude": 1891832028, + "Size": 37, + "Version": 0, + "VertPre": 0 + }, "ttl": 300, - "type": "LOC" - }, - { - "filepos": "[line:10:5]", - "localtitude": 4294967295, - "loclatitude": 2299972412, - "loclongitude": 1891832031, - "locsize": 37, - "name": "d-alt-toohigh", - "target": "42 21 28.764 N 71 0 51.617 W 42849672.95m 2000m 0m 0m", - "ttl": 300, - "type": "LOC" - }, - { - "filepos": "[line:11:5]", - "loclatitude": 2299972412, - "loclongitude": 1891832031, - "locsize": 37, - "name": "d-alt-toolow", - "target": "42 21 28.764 N 71 0 51.617 W -100000m 2000m 0m 0m", - "ttl": 300, - "type": "LOC" + "type": "LOC", + "typenum": 29 }, { + "comparablev3": "42 21 28.760 N 71 00 51.620 W 0m 1m 90000000m 0.00m", "filepos": "[line:12:5]", - "localtitude": 10000000, - "lochorizpre": 153, - "loclatitude": 2299972412, - "loclongitude": 1891832031, - "locsize": 18, "name": "d-horizprecision-hi", - "target": "42 21 28.764 N 71 0 51.617 W 0m 1m 90000000m 0m", - "ttl": 300, - "type": "LOC" - }, - { - "filepos": "[line:13:5]", - "localtitude": 10000000, - "lochorizpre": 153, - "loclatitude": 2299972412, - "loclongitude": 1891832031, - "locsize": 18, - "name": "d-horizprecision-toohi", - "target": "42 21 28.764 N 71 0 51.617 W 0m 1m 90000000m 0m", - "ttl": 300, - "type": "LOC" - }, - { - "filepos": "[line:14:5]", - "localtitude": 10000000, - "loclatitude": 2299972412, - "loclongitude": 1891832031, - "locsize": 18, - "name": "d-horizprecision-toolow", - "target": "42 21 28.764 N 71 0 51.617 W 0m 1m 0m 0m", + "name_unicode": "d-horizprecision-hi", + "rdata": { + "Altitude": 10000000, + "HorizPre": 153, + "Latitude": 2299972408, + "Longitude": 1891832028, + "Size": 18, + "Version": 0, + "VertPre": 0 + }, "ttl": 300, - "type": "LOC" + "type": "LOC", + "typenum": 29 }, { + "comparablev3": "42 21 28.760 N 71 00 51.620 W 0m 90000000m 0.00m 0.00m", "filepos": "[line:17:5]", - "localtitude": 10000000, - "loclatitude": 2299972412, - "loclongitude": 1891832031, - "locsize": 153, "name": "d-size-hi", - "target": "42 21 28.764 N 71 0 51.617 W 0m 90000000m 0m 0m", + "name_unicode": "d-size-hi", + "rdata": { + "Altitude": 10000000, + "HorizPre": 0, + "Latitude": 2299972408, + "Longitude": 1891832028, + "Size": 153, + "Version": 0, + "VertPre": 0 + }, "ttl": 300, - "type": "LOC" - }, - { - "filepos": "[line:15:5]", - "localtitude": 10000000, - "loclatitude": 2299972412, - "loclongitude": 1891832031, - "locsize": 153, - "name": "d-size-toohi", - "target": "42 21 28.764 N 71 0 51.617 W 0m 90000000m 0m 0m", - "ttl": 300, - "type": "LOC" - }, - { - "filepos": "[line:16:5]", - "localtitude": 10000000, - "loclatitude": 2299972412, - "loclongitude": 1891832031, - "name": "d-size-toolow", - "target": "42 21 28.764 N 71 0 51.617 W 0m 0m 0m 0m", - "ttl": 300, - "type": "LOC" + "type": "LOC", + "typenum": 29 }, { + "comparablev3": "42 21 28.760 N 71 00 51.620 W 0m 1m 0.00m 90000000m", "filepos": "[line:18:5]", - "localtitude": 10000000, - "loclatitude": 2299972412, - "loclongitude": 1891832031, - "locsize": 18, - "locvertpre": 153, "name": "d-vertprecision-hi", - "target": "42 21 28.764 N 71 0 51.617 W 0m 1m 0m 90000000m", - "ttl": 300, - "type": "LOC" - }, - { - "filepos": "[line:19:5]", - "localtitude": 10000000, - "loclatitude": 2299972412, - "loclongitude": 1891832031, - "locsize": 18, - "locvertpre": 153, - "name": "d-vertprecision-toohi", - "target": "42 21 28.764 N 71 0 51.617 W 0m 1m 0m 90000000m", - "ttl": 300, - "type": "LOC" - }, - { - "filepos": "[line:20:5]", - "localtitude": 10000000, - "loclatitude": 2299972412, - "loclongitude": 1891832031, - "locsize": 18, - "name": "d-vertprecision-toolow", - "target": "42 21 28.764 N 71 0 51.617 W 0m 1m 0m 0m", + "name_unicode": "d-vertprecision-hi", + "rdata": { + "Altitude": 10000000, + "HorizPre": 0, + "Latitude": 2299972408, + "Longitude": 1891832028, + "Size": 18, + "Version": 0, + "VertPre": 153 + }, "ttl": 300, - "type": "LOC" + "type": "LOC", + "typenum": 29 }, { + "comparablev3": "25 14 24.000 S 153 09 0.000 E 3m 0.00m 0.00m 0.00m", "filepos": "[line:60:5]", - "localtitude": 10000300, - "loclatitude": 2056619648, - "loclongitude": 2698823648, "name": "fraser-island", - "target": "25 14 24 S 153 9 0 E 3m 0m 0m 0m", + "name_unicode": "fraser-island", + "rdata": { + "Altitude": 10000300, + "HorizPre": 0, + "Latitude": 2056619648, + "Longitude": 2698823648, + "Size": 0, + "Version": 0, + "VertPre": 0 + }, "ttl": 300, - "type": "LOC" + "type": "LOC", + "typenum": 29 }, { + "comparablev3": "53 20 40.000 N 06 17 20.000 W 300m 0.00m 0.00m 0.00m", "filepos": "[line:85:5]", - "localtitude": 10030000, - "loclatitude": 2339523648, - "loclongitude": 2124843648, "name": "guinness-brewery", - "target": "53 20 40 N 6 17 20 W 300m 0m 0m 0m", + "name_unicode": "guinness-brewery", + "rdata": { + "Altitude": 10030000, + "HorizPre": 0, + "Latitude": 2339523648, + "Longitude": 2124843648, + "Size": 0, + "Version": 0, + "VertPre": 0 + }, "ttl": 300, - "type": "LOC" + "type": "LOC", + "typenum": 29 }, { + "comparablev3": "21 30 0.000 N 158 00 0.000 W 920m 0.00m 0.00m 0.00m", "filepos": "[line:70:5]", - "localtitude": 10092000, - "loclatitude": 2224883648, - "loclongitude": 1578683648, "name": "hawaii", - "target": "21 30 0 N 158 0 0 W 920m 0m 0m 0m", + "name_unicode": "hawaii", + "rdata": { + "Altitude": 10092000, + "HorizPre": 0, + "Latitude": 2224883648, + "Longitude": 1578683648, + "Size": 0, + "Version": 0, + "VertPre": 0 + }, "ttl": 300, - "type": "LOC" + "type": "LOC", + "typenum": 29 }, { + "comparablev3": "44 27 38.000 N 110 49 41.000 W 2240m 0.00m 0.00m 0.00m", "filepos": "[line:75:5]", - "localtitude": 10224000, - "loclatitude": 2307541648, - "loclongitude": 1748502648, "name": "old-faithful", - "target": "44 27 38 N 110 49 41 W 2240m 0m 0m 0m", + "name_unicode": "old-faithful", + "rdata": { + "Altitude": 10224000, + "HorizPre": 0, + "Latitude": 2307541648, + "Longitude": 1748502648, + "Size": 0, + "Version": 0, + "VertPre": 0 + }, "ttl": 300, - "type": "LOC" + "type": "LOC", + "typenum": 29 }, { + "comparablev3": "33 51 31.000 S 151 12 51.000 E 4m 0.00m 0.00m 0.00m", "filepos": "[line:36:5]", - "localtitude": 10000400, - "loclatitude": 2025592648, - "loclongitude": 2691854648, "name": "opera-house", - "target": "33 51 31 S 151 12 51 E 4m 0m 0m 0m", + "name_unicode": "opera-house", + "rdata": { + "Altitude": 10000400, + "HorizPre": 0, + "Latitude": 2025592648, + "Longitude": 2691854648, + "Size": 0, + "Version": 0, + "VertPre": 0 + }, "ttl": 300, - "type": "LOC" + "type": "LOC", + "typenum": 29 }, { + "comparablev3": "33 51 31.000 S 151 12 51.000 E 4m 0.00m 0.00m 0.00m", "filepos": "[line:42:5]", - "localtitude": 10000400, - "loclatitude": 2025592648, - "loclongitude": 2691854648, "name": "opera-house2", - "target": "33 51 31 S 151 12 51 E 4m 0m 0m 0m", + "name_unicode": "opera-house2", + "rdata": { + "Altitude": 10000400, + "HorizPre": 0, + "Latitude": 2025592648, + "Longitude": 2691854648, + "Size": 0, + "Version": 0, + "VertPre": 0 + }, "ttl": 300, - "type": "LOC" + "type": "LOC", + "typenum": 29 }, { + "comparablev3": "33 51 31.000 S 151 12 51.000 E 4m 0.00m 0.00m 0.00m", "filepos": "[line:48:5]", - "localtitude": 10000400, - "loclatitude": 2025592648, - "loclongitude": 2691854648, "name": "opera-house3", - "target": "33 51 31 S 151 12 51 E 4m 0m 0m 0m", + "name_unicode": "opera-house3", + "rdata": { + "Altitude": 10000400, + "HorizPre": 0, + "Latitude": 2025592648, + "Longitude": 2691854648, + "Size": 0, + "Version": 0, + "VertPre": 0 + }, "ttl": 300, - "type": "LOC" + "type": "LOC", + "typenum": 29 }, { + "comparablev3": "33 51 31.000 S 151 12 51.000 E 4m 0.00m 0.00m 0.00m", "filepos": "[line:54:5]", - "localtitude": 10000400, - "loclatitude": 2025592648, - "loclongitude": 2691854648, "name": "opera-house4", - "target": "33 51 31 S 151 12 51 E 4m 0m 0m 0m", + "name_unicode": "opera-house4", + "rdata": { + "Altitude": 10000400, + "HorizPre": 0, + "Latitude": 2025592648, + "Longitude": 2691854648, + "Size": 0, + "Version": 0, + "VertPre": 0 + }, "ttl": 300, - "type": "LOC" + "type": "LOC", + "typenum": 29 }, { + "comparablev3": "54 12 38.000 N 02 22 13.000 W 300m 0.00m 0.00m 0.00m", "filepos": "[line:80:5]", - "localtitude": 10030000, - "loclatitude": 2342641648, - "loclongitude": 2138950648, "name": "ribblehead-viaduct", - "target": "54 12 38 N 2 22 13 W 300m 0m 0m 0m", + "name_unicode": "ribblehead-viaduct", + "rdata": { + "Altitude": 10030000, + "HorizPre": 0, + "Latitude": 2342641648, + "Longitude": 2138950648, + "Size": 0, + "Version": 0, + "VertPre": 0 + }, "ttl": 300, - "type": "LOC" + "type": "LOC", + "typenum": 29 }, { + "comparablev3": "42 00 0.000 S 147 00 0.000 E 3m 0.00m 0.00m 0.00m", "filepos": "[line:65:5]", - "localtitude": 10000300, - "loclatitude": 1996283648, - "loclongitude": 2676683648, "name": "tasmania", - "target": "42 0 0 S 147 0 0 E 3m 0m 0m 0m", + "name_unicode": "tasmania", + "rdata": { + "Altitude": 10000300, + "HorizPre": 0, + "Latitude": 1996283648, + "Longitude": 2676683648, + "Size": 0, + "Version": 0, + "VertPre": 0 + }, "ttl": 300, - "type": "LOC" + "type": "LOC", + "typenum": 29 }, { + "comparablev3": "38 53 51.940 N 77 02 11.580 W 19m 0.00m 0.00m 0.00m", "filepos": "[line:29:5]", - "localtitude": 10001900, - "loclatitude": 2287515583, - "loclongitude": 1870152064, "name": "white-house", - "target": "38 53 51.935 N 77 2 11.584 W 19m 0m 0m 0m", + "name_unicode": "white-house", + "rdata": { + "Altitude": 10001900, + "HorizPre": 0, + "Latitude": 2287515588, + "Longitude": 1870152068, + "Size": 0, + "Version": 0, + "VertPre": 0 + }, "ttl": 300, - "type": "LOC" + "type": "LOC", + "typenum": 29 } ], "registrar": "none", diff --git a/pkg/js/parse_tests/045-loc/foo.com.zone b/pkg/js/parse_tests/045-loc/foo.com.zone index 1000171ba4..cc22169c57 100644 --- a/pkg/js/parse_tests/045-loc/foo.com.zone +++ b/pkg/js/parse_tests/045-loc/foo.com.zone @@ -1,23 +1,15 @@ $TTL 300 @ IN LOC 42 21 54.000 N 71 06 18.000 W -24m 30m 0.00m 0.00m -a IN LOC 42 21 43.952 N 71 05 6.344 W -24.01m 1m 200m 10m +a IN LOC 42 21 43.950 N 71 05 6.340 W -24.01m 1m 200m 10m b IN LOC 52 14 5.000 N 00 08 50.000 E 10.33m 0.00m 0.00m 0.00m -big-ben IN LOC 51 30 3.033 N 00 07 28.651 W 6m 0.00m 0.00m 0.00m +big-ben IN LOC 51 30 3.030 N 00 07 28.650 W 6m 0.00m 0.00m 0.00m c IN LOC 32 07 19.000 S 116 02 25.000 E 10m 0.00m 0.00m 0.00m -d IN LOC 42 21 28.764 N 71 00 51.617 W -44m 2000m 0.00m 0.00m -d-alt-highest IN LOC 42 21 28.764 N 71 00 51.617 W 42849672.95m 2000m 0.00m 0.00m -d-alt-lowest IN LOC 42 21 28.764 N 71 00 51.617 W -100000m 2000m 0.00m 0.00m -d-alt-toohigh IN LOC 42 21 28.764 N 71 00 51.617 W 42849672.95m 2000m 0.00m 0.00m -d-alt-toolow IN LOC 42 21 28.764 N 71 00 51.617 W -100000m 2000m 0.00m 0.00m -d-horizprecision-hi IN LOC 42 21 28.764 N 71 00 51.617 W 0m 1m 90000000m 0.00m -d-horizprecision-toohi IN LOC 42 21 28.764 N 71 00 51.617 W 0m 1m 90000000m 0.00m -d-horizprecision-toolow IN LOC 42 21 28.764 N 71 00 51.617 W 0m 1m 0.00m 0.00m -d-size-hi IN LOC 42 21 28.764 N 71 00 51.617 W 0m 90000000m 0.00m 0.00m -d-size-toohi IN LOC 42 21 28.764 N 71 00 51.617 W 0m 90000000m 0.00m 0.00m -d-size-toolow IN LOC 42 21 28.764 N 71 00 51.617 W 0m 0.00m 0.00m 0.00m -d-vertprecision-hi IN LOC 42 21 28.764 N 71 00 51.617 W 0m 1m 0.00m 90000000m -d-vertprecision-toohi IN LOC 42 21 28.764 N 71 00 51.617 W 0m 1m 0.00m 90000000m -d-vertprecision-toolow IN LOC 42 21 28.764 N 71 00 51.617 W 0m 1m 0.00m 0.00m +d IN LOC 42 21 28.760 N 71 00 51.620 W -44m 2000m 0.00m 0.00m +d-alt-highest IN LOC 42 21 28.760 N 71 00 51.620 W 42849672.95m 2000m 0.00m 0.00m +d-alt-lowest IN LOC 42 21 28.760 N 71 00 51.620 W -100000m 2000m 0.00m 0.00m +d-horizprecision-hi IN LOC 42 21 28.760 N 71 00 51.620 W 0m 1m 90000000m 0.00m +d-size-hi IN LOC 42 21 28.760 N 71 00 51.620 W 0m 90000000m 0.00m 0.00m +d-vertprecision-hi IN LOC 42 21 28.760 N 71 00 51.620 W 0m 1m 0.00m 90000000m fraser-island IN LOC 25 14 24.000 S 153 09 0.000 E 3m 0.00m 0.00m 0.00m guinness-brewery IN LOC 53 20 40.000 N 06 17 20.000 W 300m 0.00m 0.00m 0.00m hawaii IN LOC 21 30 0.000 N 158 00 0.000 W 920m 0.00m 0.00m 0.00m @@ -28,4 +20,4 @@ opera-house3 IN LOC 33 51 31.000 S 151 12 51.000 E 4m 0.00m 0.00m 0.00m opera-house4 IN LOC 33 51 31.000 S 151 12 51.000 E 4m 0.00m 0.00m 0.00m ribblehead-viaduct IN LOC 54 12 38.000 N 02 22 13.000 W 300m 0.00m 0.00m 0.00m tasmania IN LOC 42 00 0.000 S 147 00 0.000 E 3m 0.00m 0.00m 0.00m -white-house IN LOC 38 53 51.935 N 77 02 11.584 W 19m 0.00m 0.00m 0.00m +white-house IN LOC 38 53 51.940 N 77 02 11.580 W 19m 0.00m 0.00m 0.00m diff --git a/pkg/js/parse_tests/046-DHCID.json b/pkg/js/parse_tests/046-DHCID.json index bd480aafdd..103fb0a467 100644 --- a/pkg/js/parse_tests/046-DHCID.json +++ b/pkg/js/parse_tests/046-DHCID.json @@ -3,19 +3,19 @@ "domains": [ { "dnsProviders": {}, - "meta": { - "dnscontrol_nameraw": "foo.com", - "dnscontrol_nameunicode": "foo.com", - "dnscontrol_uniquename": "foo.com" - }, "name": "foo.com", "records": [ { + "comparablev3": "Test", "filepos": "[line:2:5]", "name": "@", - "target": "Test", + "name_unicode": "@", + "rdata": { + "Digest": "Test" + }, "ttl": 300, - "type": "DHCID" + "type": "DHCID", + "typenum": 49 } ], "registrar": "none", diff --git a/pkg/js/parse_tests/047-DNAME.json b/pkg/js/parse_tests/047-DNAME.json index f6925866ff..274c8dbad2 100644 --- a/pkg/js/parse_tests/047-DNAME.json +++ b/pkg/js/parse_tests/047-DNAME.json @@ -3,19 +3,19 @@ "domains": [ { "dnsProviders": {}, - "meta": { - "dnscontrol_nameraw": "foo.com", - "dnscontrol_nameunicode": "foo.com", - "dnscontrol_uniquename": "foo.com" - }, "name": "foo.com", "records": [ { + "comparablev3": "bar.com.", "filepos": "[line:2:5]", "name": "@", - "target": "bar.com.", + "name_unicode": "@", + "rdata": { + "Target": "bar.com." + }, "ttl": 300, - "type": "DNAME" + "type": "DNAME", + "typenum": 39 } ], "registrar": "none", diff --git a/pkg/js/parse_tests/047-SVCB.json b/pkg/js/parse_tests/047-SVCB.json index db0492b67a..cace3be4aa 100644 --- a/pkg/js/parse_tests/047-SVCB.json +++ b/pkg/js/parse_tests/047-SVCB.json @@ -3,29 +3,55 @@ "domains": [ { "dnsProviders": {}, - "meta": { - "dnscontrol_nameraw": "foo.com", - "dnscontrol_nameunicode": "foo.com", - "dnscontrol_uniquename": "foo.com" - }, "name": "foo.com", "records": [ { + "comparablev3": "2 . alpn=\"h3,h2\" port=\"443\" ipv4hint=\"123.123.123.123\" ipv6hint=\"dead::beaf\"", "filepos": "[line:3:5]", "name": "@", - "svcparams": "alpn=\"h3,h2\" port=443 ipv4hint=123.123.123.123 ipv6hint=dead::beaf", - "svcpriority": 2, - "target": ".", + "name_unicode": "@", + "rdata": { + "Priority": 2, + "Target": ".", + "Value": [ + { + "Alpn": [ + "h3", + "h2" + ] + }, + { + "Port": 443 + }, + { + "Hint": [ + "123.123.123.123" + ] + }, + { + "Hint": [ + "dead::beaf" + ] + } + ] + }, "ttl": 300, - "type": "HTTPS" + "type": "HTTPS", + "typenum": 65 }, { + "comparablev3": "1 .", "filepos": "[line:2:5]", "name": "@", - "svcpriority": 1, - "target": ".", + "name_unicode": "@", + "rdata": { + "Priority": 1, + "Target": ".", + "Value": null + }, "ttl": 300, - "type": "SVCB" + "type": "SVCB", + "typenum": 64 } ], "registrar": "none", diff --git a/pkg/js/parse_tests/048-DNSKEY.json b/pkg/js/parse_tests/048-DNSKEY.json index 983623ddcc..a703d1d2f9 100644 --- a/pkg/js/parse_tests/048-DNSKEY.json +++ b/pkg/js/parse_tests/048-DNSKEY.json @@ -3,23 +3,23 @@ "domains": [ { "dnsProviders": {}, - "meta": { - "dnscontrol_nameraw": "foo.com", - "dnscontrol_nameunicode": "foo.com", - "dnscontrol_uniquename": "foo.com" - }, "name": "foo.com", "records": [ { - "dnskeyalgorithm": 13, - "dnskeyflags": 257, - "dnskeyprotocol": 3, - "dnskeypublickey": "AABBCCDD", + "comparablev3": "257 3 13 AABBCCDD", "filepos": "[line:2:5]", "name": "@", - "target": "", + "name_unicode": "@", + "rdata": { + "Algorithm": 13, + "Flags": 257, + "Protocol": 3, + "PublicKey": "AABBCCDD", + "Tag": 0 + }, "ttl": 300, - "type": "DNSKEY" + "type": "DNSKEY", + "typenum": 48 } ], "registrar": "none", diff --git a/pkg/js/parse_tests/049-json5-require.json b/pkg/js/parse_tests/049-json5-require.json index 32b952ad64..1955deab71 100644 --- a/pkg/js/parse_tests/049-json5-require.json +++ b/pkg/js/parse_tests/049-json5-require.json @@ -3,19 +3,19 @@ "domains": [ { "dnsProviders": {}, - "meta": { - "dnscontrol_nameraw": "foo.com", - "dnscontrol_nameunicode": "foo.com", - "dnscontrol_uniquename": "foo.com" - }, "name": "foo.com", "records": [ { + "comparablev3": "1.1.1.1", "filepos": "[line:7:5]", "name": "@", - "target": "1.1.1.1", + "name_unicode": "@", + "rdata": { + "Addr": "1.1.1.1" + }, "ttl": 300, - "type": "A" + "type": "A", + "typenum": 1 } ], "registrar": "none", diff --git a/pkg/js/parse_tests/050-cfSingleRedirect.json b/pkg/js/parse_tests/050-cfSingleRedirect.json index de25e7dd31..47750eed25 100644 --- a/pkg/js/parse_tests/050-cfSingleRedirect.json +++ b/pkg/js/parse_tests/050-cfSingleRedirect.json @@ -3,116 +3,111 @@ "domains": [ { "dnsProviders": {}, - "meta": { - "dnscontrol_nameraw": "foo.com", - "dnscontrol_nameunicode": "foo.com", - "dnscontrol_uniquename": "foo.com" - }, "name": "foo.com", "records": [ { - "comparable": "name=(name1) code=(301) when=(when1) then=(then1)", - "fields": { - "code": 301, - "sr_display": "name=(name1) code=(301) when=(when1) then=(then1)", - "sr_name": "name1", - "sr_then": "then1", - "sr_when": "when1" - }, + "comparablev3": "name1 301 when1 then1", "filepos": "[line:5:5]", "name": "@", - "name_raw": "@", "name_unicode": "@", - "target": "name=(name1) code=(301) when=(when1) then=(then1)", - "ttl": 1, + "rdata": { + "Code": 301, + "RT_SRRRulesetID": "", + "RT_SRRRulesetRuleID": "", + "SRName": "name1", + "SRThen": "then1", + "SRWhen": "when1" + }, + "ttl": 300, "type": "CLOUDFLAREAPI_SINGLE_REDIRECT", - "zonfefilepartial": "name=(name1) code=(301) when=(when1) then=(then1)" + "typenum": 65289 }, { - "comparable": "name=(name2) code=(302) when=(when2) then=(then2)", - "fields": { - "code": 302, - "sr_display": "name=(name2) code=(302) when=(when2) then=(then2)", - "sr_name": "name2", - "sr_then": "then2", - "sr_when": "when2" - }, + "comparablev3": "name2 302 when2 then2", "filepos": "[line:6:5]", "name": "@", - "name_raw": "@", "name_unicode": "@", - "target": "name=(name2) code=(302) when=(when2) then=(then2)", - "ttl": 1, + "rdata": { + "Code": 302, + "RT_SRRRulesetID": "", + "RT_SRRRulesetRuleID": "", + "SRName": "name2", + "SRThen": "then2", + "SRWhen": "when2" + }, + "ttl": 300, "type": "CLOUDFLAREAPI_SINGLE_REDIRECT", - "zonfefilepartial": "name=(name2) code=(302) when=(when2) then=(then2)" + "typenum": 65289 }, { - "comparable": "name=(name3) code=(301) when=(when3) then=(then3)", - "fields": { - "code": 301, - "sr_display": "name=(name3) code=(301) when=(when3) then=(then3)", - "sr_name": "name3", - "sr_then": "then3", - "sr_when": "when3" - }, + "comparablev3": "name3 301 when3 then3", "filepos": "[line:7:5]", "name": "@", - "name_raw": "@", "name_unicode": "@", - "target": "name=(name3) code=(301) when=(when3) then=(then3)", - "ttl": 1, + "rdata": { + "Code": 301, + "RT_SRRRulesetID": "", + "RT_SRRRulesetRuleID": "", + "SRName": "name3", + "SRThen": "then3", + "SRWhen": "when3" + }, + "ttl": 300, "type": "CLOUDFLAREAPI_SINGLE_REDIRECT", - "zonfefilepartial": "name=(name3) code=(301) when=(when3) then=(then3)" + "typenum": 65289 }, { - "comparable": "name=(namemeta) code=(302) when=(whenmeta) then=(thenmeta)", - "fields": { - "code": 302, - "sr_display": "name=(namemeta) code=(302) when=(whenmeta) then=(thenmeta)", - "sr_name": "namemeta", - "sr_then": "thenmeta", - "sr_when": "whenmeta" - }, + "comparablev3": "namemeta 302 whenmeta thenmeta", "filepos": "[line:9:5]", "meta": { - "metanum": "22", + "metanum": "%!s(float64=22)", "metastr": "stringy" }, "name": "@", - "name_raw": "@", "name_unicode": "@", - "target": "name=(namemeta) code=(302) when=(whenmeta) then=(thenmeta)", - "ttl": 1, + "rdata": { + "Code": 302, + "RT_SRRRulesetID": "", + "RT_SRRRulesetRuleID": "", + "SRName": "namemeta", + "SRThen": "thenmeta", + "SRWhen": "whenmeta" + }, + "ttl": 300, "type": "CLOUDFLAREAPI_SINGLE_REDIRECT", - "zonfefilepartial": "name=(namemeta) code=(302) when=(whenmeta) then=(thenmeta)" + "typenum": 65289 }, { - "comparable": "name=(namettl) code=(302) when=(whenttl) then=(thenttl)", - "fields": { - "code": 302, - "sr_display": "name=(namettl) code=(302) when=(whenttl) then=(thenttl)", - "sr_name": "namettl", - "sr_then": "thenttl", - "sr_when": "whenttl" - }, + "comparablev3": "namettl 302 whenttl thenttl", "filepos": "[line:8:5]", "name": "@", - "name_raw": "@", "name_unicode": "@", - "target": "name=(namettl) code=(302) when=(whenttl) then=(thenttl)", - "ttl": 1, + "rdata": { + "Code": 302, + "RT_SRRRulesetID": "", + "RT_SRRRulesetRuleID": "", + "SRName": "namettl", + "SRThen": "thenttl", + "SRWhen": "whenttl" + }, + "ttl": 999, "type": "CLOUDFLAREAPI_SINGLE_REDIRECT", - "zonfefilepartial": "name=(namettl) code=(302) when=(whenttl) then=(thenttl)" + "typenum": 65289 }, { + "comparablev3": "1.2.3.4", "filepos": "[line:2:5]", "meta": { "meta": "value" }, "name": "name1", - "target": "1.2.3.4", + "name_unicode": "name1", + "rdata": { + "Addr": "1.2.3.4" + }, "ttl": 300, - "type": "A" + "type": "A", + "typenum": 1 } ], "registrar": "none", diff --git a/pkg/js/parse_tests/050-cfSingleRedirect/foo.com.zone b/pkg/js/parse_tests/050-cfSingleRedirect/foo.com.zone index 5ec1175bc2..b6615c7c5b 100644 --- a/pkg/js/parse_tests/050-cfSingleRedirect/foo.com.zone +++ b/pkg/js/parse_tests/050-cfSingleRedirect/foo.com.zone @@ -1,7 +1,7 @@ $TTL 300 -;@ 1 IN CLOUDFLAREAPI_SINGLE_REDIRECT name=(name1) code=(301) when=(when1) then=(then1) -;@ 1 IN CLOUDFLAREAPI_SINGLE_REDIRECT name=(name2) code=(302) when=(when2) then=(then2) -;@ 1 IN CLOUDFLAREAPI_SINGLE_REDIRECT name=(name3) code=(301) when=(when3) then=(then3) -;@ 1 IN CLOUDFLAREAPI_SINGLE_REDIRECT name=(namemeta) code=(302) when=(whenmeta) then=(thenmeta) -;@ 1 IN CLOUDFLAREAPI_SINGLE_REDIRECT name=(namettl) code=(302) when=(whenttl) then=(thenttl) +@ IN CLOUDFLAREAPI_SINGLE_REDIRECT name1 301 when1 then1 + IN CLOUDFLAREAPI_SINGLE_REDIRECT name2 302 when2 then2 + IN CLOUDFLAREAPI_SINGLE_REDIRECT name3 301 when3 then3 + IN CLOUDFLAREAPI_SINGLE_REDIRECT namemeta 302 whenmeta thenmeta + 999 IN CLOUDFLAREAPI_SINGLE_REDIRECT namettl 302 whenttl thenttl name1 IN A 1.2.3.4 diff --git a/pkg/js/parse_tests/051-HASH.json b/pkg/js/parse_tests/051-HASH.json index 443c5fb96d..c88c228dd4 100644 --- a/pkg/js/parse_tests/051-HASH.json +++ b/pkg/js/parse_tests/051-HASH.json @@ -3,11 +3,6 @@ "domains": [ { "dnsProviders": {}, - "meta": { - "dnscontrol_nameraw": "a9993e364706816aba3e25717850c26c9cd0d89d", - "dnscontrol_nameunicode": "a9993e364706816aba3e25717850c26c9cd0d89d", - "dnscontrol_uniquename": "a9993e364706816aba3e25717850c26c9cd0d89d" - }, "name": "a9993e364706816aba3e25717850c26c9cd0d89d", "records": [], "registrar": "reg", diff --git a/pkg/js/parse_tests/054-b3487_d_extend_rev.json b/pkg/js/parse_tests/054-b3487_d_extend_rev.json index 6a3245ed30..f47d456e63 100644 --- a/pkg/js/parse_tests/054-b3487_d_extend_rev.json +++ b/pkg/js/parse_tests/054-b3487_d_extend_rev.json @@ -10,106 +10,161 @@ "dnsProviders": { "bind": -1 }, - "meta": { - "dnscontrol_nameraw": "6.10.in-addr.arpa", - "dnscontrol_nameunicode": "6.10.in-addr.arpa", - "dnscontrol_uniquename": "6.10.in-addr.arpa" - }, "name": "6.10.in-addr.arpa", "records": [ { + "comparablev3": "example.site.com.", "filepos": "[line:5:5]", "name": "31.104", - "target": "example.site.com.", + "name_unicode": "31.104", + "rdata": { + "Ptr": "example.site.com." + }, "ttl": 300, - "type": "PTR" + "type": "PTR", + "typenum": 12 }, { + "comparablev3": "example2.site.com.", "filepos": "[line:6:5]", "name": "206.104", - "target": "example2.site.com.", + "name_unicode": "206.104", + "rdata": { + "Ptr": "example2.site.com." + }, "ttl": 300, - "type": "PTR" + "type": "PTR", + "typenum": 12 }, { + "comparablev3": "ip-10-6-119-0.example.com.", "filepos": "[line:17:5]", "name": "0.119", + "name_unicode": "0.119", + "rdata": { + "Ptr": "ip-10-6-119-0.example.com." + }, "subdomain": "119", - "target": "ip-10-6-119-0.example.com.", "ttl": 300, - "type": "PTR" + "type": "PTR", + "typenum": 12 }, { + "comparablev3": "ip-10-6-119-1.example.com.", "filepos": "[line:18:5]", "name": "1.119", + "name_unicode": "1.119", + "rdata": { + "Ptr": "ip-10-6-119-1.example.com." + }, "subdomain": "119", - "target": "ip-10-6-119-1.example.com.", "ttl": 300, - "type": "PTR" + "type": "PTR", + "typenum": 12 }, { + "comparablev3": "ip-10-6-119-2.example.com.", "filepos": "[line:19:5]", "name": "2.119", + "name_unicode": "2.119", + "rdata": { + "Ptr": "ip-10-6-119-2.example.com." + }, "subdomain": "119", - "target": "ip-10-6-119-2.example.com.", "ttl": 300, - "type": "PTR" + "type": "PTR", + "typenum": 12 }, { + "comparablev3": "ip-10-6-119-3.example.com.", "filepos": "[line:20:5]", "name": "3.119", + "name_unicode": "3.119", + "rdata": { + "Ptr": "ip-10-6-119-3.example.com." + }, "subdomain": "119", - "target": "ip-10-6-119-3.example.com.", "ttl": 300, - "type": "PTR" + "type": "PTR", + "typenum": 12 }, { + "comparablev3": "ip-10-6-200-50.example.com.", "filepos": "[line:10:5]", "name": "50.200", + "name_unicode": "50.200", + "rdata": { + "Ptr": "ip-10-6-200-50.example.com." + }, "subdomain": "200", - "target": "ip-10-6-200-50.example.com.", "ttl": 300, - "type": "PTR" + "type": "PTR", + "typenum": 12 }, { + "comparablev3": "ip-10-6-200-51.example.com.", "filepos": "[line:11:5]", "name": "51.200", + "name_unicode": "51.200", + "rdata": { + "Ptr": "ip-10-6-200-51.example.com." + }, "subdomain": "200", - "target": "ip-10-6-200-51.example.com.", "ttl": 300, - "type": "PTR" + "type": "PTR", + "typenum": 12 }, { + "comparablev3": "ip-10-6-200-52.example.com.", "filepos": "[line:12:5]", "name": "52.200", + "name_unicode": "52.200", + "rdata": { + "Ptr": "ip-10-6-200-52.example.com." + }, "subdomain": "200", - "target": "ip-10-6-200-52.example.com.", "ttl": 300, - "type": "PTR" + "type": "PTR", + "typenum": 12 }, { + "comparablev3": "ip-10-6-200-53.example.com.", "filepos": "[line:13:5]", "name": "53.200", + "name_unicode": "53.200", + "rdata": { + "Ptr": "ip-10-6-200-53.example.com." + }, "subdomain": "200", - "target": "ip-10-6-200-53.example.com.", "ttl": 300, - "type": "PTR" + "type": "PTR", + "typenum": 12 }, { + "comparablev3": "ip-10-6-220-20.example.com.", "filepos": "[line:24:5]", "name": "20.220", + "name_unicode": "20.220", + "rdata": { + "Ptr": "ip-10-6-220-20.example.com." + }, "subdomain": "220", - "target": "ip-10-6-220-20.example.com.", "ttl": 300, - "type": "PTR" + "type": "PTR", + "typenum": 12 }, { + "comparablev3": "ip-10-6-230-30.example.com.", "filepos": "[line:28:5]", "name": "30.230", + "name_unicode": "30.230", + "rdata": { + "Ptr": "ip-10-6-230-30.example.com." + }, "subdomain": "230", - "target": "ip-10-6-230-30.example.com.", "ttl": 300, - "type": "PTR" + "type": "PTR", + "typenum": 12 } ], "registrar": "none", diff --git a/pkg/js/parse_tests/055-b3550-ipv6ptr.json b/pkg/js/parse_tests/055-b3550-ipv6ptr.json index effa9a8c88..a0376f7b02 100644 --- a/pkg/js/parse_tests/055-b3550-ipv6ptr.json +++ b/pkg/js/parse_tests/055-b3550-ipv6ptr.json @@ -10,26 +10,31 @@ "dnsProviders": { "bind": -1 }, - "meta": { - "dnscontrol_nameraw": "d.c.b.a.1.1.0.2.ip6.arpa", - "dnscontrol_nameunicode": "d.c.b.a.1.1.0.2.ip6.arpa", - "dnscontrol_uniquename": "d.c.b.a.1.1.0.2.ip6.arpa" - }, "name": "d.c.b.a.1.1.0.2.ip6.arpa", "records": [ { + "comparablev3": "host11.example.com.", "filepos": "[line:5:5]", "name": "1.1.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0", - "target": "host11.example.com.", + "name_unicode": "2011:abcd::11", + "rdata": { + "Ptr": "host11.example.com." + }, "ttl": 300, - "type": "PTR" + "type": "PTR", + "typenum": 12 }, { + "comparablev3": "host22.example.com.", "filepos": "[line:6:5]", "name": "2.2.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0", - "target": "host22.example.com.", + "name_unicode": "2.2.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.d.c.b.a.1.1.0.2.ip6.arpa", + "rdata": { + "Ptr": "host22.example.com." + }, "ttl": 300, - "type": "PTR" + "type": "PTR", + "typenum": 12 } ], "registrar": "none", @@ -39,34 +44,44 @@ "dnsProviders": { "bind": -1 }, - "meta": { - "dnscontrol_nameraw": "8.b.d.0.1.0.0.2.ip6.arpa", - "dnscontrol_nameunicode": "8.b.d.0.1.0.0.2.ip6.arpa", - "dnscontrol_uniquename": "8.b.d.0.1.0.0.2.ip6.arpa" - }, "name": "8.b.d.0.1.0.0.2.ip6.arpa", "records": [ { + "comparablev3": "server11.example.com.", "filepos": "[line:10:5]", "name": "1.1.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0", - "target": "server11.example.com.", + "name_unicode": "2001:db8::11", + "rdata": { + "Ptr": "server11.example.com." + }, "ttl": 300, - "type": "PTR" + "type": "PTR", + "typenum": 12 }, { + "comparablev3": "server22.example.com.", "filepos": "[line:11:5]", "name": "2.2.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0", - "target": "server22.example.com.", + "name_unicode": "2.2.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.8.b.d.0.1.0.0.2.ip6.arpa", + "rdata": { + "Ptr": "server22.example.com." + }, "ttl": 300, - "type": "PTR" + "type": "PTR", + "typenum": 12 }, { + "comparablev3": "abcd.example.com.", "filepos": "[line:15:5]", "name": "d.c.b.a.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0", + "name_unicode": "d.c.b.a.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0", + "rdata": { + "Ptr": "abcd.example.com." + }, "subdomain": "d.c.b.a.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0", - "target": "abcd.example.com.", "ttl": 300, - "type": "PTR" + "type": "PTR", + "typenum": 12 } ], "registrar": "none", diff --git a/pkg/js/parse_tests/056-openpgpkey.json b/pkg/js/parse_tests/056-openpgpkey.json index 7e19f7fcd9..3b3acad3f6 100644 --- a/pkg/js/parse_tests/056-openpgpkey.json +++ b/pkg/js/parse_tests/056-openpgpkey.json @@ -3,19 +3,19 @@ "domains": [ { "dnsProviders": {}, - "meta": { - "dnscontrol_nameraw": "hex.example.com", - "dnscontrol_nameunicode": "hex.example.com", - "dnscontrol_uniquename": "hex.example.com" - }, "name": "hex.example.com", "records": [ { + "comparablev3": "mDMEAAAAARYJKwYBBAHaRw8BAQdAFHHsHVzE1rvYcCmX7Sn5X3p71eF5qo02mO/IuULrCPW0JEV4YW1wbGUgMSA8ZXhhbXBsZS0xQGRuc2NvbnRyb2wub3JnPoh+BBMWCgAmFiEEkwXxX/eDCW05Qn5tBI42Nn4+OuIFAgAAAAECGwECHgUCF4AACgkQBI42Nn4+OuL/qgD/S2rZm2Lafp11mr5q4jIBZ4DCS/Xl+Gm4ADvoPGpzkzwBALZqxlCToP4KQ0RI2ZlqtGQSy+fHDVxat0q7pFZsRo0K", "filepos": "[line:4:5]", "name": "bb7d0cf1ee44aca0bcc0f739b77b935f13aec2fd537f5c29dedd883d._openpgpkey", - "target": "mDMEAAAAARYJKwYBBAHaRw8BAQdAFHHsHVzE1rvYcCmX7Sn5X3p71eF5qo02mO/IuULrCPW0JEV4YW1wbGUgMSA8ZXhhbXBsZS0xQGRuc2NvbnRyb2wub3JnPoh+BBMWCgAmFiEEkwXxX/eDCW05Qn5tBI42Nn4+OuIFAgAAAAECGwECHgUCF4AACgkQBI42Nn4+OuL/qgD/S2rZm2Lafp11mr5q4jIBZ4DCS/Xl+Gm4ADvoPGpzkzwBALZqxlCToP4KQ0RI2ZlqtGQSy+fHDVxat0q7pFZsRo0K", + "name_unicode": "bb7d0cf1ee44aca0bcc0f739b77b935f13aec2fd537f5c29dedd883d._openpgpkey", + "rdata": { + "PublicKey": "mDMEAAAAARYJKwYBBAHaRw8BAQdAFHHsHVzE1rvYcCmX7Sn5X3p71eF5qo02mO/IuULrCPW0JEV4YW1wbGUgMSA8ZXhhbXBsZS0xQGRuc2NvbnRyb2wub3JnPoh+BBMWCgAmFiEEkwXxX/eDCW05Qn5tBI42Nn4+OuIFAgAAAAECGwECHgUCF4AACgkQBI42Nn4+OuL/qgD/S2rZm2Lafp11mr5q4jIBZ4DCS/Xl+Gm4ADvoPGpzkzwBALZqxlCToP4KQ0RI2ZlqtGQSy+fHDVxat0q7pFZsRo0K" + }, "ttl": 300, - "type": "OPENPGPKEY" + "type": "OPENPGPKEY", + "typenum": 61 } ], "registrar": "none", @@ -23,19 +23,19 @@ }, { "dnsProviders": {}, - "meta": { - "dnscontrol_nameraw": "base64.example.com", - "dnscontrol_nameunicode": "base64.example.com", - "dnscontrol_uniquename": "base64.example.com" - }, "name": "base64.example.com", "records": [ { + "comparablev3": "mDMEAAAAARYJKwYBBAHaRw8BAQdAFHHsHVzE1rvYcCmX7Sn5X3p71eF5qo02mO/IuULrCPW0JEV4YW1wbGUgMSA8ZXhhbXBsZS0xQGRuc2NvbnRyb2wub3JnPoh+BBMWCgAmFiEEkwXxX/eDCW05Qn5tBI42Nn4+OuIFAgAAAAECGwECHgUCF4AACgkQBI42Nn4+OuL/qgD/S2rZm2Lafp11mr5q4jIBZ4DCS/Xl+Gm4ADvoPGpzkzwBALZqxlCToP4KQ0RI2ZlqtGQSy+fHDVxat0q7pFZsRo0K", "filepos": "[line:21:5]", "name": "bb7d0cf1ee44aca0bcc0f739b77b935f13aec2fd537f5c29dedd883d._openpgpkey", - "target": "mDMEAAAAARYJKwYBBAHaRw8BAQdAFHHsHVzE1rvYcCmX7Sn5X3p71eF5qo02mO/IuULrCPW0JEV4YW1wbGUgMSA8ZXhhbXBsZS0xQGRuc2NvbnRyb2wub3JnPoh+BBMWCgAmFiEEkwXxX/eDCW05Qn5tBI42Nn4+OuIFAgAAAAECGwECHgUCF4AACgkQBI42Nn4+OuL/qgD/S2rZm2Lafp11mr5q4jIBZ4DCS/Xl+Gm4ADvoPGpzkzwBALZqxlCToP4KQ0RI2ZlqtGQSy+fHDVxat0q7pFZsRo0K", + "name_unicode": "bb7d0cf1ee44aca0bcc0f739b77b935f13aec2fd537f5c29dedd883d._openpgpkey", + "rdata": { + "PublicKey": "mDMEAAAAARYJKwYBBAHaRw8BAQdAFHHsHVzE1rvYcCmX7Sn5X3p71eF5qo02mO/IuULrCPW0JEV4YW1wbGUgMSA8ZXhhbXBsZS0xQGRuc2NvbnRyb2wub3JnPoh+BBMWCgAmFiEEkwXxX/eDCW05Qn5tBI42Nn4+OuIFAgAAAAECGwECHgUCF4AACgkQBI42Nn4+OuL/qgD/S2rZm2Lafp11mr5q4jIBZ4DCS/Xl+Gm4ADvoPGpzkzwBALZqxlCToP4KQ0RI2ZlqtGQSy+fHDVxat0q7pFZsRo0K" + }, "ttl": 300, - "type": "OPENPGPKEY" + "type": "OPENPGPKEY", + "typenum": 61 } ], "registrar": "none", diff --git a/pkg/js/parse_tests/057-smimea.json b/pkg/js/parse_tests/057-smimea.json index d425b75716..7dafdb09ad 100644 --- a/pkg/js/parse_tests/057-smimea.json +++ b/pkg/js/parse_tests/057-smimea.json @@ -3,20 +3,22 @@ "domains": [ { "dnsProviders": {}, - "meta": { - "dnscontrol_nameraw": "foo.com", - "dnscontrol_nameunicode": "foo.com", - "dnscontrol_uniquename": "foo.com" - }, "name": "foo.com", "records": [ { + "comparablev3": "3 0 0 MDFiYTQ3MTljODBiNmZlOTExYjA5MWE3YzA1MTI0YjY0ZWVlY2U5NjRlMDljMDU4ZWY4Zjk4MDVkYWNhNTQ2YiAgLQo=", "filepos": "[line:2:5]", - "name": "f10e7de079689f55c0cdd6782e4dd1448c84006962a4bd832e8eff73._smimecert", - "smimeausage": 3, - "target": "mdfiytq3mtljodbinmzlotexyja5mwe3yza1mti0yjy0zwvly2u5njrlmdljmdu4zwy4zjk4mdvkywnhntq2yiaglqo=", + "name": "f10e7de079689f55c0cdd6782e4dd1448c84006962a4bd832e8eff73", + "name_unicode": "f10e7de079689f55c0cdd6782e4dd1448c84006962a4bd832e8eff73", + "rdata": { + "Certificate": "MDFiYTQ3MTljODBiNmZlOTExYjA5MWE3YzA1MTI0YjY0ZWVlY2U5NjRlMDljMDU4ZWY4Zjk4MDVkYWNhNTQ2YiAgLQo=", + "MatchingType": 0, + "Selector": 0, + "Usage": 3 + }, "ttl": 300, - "type": "SMIMEA" + "type": "SMIMEA", + "typenum": 53 } ], "registrar": "none", diff --git a/pkg/js/parse_tests/058-ignore-external-dns.json b/pkg/js/parse_tests/058-ignore-external-dns.json index 95c08746ad..73674efb15 100644 --- a/pkg/js/parse_tests/058-ignore-external-dns.json +++ b/pkg/js/parse_tests/058-ignore-external-dns.json @@ -4,11 +4,6 @@ { "dnsProviders": {}, "ignore_external_dns": true, - "meta": { - "dnscontrol_nameraw": "extdns-default.com", - "dnscontrol_nameunicode": "extdns-default.com", - "dnscontrol_uniquename": "extdns-default.com" - }, "name": "extdns-default.com", "records": [], "registrar": "none", @@ -18,11 +13,6 @@ "dnsProviders": {}, "external_dns_prefix": "extdns-", "ignore_external_dns": true, - "meta": { - "dnscontrol_nameraw": "extdns-custom.com", - "dnscontrol_nameunicode": "extdns-custom.com", - "dnscontrol_uniquename": "extdns-custom.com" - }, "name": "extdns-custom.com", "records": [], "registrar": "none", @@ -31,26 +21,31 @@ { "dnsProviders": {}, "ignore_external_dns": true, - "meta": { - "dnscontrol_nameraw": "extdns-combined.com", - "dnscontrol_nameunicode": "extdns-combined.com", - "dnscontrol_uniquename": "extdns-combined.com" - }, "name": "extdns-combined.com", "records": [ { + "comparablev3": "www.extdns-combined.com.", "filepos": "[line:12:5]", "name": "api", - "target": "www.extdns-combined.com.", + "name_unicode": "api", + "rdata": { + "Target": "www.extdns-combined.com." + }, "ttl": 300, - "type": "CNAME" + "type": "CNAME", + "typenum": 5 }, { + "comparablev3": "1.2.3.4", "filepos": "[line:11:5]", "name": "www", - "target": "1.2.3.4", + "name_unicode": "www", + "rdata": { + "Addr": "1.2.3.4" + }, "ttl": 300, - "type": "A" + "type": "A", + "typenum": 1 } ], "registrar": "none", diff --git a/pkg/js/parse_tests/059-rawttls.json b/pkg/js/parse_tests/059-rawttls.json index ec27eb28c3..d17f79105a 100644 --- a/pkg/js/parse_tests/059-rawttls.json +++ b/pkg/js/parse_tests/059-rawttls.json @@ -3,173 +3,112 @@ "domains": [ { "dnsProviders": {}, - "meta": { - "dnscontrol_nameraw": "example.com", - "dnscontrol_nameunicode": "example.com", - "dnscontrol_uniquename": "example.com" - }, "name": "example.com", "records": [ { - "comparable": "user.example.com. mytxt.example.com.", - "fields": { - "Hdr": { - "Class": 1, - "Name": "example.com.", - "Rdlength": 0, - "Rrtype": 17, - "Ttl": 300 - }, - "Mbox": "user.example.com.", - "Txt": "mytxt.example.com." - }, + "comparablev3": "user.example.com. mytxt.example.com.", "filepos": "[line:6:5]", "name": "@", - "name_raw": "@", "name_unicode": "@", - "target": "", + "rdata": { + "Mbox": "user.example.com.", + "Txt": "mytxt.example.com." + }, "ttl": 300, "type": "RP", - "zonfefilepartial": "user.example.com. mytxt.example.com." + "typenum": 17 }, { - "comparable": "user2.example.com. mytxt.example.com.", - "fields": { - "Hdr": { - "Class": 1, - "Name": "example.com.", - "Rdlength": 0, - "Rrtype": 17, - "Ttl": 300 - }, - "Mbox": "user2.example.com.", - "Txt": "mytxt.example.com." - }, + "comparablev3": "user2.example.com. mytxt.example.com.", "filepos": "[line:7:5]", "name": "@", - "name_raw": "@", "name_unicode": "@", - "target": "", + "rdata": { + "Mbox": "user2.example.com.", + "Txt": "mytxt.example.com." + }, "ttl": 300, "type": "RP", - "zonfefilepartial": "user2.example.com. mytxt.example.com." + "typenum": 17 }, { - "comparable": "user.example.com. mytxt.example.com.", - "fields": { - "Hdr": { - "Class": 1, - "Name": "aaa300.example.com.", - "Rdlength": 0, - "Rrtype": 17, - "Ttl": 300 - }, - "Mbox": "user.example.com.", - "Txt": "mytxt.example.com." - }, + "comparablev3": "user.example.com. mytxt.example.com.", "filepos": "[line:10:5]", "name": "aaa300", - "name_raw": "aaa300", "name_unicode": "aaa300", - "target": "", + "rdata": { + "Mbox": "user.example.com.", + "Txt": "mytxt.example.com." + }, "ttl": 300, "type": "RP", - "zonfefilepartial": "user.example.com. mytxt.example.com." + "typenum": 17 }, { - "comparable": "user.example.com. mytxt.example.com.", - "fields": { - "Hdr": { - "Class": 1, - "Name": "bbb1.example.com.", - "Rdlength": 0, - "Rrtype": 17, - "Ttl": 1111 - }, - "Mbox": "user.example.com.", - "Txt": "mytxt.example.com." - }, + "comparablev3": "user.example.com. mytxt.example.com.", "filepos": "[line:14:5]", "name": "bbb1", - "name_raw": "bbb1", "name_unicode": "bbb1", - "target": "", + "rdata": { + "Mbox": "user.example.com.", + "Txt": "mytxt.example.com." + }, "ttl": 1111, "type": "RP", - "zonfefilepartial": "user.example.com. mytxt.example.com." + "typenum": 17 }, { - "comparable": "user.example.com. mytxt.example.com.", - "fields": { - "Hdr": { - "Class": 1, - "Name": "ccc2.example.com.", - "Rdlength": 0, - "Rrtype": 17, - "Ttl": 2222 - }, - "Mbox": "user.example.com.", - "Txt": "mytxt.example.com." - }, + "comparablev3": "user.example.com. mytxt.example.com.", "filepos": "[line:17:5]", "name": "ccc2", - "name_raw": "ccc2", "name_unicode": "ccc2", - "target": "", + "rdata": { + "Mbox": "user.example.com.", + "Txt": "mytxt.example.com." + }, "ttl": 2222, "type": "RP", - "zonfefilepartial": "user.example.com. mytxt.example.com." + "typenum": 17 }, { - "comparable": "user.example.com. mytxt.example.com.", - "fields": { - "Hdr": { - "Class": 1, - "Name": "ddd1.example.com.", - "Rdlength": 0, - "Rrtype": 17, - "Ttl": 1111 - }, - "Mbox": "user.example.com.", - "Txt": "mytxt.example.com." - }, + "comparablev3": "user.example.com. mytxt.example.com.", "filepos": "[line:20:5]", "name": "ddd1", - "name_raw": "ddd1", "name_unicode": "ddd1", - "target": "", + "rdata": { + "Mbox": "user.example.com.", + "Txt": "mytxt.example.com." + }, "ttl": 1111, "type": "RP", - "zonfefilepartial": "user.example.com. mytxt.example.com." + "typenum": 17 }, { - "comparable": "user.example.com. mytxt.example.com.", - "fields": { - "Hdr": { - "Class": 1, - "Name": "eee3.example.com.", - "Rdlength": 0, - "Rrtype": 17, - "Ttl": 3333 - }, - "Mbox": "user.example.com.", - "Txt": "mytxt.example.com." - }, + "comparablev3": "user.example.com. mytxt.example.com.", "filepos": "[line:24:5]", "name": "eee3", - "name_raw": "eee3", "name_unicode": "eee3", - "target": "", + "rdata": { + "Mbox": "user.example.com.", + "Txt": "mytxt.example.com." + }, "ttl": 3333, "type": "RP", - "zonfefilepartial": "user.example.com. mytxt.example.com." + "typenum": 17 }, { + "comparablev3": "\"Do not call me on my phone\"", "filepos": "[line:3:5]", "name": "mytxt", - "target": "Do not call me on my phone", + "name_unicode": "mytxt", + "rdata": { + "Txt": [ + "Do not call me on my phone" + ] + }, "ttl": 300, - "type": "TXT" + "type": "TXT", + "typenum": 16 } ], "registrar": "none", diff --git a/pkg/js/parse_tests/060-rawmetas.js b/pkg/js/parse_tests/060-rawmetas.js index 5c447e3051..f2de3d9a5b 100644 --- a/pkg/js/parse_tests/060-rawmetas.js +++ b/pkg/js/parse_tests/060-rawmetas.js @@ -1,6 +1,6 @@ // This tests whether or not metadata gets passed to RecordConfig v2. D("bar.com", "none", - RP("foo.bar.com", "user2.example.com.", "mytxt.example.com.", DISABLE_REPEATED_DOMAIN_CHECK), - RP("bar.com", "user2.example.com.", "mytxt.example.com.", DISABLE_REPEATED_DOMAIN_CHECK), + RP("foo.bar.com.", "user2.example.com.", "mytxt.example.com.", DISABLE_REPEATED_DOMAIN_CHECK), + RP("bar.com.", "user2.example.com.", "mytxt.example.com.", DISABLE_REPEATED_DOMAIN_CHECK), ) diff --git a/pkg/js/parse_tests/060-rawmetas.json b/pkg/js/parse_tests/060-rawmetas.json index 70ab9c06e8..5bfb9d385c 100644 --- a/pkg/js/parse_tests/060-rawmetas.json +++ b/pkg/js/parse_tests/060-rawmetas.json @@ -3,62 +3,39 @@ "domains": [ { "dnsProviders": {}, - "meta": { - "dnscontrol_nameraw": "bar.com", - "dnscontrol_nameunicode": "bar.com", - "dnscontrol_uniquename": "bar.com" - }, "name": "bar.com", "records": [ { - "comparable": "user2.example.com. mytxt.example.com.", - "fields": { - "Hdr": { - "Class": 1, - "Name": "bar.com.bar.com.", - "Rdlength": 0, - "Rrtype": 17, - "Ttl": 300 - }, - "Mbox": "user2.example.com.", - "Txt": "mytxt.example.com." - }, + "comparablev3": "user2.example.com. mytxt.example.com.", "filepos": "[line:5:5]", "meta": { "skip_fqdn_check": "true" }, - "name": "bar.com", - "name_raw": "bar.com", - "name_unicode": "bar.com", - "target": "", + "name": "@", + "name_unicode": "@", + "rdata": { + "Mbox": "user2.example.com.", + "Txt": "mytxt.example.com." + }, "ttl": 300, "type": "RP", - "zonfefilepartial": "user2.example.com. mytxt.example.com." + "typenum": 17 }, { - "comparable": "user2.example.com. mytxt.example.com.", - "fields": { - "Hdr": { - "Class": 1, - "Name": "foo.bar.com.bar.com.", - "Rdlength": 0, - "Rrtype": 17, - "Ttl": 300 - }, - "Mbox": "user2.example.com.", - "Txt": "mytxt.example.com." - }, + "comparablev3": "user2.example.com. mytxt.example.com.", "filepos": "[line:4:5]", "meta": { "skip_fqdn_check": "true" }, - "name": "foo.bar.com", - "name_raw": "foo.bar.com", - "name_unicode": "foo.bar.com", - "target": "", + "name": "foo", + "name_unicode": "foo", + "rdata": { + "Mbox": "user2.example.com.", + "Txt": "mytxt.example.com." + }, "ttl": 300, "type": "RP", - "zonfefilepartial": "user2.example.com. mytxt.example.com." + "typenum": 17 } ], "registrar": "none", diff --git a/pkg/js/parse_tests/061-mikrotik.json b/pkg/js/parse_tests/061-mikrotik.json index b1d6fa5e54..bef37556b9 100644 --- a/pkg/js/parse_tests/061-mikrotik.json +++ b/pkg/js/parse_tests/061-mikrotik.json @@ -3,14 +3,10 @@ "domains": [ { "dnsProviders": {}, - "meta": { - "dnscontrol_nameraw": "foo.com", - "dnscontrol_nameunicode": "foo.com", - "dnscontrol_uniquename": "foo.com" - }, "name": "foo.com", "records": [ { + "comparablev3": "8.8.8.8", "filepos": "[line:2:5]", "meta": { "address_list": "vpn-list", @@ -18,9 +14,13 @@ "orig_custom_type": "MIKROTIK_FWD" }, "name": "@", - "target": "8.8.8.8", + "name_unicode": "@", + "rdata": { + "ForwardTo": "8.8.8.8" + }, "ttl": 300, - "type": "MIKROTIK_FWD" + "type": "MIKROTIK_FWD", + "typenum": 65293 }, { "filepos": "[line:6:5]", @@ -28,19 +28,26 @@ "orig_custom_type": "MIKROTIK_NXDOMAIN" }, "name": "blocked", - "target": "NXDOMAIN", + "name_unicode": "blocked", + "rdata": {}, "ttl": 300, - "type": "MIKROTIK_NXDOMAIN" + "type": "MIKROTIK_NXDOMAIN", + "typenum": 65294 }, { + "comparablev3": "10.0.0.53", "filepos": "[line:7:5]", "meta": { "orig_custom_type": "MIKROTIK_FORWARDER" }, "name": "corp.example.com", - "target": "10.0.0.53", + "name_unicode": "corp.example.com", + "rdata": { + "Target": "10.0.0.53" + }, "ttl": 300, - "type": "MIKROTIK_FORWARDER" + "type": "MIKROTIK_FORWARDER", + "typenum": 65321 } ], "registrar": "none", diff --git a/pkg/js/parse_tests/062-dextendbuilder.js b/pkg/js/parse_tests/062-dextendbuilder.js new file mode 100644 index 0000000000..250a329091 --- /dev/null +++ b/pkg/js/parse_tests/062-dextendbuilder.js @@ -0,0 +1,23 @@ +// Test if a builder such as LOC() abides by the .SubDomain convention. If this +// works for one builder, it should work for them all. + +var REG = NewRegistrar("Third-Party", "NONE"); +var DNS = NewDnsProvider("Cloudflare", "CLOUDFLAREAPI"); + +// Test the name matching algorithm + +D("domain.tld", REG, DnsProvider(DNS), ); + +D("sub.domain.tld", REG, DnsProvider(DNS), ); + +// Should match domain.tld +D_EXTEND("domain.tld", + // loctest1 + LOC("loctest1", 42, 21, 54, "N", 71, 6, 18, "W", -24, 30, 0, 0), +); + +// Should match domain.tld +D_EXTEND("ssub.domain.tld", + // loctest2.ssub + LOC("loctest2", 42, 21, 54, "N", 71, 6, 18, "W", -24, 30, 0, 0), +); diff --git a/pkg/js/parse_tests/062-dextendbuilder.json b/pkg/js/parse_tests/062-dextendbuilder.json new file mode 100644 index 0000000000..47c35b3597 --- /dev/null +++ b/pkg/js/parse_tests/062-dextendbuilder.json @@ -0,0 +1,71 @@ +{ + "dns_providers": [ + { + "name": "Cloudflare", + "type": "CLOUDFLAREAPI" + } + ], + "domains": [ + { + "dnsProviders": { + "Cloudflare": -1 + }, + "name": "domain.tld", + "records": [ + { + "comparablev3": "42 21 54.000 N 71 06 18.000 W -24m 30m 0.00m 0.00m", + "filepos": "[line:16:5]", + "name": "loctest1", + "name_unicode": "loctest1", + "rdata": { + "Altitude": 9997600, + "HorizPre": 0, + "Latitude": 2299997648, + "Longitude": 1891505648, + "Size": 51, + "Version": 0, + "VertPre": 0 + }, + "ttl": 300, + "type": "LOC", + "typenum": 29 + }, + { + "comparablev3": "42 21 54.000 N 71 06 18.000 W -24m 30m 0.00m 0.00m", + "filepos": "[line:22:5]", + "name": "loctest2.ssub", + "name_unicode": "loctest2.ssub", + "rdata": { + "Altitude": 9997600, + "HorizPre": 0, + "Latitude": 2299997648, + "Longitude": 1891505648, + "Size": 51, + "Version": 0, + "VertPre": 0 + }, + "ttl": 300, + "type": "LOC", + "typenum": 29 + } + ], + "registrar": "Third-Party", + "uniquename": "domain.tld" + }, + { + "dnsProviders": { + "Cloudflare": -1 + }, + "name": "sub.domain.tld", + "records": [], + "registrar": "Third-Party", + "uniquename": "sub.domain.tld" + } + ], + "registrars": [ + { + "name": "Third-Party", + "type": "NONE" + } + ] +} diff --git a/pkg/js/parse_tests/062-dextendbuilder/domain.tld.zone b/pkg/js/parse_tests/062-dextendbuilder/domain.tld.zone new file mode 100644 index 0000000000..2b9debcfcc --- /dev/null +++ b/pkg/js/parse_tests/062-dextendbuilder/domain.tld.zone @@ -0,0 +1,3 @@ +$TTL 300 +loctest1 IN LOC 42 21 54.000 N 71 06 18.000 W -24m 30m 0.00m 0.00m +loctest2.ssub IN LOC 42 21 54.000 N 71 06 18.000 W -24m 30m 0.00m 0.00m diff --git a/pkg/js/parse_tests/062-dextendbuilder/sub.domain.tld.zone b/pkg/js/parse_tests/062-dextendbuilder/sub.domain.tld.zone new file mode 100644 index 0000000000..a3702f18cf --- /dev/null +++ b/pkg/js/parse_tests/062-dextendbuilder/sub.domain.tld.zone @@ -0,0 +1 @@ +$TTL 300 diff --git a/pkg/js/parse_tests/063-adguard.js b/pkg/js/parse_tests/063-adguard.js new file mode 100644 index 0000000000..e65ad5e796 --- /dev/null +++ b/pkg/js/parse_tests/063-adguard.js @@ -0,0 +1,4 @@ +D("example.com", "reg", + ADGUARDHOME_A_PASSTHROUGH("a", ""), + ADGUARDHOME_AAAA_PASSTHROUGH("aaaa", ""), +); diff --git a/pkg/js/parse_tests/063-adguard.json b/pkg/js/parse_tests/063-adguard.json new file mode 100644 index 0000000000..c18e9d9b8e --- /dev/null +++ b/pkg/js/parse_tests/063-adguard.json @@ -0,0 +1,44 @@ +{ + "dns_providers": [], + "domains": [ + { + "dnsProviders": {}, + "name": "example.com", + "records": [ + { + "comparablev3": "\"\"", + "filepos": "[line:2:5]", + "meta": { + "orig_custom_type": "ADGUARDHOME_A_PASSTHROUGH" + }, + "name": "a", + "name_unicode": "a", + "rdata": { + "Target": "" + }, + "ttl": 300, + "type": "ADGUARDHOME_A_PASSTHROUGH", + "typenum": 65280 + }, + { + "comparablev3": "\"\"", + "filepos": "[line:3:5]", + "meta": { + "orig_custom_type": "ADGUARDHOME_AAAA_PASSTHROUGH" + }, + "name": "aaaa", + "name_unicode": "aaaa", + "rdata": { + "Target": "" + }, + "ttl": 300, + "type": "ADGUARDHOME_AAAA_PASSTHROUGH", + "typenum": 65281 + } + ], + "registrar": "reg", + "uniquename": "example.com" + } + ], + "registrars": [] +} diff --git a/pkg/js/parse_tests/063-adguard/example.com.zone b/pkg/js/parse_tests/063-adguard/example.com.zone new file mode 100644 index 0000000000..c936118c18 --- /dev/null +++ b/pkg/js/parse_tests/063-adguard/example.com.zone @@ -0,0 +1,3 @@ +$TTL 300 +a IN ADGUARDHOME_A_PASSTHROUGH "" +aaaa IN ADGUARDHOME_AAAA_PASSTHROUGH "" diff --git a/pkg/js/parse_tests/064-lua.js b/pkg/js/parse_tests/064-lua.js new file mode 100644 index 0000000000..7a8676a38e --- /dev/null +++ b/pkg/js/parse_tests/064-lua.js @@ -0,0 +1,6 @@ +D( + 'example.com', + 'reg', + LUA('app', 'a', ['return_', '127_0_0_1'], TTL(60)), + LUA('_diag', 'txt', "; return 'ok'", TTL(30)) +); diff --git a/pkg/js/parse_tests/064-lua.json b/pkg/js/parse_tests/064-lua.json new file mode 100644 index 0000000000..bfa9e99763 --- /dev/null +++ b/pkg/js/parse_tests/064-lua.json @@ -0,0 +1,46 @@ +{ + "dns_providers": [], + "domains": [ + { + "dnsProviders": {}, + "name": "example.com", + "records": [ + { + "comparablev3": "TXT \"; return 'ok'\"", + "filepos": "[line:5:5]", + "meta": { + "orig_custom_type": "LUA" + }, + "name": "_diag", + "name_unicode": "_diag", + "rdata": { + "LuaPayload": "; return 'ok'", + "LuaType": "TXT" + }, + "ttl": 30, + "type": "LUA", + "typenum": 65292 + }, + { + "comparablev3": "A \"return_127_0_0_1\"", + "filepos": "[line:4:5]", + "meta": { + "orig_custom_type": "LUA" + }, + "name": "app", + "name_unicode": "app", + "rdata": { + "LuaPayload": "return_127_0_0_1", + "LuaType": "A" + }, + "ttl": 60, + "type": "LUA", + "typenum": 65292 + } + ], + "registrar": "reg", + "uniquename": "example.com" + } + ], + "registrars": [] +} diff --git a/pkg/js/parse_tests/065-bunny.js b/pkg/js/parse_tests/065-bunny.js new file mode 100644 index 0000000000..c4a10edb21 --- /dev/null +++ b/pkg/js/parse_tests/065-bunny.js @@ -0,0 +1,6 @@ +D( + 'example.com', + 'reg', + BUNNY_DNS_PZ('cdn', 12345), + BUNNY_DNS_RDR('go', 'https://example.com') +); diff --git a/pkg/js/parse_tests/065-bunny.json b/pkg/js/parse_tests/065-bunny.json new file mode 100644 index 0000000000..5542868dc6 --- /dev/null +++ b/pkg/js/parse_tests/065-bunny.json @@ -0,0 +1,44 @@ +{ + "dns_providers": [], + "domains": [ + { + "dnsProviders": {}, + "name": "example.com", + "records": [ + { + "comparablev3": "12345", + "filepos": "[line:4:5]", + "meta": { + "orig_custom_type": "BUNNY_DNS_PZ" + }, + "name": "cdn", + "name_unicode": "cdn", + "rdata": { + "PullZoneID": 12345 + }, + "ttl": 300, + "type": "BUNNY_DNS_PZ", + "typenum": 65287 + }, + { + "comparablev3": "\"https://example.com\"", + "filepos": "[line:5:5]", + "meta": { + "orig_custom_type": "BUNNY_DNS_RDR" + }, + "name": "go", + "name_unicode": "go", + "rdata": { + "Target": "https://example.com" + }, + "ttl": 300, + "type": "BUNNY_DNS_RDR", + "typenum": 65320 + } + ], + "registrar": "reg", + "uniquename": "example.com" + } + ], + "registrars": [] +} diff --git a/pkg/js/parse_tests/066-cloudns.js b/pkg/js/parse_tests/066-cloudns.js new file mode 100644 index 0000000000..8390bd16f1 --- /dev/null +++ b/pkg/js/parse_tests/066-cloudns.js @@ -0,0 +1 @@ +D('example.com', 'reg', CLOUDNS_WR('www', 'https://example.com')); diff --git a/pkg/js/parse_tests/066-cloudns.json b/pkg/js/parse_tests/066-cloudns.json new file mode 100644 index 0000000000..5a1f420e21 --- /dev/null +++ b/pkg/js/parse_tests/066-cloudns.json @@ -0,0 +1,29 @@ +{ + "dns_providers": [], + "domains": [ + { + "dnsProviders": {}, + "name": "example.com", + "records": [ + { + "comparablev3": "\"https://example.com\"", + "filepos": "[line:1:25]", + "meta": { + "orig_custom_type": "CLOUDNS_WR" + }, + "name": "www", + "name_unicode": "www", + "rdata": { + "Target": "https://example.com" + }, + "ttl": 300, + "type": "CLOUDNS_WR", + "typenum": 65290 + } + ], + "registrar": "reg", + "uniquename": "example.com" + } + ], + "registrars": [] +} diff --git a/pkg/js/parse_tests/067-porkbun.js b/pkg/js/parse_tests/067-porkbun.js new file mode 100644 index 0000000000..d39b205a60 --- /dev/null +++ b/pkg/js/parse_tests/067-porkbun.js @@ -0,0 +1,9 @@ +D( + 'example.com', + 'reg', + PORKBUN_URLFWD('shop', 'https://example.com', { + type: 'permanent', + includePath: 'yes', + wildcard: 'no', + }) +); diff --git a/pkg/js/parse_tests/067-porkbun.json b/pkg/js/parse_tests/067-porkbun.json new file mode 100644 index 0000000000..882b48a51c --- /dev/null +++ b/pkg/js/parse_tests/067-porkbun.json @@ -0,0 +1,32 @@ +{ + "dns_providers": [], + "domains": [ + { + "dnsProviders": {}, + "name": "example.com", + "records": [ + { + "comparablev3": "\"https://example.com\"", + "filepos": "[line:4:5]", + "meta": { + "includePath": "yes", + "orig_custom_type": "PORKBUN_URLFWD", + "type": "permanent", + "wildcard": "no" + }, + "name": "shop", + "name_unicode": "shop", + "rdata": { + "Location": "https://example.com" + }, + "ttl": 300, + "type": "PORKBUN_URLFWD", + "typenum": 65297 + } + ], + "registrar": "reg", + "uniquename": "example.com" + } + ], + "registrars": [] +} diff --git a/pkg/mustbe/README.md b/pkg/mustbe/README.md new file mode 100644 index 0000000000..379365424c --- /dev/null +++ b/pkg/mustbe/README.md @@ -0,0 +1,10 @@ +# MustBe + +`mustbe.*` functions process an argument of any type and convert it to the required type. + +- Any validation steps must be done here. Any range checking, keyword restrictions, etc. should be done here. +- Any IDNA (PunyCode) conversions must be done here. Only ASCII is stored in fields that hold hostnames. +- Any hostnames must be extended to their FQDN, including a trailing dot (if required). +- If a field is case insensitive, we convert it to lowercase (hostnames) or uppercase (base64 or similar) so that future comparisons can simply use `==`. + +In short, by the time any data makes it to into the struct, it must be valid. No later validation is done. (That's not entirely true. `pkg/normalize/validate` still does some validation/normalization but once all DNS record types have a `Make*()` function, we'll be removing validation steps from `pkg/normalize/validate`. That is, in the future, `pkg/normalize/validate` will do per-zone validation only, all per-record validations will be done in the `Make*()` functions. diff --git a/pkg/mustbe/bool.go b/pkg/mustbe/bool.go new file mode 100644 index 0000000000..73b7699074 --- /dev/null +++ b/pkg/mustbe/bool.go @@ -0,0 +1,29 @@ +package mustbe + +import ( + "fmt" + "strconv" +) + +// Bool converts to a bool. +func Bool(a any) bool { + switch v := a.(type) { + case bool: + return v + case string: + if v == "" { + v = "false" + } + b, err := strconv.ParseBool(v) + if err != nil { + panic(fmt.Sprintf("Bool: invalid boolean string: %s", a)) + } + return b + } + panic(fmt.Sprintf("Bool: unhandled type: %T", a)) +} + +// BoolString converts to a string that is either `true` or `false`. +func BoolString(a any) string { + return fmt.Sprintf("%t", Bool(a)) +} diff --git a/pkg/mustbe/hosts.go b/pkg/mustbe/hosts.go new file mode 100644 index 0000000000..314423c624 --- /dev/null +++ b/pkg/mustbe/hosts.go @@ -0,0 +1,136 @@ +package mustbe + +import ( + "fmt" + "strings" + + "github.com/DNSControl/dnscontrol/v5/pkg/domaintags" + "github.com/DNSControl/dnscontrol/v5/pkg/nrc" +) + +// TargetHost returns a FQDN (or @) suitable as a target for CNAME and other records. +// What is a target? +// * A "target" is a hostname used in fields of a DNS record. For example, in "foo IN MX 10 bar.example.com.", "bar" is the target. +// * A target is stored as a FQDN+"." with all Unicode converted to ASCII (PunyCode). +// * It is never stored as "@" or a shortname. +// * If you require a shortname, use dc.TargetAsShort(target) or dc.TargetAsShortOrAt(target). +// +// * origin must be a FQDN without a trailing dot. Violations cause a panic so that this is caught before code is shipped. +// * if origin is "", a special mode is activated that disables most action. +// - This is for legacy situations where the origin is unknown. +// - This will eventually be an error. +// - In this mode, Either the original string is returned, or if that string is "", "UNKNOWNORIGIN." is returned. This is the only situation where this function might return "@". +// +// * Normal operation: +// - arg may be a string or it will be converted to a string using fmt.Printf("%v"). +// - Unicode is converted to PunyCode. +// - The result always ends with a "." +// - The reason for not storing the short or "@" version is that "preview" output becomes ambiguous. Explicit is better than implicit. +// - Wildcards ("@") are rejected since they are not valid in targets. That's why this is called TargetHost and not Host. +// +// * origin == ".": +// - This is a special flag for TargetIsFqdnNoDot mode. +// +// * Examples: (assume $origin = "domain.com") +// - `@` -> $origin +// - `foo.$origin.` -> `foo.$origin.` +// - `$origin.` -> `$origin.` +// - `other.com.` -> `other.com.` +// - `short` -> `short.$origin` +func TargetHost(origin string, isEnabled nrc.Flags, arg any) (string, error) { + // Check for programmer error. Origin shouldn't end in ".", unless it == "." which is a special mode. + if origin != "." && strings.HasSuffix(origin, ".") { + panic(fmt.Sprintf("mustbe.Host must NOT be called with an origin ending with . (origin=%q)", origin)) + } + + var name string + switch v := arg.(type) { + case string: + name = v + case int: + name = fmt.Sprintf("%d", arg) + default: + name = fmt.Sprintf("%v", arg) + } + + if isEnabled.EnforceOneDotPolicy && violatesSingleDotPolicy(name) { + return "", MakeErrorSingleDotViolation(name) + } + + // TODO(tlim): + // origin == "." is a special flag that means the same thing as + // isEnabled.TargetIsFqdnNoDot == true. + // I'm not sure why we have two ways to signal this mode. Too much late-night + // coding, I suspect. + // Or, perhaps this was written before I decided to change the signatures of + // the Make*() functions to include isEnabled, after which I should have + // removed the origin=="." code. + // In the future we should eliminate the origin=".". + + if origin == "." && name == "" { + return ".", nil + } + + // Special symbols: + switch name { + case "@", "": + return origin + ".", nil + } + + // Normalize it + name = domaintags.EfficientToASCII(name) + + if isEnabled.TargetIsFqdnNoDot { + // The dot is unexpected but we'll allow it. + if name[len(name)-1] == '.' { + return name, nil + } + // Add the dot. + return name + ".", nil + } + + // Is this already a FQDN? Return it. + if strings.HasSuffix(name, ".") { + return name, nil + } + + // This must be a shortname without a dot. Add origin and dot. + return name + "." + origin + ".", nil +} + +// TargetHostSRV is like TargetHost with the exception that "." and "" have special meaning and are left alone. +func TargetHostSRV(origin string, isEnabled nrc.Flags, arg any) (string, error) { + + var name string + switch v := arg.(type) { + case string: + name = v + case int: + name = fmt.Sprintf("%d", arg) + default: + name = fmt.Sprintf("%v", arg) + } + + if name == "" || name == "." { + return name, nil + } + + if isEnabled.EnforceOneDotPolicy && violatesSingleDotPolicy(name) { + return "", MakeErrorSingleDotViolation(name) + } + + return TargetHost(origin, isEnabled, name) +} + +func violatesSingleDotPolicy(s string) bool { + // FQDN+"." passes. + if strings.HasSuffix(s, ".") { + return false + } + // Any interior dot (with no trailing dot to make it an FQDN) fails. + return strings.Contains(s, ".") +} + +func MakeErrorSingleDotViolation(s string) error { + return fmt.Errorf("target %q must end with a (.) [https://docs.dnscontrol.org/language-reference/why-the-dot]", s) +} diff --git a/pkg/mustbe/hosts_test.go b/pkg/mustbe/hosts_test.go new file mode 100644 index 0000000000..004fb1cc80 --- /dev/null +++ b/pkg/mustbe/hosts_test.go @@ -0,0 +1,98 @@ +package mustbe_test + +import ( + "testing" + + "github.com/DNSControl/dnscontrol/v5/pkg/mustbe" + "github.com/DNSControl/dnscontrol/v5/pkg/nrc" +) + +func TestTargetHost(t *testing.T) { + tests := []struct { + name string // description of this test case + // Named input parameters for target function. + origin string + arg any + want string + wantNoDot string + }{ + // Examples in the docs: + {"a1", "domain.com", "@", "domain.com.", ""}, + {"a2", "domain.com", "", "domain.com.", ""}, + {"a3", "domain.com", "foo.domain.com.", "foo.domain.com.", ""}, + {"a4", "domain.com", "domain.com.", "domain.com.", ""}, + {"a5", "domain.com", "other.com.", "other.com.", ""}, + {"a6", "domain.com", "short", "short.domain.com.", "short."}, + // Doc examples with name in Unicode: + {"b1", "domain.com", "München.domain.com.", "xn--mnchen-3ya.domain.com.", ""}, + {"b2", "domain.com", "münchen.domain.com.", "xn--mnchen-3ya.domain.com.", ""}, + {"b3", "domain.com", "München", "xn--mnchen-3ya.domain.com.", "xn--mnchen-3ya."}, + {"b4", "domain.com", "münchen", "xn--mnchen-3ya.domain.com.", "xn--mnchen-3ya."}, + {"b5", "domain.com", "other.com.", "other.com.", ""}, + // Doc examples with origin as Punycode: + {"c1", "xn--mnchen-3ya.com", "@", "xn--mnchen-3ya.com.", ""}, + {"c2", "xn--mnchen-3ya.com", "", "xn--mnchen-3ya.com.", ""}, + {"c3", "xn--mnchen-3ya.com", "foo.xn--mnchen-3ya.com.", "foo.xn--mnchen-3ya.com.", ""}, + {"c4", "xn--mnchen-3ya.com", "xn--mnchen-3ya.com.", "xn--mnchen-3ya.com.", ""}, + {"c5", "xn--mnchen-3ya.com", "other.com.", "other.com.", ""}, + {"c6", "xn--mnchen-3ya.com", "short", "short.xn--mnchen-3ya.com.", "short."}, + // Doc examples with origin as Punycode and name in Unicode: + {"d1", "xn--mnchen-3ya.com", "@", "xn--mnchen-3ya.com.", ""}, + {"d2", "xn--mnchen-3ya.com", "", "xn--mnchen-3ya.com.", ""}, + {"d3", "xn--mnchen-3ya.com", "foo.München.com.", "foo.xn--mnchen-3ya.com.", ""}, + {"d4", "xn--mnchen-3ya.com", "München", "xn--mnchen-3ya.xn--mnchen-3ya.com.", "xn--mnchen-3ya."}, + {"d5", "xn--mnchen-3ya.com", "München.com.", "xn--mnchen-3ya.com.", "xn--mnchen-3ya.com."}, + {"d6", "xn--mnchen-3ya.com", "other.com.", "other.com.", ""}, + // Doc examples with orgin and name in PunyCode: + {"e1", "xn--mnchen-3ya.com", "foo.xn--mnchen-3ya.com.", "foo.xn--mnchen-3ya.com.", ""}, + {"e2", "xn--mnchen-3ya.com", "xn--mnchen-3ya.xn--mnchen-3ya.com.", "xn--mnchen-3ya.xn--mnchen-3ya.com.", ""}, + {"e3", "xn--mnchen-3ya.com", "xn--mnchen-3ya.com.", "xn--mnchen-3ya.com.", ""}, + {"e4", "xn--mnchen-3ya.com", "xn--mnchen-3ya", "xn--mnchen-3ya.xn--mnchen-3ya.com.", "xn--mnchen-3ya."}, + // Other cases: + //{"f1", "domain.com", "", "domain.com.", ""}, // shouldn't happen. + {"f2", "domain.com", "42", "42.domain.com.", "42."}, + {"f3", "domain.com", 99, "99.domain.com.", "99."}, + // NullMX and NullSRV: + {"null", "example.com", ".", ".", "."}, + {"null2", "", ".", ".", "."}, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + got, err := mustbe.TargetHost(tt.origin, nrc.Flags{TargetIsFqdnNoDot: false}, tt.arg) + if err != nil { + t.Fatal(err) + } + if got != tt.want { + t.Errorf("Host() = %v, want %v", got, tt.want) + } + + wanted := tt.wantNoDot + if wanted == "" { + wanted = tt.want + } + got, err = mustbe.TargetHost(tt.origin, nrc.Flags{TargetIsFqdnNoDot: true}, tt.arg) + if err != nil { + t.Fatal(err) + } + if got != wanted { + t.Errorf("Host(ENABLED) = %v, want %v", got, tt.want) + } + }) + } +} + +func TestTargetHostSingleDotViolation(t *testing.T) { + for _, targetHost := range []func(string, nrc.Flags, any) (string, error){mustbe.TargetHost, mustbe.TargetHostSRV} { + got, err := targetHost("example.com", nrc.Flags{EnforceOneDotPolicy: true}, "www.example.com") + if err == nil { + t.Fatal("expected single-dot violation error") + } + if got != "" { + t.Errorf("TargetHost() = %q on error, want empty string", got) + } + want := `target "www.example.com" must end with a (.) [https://docs.dnscontrol.org/language-reference/why-the-dot]` + if err.Error() != want { + t.Errorf("TargetHost() error = %q, want %q", err, want) + } + } +} diff --git a/pkg/mustbe/ip.go b/pkg/mustbe/ip.go new file mode 100644 index 0000000000..60ce29c606 --- /dev/null +++ b/pkg/mustbe/ip.go @@ -0,0 +1,75 @@ +package mustbe + +import ( + "fmt" + "net" + "net/netip" +) + +func IPv4(a any) (netip.Addr, error) { + switch v := a.(type) { + case float64: + i := int32(v) + a := (i >> 24) % 256 + b := (i >> 16) % 256 + c := (i >> 8) % 256 + d := i % 256 + x := netip.AddrFrom4([4]byte{ + byte(a), + byte(b), + byte(c), + byte(d), + }) + return x, nil + case string: + a, err := netip.ParseAddr(v) + if err != nil || !a.Is4() { + return netip.Addr{}, fmt.Errorf("not a valid IPv4 address: %v", v) + } + return a, nil + case netip.Addr: + if !v.Is4() { + return netip.Addr{}, fmt.Errorf("not an IPv4 address: %v", v) + } + return v, nil + case net.IP: + ipv4Bytes := v.To4() + if ipv4Bytes == nil { + return netip.Addr{}, fmt.Errorf("not an IPv4 address: %v", v) + } + addr, ok := netip.AddrFromSlice(ipv4Bytes) + if !ok { + return netip.Addr{}, fmt.Errorf("not an IPv4 address: %v", v) + } + return addr, nil + } + panic(fmt.Sprintf("mustbe.IPv4: unhandled type: %T", a)) +} + +func IPv6(a any) (netip.Addr, error) { + switch v := a.(type) { + case string: + a, err := netip.ParseAddr(v) + if err != nil || !a.Is6() { + return netip.Addr{}, fmt.Errorf("not a valid IPv6 address: %v", v) + } + return a, nil + case netip.Addr: + if !v.Is6() { + return netip.Addr{}, fmt.Errorf("not an IPv6 address: %v", v) + } + return v, nil + case net.IP: + ipv6Bytes := v.To16() + if ipv6Bytes == nil { + return netip.Addr{}, fmt.Errorf("not a valid IPv6 address: %v", v) + } + addr, ok := netip.AddrFromSlice(ipv6Bytes) + if !ok { + return netip.Addr{}, fmt.Errorf("not a valid IPv6 address: %v", v) + } + return addr, nil + + } + panic(fmt.Sprintf("mustbe.IPv6: unhandled type: %T", a)) +} diff --git a/pkg/mustbe/ip_test.go b/pkg/mustbe/ip_test.go new file mode 100644 index 0000000000..2426973104 --- /dev/null +++ b/pkg/mustbe/ip_test.go @@ -0,0 +1,85 @@ +package mustbe_test + +import ( + "net/netip" + "testing" + + "github.com/DNSControl/dnscontrol/v5/pkg/mustbe" +) + +func TestIPv4_RoundTrip(t *testing.T) { + tests := []struct { + name string // description of this test case + // Named input parameters for target function. + a any + }{ + {"a", "1.2.3.4"}, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + // Convert + original := tt.a + originalStr := tt.a.(string) + first, _ := mustbe.IPv4(original) + firstStr := first.String() + if firstStr != originalStr { + t.Errorf("IPv4(%v) = %v, want %v", original, originalStr, firstStr) + } + // Round Trip + second, _ := mustbe.IPv4(firstStr) + secondStr := second.String() + if secondStr != originalStr { + t.Errorf("IPv4(%v) = %v, want %v", original, originalStr, secondStr) + } + }) + } +} + +func TestIPv4_Parse(t *testing.T) { + tests := []struct { + name string // description of this test case + // Named input parameters for target function. + a any + want netip.Addr + }{ + {"a", "1.2.3.4", netip.MustParseAddr("1.2.3.4")}, + {"b", float64((2 << 24) + (3 << 16) + (4 << 8) + 5), netip.MustParseAddr("2.3.4.5")}, + {"c", netip.MustParseAddr("3.4.5.6"), netip.MustParseAddr("3.4.5.6")}, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + got, _ := mustbe.IPv4(tt.a) + if tt.want != got { + t.Errorf("IPv4() = %v, want %v", got, tt.want) + } + }) + } +} + +func TestIPv6(t *testing.T) { + tests := []struct { + name string // description of this test case + a any + shouldError bool + }{ + {"b", "45::1", false}, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + // Convert + original := tt.a + originalStr := tt.a.(string) + first, _ := mustbe.IPv6(original) + firstStr := first.String() + if firstStr != originalStr { + t.Errorf("IPv6(%v) = %v, want %v", original, originalStr, firstStr) + } + // Round Trip + second, _ := mustbe.IPv6(firstStr) + secondStr := second.String() + if secondStr != originalStr { + t.Errorf("IPv6(%v) = %v, want %v", original, originalStr, secondStr) + } + }) + } +} diff --git a/pkg/mustbe/numbers.go b/pkg/mustbe/numbers.go new file mode 100644 index 0000000000..575e942d9f --- /dev/null +++ b/pkg/mustbe/numbers.go @@ -0,0 +1,208 @@ +package mustbe + +import ( + "fmt" + "math" + "strconv" +) + +func Uint8(arg any) uint8 { + switch v := arg.(type) { + case uint8: + return v + case uint16: + if v > math.MaxUint8 { + panic(fmt.Sprintf("value %v overflows uint8", arg)) + } + return uint8(v) + case int16: + if v < 0 || v > math.MaxUint8 { + panic(fmt.Sprintf("value %v overflows uint8", arg)) + } + return uint8(v) + case uint32: + if v > math.MaxUint8 { + panic(fmt.Sprintf("value %v overflows uint8", arg)) + } + return uint8(v) + case uint: + if v > math.MaxUint8 { + panic(fmt.Sprintf("value %v overflows uint8", arg)) + } + return uint8(v) + case int: + if v < 0 || v > math.MaxUint8 { + panic(fmt.Sprintf("value %v overflows uint8", arg)) + } + return uint8(v) + case float64: + if v < 0 || v > math.MaxUint8 { + panic(fmt.Sprintf("value %v overflows uint8", arg)) + } + return uint8(v) + case string: + ni, err := strconv.ParseUint(arg.(string), 10, 8) + if err != nil { + panic(fmt.Sprintf("value %v is not a number (uint8 wanted)", arg)) + } + return uint8(ni) + } + panic(fmt.Sprintf("value %v is type %T, expected uint8", arg, arg)) +} + +func Uint16(arg any) uint16 { + switch v := arg.(type) { + case uint8: + return uint16(v) + case uint16: + return v + case int16: + if v < 0 { + panic(fmt.Sprintf("value %v underflows uint16", arg)) + } + case uint: + if v > math.MaxUint16 { + panic(fmt.Sprintf("value %v overflows uint16", arg)) + } + return uint16(v) + case uint32: + if v > math.MaxUint16 { + panic(fmt.Sprintf("value %v overflows uint16", arg)) + } + return uint16(v) + case uint64: + if v > math.MaxUint16 { + panic(fmt.Sprintf("value %v overflows uint16", arg)) + } + return uint16(v) + case int: + if v < 0 || v > math.MaxUint16 { + panic(fmt.Sprintf("value %v overflows uint16", arg)) + } + return uint16(v) + case int64: + if v < 0 || v > math.MaxUint16 { + panic(fmt.Sprintf("value %v overflows uint16", arg)) + } + return uint16(v) + case float64: + if v < 0 || v > math.MaxUint16 { + panic(fmt.Sprintf("value %v overflows uint16", arg)) + } + return uint16(v) + case string: + ni, err := strconv.ParseUint(arg.(string), 10, 16) + if err != nil { + panic(fmt.Sprintf("value %v is not a number (uint16 wanted)", arg)) + } + return uint16(ni) + } + panic(fmt.Sprintf("value %v is type %T, expected uint16", arg, arg)) +} + +func Uint32(arg any) uint32 { + switch v := arg.(type) { + case uint8: + return uint32(v) + case uint16: + return uint32(v) + case int16: + if v < 0 { + panic(fmt.Sprintf("value %v underflows uint32", arg)) + } + return uint32(v) + case uint32: + return v + case uint: + if v > math.MaxUint32 { + panic(fmt.Sprintf("value %v overflows uint32", arg)) + } + return uint32(v) + case int: + if v < 0 || v > math.MaxUint32 { + panic(fmt.Sprintf("value %v overflows uint32", arg)) + } + return uint32(v) + case float64: + if v < 0 || v > math.MaxUint32 { + panic(fmt.Sprintf("value %v overflows uint32", arg)) + } + return uint32(v) + case string: + ni, err := strconv.ParseUint(arg.(string), 10, 32) + if err != nil { + panic(fmt.Sprintf("value %v is not a number (uint32 wanted)", arg)) + } + return uint32(ni) + } + panic(fmt.Sprintf("value %v is type %T, expected uint32", arg, arg)) +} + +func Uint64(arg any) uint64 { + switch v := arg.(type) { + case string: + num, err := strconv.ParseUint(v, 10, 64) + if err != nil { + panic(fmt.Sprintf("value %v is not a number (uint64 wanted)", v)) + } + return uint64(num) + case uint64: + return uint64(v) + } + panic(fmt.Sprintf("value %v is type %T, expected uint64", arg, arg)) +} + +func Int64(arg any) int64 { + switch v := arg.(type) { + case int64: + return v + case uint16: + return int64(v) + case float64: + if math.Trunc(v) != v || v < math.MinInt64 || v >= float64(math.MaxInt64) { + panic(fmt.Sprintf("value %v is not an int64", arg)) + } + return int64(v) + case string: + ni, err := strconv.ParseInt(arg.(string), 10, 64) + if err != nil { + panic(fmt.Sprintf("value %v is not a number (int64 wanted)", arg)) + } + return int64(ni) + } + panic(fmt.Sprintf("value %v is type %T, expected int64", arg, arg)) +} + +func Float32(arg any) float32 { + switch v := arg.(type) { + case float32: + return v + case string: + f, err := strconv.ParseFloat(v, 32) + if err != nil { + panic(fmt.Sprintf("string to float parse error: %q err=%s", v, err)) + } + if f < -math.MaxFloat32 || f > math.MaxFloat32 { + panic(fmt.Sprintf("value %q overflows float32", arg)) + } + return float32(f) + case float64: + if v < -math.MaxFloat32 || v > math.MaxFloat32 { + panic(fmt.Sprintf("value %v overflows float32", arg)) + } + return float32(v) + } + panic(fmt.Sprintf("value %v is type %T, expected float32", arg, arg)) +} + +func Float64(arg any) float64 { + switch v := arg.(type) { + case float64: + return v + case float32: + return float64(v) + case int: + return float64(v) + } + panic(fmt.Sprintf("value %v is type %T, expected float64", arg, arg)) +} diff --git a/pkg/mustbe/numbers_test.go b/pkg/mustbe/numbers_test.go new file mode 100644 index 0000000000..aa44abb58c --- /dev/null +++ b/pkg/mustbe/numbers_test.go @@ -0,0 +1,18 @@ +package mustbe + +import "testing" + +func TestInt64FromFloat64(t *testing.T) { + if got := Int64(float64(12345)); got != 12345 { + t.Fatalf("Int64(12345) = %d, want 12345", got) + } +} + +func TestInt64RejectsFractionalFloat64(t *testing.T) { + defer func() { + if recover() == nil { + t.Fatal("Int64(123.5) did not panic") + } + }() + Int64(123.5) +} diff --git a/pkg/mustbe/openpgpkey.go b/pkg/mustbe/openpgpkey.go new file mode 100644 index 0000000000..4e1649be14 --- /dev/null +++ b/pkg/mustbe/openpgpkey.go @@ -0,0 +1,19 @@ +package mustbe + +import ( + "fmt" + + "github.com/DNSControl/dnscontrol/v5/pkg/transform" +) + +func OpenPGPKey(a any) string { + switch v := a.(type) { + case string: + k, err := transform.OPENPGPKEY(v) + if err != nil { + return fmt.Sprintf("Can not decode %q", v) + } + return k + } + panic("mustbe.OpenPGPKey: unhandled type") +} diff --git a/pkg/mustbe/rawstring.go b/pkg/mustbe/rawstring.go new file mode 100644 index 0000000000..b006048c07 --- /dev/null +++ b/pkg/mustbe/rawstring.go @@ -0,0 +1,23 @@ +package mustbe + +import ( + "fmt" + "strings" +) + +func RawString(a any) string { + switch v := a.(type) { + case string: + return v + } + return fmt.Sprintf("%s", a) + +} + +func ToUpperRawString(a any) string { + switch v := a.(type) { + case string: + return strings.ToUpper(v) + } + return strings.ToUpper(fmt.Sprintf("%s", a)) +} diff --git a/pkg/mustbe/soamailbox.go b/pkg/mustbe/soamailbox.go new file mode 100644 index 0000000000..7b72149222 --- /dev/null +++ b/pkg/mustbe/soamailbox.go @@ -0,0 +1,50 @@ +package mustbe + +import ( + "fmt" + "strings" + + "github.com/DNSControl/dnscontrol/v5/pkg/domaintags" +) + +// SoaMailbox format a SOA Mailbox string, such as tal.example.com (The "@" in +// the email address is written as an "." because nothing in DNS is simple). +// This function also... +// * Turns normal email addresses (tal@example.com) into SOA Mailbox strings (tal.example.com). +// * Turns Unicode into PunyCode (just in the hostname part) +// * Runs ToLower. +// * Does NOT add an origin if this is a shortname. We can't know if it is a shortname because it is dotless.) +func SoaMailbox(arg any) string { + var name string + switch v := arg.(type) { + case string: + name = v + case int: + name = fmt.Sprintf("%d", arg) + default: + name = fmt.Sprintf("%v", arg) + } + + // Turn email addresses into SOAMailbox format: + name = strings.ReplaceAll(name, "@", ".") + name = strings.ToLower(name) + + if strings.Count(name, ".") == 0 { + // Techinically we should reject this but... they're digging their own grave. + return name + } + + // Normalize it (even though it isn't a hostname, + parts := strings.SplitN(name, ".", 2) + if len(parts) == 0 { + return "SHOULD_NOT_HAPPEN." + } + if len(parts) == 1 { + parts = append(parts, "") + } + username, hostname := parts[0], parts[1] + + hostname = domaintags.EfficientToASCII(hostname) + + return username + "." + hostname +} diff --git a/pkg/mustbe/soamailbox_test.go b/pkg/mustbe/soamailbox_test.go new file mode 100644 index 0000000000..045e67a556 --- /dev/null +++ b/pkg/mustbe/soamailbox_test.go @@ -0,0 +1,26 @@ +package mustbe + +import ( + "testing" +) + +func TestSoaMailbox(t *testing.T) { + tests := []struct { + name string // description of this test case + // Named input parameters for target function. + arg any + want string + }{ + {"a", "tal.example.com", "tal.example.com"}, + {"a", "DEFAULT_NOT_SET.", "default_not_set."}, + {"b", "tal@example.com", "tal.example.com"}, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + got := SoaMailbox(tt.arg) + if got != tt.want { + t.Errorf("SoaMailbox() = %v, want %v", got, tt.want) + } + }) + } +} diff --git a/pkg/mustbe/txts.go b/pkg/mustbe/txts.go new file mode 100644 index 0000000000..0127961a4b --- /dev/null +++ b/pkg/mustbe/txts.go @@ -0,0 +1,38 @@ +package mustbe + +import ( + "bytes" + "fmt" +) + +func Txts(args ...any) []string { + if len(args) == 0 { + return []string{""} + } + // Join the parts using a string builder, assuring each part is a string (or converting it if needed) + var sb bytes.Buffer + for _, a := range args { + fmt.Fprintf(&sb, "%v", a) + } + return splitChunks(sb.String(), 255) +} + +func splitChunks(buf string, lim int) []string { + if len(buf) == 0 { + return []string{""} + } + if len(buf) <= lim { + return []string{buf} + } + + 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 +} diff --git a/pkg/mustbe/txts_test.go b/pkg/mustbe/txts_test.go new file mode 100644 index 0000000000..4417ce3ced --- /dev/null +++ b/pkg/mustbe/txts_test.go @@ -0,0 +1,57 @@ +package mustbe_test + +import ( + "slices" + "strings" + "testing" + + "github.com/DNSControl/dnscontrol/v5/pkg/mustbe" +) + +func TestTxts(t *testing.T) { + tests := []struct { + name string // description of this test case + // Named input parameters for target function. + args []any + want []string + }{ + {"simple", []any{"simple"}, []string{"simple"}}, + {"any", []any{1, "foo", 45.2}, []string{"1foo45.2"}}, + {"254", []any{strings.Repeat("a", 254)}, []string{ + strings.Repeat("a", 254), + }}, + {"255", []any{strings.Repeat("b", 255)}, []string{ + strings.Repeat("b", 255), + }}, + {"256", []any{strings.Repeat("c", 256)}, []string{ + strings.Repeat("c", 255), + strings.Repeat("c", 1), + }}, + {"257", []any{strings.Repeat("d", 257)}, []string{ + strings.Repeat("d", 255), + strings.Repeat("d", 2), + }}, + {"513", []any{strings.Repeat("e", 513)}, []string{ + strings.Repeat("e", 255), + strings.Repeat("e", 255), + strings.Repeat("e", (513 - 255 - 255)), + }}, + {"200 200 200", []any{ + strings.Repeat("f", 200), + strings.Repeat("f", 200), + strings.Repeat("f", 200), + }, []string{ + strings.Repeat("f", 255), + strings.Repeat("f", 255), + strings.Repeat("f", (600 - 255 - 255)), + }}, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + got := mustbe.Txts(tt.args...) + if !slices.Equal(got, tt.want) { + t.Errorf("Txts() = %v, want %v", got, tt.want) + } + }) + } +} diff --git a/pkg/mustbe/validargs.go b/pkg/mustbe/validargs.go new file mode 100644 index 0000000000..6977123a75 --- /dev/null +++ b/pkg/mustbe/validargs.go @@ -0,0 +1,40 @@ +package mustbe + +import "fmt" + +// ValidArgs panics if args looks like a variadic call that lost its spread +// operator somewhere up the call chain. +// +// Many Make*() functions are declared `func(..., args ...any)` and forward to +// another variadic function. The forwarding call must use `f(..., args...)`. +// If the `...` is omitted, the called function sees args == []any{ []any{...} } +// i.e. a single element whose value is itself the original []any. The individual +// values are then never validated as strings/ints/etc., and the bug surfaces +// far from its cause. +// +// ValidArgs catches exactly that shape: len(args) == 1 AND args[0] is a []any. +// We panic rather than return an error because the only way to produce this +// shape is a programmer mistake at a call site; tests will surface it loudly. +func ValidArgs(args []any) { + if len(args) == 1 { + if inner, ok := args[0].([]any); ok { + panic(fmt.Sprintf( + "mustbe.ValidArgs: variadic args were not spread (missing `...`); "+ + "got a single (%T) []any of length %d: %+v", + inner, + len(inner), inner)) + } + } +} + +/* +Claude recommends: + +Alternative strategies worth considering + +1. Static analysis instead of runtime. A small go vet-style analyzer (or even a golangci-lint custom rule) could flag f(..., args) where f is variadic and args is []any in scope. Catches the bug at compile time, no runtime cost, no test coverage required. More upfront work but stronger guarantee. +2. Replace args ...any with args []any everywhere. Forces callers to write args (no ...) and removes the ambiguity entirely. Bigger refactor; the DSL ergonomics at the JS-glue layer may make this awkward. +3. Keep ValidArgs but also stamp a unique sentinel type. E.g. wrap user-supplied slices in a type Args []any so any nested Args inside Args is obviously wrong. More invasive than the current approach without much more catching power. + +I'd keep the runtime check (cheap, narrowly targeted, already wired in) and add the vet analyzer later if these bugs keep recurring. +*/ diff --git a/pkg/nameservers/nameservers.go b/pkg/nameservers/nameservers.go index 7e0978a84e..61992e7cde 100644 --- a/pkg/nameservers/nameservers.go +++ b/pkg/nameservers/nameservers.go @@ -6,18 +6,15 @@ import ( "strconv" "strings" - "github.com/DNSControl/dnscontrol/v4/models" - "github.com/DNSControl/dnscontrol/v4/pkg/printer" + dnsv2 "codeberg.org/miekg/dns" + "github.com/DNSControl/dnscontrol/v5/models" + "github.com/DNSControl/dnscontrol/v5/pkg/nrc" + "github.com/DNSControl/dnscontrol/v5/pkg/printer" ) -// DetermineNameservers will find all nameservers we should use for a domain. It follows the following rules: +// DetermineNameserversForProviders determines all nameservers to be used for a domain. It follows the following rules: // 1. All explicitly defined NAMESERVER records will be used. // 2. Each DSP declares how many nameservers to use. Default is all. 0 indicates to use none. -func DetermineNameservers(dc *models.DomainConfig) ([]*models.Nameserver, error) { - return DetermineNameserversForProviders(dc, dc.DNSProviderInstances, false) -} - -// DetermineNameserversForProviders is like DetermineNameservers, for a subset of providers. func DetermineNameserversForProviders(dc *models.DomainConfig, providers []*models.DNSProviderInstance, silent bool) ([]*models.Nameserver, error) { // start with the nameservers that have been explicitly added: ns := dc.Nameservers @@ -68,18 +65,10 @@ func AddNSRecords(dc *models.DomainConfig) { } } for _, ns := range dc.Nameservers { - rc := &models.RecordConfig{ - Type: "NS", - Metadata: map[string]string{}, - TTL: ttl, - } - rc.SetLabel("@", dc.Name) - t := ns.Name - if !strings.HasSuffix(t, ".") { - t += "." - } - if err := rc.SetTarget(t); err != nil { - fmt.Printf("failed AddNSRecords rc.SetTarget(%q): %s\n", t, err) + rc, err := dc.NewRecordConfig("@", ttl, dnsv2.TypeNS, ns.Name, + nrc.Flags{TargetIsFqdnNoDot: true}) + if err != nil { + panic("Should not happen: " + err.Error()) } dc.Records = append(dc.Records, rc) diff --git a/pkg/nameutil/nameutil.go b/pkg/nameutil/nameutil.go new file mode 100644 index 0000000000..a8886af23e --- /dev/null +++ b/pkg/nameutil/nameutil.go @@ -0,0 +1,57 @@ +package nameutil + +import ( + dnsutilv2 "codeberg.org/miekg/dns/dnsutil" +) + +// ToFqdnWithDot converts a shortname to a FQDN+".". +// ToFqdnWithDot("foo", "bar.com") = "foo.bar.com." // Typical use. +// ToFqdnWithDot("@", "bar.com") = "bar.com." // Apex returns the apex. +// ToFqdnWithDot("", "bar.com") = "bar.com." // Apex returns the apex. +// ToFqdnWithDot("foo.com."," "bar.com") = "foo.com." // FQDNs are unmodified. +// ToFqdnWithDot("foo", "bar.com.") = "foo.bar.com." // If origin ends with a ".", DTRT. +// Similar to DomainConfig.ToFqdnWithDot() but it takes origin from dc.Name. +func ToFqdnWithDot(s, origin string) string { + if s == "" || s == "@" { + return dnsutilv2.Join(origin, ".") + } + if dnsutilv2.IsFqdn(s) { + return s + } + return dnsutilv2.Join(s, origin) +} + +// ToFqdnNoDot is the same as ToFqdnWithDot but the result does not include a trailing ".". +// Similar to DomainConfig.ToFqdnNoDot() but it takes origin from dc.Name. +func ToFqdnNoDot(s, origin string) string { + t := ToFqdnWithDot(s, origin) + return t[0 : len(t)-1] +} + +// ToShort trims origin from name. If name is not below origin, name is returned unchanged. +// If the name was shortened, it does not end with a ".". If the name was untouched, it ends with a ".". +// Calling ToShort on a string that is already a shortname is unsupported. Names that do not end with "." are assumed to be FQDNs without a trailing ".". +// Similar to DomainConfig.ToShort() but you can specify the origin. +func ToShort(name, origin string) string { + if name == "" || name == "@" { + return "@" + } + + // if !dnsutilv2.IsFqdn(name) { + // //return name + // name = name + "." + // } + + origin = dnsutilv2.Fqdn(origin) + name = dnsutilv2.Fqdn(name) + canonicalName := dnsutilv2.Canonical(name) + canonicalOrigin := dnsutilv2.Canonical(origin) + if canonicalName == canonicalOrigin { + return "@" + } + if dnsutilv2.IsBelow(canonicalOrigin, canonicalName) { + return dnsutilv2.Trim(name, origin) + } + + return name +} diff --git a/pkg/nameutil/nameutil_test.go b/pkg/nameutil/nameutil_test.go new file mode 100644 index 0000000000..b3b8d88da4 --- /dev/null +++ b/pkg/nameutil/nameutil_test.go @@ -0,0 +1,72 @@ +package nameutil_test + +import ( + "testing" + + "github.com/DNSControl/dnscontrol/v5/pkg/nameutil" +) + +func TestToFqdn(t *testing.T) { + tests := []struct { + name string + label string + origin string + wantDot string + wantND string + }{ + {name: "relative name", label: "foo", origin: "bar.com", wantDot: "foo.bar.com.", wantND: "foo.bar.com"}, + {name: "apex", label: "@", origin: "bar.com", wantDot: "bar.com.", wantND: "bar.com"}, + {name: "empty label", label: "", origin: "bar.com", wantDot: "bar.com.", wantND: "bar.com"}, + {name: "absolute name", label: "foo.com.", origin: "bar.com", wantDot: "foo.com.", wantND: "foo.com"}, + {name: "trailing dot", label: "foo", origin: "bar.com.", wantDot: "foo.bar.com.", wantND: "foo.bar.com"}, + {name: "current domain", label: "foo", origin: "**current-domain**.", wantDot: "foo.**current-domain**.", wantND: "foo.**current-domain**"}, + } + + for _, tt := range tests { + + t.Run(tt.name, func(t *testing.T) { + if got := nameutil.ToFqdnWithDot(tt.label, tt.origin); got != tt.wantDot { + t.Fatalf("ToFqdnWithDot(%q, %q) = %q; want %q", tt.label, tt.origin, got, tt.wantDot) + } + }) + + t.Run(tt.name, func(t *testing.T) { + if got := nameutil.ToFqdnNoDot(tt.label, tt.origin); got != tt.wantND { + t.Fatalf("ToFqdnNoDot(%q, %q) = %q; want %q", tt.label, tt.origin, got, tt.wantND) + } + }) + + } +} + +func TestToShort(t *testing.T) { + tests := []struct { + name string // description of this test case + // Named input parameters for target function. + s string + origin string + want string + }{ + {name: "apex", s: "example.com.", origin: "example.com", want: "@"}, + {name: "name in origin", s: "foo.example.com.", origin: "example.com", want: "foo"}, + {name: "nested name in origin", s: "a.b.example.com.", origin: "example.com", want: "a.b"}, + {name: "name outside origin", s: "foo.other.com.", origin: "example.com", want: "foo.other.com."}, + {name: "similar suffix", s: "bexample.com.", origin: "example.com", want: "bexample.com."}, + {name: "a similar suffix", s: "a.bexample.com.", origin: "example.com", want: "a.bexample.com."}, + // Repeat the tests with "s" not ending in a "." + {name: "apex", s: "example.com", origin: "example.com", want: "@"}, + {name: "name in origin", s: "foo.example.com", origin: "example.com", want: "foo"}, + {name: "nested name in origin", s: "a.b.example.com", origin: "example.com", want: "a.b"}, + {name: "name outside origin", s: "foo.other.com", origin: "example.com", want: "foo.other.com."}, + {name: "similar suffix", s: "bexample.com", origin: "example.com", want: "bexample.com."}, + {name: "a similar suffix", s: "a.bexample.com", origin: "example.com", want: "a.bexample.com."}, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + got := nameutil.ToShort(tt.s, tt.origin) + if got != tt.want { + t.Errorf("ToShort() = %v, want %v", got, tt.want) + } + }) + } +} diff --git a/pkg/normalize/flatten.go b/pkg/normalize/flatten.go index 3727a3e0ba..a42552c21e 100644 --- a/pkg/normalize/flatten.go +++ b/pkg/normalize/flatten.go @@ -7,8 +7,8 @@ import ( "strconv" "strings" - "github.com/DNSControl/dnscontrol/v4/models" - "github.com/DNSControl/dnscontrol/v4/pkg/spflib" + "github.com/DNSControl/dnscontrol/v5/models" + "github.com/DNSControl/dnscontrol/v5/pkg/spflib" ) func sortedKeys[K cmp.Ordered, V any](m map[K]V) []K { @@ -22,7 +22,7 @@ func sortedKeys[K cmp.Ordered, V any](m map[K]V) []K { return keys } -// hasSpfRecords returns true if this record requests SPF unrolling. +// flattenSPFs flattens SPF records. func flattenSPFs(cfg *models.DNSConfig) []error { var cache spflib.CachingResolver var errs []error diff --git a/pkg/normalize/importTransform_test.go b/pkg/normalize/importTransform_test.go index 415ac2f381..84eb5c5a8e 100644 --- a/pkg/normalize/importTransform_test.go +++ b/pkg/normalize/importTransform_test.go @@ -3,40 +3,34 @@ package normalize import ( "testing" - "github.com/DNSControl/dnscontrol/v4/models" + dnsv2 "codeberg.org/miekg/dns" + "github.com/DNSControl/dnscontrol/v5/models" + "github.com/DNSControl/dnscontrol/v5/pkg/privatetypes" ) -func makeRC(label, domain, target string, rc models.RecordConfig) *models.RecordConfig { - rc.SetLabel(label, domain) - rc.MustSetTarget(target) - return &rc -} - func TestImportTransform(t *testing.T) { const transformDouble = "0.0.0.0~1.1.1.1~~9.0.0.0,10.0.0.0" const transformSingle = "0.0.0.0~1.1.1.1~~8.0.0.0" - src := &models.DomainConfig{ - Name: "stackexchange.com", - Records: []*models.RecordConfig{ - makeRC("*", "stackexchange.com", "0.0.2.2", models.RecordConfig{Type: "A"}), - makeRC("www", "stackexchange.com", "0.0.1.1", models.RecordConfig{Type: "A"}), - }, - } - dst := &models.DomainConfig{ - Name: "internal", - Records: []*models.RecordConfig{ - makeRC("*.stackexchange.com", "*.stackexchange.com.internal", "0.0.3.3", models.RecordConfig{Type: "A", Metadata: map[string]string{"transform_table": transformSingle}}), - makeRC("@", "internal", "stackexchange.com", models.RecordConfig{Type: "IMPORT_TRANSFORM", Metadata: map[string]string{"transform_table": transformDouble}}), - }, - } - cfg := &models.DNSConfig{ - Domains: []*models.DomainConfig{src, dst}, - } + + dcSrc := models.MustNewDomainConfig("stackexchange.com") + dcSrc.AddRecordConfig(dcSrc.MustNewRecordConfig("*", 0, dnsv2.TypeA, "0.0.2.2")) + dcSrc.AddRecordConfig(dcSrc.MustNewRecordConfig("www", 0, dnsv2.TypeA, "0.0.1.1")) + + dcDst := models.MustNewDomainConfig("internal") + d1 := dcDst.MustNewRecordConfig("*.stackexchange.com", 0, dnsv2.TypeA, "0.0.3.3") + d1.Metadata = map[string]string{"transform_table": transformSingle} + dcDst.AddRecordConfig(d1) + + d2 := dcSrc.MustNewRecordConfig("@", 0, privatetypes.TypeIMPORTTRANSFORM, transformDouble, 299, "com.internal", "internal") + d2.Metadata["transform_table"] = transformDouble + dcDst.AddRecordConfig(d2) + + cfg := &models.DNSConfig{} + cfg.Domains = append(cfg.Domains, dcSrc, dcDst) err := cfg.PostProcess() if err != nil { t.Fatal(err) } - // No need to call rtypecontrol.FixLegacyDC here. makeRC will (in the future) populate .F as needed. if errs := ValidateAndNormalizeConfig(cfg); len(errs) != 0 { for _, err := range errs { diff --git a/pkg/normalize/validate.go b/pkg/normalize/validate.go index fdcbb739bc..9ba0079e8b 100644 --- a/pkg/normalize/validate.go +++ b/pkg/normalize/validate.go @@ -3,40 +3,22 @@ package normalize import ( "errors" "fmt" - "net/netip" "slices" "sort" "strconv" "strings" - "github.com/DNSControl/dnscontrol/v4/models" - "github.com/DNSControl/dnscontrol/v4/pkg/providers" - "github.com/DNSControl/dnscontrol/v4/pkg/transform" - dnsv1 "github.com/miekg/dns" - dnsutilv1 "github.com/miekg/dns/dnsutil" + dnsv2 "codeberg.org/miekg/dns" + "github.com/DNSControl/dnscontrol/v5/models" + "github.com/DNSControl/dnscontrol/v5/pkg/nameutil" + "github.com/DNSControl/dnscontrol/v5/pkg/nrc" + "github.com/DNSControl/dnscontrol/v5/pkg/providers" + "github.com/DNSControl/dnscontrol/v5/pkg/transform" ) -// Returns false if target does not validate. -func checkIPv4(label string) error { - if addr, err := netip.ParseAddr(label); err != nil || !addr.Is4() { - return fmt.Errorf("WARNING: target (%v) is not an IPv4 address", label) - } - return nil -} - -// Returns false if target does not validate. -func checkIPv6(label string) error { - if addr, err := netip.ParseAddr(label); err != nil || !addr.Is6() { - return fmt.Errorf("WARNING: target (%v) is not an IPv6 address", label) - } - return nil -} - // make sure target is valid reference for cnames, mx, etc. func checkTarget(target string) error { - if target == "@" { - return nil - } + // The target shouldn't be "@". It should be $origin+"." if target == "" { return errors.New("empty target (\"\"). Did you mean \"@\" instead?") } @@ -46,17 +28,15 @@ func checkTarget(target string) error { if !strings.HasSuffix(target, ".in-addr.arpa.") && strings.Contains(target, "/") { return fmt.Errorf("target (%v) includes invalid char", target) } - // If it contains a ".", it must end in a ".". - if strings.ContainsRune(target, '.') && target[len(target)-1] != '.' { - return fmt.Errorf("target (%v) must end with a (.) [https://docs.dnscontrol.org/language-reference/why-the-dot]", target) - } return nil } -// validateRecordTypes list of valid rec.Type values. Returns true if this is a real DNS record type, false means it is a pseudo-type used internally. +// validateRecordTypes returns an error if this type is incompatible with the provider. +// FIXME(tlim): Is this needed any more? func validateRecordTypes(rec *models.RecordConfig, domain string, pTypes []string) error { - if rec.IsModernType() { - // Modern types do their own validation. + switch rec.Type { + // RCv3 records do not need this validation step. + case "CLOUDFLAREAPI_SINGLE_REDIRECT", "RP", "DS": return nil } @@ -89,9 +69,10 @@ func validateRecordTypes(rec *models.RecordConfig, domain string, pTypes []strin } _, ok := validTypes[rec.Type] if !ok { + cType := providers.GetCustomRecordType(rec.Type) if cType == nil { - return fmt.Errorf("unsupported record type (%v) domain=%v name=%v", rec.Type, domain, rec.GetLabel()) + return fmt.Errorf("unsupported record type (%v) domain=%v name=%v Type=%s TypeNum=%d", rec.Type, domain, rec.GetLabel(), rec.Type, rec.TypeNum) } for _, providerType := range pTypes { if providerType != cType.Provider { @@ -154,6 +135,8 @@ func checkLabel(label string, rType string, domain string, meta map[string]strin return nil } +// checkSoa checks the elements of an SOA. +// FIXME(tlim): Move this to MakeSOA(). (Note to self: API-downloaded items aren't run through validate). func checkSoa(expire uint32, minttl uint32, refresh uint32, retry uint32, mbox string) error { if expire <= 0 { return errors.New("SOA Expire must be > 0") @@ -176,18 +159,18 @@ func checkSoa(expire uint32, minttl uint32, refresh uint32, retry uint32, mbox s return nil } -// checkTargets returns true if rec.Target is valid for the rec.Type. +// checkTargets returns zero or more errors when problems are found. +// FYI: Many of these checks are obsolete since Make*() does the same thing. We'll be removing the duplicate checks over time. func checkTargets(rec *models.RecordConfig, domain string) (errs []error) { - if rec.IsModernType() { - // Modern types do their own validation. + switch rec.Type { + case "CLOUDFLAREAPI_SINGLE_REDIRECT", "RP", "DS": return nil } label := rec.GetLabel() - target := rec.GetTargetField() check := func(e error) { if e != nil { - err := fmt.Errorf("%s: %s %s.%s: %s", rec.FilePos, rec.Type, rec.GetLabel(), domain, e.Error()) + err := fmt.Errorf("%s: %s %s: %s", rec.FilePos, rec.Type, rec.GetLabelFQDN(), e.Error()) if _, ok := e.(Warning); ok { err = Warning{err} } @@ -195,57 +178,60 @@ func checkTargets(rec *models.RecordConfig, domain string) (errs []error) { } } switch rec.Type { // #rtype_variations + + // No longer needed case "A": - check(checkIPv4(target)) case "AAAA": - check(checkIPv6(target)) + case "LOC": + case "CAA", "DHCID", "DNSKEY", "DS", "HTTPS", "IMPORT_TRANSFORM", "OPENPGPKEY", "SMIMEA", "SSHFP", "SVCB", "TLSA", "TXT": + case "ALIAS": - check(checkTarget(target)) + check(checkTarget(rec.AsALIAS().Target)) case "CNAME": - check(checkTarget(target)) + check(checkTarget(rec.AsCNAME().Target)) if label == "@" { - check(errors.New("cannot create CNAME record for bare domain")) + check(errors.New("cannot create CNAME record for bare domain. Use ALIAS")) } - labelFQDN := dnsutilv1.AddOrigin(label, domain) - targetFQDN := dnsutilv1.AddOrigin(target, domain) + labelFQDN := nameutil.ToFqdnNoDot(label, domain) + targetFQDN := nameutil.ToFqdnNoDot(rec.AsCNAME().Target, domain) if labelFQDN == targetFQDN { check(errors.New("CNAME loop (target points at itself)")) } case "DNAME": - check(checkTarget(target)) - case "LOC": + check(checkTarget(rec.AsDNAME().Target)) case "MX": - check(checkTarget(target)) + check(checkTarget(rec.AsMX().Mx)) case "NAPTR": + target := rec.AsNAPTR().Replacement if target != "" { check(checkTarget(target)) } case "NS": - check(checkTarget(target)) + check(checkTarget(rec.AsNS().Ns)) if label == "@" { check(errors.New("cannot create NS record for bare domain. Use NAMESERVER instead")) } case "PTR": - check(checkTarget(target)) + check(checkTarget(rec.AsPTR().Ptr)) case "SOA": - check(checkSoa(rec.SoaExpire, rec.SoaMinttl, rec.SoaRefresh, rec.SoaRetry, rec.SoaMbox)) - check(checkTarget(target)) + f := rec.AsSOA() + check(checkSoa(f.Expire, f.Minttl, f.Refresh, f.Retry, f.Mbox)) + check(checkTarget(f.Ns)) if label != "@" { check(errors.New("SOA record is only valid for bare domain")) } case "SRV": - check(checkTarget(target)) + check(checkTarget(rec.AsSRV().Target)) case "LUA": - upper := strings.ToUpper(rec.LuaRType) + f := rec.AsLUA() + upper := strings.ToUpper(f.LuaType) if upper == "" { check(errors.New("LUA records must specify an emitted rtype")) break } - if _, ok := dnsv1.StringToType[upper]; !ok { - check(fmt.Errorf("LUA emitted rtype (%s) is not a valid DNS type", rec.LuaRType)) + if _, ok := dnsv2.StringToType[upper]; !ok { + check(fmt.Errorf("LUA emitted rtype (%s) is not a valid DNS type", f.LuaType)) } - rec.LuaRType = upper - case "CAA", "DHCID", "DNSKEY", "DS", "HTTPS", "IMPORT_TRANSFORM", "OPENPGPKEY", "SMIMEA", "SSHFP", "SVCB", "TLSA", "TXT": default: if rec.Metadata["orig_custom_type"] != "" { // it is a valid custom type. We perform no validation on target @@ -265,7 +251,7 @@ func transformCNAME(target, oldDomain, newDomain, suffixstrip string) string { if strings.HasSuffix(target, ".") { return target + nd + "." } - return dnsutilv1.AddOrigin(target, oldDomain) + "." + nd + "." + return nameutil.ToFqdnWithDot(target, oldDomain) + nd + "." } func newRec(rec *models.RecordConfig, ttl uint32) *models.RecordConfig { @@ -308,10 +294,10 @@ func importTransform(srcDomain, dstDomain *models.DomainConfig, } switch rec.Type { case "A": - addr, _ := netip.ParseAddr(rec.GetTargetField()) + addr := rec.AsA().Addr trs, err := transform.IPToList(addr, transforms) if err != nil { - return fmt.Errorf("import_transform: TransformIP(%v, %v) returned err=%w", rec.GetTargetField(), transforms, err) + return fmt.Errorf("import_transform: TransformIP(%v, %v) returned err=%w", addr, transforms, err) } for _, tr := range trs { r := newRec(rec, ttl) @@ -320,9 +306,13 @@ func importTransform(srcDomain, dstDomain *models.DomainConfig, return err } r.SetLabel(l, dstDomain.Name) - if err := r.SetTarget(tr.String()); err != nil { + + rd, err := models.MakeA(dstDomain.Name, rec.Metadata, nrc.Flags{}, tr.String()) + if err != nil { return err } + r.SetRDATA(rd) + dstDomain.Records = append(dstDomain.Records, r) } case "CNAME": @@ -332,9 +322,13 @@ func importTransform(srcDomain, dstDomain *models.DomainConfig, return err } r.SetLabel(l, dstDomain.Name) - if err := r.SetTarget(transformCNAME(r.GetTargetField(), srcDomain.Name, dstDomain.Name, suffixstrip)); err != nil { + + rd, err := models.MakeCNAME(dstDomain.Name, rec.Metadata, nrc.Flags{}, transformCNAME(r.AsCNAME().Target, srcDomain.Name, dstDomain.Name, suffixstrip)) + if err != nil { return err } + r.SetRDATA(rd) + dstDomain.Records = append(dstDomain.Records, r) default: // Anything else is ignored. @@ -346,8 +340,8 @@ func importTransform(srcDomain, dstDomain *models.DomainConfig, // deleteImportTransformRecords deletes any IMPORT_TRANSFORM records from a domain. func deleteImportTransformRecords(domain *models.DomainConfig) { - for i := len(domain.Records) - 1; i >= 0; i-- { - rec := domain.Records[i] + for i, rec := range slices.Backward(domain.Records) { + if rec.Type == "IMPORT_TRANSFORM" { domain.Records = append(domain.Records[:i], domain.Records[i+1:]...) } @@ -394,31 +388,29 @@ func ValidateAndNormalizeConfig(config *models.DNSConfig) (errs []error) { errs = append(errs, err) } // Unlike any other FQDN in this system, it is stored as a FQDN without the trailing dot. - n := dnsutilv1.AddOrigin(ns.Name, domain.Name+".") + n := nameutil.ToFqdnWithDot(ns.Name, domain.Name) ns.Name = strings.TrimSuffix(n, ".") } // Normalize Records. - models.PostProcessRecords(domain.Records) - // No need to call FixLegacyDC here. These records were created from dnsconfig.js, not from a provider. for _, rec := range domain.Records { if rec.TTL == 0 { rec.TTL = models.DefaultTTL } // Canonicalize Label: - if rec.GetLabel() == (domain.Name + ".") { - // If label == ${domain}DOT, change to "@" - rec.SetLabel("@", domain.Name) - } else if lab, suf := rec.GetLabel(), "."+domain.Name+"."; strings.HasSuffix(lab, suf) { - // If label ends with DOT${domain}DOT, strip it to a short name. - rec.SetLabel(lab[:len(lab)-len(suf)], domain.Name) - } + //if rec.GetLabel() == (domain.Name + ".") { + // // If label == ${domain}DOT, change to "@" + // rec.SetLabel("@", domain.Name) + //} else if lab, suf := rec.GetLabel(), "."+domain.Name+"."; strings.HasSuffix(lab, suf) { + // // If label ends with DOT${domain}DOT, strip it to a short name. + // rec.SetLabel(lab[:len(lab)-len(suf)], domain.Name) + //} // If label ends with dot, add to the list of errors. - if strings.HasSuffix(rec.GetLabel(), ".") { - errs = append(errs, fmt.Errorf("label %q does not match D(%q)", rec.GetLabel(), domain.Name)) - return errs // Exit early. - } + //if strings.HasSuffix(rec.GetLabel(), ".") { + // errs = append(errs, fmt.Errorf("label %q does not match D(%q)", rec.GetLabel(), domain.Name)) + // return errs // Exit early. + //} // in-addr.arpa magic if strings.HasSuffix(domain.Name, ".in-addr.arpa") || strings.HasSuffix(domain.Name, ".ip6.arpa") { @@ -442,22 +434,6 @@ func ValidateAndNormalizeConfig(config *models.DNSConfig) (errs []error) { // Canonicalize Targets. switch rec.Type { // #rtype_variations - case "ALIAS", "CNAME", "MX", "NS", "SRV": - // #rtype_variations - // These record types have a target that is a hostname. - // We normalize them to a FQDN so there is less variation to handle. If a - // provider API requires a shortname, the provider must do the shortening. - origin := domain.Name + "." - if rec.SubDomain != "" { - origin = rec.SubDomain + "." + origin - } - if err := rec.SetTarget(dnsutilv1.AddOrigin(rec.GetTargetField(), origin)); err != nil { - errs = append(errs, err) - } - case "A", "AAAA": - if err := rec.SetTargetIP(rec.GetTargetIP()); err != nil { - errs = append(errs, err) - } case "PTR": var err error var name string @@ -468,43 +444,57 @@ func ValidateAndNormalizeConfig(config *models.DNSConfig) (errs []error) { case "CAA": // Per: https://www.iana.org/assignments/pkix-parameters/pkix-parameters.xhtml#caa-properties excluding reserved tags allowedTags := []string{"issue", "issuewild", "iodef", "contactemail", "contactphone", "issuemail", "issuevmc"} - if !slices.Contains(allowedTags, rec.CaaTag) { - errs = append(errs, fmt.Errorf("CAA tag %s is invalid", rec.CaaTag)) + f := rec.AsCAA() + if !slices.Contains(allowedTags, f.Tag) { + errs = append(errs, fmt.Errorf("CAA tag %s is invalid", f.Tag)) } case "OPENPGPKEY": - target := rec.GetTargetField() - if target, err = transform.OPENPGPKEY(target); err != nil { + var orig, transformed, final string + var err error + orig = rec.AsOPENPGPKEY().PublicKey + transformed, err = transform.OPENPGPKEY(orig) + if err != nil { + final = orig errs = append(errs, err) } else { - if err := rec.SetTarget(target); err != nil { + final = transformed + } + if orig != final { + rd, err := models.MakeOPENPGPKEY("", nil, nrc.Flags{}, final) + if err != nil { errs = append(errs, err) } + rec.SetRDATA(rd) } + case "TLSA": - if rec.TlsaUsage > 3 { + f := rec.AsTLSA() + if f.Usage > 3 { + f := rec.AsTLSA() errs = append(errs, fmt.Errorf("TLSA Usage %d is invalid in record %s (domain %s)", - rec.TlsaUsage, rec.GetLabel(), domain.Name)) + f.Usage, rec.GetLabel(), domain.Name)) } - if rec.TlsaSelector > 1 { + if f.Selector > 1 { errs = append(errs, fmt.Errorf("TLSA Selector %d is invalid in record %s (domain %s)", - rec.TlsaSelector, rec.GetLabel(), domain.Name)) + f.Selector, rec.GetLabel(), domain.Name)) } - if rec.TlsaMatchingType > 2 { + if f.MatchingType > 2 { errs = append(errs, fmt.Errorf("TLSA MatchingType %d is invalid in record %s (domain %s)", - rec.TlsaMatchingType, rec.GetLabel(), domain.Name)) + f.MatchingType, rec.GetLabel(), domain.Name)) } case "SMIMEA": - if rec.SmimeaUsage > 3 { + f := rec.AsSMIMEA() + if f.Usage > 3 { errs = append(errs, fmt.Errorf("SMIMEA Usage %d is invalid in record %s (domain %s)", - rec.SmimeaUsage, rec.GetLabel(), domain.Name)) + f.Usage, rec.GetLabel(), domain.Name)) } - if rec.SmimeaSelector > 1 { + if f.Selector > 1 { errs = append(errs, fmt.Errorf("SMIMEA Selector %d is invalid in record %s (domain %s)", - rec.SmimeaSelector, rec.GetLabel(), domain.Name)) + f.Selector, rec.GetLabel(), domain.Name)) } - if rec.SmimeaMatchingType > 2 { + if f.MatchingType > 2 { errs = append(errs, fmt.Errorf("SMIMEA MatchingType %d is invalid in record %s (domain %s)", - rec.SmimeaMatchingType, rec.GetLabel(), domain.Name)) + f.MatchingType, rec.GetLabel(), domain.Name)) } } @@ -526,18 +516,22 @@ func ValidateAndNormalizeConfig(config *models.DNSConfig) (errs []error) { for _, domain := range config.Domains { for _, rec := range domain.Records { if rec.Type == "IMPORT_TRANSFORM" { - suffixstrip := rec.Metadata["transform_suffixstrip"] - table, err := transform.DecodeTransformTable(rec.Metadata["transform_table"]) + rd := rec.AsIMPORTTRANSFORM() + transformTable := rd.TransformTable + ttl := uint32(rd.TTL) + suffixstrip := rd.SuffixStrip + targetDomain := rd.TargetDomain + table, err := transform.DecodeTransformTable(transformTable) if err != nil { errs = append(errs, err) continue } - c := config.FindDomain(rec.GetTargetField()) + c := config.FindDomain(targetDomain) if c == nil { - err = fmt.Errorf("IMPORT_TRANSFORM mentions non-existent domain %q", rec.GetTargetField()) + err = fmt.Errorf("IMPORT_TRANSFORM mentions non-existent domain %q", targetDomain) errs = append(errs, err) } - err = importTransform(c, domain, table, rec.TTL, suffixstrip) + err = importTransform(c, domain, table, ttl, suffixstrip) if err != nil { errs = append(errs, err) } @@ -683,10 +677,11 @@ func checkMultipleSOAs(dc *models.DomainConfig) (errs []error) { return } -func checkDuplicates(records []*models.RecordConfig) (errs []error) { - seen := map[string]*models.RecordConfig{} +func checkDuplicates(records models.Records) (errs []error) { + seen := make(map[string]*models.RecordConfig) for _, r := range records { - diffable := fmt.Sprintf("%s %s %s", r.GetLabelFQDN(), r.Type, r.ToComparableNoTTL()) + diffable := fmt.Sprintf("%s %s %s", r.GetLabelFQDN(), r.Type, r.ComparableV3) + if seen[diffable] != nil { errs = append(errs, fmt.Errorf("exact duplicate record found: %s", diffable)) } @@ -695,7 +690,7 @@ func checkDuplicates(records []*models.RecordConfig) (errs []error) { return errs } -func checkRecordSetHasMultipleTTLs(records []*models.RecordConfig) (errs []error) { +func checkRecordSetHasMultipleTTLs(records models.Records) (errs []error) { // The RFCs say that all records at a particular recordset should have // the same TTL. Most providers don't care, and if they do the // dnscontrol provider code usually picks the lowest TTL for all of them. @@ -708,6 +703,9 @@ func checkRecordSetHasMultipleTTLs(records []*models.RecordConfig) (errs []error // Find the inconsistencies: m := make(map[string]map[uint32]map[string]bool) for _, r := range records { + if !r.IsTTLSignificant() { + continue + } label := r.GetLabelFQDN() ttl := r.TTL rtype := r.Type @@ -785,7 +783,7 @@ func commaSepInts(list []int) string { // checkR53WeightedGroupConsistency validates that all records sharing the same // label+type+set_identifier have identical weight and health_check_id, since // they map to a single Route 53 ResourceRecordSet. -func checkR53WeightedGroupConsistency(records []*models.RecordConfig) (errs []error) { +func checkR53WeightedGroupConsistency(records models.Records) (errs []error) { type groupMeta struct { weight string healthCheck string @@ -972,7 +970,7 @@ func applyRecordTransforms(domain *models.DomainConfig) error { for i, newIP := range newIPs { if i == 0 && newIP.Compare(ip) != 0 { // replace target of first record if different - if err := rec.SetTarget(newIP.String()); err != nil { + if err := rec.SetTargetIP(newIP); err != nil { return err } } else if i > 0 { @@ -981,7 +979,7 @@ func applyRecordTransforms(domain *models.DomainConfig) error { if err != nil { return err } - if err := cpy.SetTarget(newIP.String()); err != nil { + if err := cpy.SetTargetIP(newIP); err != nil { return err } domain.Records = append(domain.Records, cpy) diff --git a/pkg/normalize/validate_test.go b/pkg/normalize/validate_test.go index 12e6ec2806..d539ed6568 100644 --- a/pkg/normalize/validate_test.go +++ b/pkg/normalize/validate_test.go @@ -4,8 +4,9 @@ import ( "fmt" "testing" - "github.com/DNSControl/dnscontrol/v4/models" - "github.com/DNSControl/dnscontrol/v4/pkg/providers" + dnsv2 "codeberg.org/miekg/dns" + "github.com/DNSControl/dnscontrol/v5/models" + "github.com/DNSControl/dnscontrol/v5/pkg/providers" ) func TestSoaLabelAndTarget(t *testing.T) { @@ -15,17 +16,18 @@ func TestSoaLabelAndTarget(t *testing.T) { target string }{ {false, "@", "ns1.foo.com."}, + // Invalid target - {true, "@", "ns1.foo.com"}, + // {true, "@", "ns1.foo.com"}, + // Commented out because MustNewRecordConfig fixes this. + // Invalid label, only '@' is allowed for SOA records {true, "foo.com", "ns1.foo.com."}, } + dc := models.MustNewDomainConfig("foo.com") for _, test := range tests { experiment := fmt.Sprintf("%s %s", test.label, test.target) - rc := makeRC(test.label, "foo.com", test.target, models.RecordConfig{ - Type: "SOA", - SoaExpire: 1, SoaMinttl: 1, SoaRefresh: 1, SoaRetry: 1, SoaSerial: 1, SoaMbox: "bar.foo.com", - }) + rc := dc.MustNewRecordConfig(test.label, 0, dnsv2.TypeSOA, test.target, "bar.foo.com", 1, 1, 1, 1, 1) err := checkTargets(rc, "foo.com") if err != nil && !test.isError { t.Errorf("%v: Error (%v)\n", experiment, err) @@ -77,16 +79,9 @@ func TestCheckSoa(t *testing.T) { } func TestCheckMultipleSOAs(t *testing.T) { - dcSingleSoa := &models.DomainConfig{ - Name: "foo.com", - RegistrarName: "BIND", - Records: []*models.RecordConfig{ - makeRC("@", "foo.com", "ns1.foo.com.", models.RecordConfig{ - Type: "SOA", - SoaExpire: 1, SoaMinttl: 1, SoaRefresh: 1, SoaRetry: 1, SoaSerial: 1, SoaMbox: "bar.foo.com", - }), - }, - } + dcSingleSoa := models.MustNewDomainConfig("foo.com") + dcSingleSoa.RegistrarName = "BIND" + dcSingleSoa.AddTestRC(t, "@", 0, dnsv2.TypeSOA, "ns1.foo.com.", "bar.foo.com", 1, 1, 1, 1, 1) t.Run("single_SOA", func(t *testing.T) { errs := checkMultipleSOAs(dcSingleSoa) @@ -97,12 +92,7 @@ func TestCheckMultipleSOAs(t *testing.T) { dcTwoSoas := dcSingleSoa // Add another SOA record to DC - dcTwoSoas.Records = append(dcTwoSoas.Records, - makeRC("@", "foo.com", "ns2.foo.com.", models.RecordConfig{ - Type: "SOA", - SoaExpire: 1, SoaMinttl: 1, SoaRefresh: 1, SoaRetry: 1, SoaSerial: 1, SoaMbox: "bar.foo.com", - }), - ) + dcTwoSoas.AddTestRC(t, "@", 0, dnsv2.TypeSOA, "ns2.foo.com.", "bar.foo.com", 1, 1, 1, 1, 1) t.Run("two_SOAs", func(t *testing.T) { errs := checkMultipleSOAs(dcTwoSoas) @@ -159,33 +149,13 @@ func checkError(t *testing.T, err error, shouldError bool, experiment string) { } } -func Test_assert_valid_ipv4(t *testing.T) { - tests := []struct { - experiment string - isError bool - }{ - {"1.2.3.4", false}, - {"1.2.3.4/10", true}, - {"1.2.3", true}, - {"foo", true}, - } - - for _, test := range tests { - err := checkIPv4(test.experiment) - checkError(t, err, test.isError, test.experiment) - } -} - func Test_assert_valid_target(t *testing.T) { tests := []struct { experiment string isError bool }{ - {"@", false}, {"foo", false}, - {"foo.bar.", false}, {"foo.", false}, - {"foo.bar", true}, {"foo&bar", true}, {"foo bar", true}, {"elb21.freshdesk.com/", true}, @@ -295,10 +265,9 @@ func Test_transform_cname_strip(t *testing.T) { } func TestNSAtRoot(t *testing.T) { + dc := models.MustNewDomainConfig("foo.com") // do not allow ns records for @ - rec := &models.RecordConfig{Type: "NS"} - rec.SetLabel("test", "foo.com") - rec.MustSetTarget("ns1.name.com.") + rec := dc.MustNewRecordConfig(dc.LabelFromShort("test"), 0, dnsv2.TypeNS, "ns1.name.com.") errs := checkTargets(rec, "foo.com") if len(errs) > 0 { t.Error("Expect no error with ns record on subdomain") @@ -321,11 +290,11 @@ func TestTransforms(t *testing.T) { } const transform = "0.0.0.0~1.0.0.0~2.0.0.0~; 3.0.0.0~4.0.0.0~~5.5.5.5; 7.0.0.0~8.0.0.0~~9.9.9.9,10.10.10.10" for i, test := range tests { - dc := &models.DomainConfig{ - Records: []*models.RecordConfig{ - makeRC("f", "example.tld", test.givenIP, models.RecordConfig{Type: "A", Metadata: map[string]string{"transform": transform}}), - }, - } + dc := models.MustNewDomainConfig("example.tld") + rc1 := dc.MustNewRecordConfig("f", 0, dnsv2.TypeA, test.givenIP) + rc1.Metadata = map[string]string{"transform": transform} + dc.AddRecordConfig(rc1) + err := applyRecordTransforms(dc) if err != nil { t.Errorf("error on test %d: %s", i, err) @@ -336,234 +305,178 @@ func TestTransforms(t *testing.T) { continue } for r, rec := range dc.Records { - if rec.GetTargetField() != test.expectedRecords[r] { - t.Errorf("test %d at index %d: records don't match. Expect %s but found %s.", i, r, test.expectedRecords[r], rec.GetTargetField()) + got := rec.AsA().Addr.String() + if got != test.expectedRecords[r] { + t.Errorf("test %d at index %d: records don't match. Expect %s but found %s.", i, r, test.expectedRecords[r], got) continue } } } } -func TestCNAMEMutex(t *testing.T) { - recA := &models.RecordConfig{Type: "CNAME"} - recA.SetLabel("foo", "foo.example.com") - recA.MustSetTarget("example.com.") - tests := []struct { - rType string - name string - fail bool - }{ - {"A", "foo", true}, - {"A", "foo2", false}, - {"CNAME", "foo", true}, - {"CNAME", "foo2", false}, - } - for _, tst := range tests { - t.Run(fmt.Sprintf("%s %s", tst.rType, tst.name), func(t *testing.T) { - recB := &models.RecordConfig{Type: tst.rType} - recB.SetLabel(tst.name, "example.com") - recB.MustSetTarget("example2.com.") - dc := &models.DomainConfig{ - Name: "example.com", - Records: []*models.RecordConfig{recA, recB}, - } - errs := checkCNAMEs(dc) - if errs != nil && !tst.fail { - t.Error("Got error but expected none") - } - if errs == nil && tst.fail { - t.Error("Expected error but got none") - } - }) - } -} - func TestCNAMECloudflareProxied(t *testing.T) { + dc := models.MustNewDomainConfig("example.com") // A proxied (flattened) CNAME should be allowed alongside other record types. - recCNAME := &models.RecordConfig{ - Type: "CNAME", - Metadata: map[string]string{"cloudflare_proxy": "on"}, - } - recCNAME.SetLabel("mail", "mail.example.com") - recCNAME.MustSetTarget("example.com.") - recMX := &models.RecordConfig{Type: "MX"} - recMX.SetLabel("mail", "mail.example.com") - recMX.MustSetTarget("smtp.example.com.") - dc := &models.DomainConfig{ - Name: "example.com", - Records: []*models.RecordConfig{recCNAME, recMX}, - } + recCNAME := dc.MustNewRecordConfig("mail", 0, dnsv2.TypeCNAME, "example.com.") + recCNAME.Metadata["cloudflare_proxy"] = "on" + dc.AddRecordConfig(recCNAME) + recMX := dc.MustNewRecordConfig("mail", 0, dnsv2.TypeMX, 10, "smtp.example.com.") + dc.AddRecordConfig(recMX) errs := checkCNAMEs(dc) if len(errs) != 0 { t.Errorf("Expected no errors for proxied CNAME + MX, got: %v", errs) } // A non-proxied CNAME should still fail. - recCNAME2 := &models.RecordConfig{Type: "CNAME"} - recCNAME2.SetLabel("mail", "mail.example.com") - recCNAME2.MustSetTarget("example.com.") - dc2 := &models.DomainConfig{ - Name: "example.com", - Records: []*models.RecordConfig{recCNAME2, recMX}, - } + dc2 := models.MustNewDomainConfig("example.com") + recCNAME2 := dc2.MustNewRecordConfig("mail", 0, dnsv2.TypeCNAME, "example.com.") + //recCNAME2.SetLabel("mail", "mail.example.com") + recMX2 := dc2.MustNewRecordConfig("mail", 0, dnsv2.TypeMX, 10, "smtp.example.com.") + dc2.AddRecordConfig(recCNAME2) + dc2.AddRecordConfig(recMX2) errs2 := checkCNAMEs(dc2) if len(errs2) == 0 { t.Error("Expected error for non-proxied CNAME + MX, got none") } } -func TestCAAValidation(t *testing.T) { - config := &models.DNSConfig{ - Domains: []*models.DomainConfig{ - { - Name: "example.com", - RegistrarName: "BIND", - Records: []*models.RecordConfig{ - makeRC("@", "example.com", "example.com", models.RecordConfig{Type: "CAA", CaaTag: "invalid"}), - }, - }, - }, - } - errs := ValidateAndNormalizeConfig(config) - if len(errs) != 1 { - t.Error("Expect error on invalid CAA but got none") - } -} - func TestCheckDuplicates(t *testing.T) { - records := []*models.RecordConfig{ - // The only difference is the target: - makeRC("www", "example.com", "4.4.4.4", models.RecordConfig{Type: "A"}), - makeRC("www", "example.com", "5.5.5.5", models.RecordConfig{Type: "A"}), - // 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"}), - // 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) + dc := models.MustNewDomainConfig("example.com") + + // The only difference is the target: + dc.AddTestRC(t, "www", 0, dnsv2.TypeA, "4.4.4.4") + dc.AddTestRC(t, "www", 0, dnsv2.TypeA, "5.5.5.5") + // The only difference is the rType: + dc.AddTestRC(t, "aaa", 0, dnsv2.TypeNS, "uniquestring.com.") + dc.AddTestRC(t, "aaa", 0, dnsv2.TypePTR, "uniquestring.com.") + // Three records each with a different target. + dc.AddTestRC(t, "@", 0, dnsv2.TypeNS, "ns1.foo.com.") + dc.AddTestRC(t, "@", 0, dnsv2.TypeNS, "ns2.foo.com.") + dc.AddTestRC(t, "@", 0, dnsv2.TypeNS, "ns3.foo.com.") + + // NOTE: The comparison ignores ttl. Therefore we don't test that. + errs := checkDuplicates(dc.Records) if len(errs) != 0 { t.Errorf("Expected duplicate NOT found but found %q", errs) } } func TestCheckDuplicates_dup_a(t *testing.T) { - records := []*models.RecordConfig{ - // A records that are exact dupliates. - makeRC("@", "example.com", "1.1.1.1", models.RecordConfig{Type: "A"}), - makeRC("@", "example.com", "1.1.1.1", models.RecordConfig{Type: "A"}), - } - errs := checkDuplicates(records) + dc := models.MustNewDomainConfig("example.com") + + // A records that are exact dupliates. + dc.AddTestRC(t, "@", 0, dnsv2.TypeA, "1.1.1.1") + dc.AddTestRC(t, "@", 0, dnsv2.TypeA, "1.1.1.1") + + errs := checkDuplicates(dc.Records) if len(errs) == 0 { t.Error("Expect duplicate found but found none") } } func TestCheckDuplicates_dup_ns(t *testing.T) { - records := []*models.RecordConfig{ - // Three records, the last 2 are duplicates. - // NB: This is a common issue. - makeRC("@", "example.com", "ns1.foo.com.", models.RecordConfig{Type: "NS"}), - makeRC("@", "example.com", "ns2.foo.com.", models.RecordConfig{Type: "NS"}), - makeRC("@", "example.com", "ns2.foo.com.", models.RecordConfig{Type: "NS"}), - } - errs := checkDuplicates(records) + dc := models.MustNewDomainConfig("example.com") + + // Three records, the last 2 are duplicates. + // NB: This is a common issue. + dc.AddTestRC(t, "@", 0, dnsv2.TypeNS, "ns1.foo.com.") + dc.AddTestRC(t, "@", 0, dnsv2.TypeNS, "ns2.foo.com.") + dc.AddTestRC(t, "@", 0, dnsv2.TypeNS, "ns2.foo.com.") + + errs := checkDuplicates(dc.Records) if len(errs) == 0 { t.Error("Expect duplicate found but found none") } } func TestCheckRecordSetHasMultipleTTLs_err_1type_2ttl(t *testing.T) { - records := []*models.RecordConfig{ - // different ttl per record - makeRC("zzz", "example.com", "4.4.4.4", models.RecordConfig{Type: "A", TTL: 111}), - makeRC("zzz", "example.com", "4.4.4.5", models.RecordConfig{Type: "A", TTL: 222}), - } - errs := checkRecordSetHasMultipleTTLs(records) + dc := models.MustNewDomainConfig("example.com") + + // different ttl per record + dc.AddTestRC(t, "zzz", 111, dnsv2.TypeA, "4.4.4.4") + dc.AddTestRC(t, "zzz", 222, dnsv2.TypeA, "4.4.4.5") + + errs := checkRecordSetHasMultipleTTLs(dc.Records) if len(errs) == 0 { t.Error("Expected error on multiple TTLs under the same label, but got none") } } func TestCheckRecordSetHasMultipleTTLs_noerr_1type_1ttl(t *testing.T) { - records := []*models.RecordConfig{ - // different ttl per record - makeRC("zzz", "example.com", "4.4.4.4", models.RecordConfig{Type: "A", TTL: 111}), - makeRC("zzz", "example.com", "4.4.4.5", models.RecordConfig{Type: "A", TTL: 111}), - } - errs := checkRecordSetHasMultipleTTLs(records) + dc := models.MustNewDomainConfig("example.com") + + // different ttl per record + dc.AddTestRC(t, "zzz", 111, dnsv2.TypeA, "4.4.4.4") + dc.AddTestRC(t, "zzz", 111, dnsv2.TypeA, "4.4.4.5") + + errs := checkRecordSetHasMultipleTTLs(dc.Records) if len(errs) != 0 { t.Errorf("Expected 0 errors (same type, same TTL), but got %d", len(errs)) } } func TestCheckRecordSetHasMultipleTTLs_noerr_2type_2ttl(t *testing.T) { - records := []*models.RecordConfig{ - // different record types, different TTLs - makeRC("zzz", "example.com", "4.4.4.4", models.RecordConfig{Type: "A", TTL: 333}), - makeRC("zzz", "example.com", "4.4.4.5", models.RecordConfig{Type: "NS", TTL: 444}), - } - errs := checkRecordSetHasMultipleTTLs(records) + dc := models.MustNewDomainConfig("example.com") + + // different record types, different TTLs + dc.AddTestRC(t, "zzz", 333, dnsv2.TypeA, "4.4.4.4") + dc.AddTestRC(t, "zzz", 444, dnsv2.TypeNS, "4.4.4.5") + + errs := checkRecordSetHasMultipleTTLs(dc.Records) if len(errs) != 0 { t.Errorf("Expected 0 errors (different types, different TTLs), but got %d: %v", len(errs), errs) } } func TestCheckRecordSetHasMultipleTTLs_noerr_2type_1ttl(t *testing.T) { - records := []*models.RecordConfig{ - // different record types, different TTLs - makeRC("zzz", "example.com", "4.4.4.4", models.RecordConfig{Type: "A", TTL: 333}), - makeRC("zzz", "example.com", "4.4.4.5", models.RecordConfig{Type: "NS", TTL: 333}), - } - errs := checkRecordSetHasMultipleTTLs(records) + dc := models.MustNewDomainConfig("example.com") + + // different record types, different TTLs + dc.AddTestRC(t, "zzz", 333, dnsv2.TypeA, "4.4.4.4") + dc.AddTestRC(t, "zzz", 333, dnsv2.TypeNS, "4.4.4.5") + + errs := checkRecordSetHasMultipleTTLs(dc.Records) if len(errs) != 0 { t.Errorf("Expected 0 errors (different types, same TTLs) but got %d: %v", len(errs), errs) } } func TestCheckRecordSetHasMultipleTTLs_err_3type_2ttl(t *testing.T) { - records := []*models.RecordConfig{ - // different record types, different TTLs - makeRC("zzz", "example.com", "4.4.4.4", models.RecordConfig{Type: "A", TTL: 555}), - makeRC("zzz", "example.com", "4.4.4.4", models.RecordConfig{Type: "A", TTL: 555}), - makeRC("zzz", "example.com", "4.4.4.5", models.RecordConfig{Type: "NS", TTL: 666}), - } - errs := checkRecordSetHasMultipleTTLs(records) + dc := models.MustNewDomainConfig("example.com") + + // different record types, different TTLs + dc.AddTestRC(t, "zzz", 555, dnsv2.TypeA, "4.4.4.4") + dc.AddTestRC(t, "zzz", 555, dnsv2.TypeA, "4.4.4.4") + dc.AddTestRC(t, "zzz", 666, dnsv2.TypeNS, "4.4.4.5") + + errs := checkRecordSetHasMultipleTTLs(dc.Records) if len(errs) != 0 { t.Errorf("Expected 0 errors (different types, no errors), but got %d: %v", len(errs), errs) } } func TestCheckRecordSetHasMultipleTTLs_err_3type_3ttl(t *testing.T) { - records := []*models.RecordConfig{ - // different record types, different TTLs - makeRC("zzz", "example.com", "4.4.4.4", models.RecordConfig{Type: "A", TTL: 777}), - makeRC("zzz", "example.com", "4.4.4.4", models.RecordConfig{Type: "A", TTL: 888}), - makeRC("zzz", "example.com", "4.4.4.5", models.RecordConfig{Type: "NS", TTL: 999}), - } - errs := checkRecordSetHasMultipleTTLs(records) + dc := models.MustNewDomainConfig("example.com") + + // different record types, different TTLs + dc.AddTestRC(t, "zzz", 777, dnsv2.TypeA, "4.4.4.4") + dc.AddTestRC(t, "zzz", 888, dnsv2.TypeA, "4.4.4.4") + dc.AddTestRC(t, "zzz", 999, dnsv2.TypeNS, "4.4.4.5") + + errs := checkRecordSetHasMultipleTTLs(dc.Records) if len(errs) != 1 { t.Errorf("Expected 0 errors (different types, 1 error), but got %d: %v", len(errs), errs) } } func TestTLSAValidation(t *testing.T) { - config := &models.DNSConfig{ - Domains: []*models.DomainConfig{ - { - Name: "_443._tcp.example.com", - RegistrarName: "BIND", - Records: []*models.RecordConfig{ - makeRC("_443._tcp", "_443._tcp.example.com", "abcdef0", models.RecordConfig{ - Type: "TLSA", TlsaUsage: 4, TlsaSelector: 1, TlsaMatchingType: 1, - }), - }, - }, - }, - } + dc := models.MustNewDomainConfig("_443._tcp.example.com") + dc.RegistrarName = "BIND" + dc.AddTestRC(t, "_443._tcp", 0, dnsv2.TypeTLSA, 4, 1, 1, "abcdef0") + + config := &models.DNSConfig{} + config.Domains = append(config.Domains, dc) + errs := ValidateAndNormalizeConfig(config) if len(errs) != 1 { t.Error("Expect error on invalid TLSA but got none") @@ -600,13 +513,10 @@ func Test_DSChecks(t *testing.T) { }) t.Run("full DS support", func(t *testing.T) { - apexDS := models.RecordConfig{Type: "DS"} - apexDS.SetLabel("@", "example.com") - - childDS := models.RecordConfig{Type: "DS"} - childDS.SetLabel("child", "example.com") - - records := models.Records{&apexDS, &childDS} + dc := models.MustNewDomainConfig("example.com") + apexDS := dc.MustNewRecordConfig("@", 0, dnsv2.TypeDS, 1, 1, 1, 1) + childDS := dc.MustNewRecordConfig("child", 0, dnsv2.TypeDS, 1, 1, 1, 1) + records := models.Records{apexDS, childDS} // check permutations of ProviderCanDS and having both DS caps for _, pType := range []string{ProviderFullDS, ProviderBothDSCaps} { @@ -618,19 +528,16 @@ func Test_DSChecks(t *testing.T) { }) t.Run("child DS support only", func(t *testing.T) { - apexDS := models.RecordConfig{Type: "DS"} - apexDS.SetLabel("@", "example.com") - - childDS := models.RecordConfig{Type: "DS"} - childDS.SetLabel("child", "example.com") + dc := models.MustNewDomainConfig("example.com") + apexDS := dc.MustNewRecordConfig("@", 0, dnsv2.TypeDS, 1, 1, 1, 1) + childDS := dc.MustNewRecordConfig("child", 0, dnsv2.TypeDS, 1, 1, 1, 1) // this record is included at the apex to check the Type of the // recordset is verified to only inspect records with type == DS - apexA := models.RecordConfig{Type: "A"} - apexA.SetLabel("@", "example.com") + apexA := dc.MustNewRecordConfig("@", 0, dnsv2.TypeA, "1.2.3.4") t.Run("accepts when child DS records only", func(t *testing.T) { - records := models.Records{&childDS, &apexA} + records := models.Records{childDS, apexA} err := checkProviderDS(ProviderChildDSOnly, records) if err != nil { t.Errorf("Provider %s implements child DS support so the provided records should be accepted", @@ -640,7 +547,7 @@ func Test_DSChecks(t *testing.T) { }) t.Run("fails with apex and child DS records", func(t *testing.T) { - records := models.Records{&apexDS, &childDS, &apexA} + records := models.Records{apexDS, childDS, apexA} err := checkProviderDS(ProviderChildDSOnly, records) if err == nil { t.Errorf("Provider %s does not implement DS support at the zone apex, so should reject provided records", @@ -652,96 +559,95 @@ func Test_DSChecks(t *testing.T) { } func TestCheckR53WeightedGroupConsistency_noerr_consistent(t *testing.T) { - records := []*models.RecordConfig{ - makeRC("@", "example.com", "1.2.3.4", models.RecordConfig{ - Type: "A", - Metadata: map[string]string{"r53_weight": "70", "r53_set_identifier": "primary", "r53_health_check_id": "hc-1"}, - }), - makeRC("@", "example.com", "2.3.4.5", models.RecordConfig{ - Type: "A", - Metadata: map[string]string{"r53_weight": "70", "r53_set_identifier": "primary", "r53_health_check_id": "hc-1"}, - }), - } - errs := checkR53WeightedGroupConsistency(records) + dc := models.MustNewDomainConfig("example.com") + + rc1 := dc.MustNewRecordConfig("@", 0, dnsv2.TypeA, "1.2.3.4") + rc1.Metadata = map[string]string{"r53_weight": "70", "r53_set_identifier": "primary", "r53_health_check_id": "hc-1"} + dc.AddRecordConfig(rc1) + + rc2 := dc.MustNewRecordConfig("@", 0, dnsv2.TypeA, "2.3.4.5") + rc2.Metadata = map[string]string{"r53_weight": "70", "r53_set_identifier": "primary", "r53_health_check_id": "hc-1"} + dc.AddRecordConfig(rc2) + + errs := checkR53WeightedGroupConsistency(dc.Records) if len(errs) != 0 { t.Errorf("Expected 0 errors but got %d: %v", len(errs), errs) } } func TestCheckR53WeightedGroupConsistency_noerr_different_set_ids(t *testing.T) { - records := []*models.RecordConfig{ - makeRC("@", "example.com", "1.2.3.4", models.RecordConfig{ - Type: "A", - Metadata: map[string]string{"r53_weight": "70", "r53_set_identifier": "primary"}, - }), - makeRC("@", "example.com", "5.6.7.8", models.RecordConfig{ - Type: "A", - Metadata: map[string]string{"r53_weight": "30", "r53_set_identifier": "secondary"}, - }), - } - errs := checkR53WeightedGroupConsistency(records) + dc := models.MustNewDomainConfig("example.com") + + rc1 := dc.MustNewRecordConfig("@", 0, dnsv2.TypeA, "1.2.3.4") + rc1.Metadata = map[string]string{"r53_weight": "70", "r53_set_identifier": "primary"} + dc.AddRecordConfig(rc1) + + rc2 := dc.MustNewRecordConfig("@", 0, dnsv2.TypeA, "5.6.7.8") + rc2.Metadata = map[string]string{"r53_weight": "30", "r53_set_identifier": "secondary"} + dc.AddRecordConfig(rc2) + + errs := checkR53WeightedGroupConsistency(dc.Records) if len(errs) != 0 { t.Errorf("Expected 0 errors but got %d: %v", len(errs), errs) } } func TestCheckR53WeightedGroupConsistency_noerr_no_metadata(t *testing.T) { - records := []*models.RecordConfig{ - makeRC("@", "example.com", "1.2.3.4", models.RecordConfig{Type: "A"}), - makeRC("@", "example.com", "5.6.7.8", models.RecordConfig{Type: "A"}), - } - errs := checkR53WeightedGroupConsistency(records) + dc := models.MustNewDomainConfig("example.com") + dc.AddTestRC(t, "@", 0, dnsv2.TypeA, "1.2.3.4") + dc.AddTestRC(t, "@", 0, dnsv2.TypeA, "5.6.7.8") + errs := checkR53WeightedGroupConsistency(dc.Records) if len(errs) != 0 { t.Errorf("Expected 0 errors but got %d: %v", len(errs), errs) } } func TestCheckR53WeightedGroupConsistency_err_different_weights(t *testing.T) { - records := []*models.RecordConfig{ - makeRC("@", "example.com", "1.2.3.4", models.RecordConfig{ - Type: "A", - Metadata: map[string]string{"r53_weight": "70", "r53_set_identifier": "primary"}, - }), - makeRC("@", "example.com", "2.3.4.5", models.RecordConfig{ - Type: "A", - Metadata: map[string]string{"r53_weight": "50", "r53_set_identifier": "primary"}, - }), - } - errs := checkR53WeightedGroupConsistency(records) + dc := models.MustNewDomainConfig("example.com") + + rc1 := dc.MustNewRecordConfig("@", 0, dnsv2.TypeA, "1.2.3.4") + rc1.Metadata = map[string]string{"r53_weight": "70", "r53_set_identifier": "primary"} + dc.AddRecordConfig(rc1) + + rc2 := dc.MustNewRecordConfig("@", 0, dnsv2.TypeA, "2.3.4.5") + rc2.Metadata = map[string]string{"r53_weight": "50", "r53_set_identifier": "primary"} + dc.AddRecordConfig(rc2) + + errs := checkR53WeightedGroupConsistency(dc.Records) if len(errs) != 1 { t.Errorf("Expected 1 error for inconsistent weights but got %d: %v", len(errs), errs) } } func TestCheckR53WeightedGroupConsistency_err_different_health_checks(t *testing.T) { - records := []*models.RecordConfig{ - makeRC("@", "example.com", "1.2.3.4", models.RecordConfig{ - Type: "A", - Metadata: map[string]string{"r53_weight": "70", "r53_set_identifier": "primary", "r53_health_check_id": "hc-1"}, - }), - makeRC("@", "example.com", "2.3.4.5", models.RecordConfig{ - Type: "A", - Metadata: map[string]string{"r53_weight": "70", "r53_set_identifier": "primary", "r53_health_check_id": "hc-2"}, - }), - } - errs := checkR53WeightedGroupConsistency(records) + dc := models.MustNewDomainConfig("example.com") + + rc1 := dc.MustNewRecordConfig("@", 0, dnsv2.TypeA, "1.2.3.4") + rc1.Metadata = map[string]string{"r53_weight": "70", "r53_set_identifier": "primary", "r53_health_check_id": "hc-1"} + dc.AddRecordConfig(rc1) + + rc2 := dc.MustNewRecordConfig("@", 0, dnsv2.TypeA, "2.3.4.5") + rc2.Metadata = map[string]string{"r53_weight": "70", "r53_set_identifier": "primary", "r53_health_check_id": "hc-2"} + dc.AddRecordConfig(rc2) + + errs := checkR53WeightedGroupConsistency(dc.Records) if len(errs) != 1 { t.Errorf("Expected 1 error for inconsistent health checks but got %d: %v", len(errs), errs) } } func TestCheckR53WeightedGroupConsistency_err_both_inconsistent(t *testing.T) { - records := []*models.RecordConfig{ - makeRC("@", "example.com", "1.2.3.4", models.RecordConfig{ - Type: "A", - Metadata: map[string]string{"r53_weight": "70", "r53_set_identifier": "primary", "r53_health_check_id": "hc-1"}, - }), - makeRC("@", "example.com", "2.3.4.5", models.RecordConfig{ - Type: "A", - Metadata: map[string]string{"r53_weight": "50", "r53_set_identifier": "primary", "r53_health_check_id": "hc-2"}, - }), - } - errs := checkR53WeightedGroupConsistency(records) + dc := models.MustNewDomainConfig("example.com") + + rc1 := dc.MustNewRecordConfig("@", 0, dnsv2.TypeA, "1.2.3.4") + rc1.Metadata = map[string]string{"r53_weight": "70", "r53_set_identifier": "primary", "r53_health_check_id": "hc-1"} + dc.AddRecordConfig(rc1) + + rc2 := dc.MustNewRecordConfig("@", 0, dnsv2.TypeA, "2.3.4.5") + rc2.Metadata = map[string]string{"r53_weight": "50", "r53_set_identifier": "primary", "r53_health_check_id": "hc-2"} + dc.AddRecordConfig(rc2) + + errs := checkR53WeightedGroupConsistency(dc.Records) if len(errs) != 2 { t.Errorf("Expected 2 errors (weight + health check) but got %d: %v", len(errs), errs) } diff --git a/pkg/nrc/nrcflag.go b/pkg/nrc/nrcflag.go new file mode 100644 index 0000000000..56e11ed4f7 --- /dev/null +++ b/pkg/nrc/nrcflag.go @@ -0,0 +1,26 @@ +package nrc + +type Flags struct { + // EnforceOneDotPolicy instructs mustbe.Target* functions to return an error + // if it looks like the user forgot the trailing dot. This is enforced by + // the rule, "If a hostname contains any dots (even a single dot), there + // must be a trailing dot." + EnforceOneDotPolicy bool + + // SrvWeirdSplit the last field contains multiple fields. + // Only for use with NewRecordConfigParse() && rtype=="SRV" && len(args) == 2. + // Some APIs deliver SRV fields as two strings: "priority" and "weight port hostname." + // This happens often enough to warrant a flag to handle this case. + // true: last 2 args are combined and sent to NewRecordConfigParse() + SrvWeirdSplit bool + + // TargetIsFqdnNoDot modifies how RDATA host target fields are parsed. + // Normally a target host for MX, CNAME, and others, is assumed to be a + // shortname (no dot) or FQDN (dot). When this flag is set, it is assumed to be a FQDN no matter what. + // false: ends with ".": FQDN; no dot: shortname. + // true: ends with ".": FQDN; no dot: FQDN. + TargetIsFqdnNoDot bool + + // TxtDontParse tells NewRecordConfigParse() that the TXT data is raw bytes, not to be parsed. + TxtDontParse bool +} diff --git a/pkg/prettyzone/prettyzone.go b/pkg/prettyzone/prettyzone.go index 20f893807a..99eb88b85d 100644 --- a/pkg/prettyzone/prettyzone.go +++ b/pkg/prettyzone/prettyzone.go @@ -10,9 +10,8 @@ import ( "strconv" "strings" - "github.com/DNSControl/dnscontrol/v4/models" - "github.com/DNSControl/dnscontrol/v4/pkg/txtutil" - dnsv1 "github.com/miekg/dns" + "github.com/DNSControl/dnscontrol/v5/models" + "github.com/DNSControl/dnscontrol/v5/pkg/txtutil" ) // MostCommonTTL returns the most common TTL in a set of records. If there is @@ -52,7 +51,7 @@ func WriteZoneFileRC(w io.Writer, records models.Records, origin string, default // be easy to read and pleasant to the eye. // * Within a label, SOA and NS records are listed first. // * MX records are sorted numericly by preference value. - // * SRV records are sorted numericly by port, then priority, then weight. + // * SRV records are sorted numericly by priority, then weight, then port. // * A records are sorted by IP address, not lexicographically. // * Repeated labels are removed. // * $TTL is used to eliminate clutter. The most common TTL value is used. @@ -103,21 +102,14 @@ func (z *ZoneGenData) generateZoneFileHelper(w io.Writer) error { } } for i, rr := range z.Records { - // Fake types are commented out. - prefix := "" - _, ok := dnsv1.StringToType[rr.Type] - if !ok { - prefix = ";" + // label + nameShort := txtutil.StripZone(rr.Name, z.Origin) + if i > 0 && nameShort == nameShortPrevious { + nameShort = "" + } else { + nameShortPrevious = nameShort } - // name - nameShort := rr.Name - name := nameShort - if (prefix == "") && (i > 0 && nameShort == nameShortPrevious) { - name = "" - } - nameShortPrevious = nameShort - // ttl ttl := "" if rr.TTL != z.DefaultTTL && rr.TTL != 0 { @@ -130,8 +122,8 @@ func (z *ZoneGenData) generateZoneFileHelper(w io.Writer) error { typeStr = rr.UnknownTypeName } - // the remaining line - target := rr.GetTargetCombinedFunc(txtutil.EncodeQuoted) + // target + target := rr.GetRDATA().String() // comment comment := "" @@ -155,8 +147,8 @@ func (z *ZoneGenData) generateZoneFileHelper(w io.Writer) error { comment = " ;" + comment } - fmt.Fprintf(w, "%s%s%s\n", - prefix, FormatLine([]int{10, 5, 2, 5, 0}, []string{name, ttl, "IN", typeStr, target}), comment) + fmt.Fprintf(w, "%s%s\n", + FormatLine([]int{10, 5, 2, 5, 0}, []string{nameShort, ttl, "IN", typeStr, target}), comment) } return nil } diff --git a/pkg/prettyzone/prettyzone_test.go b/pkg/prettyzone/prettyzone_test.go index 52d00a0690..206b7d918c 100644 --- a/pkg/prettyzone/prettyzone_test.go +++ b/pkg/prettyzone/prettyzone_test.go @@ -9,11 +9,12 @@ import ( "strings" "testing" - "github.com/DNSControl/dnscontrol/v4/models" - "github.com/DNSControl/dnscontrol/v4/pkg/dnsrr" - _ "github.com/DNSControl/dnscontrol/v4/pkg/rtype" - dnsv1 "github.com/miekg/dns" - dnsutilv1 "github.com/miekg/dns/dnsutil" + dnsv2 "codeberg.org/miekg/dns" + dnstestv2 "codeberg.org/miekg/dns/dnstest" + "github.com/DNSControl/dnscontrol/v5/models" + "github.com/DNSControl/dnscontrol/v5/pkg/dnsrr" + "github.com/DNSControl/dnscontrol/v5/pkg/nameutil" + "github.com/DNSControl/dnscontrol/v5/pkg/privatetypes" ) func parseAndRegen(t *testing.T, buf *bytes.Buffer, expected string) { @@ -21,9 +22,11 @@ func parseAndRegen(t *testing.T, buf *bytes.Buffer, expected string) { // get back the same string. // This is used after any WriteZoneFile test as an extra verification step. - zp := dnsv1.NewZoneParser(buf, "bosun.org", "bozun.org.zone") - var parsed []dnsv1.RR + zp := dnsv2.NewZoneParser(buf, "bosun.org", "bozun.org.zone") + //fmt.Printf("DEBUG: regen expected=\n%s\n\n", expected) + var parsed []dnsv2.RR for rr, ok := zp.Next(); ok; rr, ok = zp.Next() { + // fmt.Printf("DEBUG: REGEN rec=%v\n", rr) parsed = append(parsed, rr) } if err := zp.Err(); err != nil { @@ -43,21 +46,22 @@ func parseAndRegen(t *testing.T, buf *bytes.Buffer, expected string) { } // rrstoRCs converts []dns.RR to []RecordConfigs. -func rrstoRCs(rrs []dnsv1.RR, origin string) (models.Records, error) { +func rrstoRCs(rrs []dnsv2.RR, origin string) (models.Records, error) { + dc := models.MustNewDomainConfig(origin) rcs := make(models.Records, 0, len(rrs)) for _, r := range rrs { - rc, err := dnsrr.RRtoRC(r, origin) + rc, err := dnsrr.RRv2toRC(dc, r) if err != nil { return nil, err } - rcs = append(rcs, &rc) + rcs = append(rcs, rc) } return rcs, nil } // writeZoneFileRR is a helper for when you have []dns.RR instead of models.Records. -func writeZoneFileRR(w io.Writer, records []dnsv1.RR, origin string) error { +func writeZoneFileRR(w io.Writer, records []dnsv2.RR, origin string) error { rcs, err := rrstoRCs(records, origin) if err != nil { return err @@ -67,13 +71,13 @@ func writeZoneFileRR(w io.Writer, records []dnsv1.RR, origin string) error { } func TestMostCommonTtl(t *testing.T) { - var records []dnsv1.RR + var records []dnsv2.RR var g, e uint32 - r1, _ := dnsv1.NewRR("bosun.org. 100 IN A 1.1.1.1") - r2, _ := dnsv1.NewRR("bosun.org. 200 IN A 1.1.1.1") - r3, _ := dnsv1.NewRR("bosun.org. 300 IN A 1.1.1.1") - r4, _ := dnsv1.NewRR("bosun.org. 400 IN NS foo.bosun.org.") - r5, _ := dnsv1.NewRR("bosun.org. 400 IN NS bar.bosun.org.") + r1 := dnstestv2.New("bosun.org. 100 IN A 1.1.1.1") + r2 := dnstestv2.New("bosun.org. 200 IN A 1.1.1.1") + r3 := dnstestv2.New("bosun.org. 300 IN A 1.1.1.1") + r4 := dnstestv2.New("bosun.org. 400 IN NS foo.bosun.org.") + r5 := dnstestv2.New("bosun.org. 400 IN NS bar.bosun.org.") // All records are TTL=100 records = nil @@ -127,11 +131,11 @@ func TestMostCommonTtl(t *testing.T) { // func WriteZoneFile func TestWriteZoneFileSimple(t *testing.T) { - r1, _ := dnsv1.NewRR("bosun.org. 300 IN A 192.30.252.153") - r2, _ := dnsv1.NewRR("bosun.org. 300 IN A 192.30.252.154") - r3, _ := dnsv1.NewRR("www.bosun.org. 300 IN CNAME bosun.org.") + r1 := dnstestv2.New("bosun.org. 300 IN A 192.30.252.153") + r2 := dnstestv2.New("bosun.org. 300 IN A 192.30.252.154") + r3 := dnstestv2.New("www.bosun.org. 300 IN CNAME bosun.org.") buf := &bytes.Buffer{} - if err := writeZoneFileRR(buf, []dnsv1.RR{r1, r2, r3}, "bosun.org"); err != nil { + if err := writeZoneFileRR(buf, []dnsv2.RR{r1, r2, r3}, "bosun.org"); err != nil { t.Fatal(err) } expected := `$TTL 300 @@ -149,12 +153,12 @@ www IN CNAME bosun.org. } func TestWriteZoneFileSimpleTtl(t *testing.T) { - r1, _ := dnsv1.NewRR("bosun.org. 100 IN A 192.30.252.153") - r2, _ := dnsv1.NewRR("bosun.org. 100 IN A 192.30.252.154") - r3, _ := dnsv1.NewRR("bosun.org. 100 IN A 192.30.252.155") - r4, _ := dnsv1.NewRR("www.bosun.org. 300 IN CNAME bosun.org.") + r1 := dnstestv2.New("bosun.org. 100 IN A 192.30.252.153") + r2 := dnstestv2.New("bosun.org. 100 IN A 192.30.252.154") + r3 := dnstestv2.New("bosun.org. 100 IN A 192.30.252.155") + r4 := dnstestv2.New("www.bosun.org. 300 IN CNAME bosun.org.") buf := &bytes.Buffer{} - if err := writeZoneFileRR(buf, []dnsv1.RR{r1, r2, r3, r4}, "bosun.org"); err != nil { + if err := writeZoneFileRR(buf, []dnsv2.RR{r1, r2, r3, r4}, "bosun.org"); err != nil { t.Fatal(err) } expected := `$TTL 100 @@ -174,19 +178,19 @@ www 300 IN CNAME bosun.org. func TestWriteZoneFileMx(t *testing.T) { // sort by priority - r1, _ := dnsv1.NewRR("aaa.bosun.org. IN MX 1 aaa.example.com.") - r2, _ := dnsv1.NewRR("aaa.bosun.org. IN MX 5 aaa.example.com.") - r3, _ := dnsv1.NewRR("aaa.bosun.org. IN MX 10 aaa.example.com.") + r1 := dnstestv2.New("aaa.bosun.org. IN MX 1 aaa.example.com.") + r2 := dnstestv2.New("aaa.bosun.org. IN MX 5 aaa.example.com.") + r3 := dnstestv2.New("aaa.bosun.org. IN MX 10 aaa.example.com.") // same priority? sort by name - r4, _ := dnsv1.NewRR("bbb.bosun.org. IN MX 10 ccc.example.com.") - r5, _ := dnsv1.NewRR("bbb.bosun.org. IN MX 10 bbb.example.com.") - r6, _ := dnsv1.NewRR("bbb.bosun.org. IN MX 10 aaa.example.com.") + r4 := dnstestv2.New("bbb.bosun.org. IN MX 10 ccc.example.com.") + r5 := dnstestv2.New("bbb.bosun.org. IN MX 10 bbb.example.com.") + r6 := dnstestv2.New("bbb.bosun.org. IN MX 10 aaa.example.com.") // a mix - r7, _ := dnsv1.NewRR("ccc.bosun.org. IN MX 40 zzz.example.com.") - r8, _ := dnsv1.NewRR("ccc.bosun.org. IN MX 40 aaa.example.com.") - r9, _ := dnsv1.NewRR("ccc.bosun.org. IN MX 1 ttt.example.com.") + r7 := dnstestv2.New("ccc.bosun.org. IN MX 40 zzz.example.com.") + r8 := dnstestv2.New("ccc.bosun.org. IN MX 40 aaa.example.com.") + r9 := dnstestv2.New("ccc.bosun.org. IN MX 1 ttt.example.com.") buf := &bytes.Buffer{} - if err := writeZoneFileRR(buf, []dnsv1.RR{r1, r2, r3, r4, r5, r6, r7, r8, r9}, "bosun.org"); err != nil { + if err := writeZoneFileRR(buf, []dnsv2.RR{r1, r2, r3, r4, r5, r6, r7, r8, r9}, "bosun.org"); err != nil { t.Fatal(err) } if buf.String() != testdataZFMX { @@ -211,13 +215,13 @@ ccc IN MX 1 ttt.example.com. func TestWriteZoneFileSrv(t *testing.T) { // exhibits explicit ttls and long name - r1, _ := dnsv1.NewRR(`bosun.org. 300 IN SRV 10 10 9999 foo.com.`) - r2, _ := dnsv1.NewRR(`bosun.org. 300 IN SRV 10 20 5050 foo.com.`) - r3, _ := dnsv1.NewRR(`bosun.org. 300 IN SRV 10 10 5050 foo.com.`) - r4, _ := dnsv1.NewRR(`bosun.org. 300 IN SRV 20 10 5050 foo.com.`) - r5, _ := dnsv1.NewRR(`bosun.org. 300 IN SRV 10 10 5050 foo.com.`) + r1 := dnstestv2.New(`bosun.org. 300 IN SRV 10 10 9999 foo.com.`) + r2 := dnstestv2.New(`bosun.org. 300 IN SRV 10 20 5050 foo.com.`) + r3 := dnstestv2.New(`bosun.org. 300 IN SRV 10 10 5050 foo.com.`) + r4 := dnstestv2.New(`bosun.org. 300 IN SRV 20 10 5050 foo.com.`) + r5 := dnstestv2.New(`bosun.org. 300 IN SRV 10 10 5050 foo.com.`) buf := &bytes.Buffer{} - if err := writeZoneFileRR(buf, []dnsv1.RR{r1, r2, r3, r4, r5}, "bosun.org"); err != nil { // 5 + if err := writeZoneFileRR(buf, []dnsv2.RR{r1, r2, r3, r4, r5}, "bosun.org"); err != nil { // 5 t.Fatal(err) } if buf.String() != testdataZFSRV { @@ -231,18 +235,18 @@ func TestWriteZoneFileSrv(t *testing.T) { var testdataZFSRV = `$TTL 300 @ IN SRV 10 10 5050 foo.com. IN SRV 10 10 5050 foo.com. + IN SRV 10 10 9999 foo.com. IN SRV 10 20 5050 foo.com. IN SRV 20 10 5050 foo.com. - IN SRV 10 10 9999 foo.com. ` func TestWriteZoneFilePtr(t *testing.T) { // exhibits explicit ttls and long name - r1, _ := dnsv1.NewRR(`bosun.org. 300 IN PTR chell.bosun.org`) - r2, _ := dnsv1.NewRR(`bosun.org. 300 IN PTR barney.bosun.org.`) - r3, _ := dnsv1.NewRR(`bosun.org. 300 IN PTR alex.bosun.org.`) + r1 := dnstestv2.New(`bosun.org. 300 IN PTR chell.bosun.org`) + r2 := dnstestv2.New(`bosun.org. 300 IN PTR barney.bosun.org.`) + r3 := dnstestv2.New(`bosun.org. 300 IN PTR alex.bosun.org.`) buf := &bytes.Buffer{} - if err := writeZoneFileRR(buf, []dnsv1.RR{r1, r2, r3}, "bosun.org"); err != nil { + if err := writeZoneFileRR(buf, []dnsv2.RR{r1, r2, r3}, "bosun.org"); err != nil { t.Fatal(err) } if buf.String() != testdataZFPTR { @@ -261,14 +265,14 @@ var testdataZFPTR = `$TTL 300 func TestWriteZoneFileCaa(t *testing.T) { // exhibits explicit ttls and long name - r1, _ := dnsv1.NewRR(`bosun.org. 300 IN CAA 0 issuewild ";"`) - r2, _ := dnsv1.NewRR(`bosun.org. 300 IN CAA 0 issue "letsencrypt.org"`) - r3, _ := dnsv1.NewRR(`bosun.org. 300 IN CAA 1 iodef "http://example.com"`) - r4, _ := dnsv1.NewRR(`bosun.org. 300 IN CAA 0 iodef "https://example.com"`) - r5, _ := dnsv1.NewRR(`bosun.org. 300 IN CAA 0 iodef "https://example.net"`) - r6, _ := dnsv1.NewRR(`bosun.org. 300 IN CAA 1 iodef "mailto:example.com"`) + r1 := dnstestv2.New(`bosun.org. 300 IN CAA 0 issuewild ";"`) + r2 := dnstestv2.New(`bosun.org. 300 IN CAA 0 issue "letsencrypt.org"`) + r3 := dnstestv2.New(`bosun.org. 300 IN CAA 1 iodef "http://example.com"`) + r4 := dnstestv2.New(`bosun.org. 300 IN CAA 0 iodef "https://example.com"`) + r5 := dnstestv2.New(`bosun.org. 300 IN CAA 0 iodef "https://example.net"`) + r6 := dnstestv2.New(`bosun.org. 300 IN CAA 1 iodef "mailto:example.com"`) buf := &bytes.Buffer{} - if err := writeZoneFileRR(buf, []dnsv1.RR{r1, r2, r3, r4, r5, r6}, "bosun.org"); err != nil { + if err := writeZoneFileRR(buf, []dnsv2.RR{r1, r2, r3, r4, r5, r6}, "bosun.org"); err != nil { t.Fatal(err) } if buf.String() != testdataZFCAA { @@ -293,28 +297,25 @@ 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) + `"` + t10 := `t10.bosun.org. IN TXT "ten4567890"` + t254 := `t254.bosun.org. IN TXT "` + r("a", 254) + `"` + t255 := `t255.bosun.org. IN TXT "` + r("b", 255) + `"` + t256 := `t256.bosun.org. IN TXT "` + r("c", 255) + `" "` + r("D", 1) + `"` + t509 := `t509.bosun.org. IN TXT "` + r("e", 255) + `" "` + r("F", 254) + `"` + t510 := `t510.bosun.org. IN TXT "` + r("g", 255) + `" "` + r("H", 255) + `"` + t511 := `t511.bosun.org. IN TXT "` + r("i", 255) + `" "` + r("J", 255) + `" "` + r("k", 1) + `"` + t512 := `t511.bosun.org. IN TXT "` + r("L", 255) + `" "` + r("M", 255) + `" "` + r("n", 2) + `"` + t513 := `t511.bosun.org. 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 := dnsv1.NewRR(d) - if err != nil { - t.Fatal(err) - } + rr := dnstestv2.New(d) // Make the expected zonefile: - ez := "$TTL 3600\n" + d + "\n" + ez := "$TTL 3600\n" + strings.Replace(d, ".bosun.org.", " ", 1) + "\n" // Generate the zonefile: buf := &bytes.Buffer{} - if err := writeZoneFileRR(buf, []dnsv1.RR{rr}, "bosun.org"); err != nil { + if err := writeZoneFileRR(buf, []dnsv2.RR{rr}, "bosun.org"); err != nil { t.Fatal(err) } gz := buf.String() @@ -331,8 +332,8 @@ func TestWriteZoneFileTxt(t *testing.T) { // Test 1 of each record type -func mustNewRR(s string) dnsv1.RR { - r, err := dnsv1.NewRR(s) +func mustNewRR(s string) dnsv2.RR { + r, err := dnsv2.New(s) if err != nil { panic(err) } @@ -342,9 +343,9 @@ func mustNewRR(s string) dnsv1.RR { func TestWriteZoneFileEach(t *testing.T) { // Each rtype should be listed in this test exactly once. // If an rtype has more than one variations, add a test like TestWriteZoneFileCaa to test each. - var d []dnsv1.RR + var d []dnsv2.RR // #rtype_variations - d = append(d, mustNewRR(`4.5 300 IN PTR y.bosun.org.`)) // Wouldn't actually be in this domain. + d = append(d, mustNewRR(`4.5.bosun.org. 300 IN PTR y.bosun.org.`)) // Wouldn't actually be in this domain. d = append(d, mustNewRR(`bosun.org. 300 IN A 1.2.3.4`)) d = append(d, mustNewRR(`bosun.org. 300 IN MX 1 bosun.org.`)) d = append(d, mustNewRR(`bosun.org. 300 IN TXT "my text"`)) @@ -389,7 +390,7 @@ var testdataZFEach = `$TTL 300 4.5 IN PTR y.bosun.org. 9f86d081884c7d659a2feaa0c55ad015a3bf4f1b2b0b822cd15d6c15._openpgpkey IN OPENPGPKEY 9901a204447450b7110400d9bef554b145128ccc90d9f52df14bb878626e3db32112d47fbc5ee9cc5ffcbbd06bee487a580481674d9d31e368a85ccf4d4ef3bfa3e23fdde238bc32d8c40d39204b912f8cb1c47a7f34ba64bf3598dafe0f080e17facb678b6e700b0163d677960471d265a197e5ee9d53d71e1911f47f518a0e303abaf3c01b188e37d7bf00a0b90d4f43af944202fc49356a35a367955633cd4503ff7dfa21fb70a201ffb4aa7a755fc560ffd5a4b1d7b7015e7b4bdc0a1e45c1c28fd2f628f4d21f07a091da0d29c98b070566e178c5974554e509a5153a16b271df835e8c8a97715cc4beb5383d05fdf7a0d9412a1fb9f572c195d8c0c696a5ec179bab29d3d8701446e7aca79565ecdd6ec3ceef4937cb248564a75ddb4115adc10400a8f820174b32c99c5ac6ee483c0184fed24fa44d2fd4c9dc00af9ed048b51cfdb95747ab1e35df933382b08f8223da934bfcba59cb356b0d2f4158d647ab76d09c444fadf5e92b95d65f4aae667f33835226170c6625db872a6b72cb13638cf4754941730f5117a4f7c262044bea453839f95b806a0bd98a668073ba2d0fce1ab4326f70656e53555345204275696c642053657276696365203c6275696c6473657276696365406f70656e737573652e6f72673e8864041311020024021b03060b09080703020315020303160201021e01021780050253674e3b050921bf0084000a09103b3011b76b9d65234a5b00a095c38bcfaa29f80adefc0cf9ba2abf3a3e9b516b009e367296e1a96af211f8cded2493f7f6ac09de41 f10e7de079689f55c0cdd6782e4dd1448c84006962a4bd832e8eff73._smimecert IN SMIMEA 3 0 0 abcdef0 -_443._tcp IN TLSA 3 1 1 abcdef0 +_443._tcp IN TLSA 3 1 1 ABCDEF0 dname IN DNAME example.com. dnssec IN DNSKEY 257 3 13 rNR701yiOPHfqDP53GnsHZdlsRqI7O1ksk60rnFILZVk7Z4eTBd1U49oSkTNVNox9tb7N15N2hboXoMEyFFzcw== IN DS 31334 13 2 94CC505EBC36B1F4E051268B820EFB230F1572D445E833BB5BF7380D6C2CBC0A @@ -398,24 +399,18 @@ x IN CNAME bosun.org. ` func TestWriteZoneFileSynth(t *testing.T) { - r1, _ := dnsv1.NewRR("bosun.org. 300 IN A 192.30.252.153") - r2, _ := dnsv1.NewRR("bosun.org. 300 IN A 192.30.252.154") - r3, _ := dnsv1.NewRR("www.bosun.org. 300 IN CNAME bosun.org.") - rsynm := &models.RecordConfig{Type: "R53_ALIAS", TTL: 300} - rsynm.SetLabel("myalias", "bosun.org") - rsynz := &models.RecordConfig{Type: "R53_ALIAS", TTL: 300} - rsynz.SetLabel("zalias", "bosun.org") - - recs, err := rrstoRCs([]dnsv1.RR{r1, r2, r3}, "bosun.org") - if err != nil { - panic(err) - } - recs = append(recs, rsynm) - recs = append(recs, rsynm) - recs = append(recs, rsynz) + dc := models.MustNewDomainConfig("bosun.org") + + dc.AddTestRC(t, "bosun.org.", 300, dnsv2.TypeA, "192.30.252.153") + dc.AddTestRC(t, "bosun.org.", 300, dnsv2.TypeA, "192.30.252.154") + dc.AddTestRC(t, "www.bosun.org.", 300, dnsv2.TypeCNAME, "bosun.org.") + + dc.AddTestRC(t, "myalias", 300, privatetypes.TypeR53ALIAS, "foo1", "A", "id123", "true") + dc.AddTestRC(t, "myalias", 300, privatetypes.TypeR53ALIAS, "foo2", "A", "id123", "true") + dc.AddTestRC(t, "zalias", 300, privatetypes.TypeR53ALIAS, "foo3", "A", "id123", "true") buf := &bytes.Buffer{} - if err := WriteZoneFileRC(buf, recs, "bosun.org", 0, []string{"c1", "c2", "c3\nc4"}); err != nil { + if err := WriteZoneFileRC(buf, dc.Records, "bosun.org", 0, []string{"c1", "c2", "c3\nc4"}); err != nil { t.Fatal(err) } expected := `$TTL 300 @@ -425,10 +420,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= evaluate_target_health= -;myalias IN R53_ALIAS atype= zone_id= evaluate_target_health= +myalias IN R53_ALIAS foo1 a.bosun.org. id123 true + IN R53_ALIAS foo2 a.bosun.org. id123 true www IN CNAME bosun.org. -;zalias IN R53_ALIAS atype= zone_id= evaluate_target_health= +zalias IN R53_ALIAS foo3 a.bosun.org. id123 true ` if buf.String() != expected { t.Log(buf.String()) @@ -440,7 +435,7 @@ www IN CNAME bosun.org. // Test sorting func TestWriteZoneFileOrder(t *testing.T) { - var records []dnsv1.RR + var records []dnsv2.RR for i, td := range []string{ "@", "@", @@ -459,8 +454,8 @@ func TestWriteZoneFileOrder(t *testing.T) { "zt.mup", "zap", } { - name := dnsutilv1.AddOrigin(td, "stackoverflow.com.") - r, _ := dnsv1.NewRR(fmt.Sprintf("%s 300 IN A 1.2.3.%d", name, i)) + name := nameutil.ToFqdnWithDot(td, "stackoverflow.com.") + r := dnstestv2.New(fmt.Sprintf("%s 300 IN A 1.2.3.%d", name, i)) records = append(records, r) } diff --git a/pkg/prettyzone/sorting.go b/pkg/prettyzone/sorting.go index ceff8c6fe3..035efb43ff 100644 --- a/pkg/prettyzone/sorting.go +++ b/pkg/prettyzone/sorting.go @@ -9,7 +9,8 @@ import ( "strconv" "strings" - "github.com/DNSControl/dnscontrol/v4/models" + dnsv2 "codeberg.org/miekg/dns" + "github.com/DNSControl/dnscontrol/v5/models" ) // ZoneGenData is the configuration description for the zone generator. @@ -27,15 +28,7 @@ func (z *ZoneGenData) Less(i, j int) bool { // Sort by name. - //fmt.Printf("DEBUG: LabelLess(%q, %q) = %v %q %q\n", compA, compB, LabelLess(compA, compB), a.Name, b.Name) - compA, compB := a.NameFQDN, b.NameFQDN - // Unify FQDNs to "@". LabelLess needs FQDNs to be "@" to work properly. - if a.Name == "@" { - compA = "@" - } - if b.Name == "@" { - compB = "@" - } + compA, compB := a.GetLabelFQDN(), b.GetLabelFQDN() if compA != compB { return LabelLess(compA, compB) } @@ -46,85 +39,97 @@ func (z *ZoneGenData) Less(i, j int) bool { } // sub-sort within type: - switch a.Type { // #rtype_variations - case "A": + switch a.TypeNum { + case dnsv2.TypeA: ta2, tb2 := a.GetTargetIP(), b.GetTargetIP() - if !ta2.Is4() || !tb2.Is4() { - log.Fatalf("should not happen: Invalid IPv4 address: %s %s", - a.GetTargetIP().String(), b.GetTargetIP().String()) + if ta2.Is4() && tb2.Is4() { + return bytes.Compare(ta2.AsSlice(), tb2.AsSlice()) == -1 } - return bytes.Compare(ta2.AsSlice(), tb2.AsSlice()) == -1 - case "AAAA": + case dnsv2.TypeAAAA: ta2, tb2 := a.GetTargetIP(), b.GetTargetIP() if !ta2.Is6() || !tb2.Is6() { log.Fatalf("should not happen: Invalid IPv6 address: %s %s", a.GetTargetIP().String(), b.GetTargetIP().String()) } return ta2.Compare(tb2) == -1 - case "MX": + case dnsv2.TypeMX: // sort by priority. If they are equal, sort by Mx. - if a.MxPreference == b.MxPreference { - return a.GetTargetField() < b.GetTargetField() - } - return a.MxPreference < b.MxPreference - case "SRV": - // ta2, tb2 := a.(*dns.SRV), b.(*dns.SRV) - pa, pb := a.SrvPort, b.SrvPort - if pa != pb { - return pa < pb - } - pa, pb = a.SrvPriority, b.SrvPriority + fa := a.AsMX() + fb := b.AsMX() + if fa.Preference != fb.Preference { + return fa.Preference < fb.Preference + } + return fa.Mx < fb.Mx + case dnsv2.TypeSRV: + fa := a.AsSRV() + fb := b.AsSRV() + pa, pb := fa.Priority, fb.Priority if pa != pb { return pa < pb } - pa, pb = a.SrvWeight, b.SrvWeight + wa, wb := fa.Weight, fb.Weight + if wa != wb { + return wa < wb + } + ppa, ppb := fa.Port, fb.Port + if ppa != ppb { + return ppa < ppb + } + return fa.Target < fb.Target + case dnsv2.TypeSVCB, dnsv2.TypeHTTPS: + fa := a.AsSVCB() + fb := b.AsSVCB() + // sort by priority. If they are equal, sort by ASCII + if fa.Priority != fb.Priority { + return fa.Priority < fb.Priority + } + if fa.Target != fb.Target { + return fa.Target < fb.Target + } + case dnsv2.TypePTR: + fa := a.AsPTR() + fb := b.AsPTR() + // TODO(tlim): Sort by fancy host sort. + pa, pb := fa.Ptr, fb.Ptr if pa != pb { return pa < pb } - case "SVCB", "HTTPS": - // sort by priority. If they are equal, sort by record. - if a.SvcPriority == b.SvcPriority { - return a.GetTargetField() < b.GetTargetField() - } - return a.SvcPriority < b.SvcPriority - case "PTR": - // ta2, tb2 := a.(*dns.PTR), b.(*dns.PTR) - pa, pb := a.GetTargetField(), b.GetTargetField() - if pa != pb { - return pa < pb - } - case "CAA": + case dnsv2.TypeCAA: // ta2, tb2 := a.(*dns.CAA), b.(*dns.CAA) // sort by tag - pa, pb := a.CaaTag, b.CaaTag + fa := a.AsCAA() + fb := b.AsCAA() + pa, pb := fa.Tag, fb.Tag if pa != pb { return pa < pb } // then flag - fa, fb := a.CaaFlag, b.CaaFlag - if fa != fb { + flaga, flagb := fa.Flag, fb.Flag + if flaga != flagb { // flag set goes before ones without flag set - return fa > fb + return flaga > flagb } - case "DS": - pa, pb := a.DsKeyTag, b.DsKeyTag + case dnsv2.TypeDS: + fa := a.AsDS() + fb := b.AsDS() + pa, pb := fa.KeyTag, fb.KeyTag if pa != pb { return pa < pb } - case "DNSKEY": - pa, pb := a.DnskeyFlags, b.DnskeyFlags + case dnsv2.TypeDNSKEY: + fa := a.AsDNSKEY() + fb := b.AsDNSKEY() + flga, flgb := fa.Flags, fb.Flags + if flga != flgb { + return flga < flgb + } + pa, pb := fa.Protocol, fb.Protocol if pa != pb { return pa < pb } - fa, fb := a.DnskeyProtocol, b.DnskeyProtocol - if fa != fb { - return fa < fb - } - default: - // pass through. String comparison is sufficient. } // fmt.Printf("DEBUG: Less %q < %q == %v\n", a.String(), b.String(), a.String() < b.String()) - return a.String() < b.String() + return a.GetRDATA().String() < b.GetRDATA().String() } // LabelLess provides a "Less" function for two labels as needed for sorting. It @@ -132,7 +137,7 @@ func (z *ZoneGenData) Less(i, j int) bool { func LabelLess(a, b string) bool { // Compare two zone labels for the purpose of sorting the RRs in a Zone. - // If they are equal, we are done. The remainingi code can assume a != b. + // If they are equal, we are done. The remaining code can assume a != b. if a == b { return false } diff --git a/pkg/prettyzone/sorting_test.go b/pkg/prettyzone/sorting_test.go new file mode 100644 index 0000000000..d0169dedf1 --- /dev/null +++ b/pkg/prettyzone/sorting_test.go @@ -0,0 +1,75 @@ +package prettyzone_test + +import ( + "testing" + + dnsv2 "codeberg.org/miekg/dns" + "github.com/DNSControl/dnscontrol/v5/models" + "github.com/DNSControl/dnscontrol/v5/pkg/prettyzone" +) + +func TestLabelLess(t *testing.T) { + tests := []struct { + name string // description of this test case + // Named input parameters for target function. + a string + b string + want bool + }{ + {"a", "example.com", "example.com", false}, + {"b", "example.com", "foo.example.com", true}, + {"c", "foo.example.com", "example.com", false}, + {"d", "foo.example.com", "bar.example.com", false}, + {"e", "bar.example.com", "foo.example.com", true}, + {"f", "4.5.example.com", "example.com", false}, + {"h", "*.bzt.mup", "aaa.bzt.mup", true}, + {"i", "aaa.bzt.mup", "*.bzt.mup", false}, + {"j", "1.bzt.mup", "aaa.bzt.mup", true}, + {"k", "aaa.bzt.mup", "1.bzt.mup", false}, + {"m", "@", "@", false}, + {"n", "@", "*", true}, + {"o", "*", "@", false}, + {"p", "@", "b", true}, + {"q", "b", "@", false}, + {"v", "*", "b", true}, + {"w", "b", "*", false}, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + got := prettyzone.LabelLess(tt.a, tt.b) + if got != tt.want { + t.Errorf("LabelLess(%q, %q) = %v, want %v", tt.a, tt.b, got, tt.want) + } + }) + } +} + +func TestZoneGenData_Less(t *testing.T) { + dc, _ := models.NewDomainConfig("example.com") + dc.AddTestRC(t, dc.LabelFromFQDNNoDot("example.com"), 300, dnsv2.TypeRP, "user.example.com.", "example.com.") + dc.AddTestRC(t, dc.LabelFromFQDNNoDot("4.5.example.com"), 300, dnsv2.TypePTR, "y.bosun.org.") + + tests := []struct { + name string // description of this test case + // Named input parameters for receiver constructor. + records models.Records + origin string + defaultTTL uint32 + comments []string + // Named input parameters for target function. + i int + j int + want bool + }{ + {"a", dc.Records, "example.com", 300, nil, 0, 1, true}, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + z := prettyzone.PrettySort(tt.records, tt.origin, tt.defaultTTL, tt.comments) + got := z.Less(tt.i, tt.j) + if got != tt.want { + t.Errorf("Less(%d, %d) = %v, want %v", tt.i, tt.j, got, tt.want) + } + }) + } +} diff --git a/pkg/printer/printer.go b/pkg/printer/printer.go index 1bdc2c917b..f3d145bd59 100644 --- a/pkg/printer/printer.go +++ b/pkg/printer/printer.go @@ -7,7 +7,7 @@ import ( "os" "strings" - "github.com/DNSControl/dnscontrol/v4/models" + "github.com/DNSControl/dnscontrol/v5/models" ) // CLI is an abstraction around the CLI. diff --git a/pkg/privatetypes/rdata/rdata_adguardhome_a_passthrough.go b/pkg/privatetypes/rdata/rdata_adguardhome_a_passthrough.go new file mode 100644 index 0000000000..cd63b20459 --- /dev/null +++ b/pkg/privatetypes/rdata/rdata_adguardhome_a_passthrough.go @@ -0,0 +1,39 @@ +package privatetypesrdata + +// Code generated by "go run types_generate.go"; DO NOT EDIT. + +import ( + "fmt" + "strings" + + dnsv2 "codeberg.org/miekg/dns" + "github.com/DNSControl/dnscontrol/v5/pkg/mustbe" + "github.com/DNSControl/dnscontrol/v5/pkg/nrc" + "github.com/DNSControl/dnscontrol/v5/pkg/txtutil" +) + +type ADGUARDHOMEAPASSTHROUGH struct { + Target string +} + +func (rd ADGUARDHOMEAPASSTHROUGH) Len() int { + return len(rd.String()) +} + +func (rd ADGUARDHOMEAPASSTHROUGH) String() string { + parts := make([]string, 0, 1) + parts = append(parts, txtutil.ZoneifyString(rd.Target)) + return strings.Join(parts, " ") +} + +func MakeADGUARDHOMEAPASSTHROUGH(origin string, _ map[string]string, _ nrc.Flags, args ...any) (dnsv2.RDATA, error) { + mustbe.ValidArgs(args) + if len(args) != 1 { + return nil, fmt.Errorf("ADGUARDHOME_A_PASSTHROUGH expects 1 arguments, got %d: %+v", len(args), args) + } + return ADGUARDHOMEAPASSTHROUGH{ + Target: mustbe.RawString(args[0]), + }, nil +} + +// Code generated by "go run types_generate.go"; DO NOT EDIT. diff --git a/pkg/privatetypes/rdata/rdata_adguardhome_aaaa_passthrough.go b/pkg/privatetypes/rdata/rdata_adguardhome_aaaa_passthrough.go new file mode 100644 index 0000000000..f6380e3b04 --- /dev/null +++ b/pkg/privatetypes/rdata/rdata_adguardhome_aaaa_passthrough.go @@ -0,0 +1,39 @@ +package privatetypesrdata + +// Code generated by "go run types_generate.go"; DO NOT EDIT. + +import ( + "fmt" + "strings" + + dnsv2 "codeberg.org/miekg/dns" + "github.com/DNSControl/dnscontrol/v5/pkg/mustbe" + "github.com/DNSControl/dnscontrol/v5/pkg/nrc" + "github.com/DNSControl/dnscontrol/v5/pkg/txtutil" +) + +type ADGUARDHOMEAAAAPASSTHROUGH struct { + Target string +} + +func (rd ADGUARDHOMEAAAAPASSTHROUGH) Len() int { + return len(rd.String()) +} + +func (rd ADGUARDHOMEAAAAPASSTHROUGH) String() string { + parts := make([]string, 0, 1) + parts = append(parts, txtutil.ZoneifyString(rd.Target)) + return strings.Join(parts, " ") +} + +func MakeADGUARDHOMEAAAAPASSTHROUGH(origin string, _ map[string]string, _ nrc.Flags, args ...any) (dnsv2.RDATA, error) { + mustbe.ValidArgs(args) + if len(args) != 1 { + return nil, fmt.Errorf("ADGUARDHOME_AAAA_PASSTHROUGH expects 1 arguments, got %d: %+v", len(args), args) + } + return ADGUARDHOMEAAAAPASSTHROUGH{ + Target: mustbe.RawString(args[0]), + }, nil +} + +// Code generated by "go run types_generate.go"; DO NOT EDIT. diff --git a/pkg/privatetypes/rdata/rdata_akamaicdn.go b/pkg/privatetypes/rdata/rdata_akamaicdn.go new file mode 100644 index 0000000000..832f56fc49 --- /dev/null +++ b/pkg/privatetypes/rdata/rdata_akamaicdn.go @@ -0,0 +1,45 @@ +package privatetypesrdata + +// Code generated by "go run types_generate.go"; DO NOT EDIT. + +import ( + "fmt" + "strings" + + dnsv2 "codeberg.org/miekg/dns" + "github.com/DNSControl/dnscontrol/v5/pkg/mustbe" + "github.com/DNSControl/dnscontrol/v5/pkg/nrc" +) + +type AKAMAICDN struct { + Target string +} + +func (rd AKAMAICDN) Len() int { + return len(rd.String()) +} + +func (rd AKAMAICDN) String() string { + parts := make([]string, 0, 1) + parts = append(parts, rd.Target) + return strings.Join(parts, " ") +} + +func MakeAKAMAICDN(origin string, _ map[string]string, isEnabled nrc.Flags, args ...any) (dnsv2.RDATA, error) { + mustbe.ValidArgs(args) + if len(args) != 1 { + return nil, fmt.Errorf("AKAMAICDN expects 1 arguments, got %d: %+v", len(args), args) + } + if isEnabled.TargetIsFqdnNoDot { + origin = "." + } + targetHost0, err := mustbe.TargetHost(origin, isEnabled, args[0]) + if err != nil { + return nil, err + } + return AKAMAICDN{ + Target: targetHost0, + }, nil +} + +// Code generated by "go run types_generate.go"; DO NOT EDIT. diff --git a/pkg/privatetypes/rdata/rdata_akamaitlc.go b/pkg/privatetypes/rdata/rdata_akamaitlc.go new file mode 100644 index 0000000000..5a9416562e --- /dev/null +++ b/pkg/privatetypes/rdata/rdata_akamaitlc.go @@ -0,0 +1,49 @@ +package privatetypesrdata + +// Code generated by "go run types_generate.go"; DO NOT EDIT. + +import ( + "fmt" + "strings" + + dnsv2 "codeberg.org/miekg/dns" + "github.com/DNSControl/dnscontrol/v5/pkg/mustbe" + "github.com/DNSControl/dnscontrol/v5/pkg/nrc" + "github.com/DNSControl/dnscontrol/v5/pkg/txtutil" +) + +type AKAMAITLC struct { + AnswerType string + Target string +} + +func (rd AKAMAITLC) Len() int { + return len(rd.String()) +} + +func (rd AKAMAITLC) String() string { + parts := make([]string, 0, 2) + parts = append(parts, txtutil.ZoneifyString(rd.AnswerType)) + parts = append(parts, rd.Target) + return strings.Join(parts, " ") +} + +func MakeAKAMAITLC(origin string, _ map[string]string, isEnabled nrc.Flags, args ...any) (dnsv2.RDATA, error) { + mustbe.ValidArgs(args) + if len(args) != 2 { + return nil, fmt.Errorf("AKAMAITLC expects 2 arguments, got %d: %+v", len(args), args) + } + if isEnabled.TargetIsFqdnNoDot { + origin = "." + } + targetHost1, err := mustbe.TargetHost(origin, isEnabled, args[1]) + if err != nil { + return nil, err + } + return AKAMAITLC{ + AnswerType: mustbe.RawString(args[0]), + Target: targetHost1, + }, nil +} + +// Code generated by "go run types_generate.go"; DO NOT EDIT. diff --git a/pkg/privatetypes/rdata/rdata_alias.go b/pkg/privatetypes/rdata/rdata_alias.go new file mode 100644 index 0000000000..32a6f10953 --- /dev/null +++ b/pkg/privatetypes/rdata/rdata_alias.go @@ -0,0 +1,45 @@ +package privatetypesrdata + +// Code generated by "go run types_generate.go"; DO NOT EDIT. + +import ( + "fmt" + "strings" + + dnsv2 "codeberg.org/miekg/dns" + "github.com/DNSControl/dnscontrol/v5/pkg/mustbe" + "github.com/DNSControl/dnscontrol/v5/pkg/nrc" +) + +type ALIAS struct { + Target string +} + +func (rd ALIAS) Len() int { + return len(rd.String()) +} + +func (rd ALIAS) String() string { + parts := make([]string, 0, 1) + parts = append(parts, rd.Target) + return strings.Join(parts, " ") +} + +func MakeALIAS(origin string, _ map[string]string, isEnabled nrc.Flags, args ...any) (dnsv2.RDATA, error) { + mustbe.ValidArgs(args) + if len(args) != 1 { + return nil, fmt.Errorf("ALIAS expects 1 arguments, got %d: %+v", len(args), args) + } + if isEnabled.TargetIsFqdnNoDot { + origin = "." + } + targetHost0, err := mustbe.TargetHost(origin, isEnabled, args[0]) + if err != nil { + return nil, err + } + return ALIAS{ + Target: targetHost0, + }, nil +} + +// Code generated by "go run types_generate.go"; DO NOT EDIT. diff --git a/pkg/privatetypes/rdata/rdata_azure_alias.go b/pkg/privatetypes/rdata/rdata_azure_alias.go new file mode 100644 index 0000000000..a4ca2aedd0 --- /dev/null +++ b/pkg/privatetypes/rdata/rdata_azure_alias.go @@ -0,0 +1,42 @@ +package privatetypesrdata + +// Code generated by "go run types_generate.go"; DO NOT EDIT. + +import ( + "fmt" + "strings" + + dnsv2 "codeberg.org/miekg/dns" + "github.com/DNSControl/dnscontrol/v5/pkg/mustbe" + "github.com/DNSControl/dnscontrol/v5/pkg/nrc" + "github.com/DNSControl/dnscontrol/v5/pkg/txtutil" +) + +type AZUREALIAS struct { + AliasType string + Target string +} + +func (rd AZUREALIAS) Len() int { + return len(rd.String()) +} + +func (rd AZUREALIAS) String() string { + parts := make([]string, 0, 2) + parts = append(parts, txtutil.ZoneifyString(rd.AliasType)) + parts = append(parts, txtutil.ZoneifyString(rd.Target)) + return strings.Join(parts, " ") +} + +func MakeAZUREALIAS(origin string, _ map[string]string, _ nrc.Flags, args ...any) (dnsv2.RDATA, error) { + mustbe.ValidArgs(args) + if len(args) != 2 { + return nil, fmt.Errorf("AZURE_ALIAS expects 2 arguments, got %d: %+v", len(args), args) + } + return AZUREALIAS{ + AliasType: mustbe.RawString(args[0]), + Target: mustbe.RawString(args[1]), + }, nil +} + +// Code generated by "go run types_generate.go"; DO NOT EDIT. diff --git a/pkg/privatetypes/rdata/rdata_bunny_dns_pz.go b/pkg/privatetypes/rdata/rdata_bunny_dns_pz.go new file mode 100644 index 0000000000..2cce33e2b2 --- /dev/null +++ b/pkg/privatetypes/rdata/rdata_bunny_dns_pz.go @@ -0,0 +1,38 @@ +package privatetypesrdata + +// Code generated by "go run types_generate.go"; DO NOT EDIT. + +import ( + "fmt" + "strings" + + dnsv2 "codeberg.org/miekg/dns" + "github.com/DNSControl/dnscontrol/v5/pkg/mustbe" + "github.com/DNSControl/dnscontrol/v5/pkg/nrc" +) + +type BUNNYDNSPZ struct { + PullZoneID int64 +} + +func (rd BUNNYDNSPZ) Len() int { + return len(rd.String()) +} + +func (rd BUNNYDNSPZ) String() string { + parts := make([]string, 0, 1) + parts = append(parts, fmt.Sprintf("%d", rd.PullZoneID)) + return strings.Join(parts, " ") +} + +func MakeBUNNYDNSPZ(origin string, _ map[string]string, _ nrc.Flags, args ...any) (dnsv2.RDATA, error) { + mustbe.ValidArgs(args) + if len(args) != 1 { + return nil, fmt.Errorf("BUNNY_DNS_PZ expects 1 arguments, got %d: %+v", len(args), args) + } + return BUNNYDNSPZ{ + PullZoneID: mustbe.Int64(args[0]), + }, nil +} + +// Code generated by "go run types_generate.go"; DO NOT EDIT. diff --git a/pkg/privatetypes/rdata/rdata_bunny_dns_rdr.go b/pkg/privatetypes/rdata/rdata_bunny_dns_rdr.go new file mode 100644 index 0000000000..48142a1719 --- /dev/null +++ b/pkg/privatetypes/rdata/rdata_bunny_dns_rdr.go @@ -0,0 +1,39 @@ +package privatetypesrdata + +// Code generated by "go run types_generate.go"; DO NOT EDIT. + +import ( + "fmt" + "strings" + + dnsv2 "codeberg.org/miekg/dns" + "github.com/DNSControl/dnscontrol/v5/pkg/mustbe" + "github.com/DNSControl/dnscontrol/v5/pkg/nrc" + "github.com/DNSControl/dnscontrol/v5/pkg/txtutil" +) + +type BUNNYDNSRDR struct { + Target string +} + +func (rd BUNNYDNSRDR) Len() int { + return len(rd.String()) +} + +func (rd BUNNYDNSRDR) String() string { + parts := make([]string, 0, 1) + parts = append(parts, txtutil.ZoneifyString(rd.Target)) + return strings.Join(parts, " ") +} + +func MakeBUNNYDNSRDR(origin string, _ map[string]string, _ nrc.Flags, args ...any) (dnsv2.RDATA, error) { + mustbe.ValidArgs(args) + if len(args) != 1 { + return nil, fmt.Errorf("BUNNY_DNS_RDR expects 1 arguments, got %d: %+v", len(args), args) + } + return BUNNYDNSRDR{ + Target: mustbe.RawString(args[0]), + }, nil +} + +// Code generated by "go run types_generate.go"; DO NOT EDIT. diff --git a/pkg/privatetypes/rdata/rdata_cf_worker_route.go b/pkg/privatetypes/rdata/rdata_cf_worker_route.go new file mode 100644 index 0000000000..c6123856ec --- /dev/null +++ b/pkg/privatetypes/rdata/rdata_cf_worker_route.go @@ -0,0 +1,42 @@ +package privatetypesrdata + +// Code generated by "go run types_generate.go"; DO NOT EDIT. + +import ( + "fmt" + "strings" + + dnsv2 "codeberg.org/miekg/dns" + "github.com/DNSControl/dnscontrol/v5/pkg/mustbe" + "github.com/DNSControl/dnscontrol/v5/pkg/nrc" + "github.com/DNSControl/dnscontrol/v5/pkg/txtutil" +) + +type CFWORKERROUTE struct { + When string + Then string +} + +func (rd CFWORKERROUTE) Len() int { + return len(rd.String()) +} + +func (rd CFWORKERROUTE) String() string { + parts := make([]string, 0, 2) + parts = append(parts, txtutil.ZoneifyString(rd.When)) + parts = append(parts, txtutil.ZoneifyString(rd.Then)) + return strings.Join(parts, " ") +} + +func MakeCFWORKERROUTE(origin string, _ map[string]string, _ nrc.Flags, args ...any) (dnsv2.RDATA, error) { + mustbe.ValidArgs(args) + if len(args) != 2 { + return nil, fmt.Errorf("CF_WORKER_ROUTE expects 2 arguments, got %d: %+v", len(args), args) + } + return CFWORKERROUTE{ + When: mustbe.RawString(args[0]), + Then: mustbe.RawString(args[1]), + }, nil +} + +// Code generated by "go run types_generate.go"; DO NOT EDIT. diff --git a/pkg/privatetypes/rdata/rdata_cloudflareapi_single_redirect.go b/pkg/privatetypes/rdata/rdata_cloudflareapi_single_redirect.go new file mode 100644 index 0000000000..63981339a9 --- /dev/null +++ b/pkg/privatetypes/rdata/rdata_cloudflareapi_single_redirect.go @@ -0,0 +1,50 @@ +package privatetypesrdata + +// Code generated by "go run types_generate.go"; DO NOT EDIT. + +import ( + "fmt" + "strings" + + dnsv2 "codeberg.org/miekg/dns" + "github.com/DNSControl/dnscontrol/v5/pkg/mustbe" + "github.com/DNSControl/dnscontrol/v5/pkg/nrc" + "github.com/DNSControl/dnscontrol/v5/pkg/txtutil" +) + +type CLOUDFLAREAPISINGLEREDIRECT struct { + SRName string + Code uint16 + SRWhen string + SRThen string + RT_SRRRulesetID string + RT_SRRRulesetRuleID string +} + +func (rd CLOUDFLAREAPISINGLEREDIRECT) Len() int { + return len(rd.String()) +} + +func (rd CLOUDFLAREAPISINGLEREDIRECT) String() string { + parts := make([]string, 0, 4) + parts = append(parts, txtutil.ZoneifyString(rd.SRName)) + parts = append(parts, fmt.Sprintf("%d", rd.Code)) + parts = append(parts, txtutil.ZoneifyString(rd.SRWhen)) + parts = append(parts, txtutil.ZoneifyString(rd.SRThen)) + return strings.Join(parts, " ") +} + +func MakeCLOUDFLAREAPISINGLEREDIRECT(origin string, _ map[string]string, _ nrc.Flags, args ...any) (dnsv2.RDATA, error) { + mustbe.ValidArgs(args) + if len(args) != 4 { + return nil, fmt.Errorf("CLOUDFLAREAPI_SINGLE_REDIRECT expects 4 arguments, got %d: %+v", len(args), args) + } + return CLOUDFLAREAPISINGLEREDIRECT{ + SRName: mustbe.RawString(args[0]), + Code: mustbe.Uint16(args[1]), + SRWhen: mustbe.RawString(args[2]), + SRThen: mustbe.RawString(args[3]), + }, nil +} + +// Code generated by "go run types_generate.go"; DO NOT EDIT. diff --git a/pkg/privatetypes/rdata/rdata_cloudns_wr.go b/pkg/privatetypes/rdata/rdata_cloudns_wr.go new file mode 100644 index 0000000000..f1295b9822 --- /dev/null +++ b/pkg/privatetypes/rdata/rdata_cloudns_wr.go @@ -0,0 +1,39 @@ +package privatetypesrdata + +// Code generated by "go run types_generate.go"; DO NOT EDIT. + +import ( + "fmt" + "strings" + + dnsv2 "codeberg.org/miekg/dns" + "github.com/DNSControl/dnscontrol/v5/pkg/mustbe" + "github.com/DNSControl/dnscontrol/v5/pkg/nrc" + "github.com/DNSControl/dnscontrol/v5/pkg/txtutil" +) + +type CLOUDNSWR struct { + Target string +} + +func (rd CLOUDNSWR) Len() int { + return len(rd.String()) +} + +func (rd CLOUDNSWR) String() string { + parts := make([]string, 0, 1) + parts = append(parts, txtutil.ZoneifyString(rd.Target)) + return strings.Join(parts, " ") +} + +func MakeCLOUDNSWR(origin string, _ map[string]string, _ nrc.Flags, args ...any) (dnsv2.RDATA, error) { + mustbe.ValidArgs(args) + if len(args) != 1 { + return nil, fmt.Errorf("CLOUDNS_WR expects 1 arguments, got %d: %+v", len(args), args) + } + return CLOUDNSWR{ + Target: mustbe.RawString(args[0]), + }, nil +} + +// Code generated by "go run types_generate.go"; DO NOT EDIT. diff --git a/pkg/privatetypes/rdata/rdata_frame.go b/pkg/privatetypes/rdata/rdata_frame.go new file mode 100644 index 0000000000..d181662ce4 --- /dev/null +++ b/pkg/privatetypes/rdata/rdata_frame.go @@ -0,0 +1,39 @@ +package privatetypesrdata + +// Code generated by "go run types_generate.go"; DO NOT EDIT. + +import ( + "fmt" + "strings" + + dnsv2 "codeberg.org/miekg/dns" + "github.com/DNSControl/dnscontrol/v5/pkg/mustbe" + "github.com/DNSControl/dnscontrol/v5/pkg/nrc" + "github.com/DNSControl/dnscontrol/v5/pkg/txtutil" +) + +type FRAME struct { + Target string +} + +func (rd FRAME) Len() int { + return len(rd.String()) +} + +func (rd FRAME) String() string { + parts := make([]string, 0, 1) + parts = append(parts, txtutil.ZoneifyString(rd.Target)) + return strings.Join(parts, " ") +} + +func MakeFRAME(origin string, _ map[string]string, _ nrc.Flags, args ...any) (dnsv2.RDATA, error) { + mustbe.ValidArgs(args) + if len(args) != 1 { + return nil, fmt.Errorf("FRAME expects 1 arguments, got %d: %+v", len(args), args) + } + return FRAME{ + Target: mustbe.RawString(args[0]), + }, nil +} + +// Code generated by "go run types_generate.go"; DO NOT EDIT. diff --git a/pkg/privatetypes/rdata/rdata_import_transform.go b/pkg/privatetypes/rdata/rdata_import_transform.go new file mode 100644 index 0000000000..6dbb665332 --- /dev/null +++ b/pkg/privatetypes/rdata/rdata_import_transform.go @@ -0,0 +1,48 @@ +package privatetypesrdata + +// Code generated by "go run types_generate.go"; DO NOT EDIT. + +import ( + "fmt" + "strings" + + dnsv2 "codeberg.org/miekg/dns" + "github.com/DNSControl/dnscontrol/v5/pkg/mustbe" + "github.com/DNSControl/dnscontrol/v5/pkg/nrc" + "github.com/DNSControl/dnscontrol/v5/pkg/txtutil" +) + +type IMPORTTRANSFORM struct { + TransformTable string + TTL uint16 + SuffixStrip string + TargetDomain string +} + +func (rd IMPORTTRANSFORM) Len() int { + return len(rd.String()) +} + +func (rd IMPORTTRANSFORM) String() string { + parts := make([]string, 0, 4) + parts = append(parts, txtutil.ZoneifyString(rd.TransformTable)) + parts = append(parts, fmt.Sprintf("%d", rd.TTL)) + parts = append(parts, txtutil.ZoneifyString(rd.SuffixStrip)) + parts = append(parts, txtutil.ZoneifyString(rd.TargetDomain)) + return strings.Join(parts, " ") +} + +func MakeIMPORTTRANSFORM(origin string, _ map[string]string, _ nrc.Flags, args ...any) (dnsv2.RDATA, error) { + mustbe.ValidArgs(args) + if len(args) != 4 { + return nil, fmt.Errorf("IMPORT_TRANSFORM expects 4 arguments, got %d: %+v", len(args), args) + } + return IMPORTTRANSFORM{ + TransformTable: mustbe.RawString(args[0]), + TTL: mustbe.Uint16(args[1]), + SuffixStrip: mustbe.RawString(args[2]), + TargetDomain: mustbe.RawString(args[3]), + }, nil +} + +// Code generated by "go run types_generate.go"; DO NOT EDIT. diff --git a/pkg/privatetypes/rdata/rdata_lua.go b/pkg/privatetypes/rdata/rdata_lua.go new file mode 100644 index 0000000000..13068bf57b --- /dev/null +++ b/pkg/privatetypes/rdata/rdata_lua.go @@ -0,0 +1,42 @@ +package privatetypesrdata + +// Code generated by "go run types_generate.go"; DO NOT EDIT. + +import ( + "fmt" + "strings" + + dnsv2 "codeberg.org/miekg/dns" + "github.com/DNSControl/dnscontrol/v5/pkg/mustbe" + "github.com/DNSControl/dnscontrol/v5/pkg/nrc" + "github.com/DNSControl/dnscontrol/v5/pkg/txtutil" +) + +type LUA struct { + LuaType string + LuaPayload string +} + +func (rd LUA) Len() int { + return len(rd.String()) +} + +func (rd LUA) String() string { + parts := make([]string, 0, 2) + parts = append(parts, txtutil.ZoneifyString(rd.LuaType)) + parts = append(parts, txtutil.ZoneifyString(rd.LuaPayload)) + return strings.Join(parts, " ") +} + +func MakeLUA(origin string, _ map[string]string, _ nrc.Flags, args ...any) (dnsv2.RDATA, error) { + mustbe.ValidArgs(args) + if len(args) != 2 { + return nil, fmt.Errorf("LUA expects 2 arguments, got %d: %+v", len(args), args) + } + return LUA{ + LuaType: mustbe.ToUpperRawString(args[0]), + LuaPayload: mustbe.RawString(args[1]), + }, nil +} + +// Code generated by "go run types_generate.go"; DO NOT EDIT. diff --git a/pkg/privatetypes/rdata/rdata_mikrotik_forwarder.go b/pkg/privatetypes/rdata/rdata_mikrotik_forwarder.go new file mode 100644 index 0000000000..d718487676 --- /dev/null +++ b/pkg/privatetypes/rdata/rdata_mikrotik_forwarder.go @@ -0,0 +1,39 @@ +package privatetypesrdata + +// Code generated by "go run types_generate.go"; DO NOT EDIT. + +import ( + "fmt" + "strings" + + dnsv2 "codeberg.org/miekg/dns" + "github.com/DNSControl/dnscontrol/v5/pkg/mustbe" + "github.com/DNSControl/dnscontrol/v5/pkg/nrc" + "github.com/DNSControl/dnscontrol/v5/pkg/txtutil" +) + +type MIKROTIKFORWARDER struct { + Target string +} + +func (rd MIKROTIKFORWARDER) Len() int { + return len(rd.String()) +} + +func (rd MIKROTIKFORWARDER) String() string { + parts := make([]string, 0, 1) + parts = append(parts, txtutil.ZoneifyString(rd.Target)) + return strings.Join(parts, " ") +} + +func MakeMIKROTIKFORWARDER(origin string, _ map[string]string, _ nrc.Flags, args ...any) (dnsv2.RDATA, error) { + mustbe.ValidArgs(args) + if len(args) != 1 { + return nil, fmt.Errorf("MIKROTIK_FORWARDER expects 1 arguments, got %d: %+v", len(args), args) + } + return MIKROTIKFORWARDER{ + Target: mustbe.RawString(args[0]), + }, nil +} + +// Code generated by "go run types_generate.go"; DO NOT EDIT. diff --git a/pkg/privatetypes/rdata/rdata_mikrotik_fwd.go b/pkg/privatetypes/rdata/rdata_mikrotik_fwd.go new file mode 100644 index 0000000000..f9dbc7564f --- /dev/null +++ b/pkg/privatetypes/rdata/rdata_mikrotik_fwd.go @@ -0,0 +1,39 @@ +package privatetypesrdata + +// Code generated by "go run types_generate.go"; DO NOT EDIT. + +import ( + "fmt" + "strings" + + dnsv2 "codeberg.org/miekg/dns" + "github.com/DNSControl/dnscontrol/v5/pkg/mustbe" + "github.com/DNSControl/dnscontrol/v5/pkg/nrc" + "github.com/DNSControl/dnscontrol/v5/pkg/txtutil" +) + +type MIKROTIKFWD struct { + ForwardTo string +} + +func (rd MIKROTIKFWD) Len() int { + return len(rd.String()) +} + +func (rd MIKROTIKFWD) String() string { + parts := make([]string, 0, 1) + parts = append(parts, txtutil.ZoneifyString(rd.ForwardTo)) + return strings.Join(parts, " ") +} + +func MakeMIKROTIKFWD(origin string, _ map[string]string, _ nrc.Flags, args ...any) (dnsv2.RDATA, error) { + mustbe.ValidArgs(args) + if len(args) != 1 { + return nil, fmt.Errorf("MIKROTIK_FWD expects 1 arguments, got %d: %+v", len(args), args) + } + return MIKROTIKFWD{ + ForwardTo: mustbe.RawString(args[0]), + }, nil +} + +// Code generated by "go run types_generate.go"; DO NOT EDIT. diff --git a/pkg/privatetypes/rdata/rdata_mikrotik_nxdomain.go b/pkg/privatetypes/rdata/rdata_mikrotik_nxdomain.go new file mode 100644 index 0000000000..1a39bfe160 --- /dev/null +++ b/pkg/privatetypes/rdata/rdata_mikrotik_nxdomain.go @@ -0,0 +1,32 @@ +package privatetypesrdata + +// Code generated by "go run types_generate.go"; DO NOT EDIT. + +import ( + "fmt" + + dnsv2 "codeberg.org/miekg/dns" + "github.com/DNSControl/dnscontrol/v5/pkg/mustbe" + "github.com/DNSControl/dnscontrol/v5/pkg/nrc" +) + +type MIKROTIKNXDOMAIN struct { +} + +func (rd MIKROTIKNXDOMAIN) Len() int { + return 0 +} + +func (rd MIKROTIKNXDOMAIN) String() string { + return "" +} + +func MakeMIKROTIKNXDOMAIN(origin string, _ map[string]string, _ nrc.Flags, args ...any) (dnsv2.RDATA, error) { + mustbe.ValidArgs(args) + if len(args) != 0 { + return nil, fmt.Errorf("MIKROTIK_NXDOMAIN expects 0 arguments, got %d: %+v", len(args), args) + } + return MIKROTIKNXDOMAIN{}, nil +} + +// Code generated by "go run types_generate.go"; DO NOT EDIT. diff --git a/pkg/privatetypes/rdata/rdata_netlify.go b/pkg/privatetypes/rdata/rdata_netlify.go new file mode 100644 index 0000000000..37d0649dd7 --- /dev/null +++ b/pkg/privatetypes/rdata/rdata_netlify.go @@ -0,0 +1,32 @@ +package privatetypesrdata + +// Code generated by "go run types_generate.go"; DO NOT EDIT. + +import ( + "fmt" + + dnsv2 "codeberg.org/miekg/dns" + "github.com/DNSControl/dnscontrol/v5/pkg/mustbe" + "github.com/DNSControl/dnscontrol/v5/pkg/nrc" +) + +type NETLIFY struct { +} + +func (rd NETLIFY) Len() int { + return 0 +} + +func (rd NETLIFY) String() string { + return "" +} + +func MakeNETLIFY(origin string, _ map[string]string, _ nrc.Flags, args ...any) (dnsv2.RDATA, error) { + mustbe.ValidArgs(args) + if len(args) != 0 { + return nil, fmt.Errorf("NETLIFY expects 0 arguments, got %d: %+v", len(args), args) + } + return NETLIFY{}, nil +} + +// Code generated by "go run types_generate.go"; DO NOT EDIT. diff --git a/pkg/privatetypes/rdata/rdata_netlifyv6.go b/pkg/privatetypes/rdata/rdata_netlifyv6.go new file mode 100644 index 0000000000..ef4cb7e42f --- /dev/null +++ b/pkg/privatetypes/rdata/rdata_netlifyv6.go @@ -0,0 +1,32 @@ +package privatetypesrdata + +// Code generated by "go run types_generate.go"; DO NOT EDIT. + +import ( + "fmt" + + dnsv2 "codeberg.org/miekg/dns" + "github.com/DNSControl/dnscontrol/v5/pkg/mustbe" + "github.com/DNSControl/dnscontrol/v5/pkg/nrc" +) + +type NETLIFYV6 struct { +} + +func (rd NETLIFYV6) Len() int { + return 0 +} + +func (rd NETLIFYV6) String() string { + return "" +} + +func MakeNETLIFYV6(origin string, _ map[string]string, _ nrc.Flags, args ...any) (dnsv2.RDATA, error) { + mustbe.ValidArgs(args) + if len(args) != 0 { + return nil, fmt.Errorf("NETLIFYV6 expects 0 arguments, got %d: %+v", len(args), args) + } + return NETLIFYV6{}, nil +} + +// Code generated by "go run types_generate.go"; DO NOT EDIT. diff --git a/pkg/privatetypes/rdata/rdata_porkbun_urlfwd.go b/pkg/privatetypes/rdata/rdata_porkbun_urlfwd.go new file mode 100644 index 0000000000..63846cec35 --- /dev/null +++ b/pkg/privatetypes/rdata/rdata_porkbun_urlfwd.go @@ -0,0 +1,39 @@ +package privatetypesrdata + +// Code generated by "go run types_generate.go"; DO NOT EDIT. + +import ( + "fmt" + "strings" + + dnsv2 "codeberg.org/miekg/dns" + "github.com/DNSControl/dnscontrol/v5/pkg/mustbe" + "github.com/DNSControl/dnscontrol/v5/pkg/nrc" + "github.com/DNSControl/dnscontrol/v5/pkg/txtutil" +) + +type PORKBUNURLFWD struct { + Location string +} + +func (rd PORKBUNURLFWD) Len() int { + return len(rd.String()) +} + +func (rd PORKBUNURLFWD) String() string { + parts := make([]string, 0, 1) + parts = append(parts, txtutil.ZoneifyString(rd.Location)) + return strings.Join(parts, " ") +} + +func MakePORKBUNURLFWD(origin string, _ map[string]string, _ nrc.Flags, args ...any) (dnsv2.RDATA, error) { + mustbe.ValidArgs(args) + if len(args) != 1 { + return nil, fmt.Errorf("PORKBUN_URLFWD expects 1 arguments, got %d: %+v", len(args), args) + } + return PORKBUNURLFWD{ + Location: mustbe.RawString(args[0]), + }, nil +} + +// Code generated by "go run types_generate.go"; DO NOT EDIT. diff --git a/pkg/privatetypes/rdata/rdata_r53_alias.go b/pkg/privatetypes/rdata/rdata_r53_alias.go new file mode 100644 index 0000000000..1cf0ae82a4 --- /dev/null +++ b/pkg/privatetypes/rdata/rdata_r53_alias.go @@ -0,0 +1,58 @@ +package privatetypesrdata + +// Code generated by "go run types_generate.go"; DO NOT EDIT. + +import ( + "fmt" + "strings" + + dnsv2 "codeberg.org/miekg/dns" + "github.com/DNSControl/dnscontrol/v5/pkg/mustbe" + "github.com/DNSControl/dnscontrol/v5/pkg/nrc" + "github.com/DNSControl/dnscontrol/v5/pkg/txtutil" +) + +type R53ALIAS struct { + AliasType string + Target string + EvalTargetHealth string + ZoneID string +} + +func (rd R53ALIAS) Len() int { + return len(rd.String()) +} + +func (rd R53ALIAS) String() string { + parts := make([]string, 0, 4) + parts = append(parts, txtutil.ZoneifyString(rd.AliasType)) + parts = append(parts, rd.Target) + parts = append(parts, txtutil.ZoneifyString(rd.EvalTargetHealth)) + parts = append(parts, txtutil.ZoneifyString(rd.ZoneID)) + return strings.Join(parts, " ") +} + +func MakeR53ALIAS(origin string, _ map[string]string, isEnabled nrc.Flags, args ...any) (dnsv2.RDATA, error) { + mustbe.ValidArgs(args) + if len(args) < 2 || len(args) > 4 { + return nil, fmt.Errorf("R53_ALIAS expects 4 arguments, got %d: %+v", len(args), args) + } + for len(args) < 4 { + args = append(args, "") + } + if isEnabled.TargetIsFqdnNoDot { + origin = "." + } + targetHost1, err := mustbe.TargetHost(origin, isEnabled, args[1]) + if err != nil { + return nil, err + } + return R53ALIAS{ + AliasType: mustbe.RawString(args[0]), + Target: targetHost1, + EvalTargetHealth: mustbe.RawString(args[2]), + ZoneID: mustbe.RawString(args[3]), + }, nil +} + +// Code generated by "go run types_generate.go"; DO NOT EDIT. diff --git a/pkg/privatetypes/rdata/rdata_url.go b/pkg/privatetypes/rdata/rdata_url.go new file mode 100644 index 0000000000..a3823b749d --- /dev/null +++ b/pkg/privatetypes/rdata/rdata_url.go @@ -0,0 +1,39 @@ +package privatetypesrdata + +// Code generated by "go run types_generate.go"; DO NOT EDIT. + +import ( + "fmt" + "strings" + + dnsv2 "codeberg.org/miekg/dns" + "github.com/DNSControl/dnscontrol/v5/pkg/mustbe" + "github.com/DNSControl/dnscontrol/v5/pkg/nrc" + "github.com/DNSControl/dnscontrol/v5/pkg/txtutil" +) + +type URL struct { + Location string +} + +func (rd URL) Len() int { + return len(rd.String()) +} + +func (rd URL) String() string { + parts := make([]string, 0, 1) + parts = append(parts, txtutil.ZoneifyString(rd.Location)) + return strings.Join(parts, " ") +} + +func MakeURL(origin string, _ map[string]string, _ nrc.Flags, args ...any) (dnsv2.RDATA, error) { + mustbe.ValidArgs(args) + if len(args) != 1 { + return nil, fmt.Errorf("URL expects 1 arguments, got %d: %+v", len(args), args) + } + return URL{ + Location: mustbe.RawString(args[0]), + }, nil +} + +// Code generated by "go run types_generate.go"; DO NOT EDIT. diff --git a/pkg/privatetypes/rdata/rdata_url301.go b/pkg/privatetypes/rdata/rdata_url301.go new file mode 100644 index 0000000000..d30b4f5539 --- /dev/null +++ b/pkg/privatetypes/rdata/rdata_url301.go @@ -0,0 +1,39 @@ +package privatetypesrdata + +// Code generated by "go run types_generate.go"; DO NOT EDIT. + +import ( + "fmt" + "strings" + + dnsv2 "codeberg.org/miekg/dns" + "github.com/DNSControl/dnscontrol/v5/pkg/mustbe" + "github.com/DNSControl/dnscontrol/v5/pkg/nrc" + "github.com/DNSControl/dnscontrol/v5/pkg/txtutil" +) + +type URL301 struct { + Location string +} + +func (rd URL301) Len() int { + return len(rd.String()) +} + +func (rd URL301) String() string { + parts := make([]string, 0, 1) + parts = append(parts, txtutil.ZoneifyString(rd.Location)) + return strings.Join(parts, " ") +} + +func MakeURL301(origin string, _ map[string]string, _ nrc.Flags, args ...any) (dnsv2.RDATA, error) { + mustbe.ValidArgs(args) + if len(args) != 1 { + return nil, fmt.Errorf("URL301 expects 1 arguments, got %d: %+v", len(args), args) + } + return URL301{ + Location: mustbe.RawString(args[0]), + }, nil +} + +// Code generated by "go run types_generate.go"; DO NOT EDIT. diff --git a/pkg/privatetypes/register.go b/pkg/privatetypes/register.go new file mode 100644 index 0000000000..05108efbc1 --- /dev/null +++ b/pkg/privatetypes/register.go @@ -0,0 +1,91 @@ +package privatetypes + +//go:generate go run types_generate.go + +import ( + "fmt" + "maps" + "slices" + + dnsv2 "codeberg.org/miekg/dns" + "github.com/DNSControl/dnscontrol/v5/pkg/nrc" +) + +// TypeToMakeRDATA returns a function that accepts arguments of any type and returns a dnsv2.RDATA struct. +// TODO: At which level should we require "mustbe."? +// Examples: +// +// demoRC1, err := TypeToMakeRDATA[dnsv2.TypeA](mustbe.IPv4("1.2.3.4")) +// demoRC2, err := TypeToMakeRDATA[dnsv2.TypeCNAME](mustbe.Host("www", "example.com")) +// demoRC3, err := TypeToMakeRDATA[privatetypes.TypeCFWORKERROUTE](mustbe.RawString("example.com/*"), mustbe.RawString("example.com/worker")) + +type MakerRn func(origin string, metadata map[string]string, isEnabled nrc.Flags, args ...any) (dnsv2.RDATA, error) + +var TypeToMakeRDATA = make(map[uint16]MakerRn) + +// Register registers a new private RR type. It panics if the code point or name is already in use. +func Register(codepoint uint16, typeName string, newFn func() dnsv2.RR, makeFn MakerRn) { + + /* + # Private Resource Records + + Any struct can be used as a private resource record. To make it work you need to implement the following interfaces. + + - [Typer], to give your RR a code point, and see documentation of that interface. + - [RR], all RRs implement this, if you want to have a private EDNS0 option, implement [EDNS0] interface, this + adds a Pseudo() bool method. + - [Parser], so it can be parsed to and from strings. + - [Packer], if you need to use your new RR on the wire. + - [Comparer], if your RR will be signed with DNSSEC. + + See rr_test.go for a complete example for both an external [RR] and [EDNS0]. + */ + + // typenum -> func() RR i.e. a function that creates a new RR struct for the given code point. + if _, ok := dnsv2.TypeToRR[codepoint]; ok { + panic(fmt.Sprintf("TypeToRR[%d] already in use (check for duplicate codepoint assignments)", codepoint)) + } + dnsv2.TypeToRR[codepoint] = newFn + + // typenum -> typename + if _, ok := dnsv2.TypeToString[codepoint]; ok { + panic(fmt.Sprintf("TypeToString[%d] already in use by %s", codepoint, dnsv2.TypeToString[codepoint])) + } + dnsv2.TypeToString[codepoint] = typeName + + // typename -> typenum + if s, exists := dnsv2.StringToType[typeName]; exists { + panic(fmt.Sprintf("StringToType[%s] already in use by %d", typeName, s)) + } + dnsv2.StringToType[typeName] = codepoint + + RegisterMaker(codepoint, makeFn) +} + +// RegisterMaker registers just the Make*() function for an rtype. This is needed for non-private types. +func RegisterMaker(codepoint uint16, makeFn MakerRn) { + + typeName := dnsv2.TypeToString[codepoint] + + // typenum -> func(args ...any) (RDATA, error) i.e. a function that creates an RDATA struct for the given code point, with fields filled from the given args. + if s, exists := TypeToMakeRDATA[codepoint]; exists { + panic(fmt.Sprintf("TypeToMakeRDATA[%d] a.k.a. %s already in use by %T", codepoint, typeName, s)) + } + TypeToMakeRDATA[codepoint] = makeFn +} + +// GetAllTypeNames returns a sorted list of all type names. +func GetAllTypeNames() []string { + return slices.Sorted(maps.Keys(dnsv2.StringToType)) +} + +// IsPrivateType returns true if the codepoint is for a private type. +func IsPrivateType(codepoint uint16) bool { + if codepoint >= 65280 { + _, ok := dnsv2.TypeToString[codepoint] + if ok { + return true + } + } + return false +} diff --git a/pkg/privatetypes/t_adguardhome_a_passthrough.go b/pkg/privatetypes/t_adguardhome_a_passthrough.go new file mode 100644 index 0000000000..e12b4d5c41 --- /dev/null +++ b/pkg/privatetypes/t_adguardhome_a_passthrough.go @@ -0,0 +1,64 @@ +package privatetypes + +// Code generated by "go run types_generate.go"; DO NOT EDIT. + +import ( + "fmt" + "strconv" + + dnsv2 "codeberg.org/miekg/dns" + dnsutilv2 "codeberg.org/miekg/dns/dnsutil" + "github.com/DNSControl/dnscontrol/v5/pkg/mustbe" + privatetypesrdata "github.com/DNSControl/dnscontrol/v5/pkg/privatetypes/rdata" +) + +// ADGUARDHOME_A_PASSTHROUGH + +func init() { + Register(TypeADGUARDHOMEAPASSTHROUGH, "ADGUARDHOME_A_PASSTHROUGH", func() dnsv2.RR { return new(ADGUARDHOMEAPASSTHROUGH) }, privatetypesrdata.MakeADGUARDHOMEAPASSTHROUGH) +} + +const TypeADGUARDHOMEAPASSTHROUGH = uint16(65280) + +type ADGUARDHOMEAPASSTHROUGH struct { + Hdr dnsv2.Header + + privatetypesrdata.ADGUARDHOMEAPASSTHROUGH + // Target string +} + +// Typer interface. + +func (rr *ADGUARDHOMEAPASSTHROUGH) Type() uint16 { return TypeADGUARDHOMEAPASSTHROUGH } + +// RR interface. + +func (rr *ADGUARDHOMEAPASSTHROUGH) Header() *dnsv2.Header { return &rr.Hdr } +func (rr *ADGUARDHOMEAPASSTHROUGH) Len() int { + return rr.Hdr.Len() + rr.Data().Len() +} +func (rr *ADGUARDHOMEAPASSTHROUGH) Data() dnsv2.RDATA { + return privatetypesrdata.ADGUARDHOMEAPASSTHROUGH{Target: rr.Target} +} +func (rr *ADGUARDHOMEAPASSTHROUGH) Clone() dnsv2.RR { + return &ADGUARDHOMEAPASSTHROUGH{ + Hdr: rr.Hdr, + Target: rr.Target} +} +func (rr *ADGUARDHOMEAPASSTHROUGH) String() string { + return (rr.Header().Name + "\t" + + strconv.FormatInt(int64(rr.Header().TTL), 10) + "\t" + + dnsutilv2.ClassToString(rr.Header().Class) + "\tADGUARDHOME_A_PASSTHROUGH\t" + rr.Data().String()) +} + +// Parse makes an RDATA for this type using the tokens from dnsv2's parser. +func (rr *ADGUARDHOMEAPASSTHROUGH) Parse(tokens []string, s string) error { + args := TokensToArgs(tokens) + if len(args) != 1 { + return fmt.Errorf("ADGUARDHOME_A_PASSTHROUGH requires exactly 1 arguments, got %d: %v", len(args), args) + } + rr.Target = mustbe.RawString(args[0]) + return nil +} + +// Code generated by "go run types_generate.go"; DO NOT EDIT. diff --git a/pkg/privatetypes/t_adguardhome_a_passthrough_test.go b/pkg/privatetypes/t_adguardhome_a_passthrough_test.go new file mode 100644 index 0000000000..5a6fa1e0a2 --- /dev/null +++ b/pkg/privatetypes/t_adguardhome_a_passthrough_test.go @@ -0,0 +1,25 @@ +package privatetypes + +// Code generated by "go run types_generate.go"; DO NOT EDIT. + +import ( + "testing" + + dnsv2 "codeberg.org/miekg/dns" +) + +func TestAdguardhomeAPassthrough(t *testing.T) { + y := &ADGUARDHOMEAPASSTHROUGH{ + Hdr: dnsv2.Header{Name: "example.org.", Class: dnsv2.ClassINET}, + Target: "", + } + rry, err := dnsv2.New(y.String()) + if err != nil { + t.Fatal(err) + } + if rry.String() != y.String() { + t.Fatalf("ADGUARDHOME_A_PASSTHROUGH string presentations should be identical:\n%s\n%s", rry.String(), y.String()) + } +} + +// Code generated by "go run types_generate.go"; DO NOT EDIT. diff --git a/pkg/privatetypes/t_adguardhome_aaaa_passthrough.go b/pkg/privatetypes/t_adguardhome_aaaa_passthrough.go new file mode 100644 index 0000000000..09575b3fe3 --- /dev/null +++ b/pkg/privatetypes/t_adguardhome_aaaa_passthrough.go @@ -0,0 +1,64 @@ +package privatetypes + +// Code generated by "go run types_generate.go"; DO NOT EDIT. + +import ( + "fmt" + "strconv" + + dnsv2 "codeberg.org/miekg/dns" + dnsutilv2 "codeberg.org/miekg/dns/dnsutil" + "github.com/DNSControl/dnscontrol/v5/pkg/mustbe" + privatetypesrdata "github.com/DNSControl/dnscontrol/v5/pkg/privatetypes/rdata" +) + +// ADGUARDHOME_AAAA_PASSTHROUGH + +func init() { + Register(TypeADGUARDHOMEAAAAPASSTHROUGH, "ADGUARDHOME_AAAA_PASSTHROUGH", func() dnsv2.RR { return new(ADGUARDHOMEAAAAPASSTHROUGH) }, privatetypesrdata.MakeADGUARDHOMEAAAAPASSTHROUGH) +} + +const TypeADGUARDHOMEAAAAPASSTHROUGH = uint16(65281) + +type ADGUARDHOMEAAAAPASSTHROUGH struct { + Hdr dnsv2.Header + + privatetypesrdata.ADGUARDHOMEAAAAPASSTHROUGH + // Target string +} + +// Typer interface. + +func (rr *ADGUARDHOMEAAAAPASSTHROUGH) Type() uint16 { return TypeADGUARDHOMEAAAAPASSTHROUGH } + +// RR interface. + +func (rr *ADGUARDHOMEAAAAPASSTHROUGH) Header() *dnsv2.Header { return &rr.Hdr } +func (rr *ADGUARDHOMEAAAAPASSTHROUGH) Len() int { + return rr.Hdr.Len() + rr.Data().Len() +} +func (rr *ADGUARDHOMEAAAAPASSTHROUGH) Data() dnsv2.RDATA { + return privatetypesrdata.ADGUARDHOMEAAAAPASSTHROUGH{Target: rr.Target} +} +func (rr *ADGUARDHOMEAAAAPASSTHROUGH) Clone() dnsv2.RR { + return &ADGUARDHOMEAAAAPASSTHROUGH{ + Hdr: rr.Hdr, + Target: rr.Target} +} +func (rr *ADGUARDHOMEAAAAPASSTHROUGH) String() string { + return (rr.Header().Name + "\t" + + strconv.FormatInt(int64(rr.Header().TTL), 10) + "\t" + + dnsutilv2.ClassToString(rr.Header().Class) + "\tADGUARDHOME_AAAA_PASSTHROUGH\t" + rr.Data().String()) +} + +// Parse makes an RDATA for this type using the tokens from dnsv2's parser. +func (rr *ADGUARDHOMEAAAAPASSTHROUGH) Parse(tokens []string, s string) error { + args := TokensToArgs(tokens) + if len(args) != 1 { + return fmt.Errorf("ADGUARDHOME_AAAA_PASSTHROUGH requires exactly 1 arguments, got %d: %v", len(args), args) + } + rr.Target = mustbe.RawString(args[0]) + return nil +} + +// Code generated by "go run types_generate.go"; DO NOT EDIT. diff --git a/pkg/privatetypes/t_adguardhome_aaaa_passthrough_test.go b/pkg/privatetypes/t_adguardhome_aaaa_passthrough_test.go new file mode 100644 index 0000000000..fa3c4d5ee6 --- /dev/null +++ b/pkg/privatetypes/t_adguardhome_aaaa_passthrough_test.go @@ -0,0 +1,25 @@ +package privatetypes + +// Code generated by "go run types_generate.go"; DO NOT EDIT. + +import ( + "testing" + + dnsv2 "codeberg.org/miekg/dns" +) + +func TestAdguardhomeAaaaPassthrough(t *testing.T) { + y := &ADGUARDHOMEAAAAPASSTHROUGH{ + Hdr: dnsv2.Header{Name: "example.org.", Class: dnsv2.ClassINET}, + Target: "", + } + rry, err := dnsv2.New(y.String()) + if err != nil { + t.Fatal(err) + } + if rry.String() != y.String() { + t.Fatalf("ADGUARDHOME_AAAA_PASSTHROUGH string presentations should be identical:\n%s\n%s", rry.String(), y.String()) + } +} + +// Code generated by "go run types_generate.go"; DO NOT EDIT. diff --git a/pkg/privatetypes/t_akamaicdn.go b/pkg/privatetypes/t_akamaicdn.go new file mode 100644 index 0000000000..3c3e364c35 --- /dev/null +++ b/pkg/privatetypes/t_akamaicdn.go @@ -0,0 +1,69 @@ +package privatetypes + +// Code generated by "go run types_generate.go"; DO NOT EDIT. + +import ( + "fmt" + "strconv" + + dnsv2 "codeberg.org/miekg/dns" + dnsutilv2 "codeberg.org/miekg/dns/dnsutil" + "github.com/DNSControl/dnscontrol/v5/pkg/mustbe" + "github.com/DNSControl/dnscontrol/v5/pkg/nrc" + privatetypesrdata "github.com/DNSControl/dnscontrol/v5/pkg/privatetypes/rdata" +) + +// AKAMAICDN + +func init() { + Register(TypeAKAMAICDN, "AKAMAICDN", func() dnsv2.RR { return new(AKAMAICDN) }, privatetypesrdata.MakeAKAMAICDN) +} + +const TypeAKAMAICDN = uint16(65282) + +type AKAMAICDN struct { + Hdr dnsv2.Header + + privatetypesrdata.AKAMAICDN + // Target string +} + +// Typer interface. + +func (rr *AKAMAICDN) Type() uint16 { return TypeAKAMAICDN } + +// RR interface. + +func (rr *AKAMAICDN) Header() *dnsv2.Header { return &rr.Hdr } +func (rr *AKAMAICDN) Len() int { + return rr.Hdr.Len() + rr.Data().Len() +} +func (rr *AKAMAICDN) Data() dnsv2.RDATA { + return privatetypesrdata.AKAMAICDN{Target: rr.Target} +} +func (rr *AKAMAICDN) Clone() dnsv2.RR { + return &AKAMAICDN{ + Hdr: rr.Hdr, + Target: rr.Target} +} +func (rr *AKAMAICDN) String() string { + return (rr.Header().Name + "\t" + + strconv.FormatInt(int64(rr.Header().TTL), 10) + "\t" + + dnsutilv2.ClassToString(rr.Header().Class) + "\tAKAMAICDN\t" + rr.Data().String()) +} + +// Parse makes an RDATA for this type using the tokens from dnsv2's parser. +func (rr *AKAMAICDN) Parse(tokens []string, s string) error { + args := TokensToArgs(tokens) + if len(args) != 1 { + return fmt.Errorf("AKAMAICDN requires exactly 1 arguments, got %d: %v", len(args), args) + } + targetHost0, err := mustbe.TargetHost("", nrc.Flags{}, args[0]) + if err != nil { + return err + } + rr.Target = targetHost0 + return nil +} + +// Code generated by "go run types_generate.go"; DO NOT EDIT. diff --git a/pkg/privatetypes/t_akamaicdn_test.go b/pkg/privatetypes/t_akamaicdn_test.go new file mode 100644 index 0000000000..8d638c5141 --- /dev/null +++ b/pkg/privatetypes/t_akamaicdn_test.go @@ -0,0 +1,25 @@ +package privatetypes + +// Code generated by "go run types_generate.go"; DO NOT EDIT. + +import ( + "testing" + + dnsv2 "codeberg.org/miekg/dns" +) + +func TestAkamaicdn(t *testing.T) { + y := &AKAMAICDN{ + Hdr: dnsv2.Header{Name: "example.org.", Class: dnsv2.ClassINET}, + Target: "example.com.", + } + rry, err := dnsv2.New(y.String()) + if err != nil { + t.Fatal(err) + } + if rry.String() != y.String() { + t.Fatalf("AKAMAICDN string presentations should be identical:\n%s\n%s", rry.String(), y.String()) + } +} + +// Code generated by "go run types_generate.go"; DO NOT EDIT. diff --git a/pkg/privatetypes/t_akamaitlc.go b/pkg/privatetypes/t_akamaitlc.go new file mode 100644 index 0000000000..a185c835c8 --- /dev/null +++ b/pkg/privatetypes/t_akamaitlc.go @@ -0,0 +1,72 @@ +package privatetypes + +// Code generated by "go run types_generate.go"; DO NOT EDIT. + +import ( + "fmt" + "strconv" + + dnsv2 "codeberg.org/miekg/dns" + dnsutilv2 "codeberg.org/miekg/dns/dnsutil" + "github.com/DNSControl/dnscontrol/v5/pkg/mustbe" + "github.com/DNSControl/dnscontrol/v5/pkg/nrc" + privatetypesrdata "github.com/DNSControl/dnscontrol/v5/pkg/privatetypes/rdata" +) + +// AKAMAITLC + +func init() { + Register(TypeAKAMAITLC, "AKAMAITLC", func() dnsv2.RR { return new(AKAMAITLC) }, privatetypesrdata.MakeAKAMAITLC) +} + +const TypeAKAMAITLC = uint16(65284) + +type AKAMAITLC struct { + Hdr dnsv2.Header + + privatetypesrdata.AKAMAITLC + // AnswerType string + // Target string +} + +// Typer interface. + +func (rr *AKAMAITLC) Type() uint16 { return TypeAKAMAITLC } + +// RR interface. + +func (rr *AKAMAITLC) Header() *dnsv2.Header { return &rr.Hdr } +func (rr *AKAMAITLC) Len() int { + return rr.Hdr.Len() + rr.Data().Len() +} +func (rr *AKAMAITLC) Data() dnsv2.RDATA { + return privatetypesrdata.AKAMAITLC{AnswerType: rr.AnswerType, Target: rr.Target} +} +func (rr *AKAMAITLC) Clone() dnsv2.RR { + return &AKAMAITLC{ + Hdr: rr.Hdr, + AnswerType: rr.AnswerType, + Target: rr.Target} +} +func (rr *AKAMAITLC) String() string { + return (rr.Header().Name + "\t" + + strconv.FormatInt(int64(rr.Header().TTL), 10) + "\t" + + dnsutilv2.ClassToString(rr.Header().Class) + "\tAKAMAITLC\t" + rr.Data().String()) +} + +// Parse makes an RDATA for this type using the tokens from dnsv2's parser. +func (rr *AKAMAITLC) Parse(tokens []string, s string) error { + args := TokensToArgs(tokens) + if len(args) != 2 { + return fmt.Errorf("AKAMAITLC requires exactly 2 arguments, got %d: %v", len(args), args) + } + rr.AnswerType = mustbe.RawString(args[0]) + targetHost1, err := mustbe.TargetHost("", nrc.Flags{}, args[1]) + if err != nil { + return err + } + rr.Target = targetHost1 + return nil +} + +// Code generated by "go run types_generate.go"; DO NOT EDIT. diff --git a/pkg/privatetypes/t_akamaitlc_test.go b/pkg/privatetypes/t_akamaitlc_test.go new file mode 100644 index 0000000000..e89e0d5d3e --- /dev/null +++ b/pkg/privatetypes/t_akamaitlc_test.go @@ -0,0 +1,26 @@ +package privatetypes + +// Code generated by "go run types_generate.go"; DO NOT EDIT. + +import ( + "testing" + + dnsv2 "codeberg.org/miekg/dns" +) + +func TestAkamaitlc(t *testing.T) { + y := &AKAMAITLC{ + Hdr: dnsv2.Header{Name: "example.org.", Class: dnsv2.ClassINET}, + AnswerType: "cname", + Target: "example.com.", + } + rry, err := dnsv2.New(y.String()) + if err != nil { + t.Fatal(err) + } + if rry.String() != y.String() { + t.Fatalf("AKAMAITLC string presentations should be identical:\n%s\n%s", rry.String(), y.String()) + } +} + +// Code generated by "go run types_generate.go"; DO NOT EDIT. diff --git a/pkg/privatetypes/t_alias.go b/pkg/privatetypes/t_alias.go new file mode 100644 index 0000000000..3106e3c9e2 --- /dev/null +++ b/pkg/privatetypes/t_alias.go @@ -0,0 +1,69 @@ +package privatetypes + +// Code generated by "go run types_generate.go"; DO NOT EDIT. + +import ( + "fmt" + "strconv" + + dnsv2 "codeberg.org/miekg/dns" + dnsutilv2 "codeberg.org/miekg/dns/dnsutil" + "github.com/DNSControl/dnscontrol/v5/pkg/mustbe" + "github.com/DNSControl/dnscontrol/v5/pkg/nrc" + privatetypesrdata "github.com/DNSControl/dnscontrol/v5/pkg/privatetypes/rdata" +) + +// ALIAS + +func init() { + Register(TypeALIAS, "ALIAS", func() dnsv2.RR { return new(ALIAS) }, privatetypesrdata.MakeALIAS) +} + +const TypeALIAS = uint16(65285) + +type ALIAS struct { + Hdr dnsv2.Header + + privatetypesrdata.ALIAS + // Target string +} + +// Typer interface. + +func (rr *ALIAS) Type() uint16 { return TypeALIAS } + +// RR interface. + +func (rr *ALIAS) Header() *dnsv2.Header { return &rr.Hdr } +func (rr *ALIAS) Len() int { + return rr.Hdr.Len() + rr.Data().Len() +} +func (rr *ALIAS) Data() dnsv2.RDATA { + return privatetypesrdata.ALIAS{Target: rr.Target} +} +func (rr *ALIAS) Clone() dnsv2.RR { + return &ALIAS{ + Hdr: rr.Hdr, + Target: rr.Target} +} +func (rr *ALIAS) String() string { + return (rr.Header().Name + "\t" + + strconv.FormatInt(int64(rr.Header().TTL), 10) + "\t" + + dnsutilv2.ClassToString(rr.Header().Class) + "\tALIAS\t" + rr.Data().String()) +} + +// Parse makes an RDATA for this type using the tokens from dnsv2's parser. +func (rr *ALIAS) Parse(tokens []string, s string) error { + args := TokensToArgs(tokens) + if len(args) != 1 { + return fmt.Errorf("ALIAS requires exactly 1 arguments, got %d: %v", len(args), args) + } + targetHost0, err := mustbe.TargetHost("", nrc.Flags{}, args[0]) + if err != nil { + return err + } + rr.Target = targetHost0 + return nil +} + +// Code generated by "go run types_generate.go"; DO NOT EDIT. diff --git a/pkg/privatetypes/t_alias_test.go b/pkg/privatetypes/t_alias_test.go new file mode 100644 index 0000000000..f5a25910f7 --- /dev/null +++ b/pkg/privatetypes/t_alias_test.go @@ -0,0 +1,25 @@ +package privatetypes + +// Code generated by "go run types_generate.go"; DO NOT EDIT. + +import ( + "testing" + + dnsv2 "codeberg.org/miekg/dns" +) + +func TestAlias(t *testing.T) { + y := &ALIAS{ + Hdr: dnsv2.Header{Name: "example.org.", Class: dnsv2.ClassINET}, + Target: "example.com.", + } + rry, err := dnsv2.New(y.String()) + if err != nil { + t.Fatal(err) + } + if rry.String() != y.String() { + t.Fatalf("ALIAS string presentations should be identical:\n%s\n%s", rry.String(), y.String()) + } +} + +// Code generated by "go run types_generate.go"; DO NOT EDIT. diff --git a/pkg/privatetypes/t_azure_alias.go b/pkg/privatetypes/t_azure_alias.go new file mode 100644 index 0000000000..db12dbb215 --- /dev/null +++ b/pkg/privatetypes/t_azure_alias.go @@ -0,0 +1,67 @@ +package privatetypes + +// Code generated by "go run types_generate.go"; DO NOT EDIT. + +import ( + "fmt" + "strconv" + + dnsv2 "codeberg.org/miekg/dns" + dnsutilv2 "codeberg.org/miekg/dns/dnsutil" + "github.com/DNSControl/dnscontrol/v5/pkg/mustbe" + privatetypesrdata "github.com/DNSControl/dnscontrol/v5/pkg/privatetypes/rdata" +) + +// AZURE_ALIAS + +func init() { + Register(TypeAZUREALIAS, "AZURE_ALIAS", func() dnsv2.RR { return new(AZUREALIAS) }, privatetypesrdata.MakeAZUREALIAS) +} + +const TypeAZUREALIAS = uint16(65286) + +type AZUREALIAS struct { + Hdr dnsv2.Header + + privatetypesrdata.AZUREALIAS + // AliasType string + // Target string +} + +// Typer interface. + +func (rr *AZUREALIAS) Type() uint16 { return TypeAZUREALIAS } + +// RR interface. + +func (rr *AZUREALIAS) Header() *dnsv2.Header { return &rr.Hdr } +func (rr *AZUREALIAS) Len() int { + return rr.Hdr.Len() + rr.Data().Len() +} +func (rr *AZUREALIAS) Data() dnsv2.RDATA { + return privatetypesrdata.AZUREALIAS{AliasType: rr.AliasType, Target: rr.Target} +} +func (rr *AZUREALIAS) Clone() dnsv2.RR { + return &AZUREALIAS{ + Hdr: rr.Hdr, + AliasType: rr.AliasType, + Target: rr.Target} +} +func (rr *AZUREALIAS) String() string { + return (rr.Header().Name + "\t" + + strconv.FormatInt(int64(rr.Header().TTL), 10) + "\t" + + dnsutilv2.ClassToString(rr.Header().Class) + "\tAZURE_ALIAS\t" + rr.Data().String()) +} + +// Parse makes an RDATA for this type using the tokens from dnsv2's parser. +func (rr *AZUREALIAS) Parse(tokens []string, s string) error { + args := TokensToArgs(tokens) + if len(args) != 2 { + return fmt.Errorf("AZURE_ALIAS requires exactly 2 arguments, got %d: %v", len(args), args) + } + rr.AliasType = mustbe.RawString(args[0]) + rr.Target = mustbe.RawString(args[1]) + return nil +} + +// Code generated by "go run types_generate.go"; DO NOT EDIT. diff --git a/pkg/privatetypes/t_azure_alias_test.go b/pkg/privatetypes/t_azure_alias_test.go new file mode 100644 index 0000000000..116231413d --- /dev/null +++ b/pkg/privatetypes/t_azure_alias_test.go @@ -0,0 +1,26 @@ +package privatetypes + +// Code generated by "go run types_generate.go"; DO NOT EDIT. + +import ( + "testing" + + dnsv2 "codeberg.org/miekg/dns" +) + +func TestAzureAlias(t *testing.T) { + y := &AZUREALIAS{ + Hdr: dnsv2.Header{Name: "example.org.", Class: dnsv2.ClassINET}, + AliasType: "A", + Target: "example.com.", + } + rry, err := dnsv2.New(y.String()) + if err != nil { + t.Fatal(err) + } + if rry.String() != y.String() { + t.Fatalf("AZURE_ALIAS string presentations should be identical:\n%s\n%s", rry.String(), y.String()) + } +} + +// Code generated by "go run types_generate.go"; DO NOT EDIT. diff --git a/pkg/privatetypes/t_bunny_dns_pz.go b/pkg/privatetypes/t_bunny_dns_pz.go new file mode 100644 index 0000000000..e6cbeab4c1 --- /dev/null +++ b/pkg/privatetypes/t_bunny_dns_pz.go @@ -0,0 +1,64 @@ +package privatetypes + +// Code generated by "go run types_generate.go"; DO NOT EDIT. + +import ( + "fmt" + "strconv" + + dnsv2 "codeberg.org/miekg/dns" + dnsutilv2 "codeberg.org/miekg/dns/dnsutil" + "github.com/DNSControl/dnscontrol/v5/pkg/mustbe" + privatetypesrdata "github.com/DNSControl/dnscontrol/v5/pkg/privatetypes/rdata" +) + +// BUNNY_DNS_PZ + +func init() { + Register(TypeBUNNYDNSPZ, "BUNNY_DNS_PZ", func() dnsv2.RR { return new(BUNNYDNSPZ) }, privatetypesrdata.MakeBUNNYDNSPZ) +} + +const TypeBUNNYDNSPZ = uint16(65287) + +type BUNNYDNSPZ struct { + Hdr dnsv2.Header + + privatetypesrdata.BUNNYDNSPZ + // PullZoneID int64 +} + +// Typer interface. + +func (rr *BUNNYDNSPZ) Type() uint16 { return TypeBUNNYDNSPZ } + +// RR interface. + +func (rr *BUNNYDNSPZ) Header() *dnsv2.Header { return &rr.Hdr } +func (rr *BUNNYDNSPZ) Len() int { + return rr.Hdr.Len() + rr.Data().Len() +} +func (rr *BUNNYDNSPZ) Data() dnsv2.RDATA { + return privatetypesrdata.BUNNYDNSPZ{PullZoneID: rr.PullZoneID} +} +func (rr *BUNNYDNSPZ) Clone() dnsv2.RR { + return &BUNNYDNSPZ{ + Hdr: rr.Hdr, + PullZoneID: rr.PullZoneID} +} +func (rr *BUNNYDNSPZ) String() string { + return (rr.Header().Name + "\t" + + strconv.FormatInt(int64(rr.Header().TTL), 10) + "\t" + + dnsutilv2.ClassToString(rr.Header().Class) + "\tBUNNY_DNS_PZ\t" + rr.Data().String()) +} + +// Parse makes an RDATA for this type using the tokens from dnsv2's parser. +func (rr *BUNNYDNSPZ) Parse(tokens []string, s string) error { + args := TokensToArgs(tokens) + if len(args) != 1 { + return fmt.Errorf("BUNNY_DNS_PZ requires exactly 1 arguments, got %d: %v", len(args), args) + } + rr.PullZoneID = mustbe.Int64(args[0]) + return nil +} + +// Code generated by "go run types_generate.go"; DO NOT EDIT. diff --git a/pkg/privatetypes/t_bunny_dns_pz_test.go b/pkg/privatetypes/t_bunny_dns_pz_test.go new file mode 100644 index 0000000000..5b93e88f54 --- /dev/null +++ b/pkg/privatetypes/t_bunny_dns_pz_test.go @@ -0,0 +1,25 @@ +package privatetypes + +// Code generated by "go run types_generate.go"; DO NOT EDIT. + +import ( + "testing" + + dnsv2 "codeberg.org/miekg/dns" +) + +func TestBunnyDnsPz(t *testing.T) { + y := &BUNNYDNSPZ{ + Hdr: dnsv2.Header{Name: "example.org.", Class: dnsv2.ClassINET}, + PullZoneID: 123, + } + rry, err := dnsv2.New(y.String()) + if err != nil { + t.Fatal(err) + } + if rry.String() != y.String() { + t.Fatalf("BUNNY_DNS_PZ string presentations should be identical:\n%s\n%s", rry.String(), y.String()) + } +} + +// Code generated by "go run types_generate.go"; DO NOT EDIT. diff --git a/pkg/privatetypes/t_bunny_dns_rdr.go b/pkg/privatetypes/t_bunny_dns_rdr.go new file mode 100644 index 0000000000..d5843427cd --- /dev/null +++ b/pkg/privatetypes/t_bunny_dns_rdr.go @@ -0,0 +1,64 @@ +package privatetypes + +// Code generated by "go run types_generate.go"; DO NOT EDIT. + +import ( + "fmt" + "strconv" + + dnsv2 "codeberg.org/miekg/dns" + dnsutilv2 "codeberg.org/miekg/dns/dnsutil" + "github.com/DNSControl/dnscontrol/v5/pkg/mustbe" + privatetypesrdata "github.com/DNSControl/dnscontrol/v5/pkg/privatetypes/rdata" +) + +// BUNNY_DNS_RDR + +func init() { + Register(TypeBUNNYDNSRDR, "BUNNY_DNS_RDR", func() dnsv2.RR { return new(BUNNYDNSRDR) }, privatetypesrdata.MakeBUNNYDNSRDR) +} + +const TypeBUNNYDNSRDR = uint16(65320) + +type BUNNYDNSRDR struct { + Hdr dnsv2.Header + + privatetypesrdata.BUNNYDNSRDR + // Target string +} + +// Typer interface. + +func (rr *BUNNYDNSRDR) Type() uint16 { return TypeBUNNYDNSRDR } + +// RR interface. + +func (rr *BUNNYDNSRDR) Header() *dnsv2.Header { return &rr.Hdr } +func (rr *BUNNYDNSRDR) Len() int { + return rr.Hdr.Len() + rr.Data().Len() +} +func (rr *BUNNYDNSRDR) Data() dnsv2.RDATA { + return privatetypesrdata.BUNNYDNSRDR{Target: rr.Target} +} +func (rr *BUNNYDNSRDR) Clone() dnsv2.RR { + return &BUNNYDNSRDR{ + Hdr: rr.Hdr, + Target: rr.Target} +} +func (rr *BUNNYDNSRDR) String() string { + return (rr.Header().Name + "\t" + + strconv.FormatInt(int64(rr.Header().TTL), 10) + "\t" + + dnsutilv2.ClassToString(rr.Header().Class) + "\tBUNNY_DNS_RDR\t" + rr.Data().String()) +} + +// Parse makes an RDATA for this type using the tokens from dnsv2's parser. +func (rr *BUNNYDNSRDR) Parse(tokens []string, s string) error { + args := TokensToArgs(tokens) + if len(args) != 1 { + return fmt.Errorf("BUNNY_DNS_RDR requires exactly 1 arguments, got %d: %v", len(args), args) + } + rr.Target = mustbe.RawString(args[0]) + return nil +} + +// Code generated by "go run types_generate.go"; DO NOT EDIT. diff --git a/pkg/privatetypes/t_bunny_dns_rdr_test.go b/pkg/privatetypes/t_bunny_dns_rdr_test.go new file mode 100644 index 0000000000..16fa87a125 --- /dev/null +++ b/pkg/privatetypes/t_bunny_dns_rdr_test.go @@ -0,0 +1,25 @@ +package privatetypes + +// Code generated by "go run types_generate.go"; DO NOT EDIT. + +import ( + "testing" + + dnsv2 "codeberg.org/miekg/dns" +) + +func TestBunnyDnsRdr(t *testing.T) { + y := &BUNNYDNSRDR{ + Hdr: dnsv2.Header{Name: "example.org.", Class: dnsv2.ClassINET}, + Target: "https://example.com", + } + rry, err := dnsv2.New(y.String()) + if err != nil { + t.Fatal(err) + } + if rry.String() != y.String() { + t.Fatalf("BUNNY_DNS_RDR string presentations should be identical:\n%s\n%s", rry.String(), y.String()) + } +} + +// Code generated by "go run types_generate.go"; DO NOT EDIT. diff --git a/pkg/privatetypes/t_cf_worker_route.go b/pkg/privatetypes/t_cf_worker_route.go new file mode 100644 index 0000000000..d4988d1d69 --- /dev/null +++ b/pkg/privatetypes/t_cf_worker_route.go @@ -0,0 +1,67 @@ +package privatetypes + +// Code generated by "go run types_generate.go"; DO NOT EDIT. + +import ( + "fmt" + "strconv" + + dnsv2 "codeberg.org/miekg/dns" + dnsutilv2 "codeberg.org/miekg/dns/dnsutil" + "github.com/DNSControl/dnscontrol/v5/pkg/mustbe" + privatetypesrdata "github.com/DNSControl/dnscontrol/v5/pkg/privatetypes/rdata" +) + +// CF_WORKER_ROUTE + +func init() { + Register(TypeCFWORKERROUTE, "CF_WORKER_ROUTE", func() dnsv2.RR { return new(CFWORKERROUTE) }, privatetypesrdata.MakeCFWORKERROUTE) +} + +const TypeCFWORKERROUTE = uint16(65288) + +type CFWORKERROUTE struct { + Hdr dnsv2.Header + + privatetypesrdata.CFWORKERROUTE + // When string + // Then string +} + +// Typer interface. + +func (rr *CFWORKERROUTE) Type() uint16 { return TypeCFWORKERROUTE } + +// RR interface. + +func (rr *CFWORKERROUTE) Header() *dnsv2.Header { return &rr.Hdr } +func (rr *CFWORKERROUTE) Len() int { + return rr.Hdr.Len() + rr.Data().Len() +} +func (rr *CFWORKERROUTE) Data() dnsv2.RDATA { + return privatetypesrdata.CFWORKERROUTE{When: rr.When, Then: rr.Then} +} +func (rr *CFWORKERROUTE) Clone() dnsv2.RR { + return &CFWORKERROUTE{ + Hdr: rr.Hdr, + When: rr.When, + Then: rr.Then} +} +func (rr *CFWORKERROUTE) String() string { + return (rr.Header().Name + "\t" + + strconv.FormatInt(int64(rr.Header().TTL), 10) + "\t" + + dnsutilv2.ClassToString(rr.Header().Class) + "\tCF_WORKER_ROUTE\t" + rr.Data().String()) +} + +// Parse makes an RDATA for this type using the tokens from dnsv2's parser. +func (rr *CFWORKERROUTE) Parse(tokens []string, s string) error { + args := TokensToArgs(tokens) + if len(args) != 2 { + return fmt.Errorf("CF_WORKER_ROUTE requires exactly 2 arguments, got %d: %v", len(args), args) + } + rr.When = mustbe.RawString(args[0]) + rr.Then = mustbe.RawString(args[1]) + return nil +} + +// Code generated by "go run types_generate.go"; DO NOT EDIT. diff --git a/pkg/privatetypes/t_cf_worker_route_test.go b/pkg/privatetypes/t_cf_worker_route_test.go new file mode 100644 index 0000000000..25cd6085ea --- /dev/null +++ b/pkg/privatetypes/t_cf_worker_route_test.go @@ -0,0 +1,26 @@ +package privatetypes + +// Code generated by "go run types_generate.go"; DO NOT EDIT. + +import ( + "testing" + + dnsv2 "codeberg.org/miekg/dns" +) + +func TestCfWorkerRoute(t *testing.T) { + y := &CFWORKERROUTE{ + Hdr: dnsv2.Header{Name: "example.org.", Class: dnsv2.ClassINET}, + When: "whenWhen", + Then: "ThenThen", + } + rry, err := dnsv2.New(y.String()) + if err != nil { + t.Fatal(err) + } + if rry.String() != y.String() { + t.Fatalf("CF_WORKER_ROUTE string presentations should be identical:\n%s\n%s", rry.String(), y.String()) + } +} + +// Code generated by "go run types_generate.go"; DO NOT EDIT. diff --git a/pkg/privatetypes/t_cloudflareapi_single_redirect.go b/pkg/privatetypes/t_cloudflareapi_single_redirect.go new file mode 100644 index 0000000000..93e0296634 --- /dev/null +++ b/pkg/privatetypes/t_cloudflareapi_single_redirect.go @@ -0,0 +1,77 @@ +package privatetypes + +// Code generated by "go run types_generate.go"; DO NOT EDIT. + +import ( + "fmt" + "strconv" + + dnsv2 "codeberg.org/miekg/dns" + dnsutilv2 "codeberg.org/miekg/dns/dnsutil" + "github.com/DNSControl/dnscontrol/v5/pkg/mustbe" + privatetypesrdata "github.com/DNSControl/dnscontrol/v5/pkg/privatetypes/rdata" +) + +// CLOUDFLAREAPI_SINGLE_REDIRECT + +func init() { + Register(TypeCLOUDFLAREAPISINGLEREDIRECT, "CLOUDFLAREAPI_SINGLE_REDIRECT", func() dnsv2.RR { return new(CLOUDFLAREAPISINGLEREDIRECT) }, privatetypesrdata.MakeCLOUDFLAREAPISINGLEREDIRECT) +} + +const TypeCLOUDFLAREAPISINGLEREDIRECT = uint16(65289) + +type CLOUDFLAREAPISINGLEREDIRECT struct { + Hdr dnsv2.Header + + privatetypesrdata.CLOUDFLAREAPISINGLEREDIRECT + // SRName string + // Code uint16 + // SRWhen string + // SRThen string + // RT_SRRRulesetID string // Runtime + // RT_SRRRulesetRuleID string // Runtime +} + +// Typer interface. + +func (rr *CLOUDFLAREAPISINGLEREDIRECT) Type() uint16 { return TypeCLOUDFLAREAPISINGLEREDIRECT } + +// RR interface. + +func (rr *CLOUDFLAREAPISINGLEREDIRECT) Header() *dnsv2.Header { return &rr.Hdr } +func (rr *CLOUDFLAREAPISINGLEREDIRECT) Len() int { + return rr.Hdr.Len() + rr.Data().Len() +} +func (rr *CLOUDFLAREAPISINGLEREDIRECT) Data() dnsv2.RDATA { + return privatetypesrdata.CLOUDFLAREAPISINGLEREDIRECT{SRName: rr.SRName, Code: rr.Code, SRWhen: rr.SRWhen, SRThen: rr.SRThen, RT_SRRRulesetID: rr.RT_SRRRulesetID, RT_SRRRulesetRuleID: rr.RT_SRRRulesetRuleID} +} +func (rr *CLOUDFLAREAPISINGLEREDIRECT) Clone() dnsv2.RR { + return &CLOUDFLAREAPISINGLEREDIRECT{ + Hdr: rr.Hdr, + SRName: rr.SRName, + Code: rr.Code, + SRWhen: rr.SRWhen, + SRThen: rr.SRThen, + RT_SRRRulesetID: rr.RT_SRRRulesetID, + RT_SRRRulesetRuleID: rr.RT_SRRRulesetRuleID} +} +func (rr *CLOUDFLAREAPISINGLEREDIRECT) String() string { + return (rr.Header().Name + "\t" + + strconv.FormatInt(int64(rr.Header().TTL), 10) + "\t" + + dnsutilv2.ClassToString(rr.Header().Class) + "\tCLOUDFLAREAPI_SINGLE_REDIRECT\t" + rr.Data().String()) +} + +// Parse makes an RDATA for this type using the tokens from dnsv2's parser. +func (rr *CLOUDFLAREAPISINGLEREDIRECT) Parse(tokens []string, s string) error { + args := TokensToArgs(tokens) + if len(args) != 4 { + return fmt.Errorf("CLOUDFLAREAPI_SINGLE_REDIRECT requires exactly 4 arguments, got %d: %v", len(args), args) + } + rr.SRName = mustbe.RawString(args[0]) + rr.Code = mustbe.Uint16(args[1]) + rr.SRWhen = mustbe.RawString(args[2]) + rr.SRThen = mustbe.RawString(args[3]) + return nil +} + +// Code generated by "go run types_generate.go"; DO NOT EDIT. diff --git a/pkg/privatetypes/t_cloudflareapi_single_redirect_test.go b/pkg/privatetypes/t_cloudflareapi_single_redirect_test.go new file mode 100644 index 0000000000..1cd29a6655 --- /dev/null +++ b/pkg/privatetypes/t_cloudflareapi_single_redirect_test.go @@ -0,0 +1,28 @@ +package privatetypes + +// Code generated by "go run types_generate.go"; DO NOT EDIT. + +import ( + "testing" + + dnsv2 "codeberg.org/miekg/dns" +) + +func TestCloudflareapiSingleRedirect(t *testing.T) { + y := &CLOUDFLAREAPISINGLEREDIRECT{ + Hdr: dnsv2.Header{Name: "example.org.", Class: dnsv2.ClassINET}, + SRName: "first_rule", + Code: 301, + SRWhen: "when_string", + SRThen: "then_string", + } + rry, err := dnsv2.New(y.String()) + if err != nil { + t.Fatal(err) + } + if rry.String() != y.String() { + t.Fatalf("CLOUDFLAREAPI_SINGLE_REDIRECT string presentations should be identical:\n%s\n%s", rry.String(), y.String()) + } +} + +// Code generated by "go run types_generate.go"; DO NOT EDIT. diff --git a/pkg/privatetypes/t_cloudns_wr.go b/pkg/privatetypes/t_cloudns_wr.go new file mode 100644 index 0000000000..d724e56f8e --- /dev/null +++ b/pkg/privatetypes/t_cloudns_wr.go @@ -0,0 +1,64 @@ +package privatetypes + +// Code generated by "go run types_generate.go"; DO NOT EDIT. + +import ( + "fmt" + "strconv" + + dnsv2 "codeberg.org/miekg/dns" + dnsutilv2 "codeberg.org/miekg/dns/dnsutil" + "github.com/DNSControl/dnscontrol/v5/pkg/mustbe" + privatetypesrdata "github.com/DNSControl/dnscontrol/v5/pkg/privatetypes/rdata" +) + +// CLOUDNS_WR + +func init() { + Register(TypeCLOUDNSWR, "CLOUDNS_WR", func() dnsv2.RR { return new(CLOUDNSWR) }, privatetypesrdata.MakeCLOUDNSWR) +} + +const TypeCLOUDNSWR = uint16(65290) + +type CLOUDNSWR struct { + Hdr dnsv2.Header + + privatetypesrdata.CLOUDNSWR + // Target string +} + +// Typer interface. + +func (rr *CLOUDNSWR) Type() uint16 { return TypeCLOUDNSWR } + +// RR interface. + +func (rr *CLOUDNSWR) Header() *dnsv2.Header { return &rr.Hdr } +func (rr *CLOUDNSWR) Len() int { + return rr.Hdr.Len() + rr.Data().Len() +} +func (rr *CLOUDNSWR) Data() dnsv2.RDATA { + return privatetypesrdata.CLOUDNSWR{Target: rr.Target} +} +func (rr *CLOUDNSWR) Clone() dnsv2.RR { + return &CLOUDNSWR{ + Hdr: rr.Hdr, + Target: rr.Target} +} +func (rr *CLOUDNSWR) String() string { + return (rr.Header().Name + "\t" + + strconv.FormatInt(int64(rr.Header().TTL), 10) + "\t" + + dnsutilv2.ClassToString(rr.Header().Class) + "\tCLOUDNS_WR\t" + rr.Data().String()) +} + +// Parse makes an RDATA for this type using the tokens from dnsv2's parser. +func (rr *CLOUDNSWR) Parse(tokens []string, s string) error { + args := TokensToArgs(tokens) + if len(args) != 1 { + return fmt.Errorf("CLOUDNS_WR requires exactly 1 arguments, got %d: %v", len(args), args) + } + rr.Target = mustbe.RawString(args[0]) + return nil +} + +// Code generated by "go run types_generate.go"; DO NOT EDIT. diff --git a/pkg/privatetypes/t_cloudns_wr_test.go b/pkg/privatetypes/t_cloudns_wr_test.go new file mode 100644 index 0000000000..432f55de57 --- /dev/null +++ b/pkg/privatetypes/t_cloudns_wr_test.go @@ -0,0 +1,25 @@ +package privatetypes + +// Code generated by "go run types_generate.go"; DO NOT EDIT. + +import ( + "testing" + + dnsv2 "codeberg.org/miekg/dns" +) + +func TestCloudnsWr(t *testing.T) { + y := &CLOUDNSWR{ + Hdr: dnsv2.Header{Name: "example.org.", Class: dnsv2.ClassINET}, + Target: "example.com.", + } + rry, err := dnsv2.New(y.String()) + if err != nil { + t.Fatal(err) + } + if rry.String() != y.String() { + t.Fatalf("CLOUDNS_WR string presentations should be identical:\n%s\n%s", rry.String(), y.String()) + } +} + +// Code generated by "go run types_generate.go"; DO NOT EDIT. diff --git a/pkg/privatetypes/t_frame.go b/pkg/privatetypes/t_frame.go new file mode 100644 index 0000000000..96d4244a69 --- /dev/null +++ b/pkg/privatetypes/t_frame.go @@ -0,0 +1,64 @@ +package privatetypes + +// Code generated by "go run types_generate.go"; DO NOT EDIT. + +import ( + "fmt" + "strconv" + + dnsv2 "codeberg.org/miekg/dns" + dnsutilv2 "codeberg.org/miekg/dns/dnsutil" + "github.com/DNSControl/dnscontrol/v5/pkg/mustbe" + privatetypesrdata "github.com/DNSControl/dnscontrol/v5/pkg/privatetypes/rdata" +) + +// FRAME + +func init() { + Register(TypeFRAME, "FRAME", func() dnsv2.RR { return new(FRAME) }, privatetypesrdata.MakeFRAME) +} + +const TypeFRAME = uint16(65291) + +type FRAME struct { + Hdr dnsv2.Header + + privatetypesrdata.FRAME + // Target string +} + +// Typer interface. + +func (rr *FRAME) Type() uint16 { return TypeFRAME } + +// RR interface. + +func (rr *FRAME) Header() *dnsv2.Header { return &rr.Hdr } +func (rr *FRAME) Len() int { + return rr.Hdr.Len() + rr.Data().Len() +} +func (rr *FRAME) Data() dnsv2.RDATA { + return privatetypesrdata.FRAME{Target: rr.Target} +} +func (rr *FRAME) Clone() dnsv2.RR { + return &FRAME{ + Hdr: rr.Hdr, + Target: rr.Target} +} +func (rr *FRAME) String() string { + return (rr.Header().Name + "\t" + + strconv.FormatInt(int64(rr.Header().TTL), 10) + "\t" + + dnsutilv2.ClassToString(rr.Header().Class) + "\tFRAME\t" + rr.Data().String()) +} + +// Parse makes an RDATA for this type using the tokens from dnsv2's parser. +func (rr *FRAME) Parse(tokens []string, s string) error { + args := TokensToArgs(tokens) + if len(args) != 1 { + return fmt.Errorf("FRAME requires exactly 1 arguments, got %d: %v", len(args), args) + } + rr.Target = mustbe.RawString(args[0]) + return nil +} + +// Code generated by "go run types_generate.go"; DO NOT EDIT. diff --git a/pkg/privatetypes/t_frame_test.go b/pkg/privatetypes/t_frame_test.go new file mode 100644 index 0000000000..d74c671404 --- /dev/null +++ b/pkg/privatetypes/t_frame_test.go @@ -0,0 +1,25 @@ +package privatetypes + +// Code generated by "go run types_generate.go"; DO NOT EDIT. + +import ( + "testing" + + dnsv2 "codeberg.org/miekg/dns" +) + +func TestFrame(t *testing.T) { + y := &FRAME{ + Hdr: dnsv2.Header{Name: "example.org.", Class: dnsv2.ClassINET}, + Target: "example.com.", + } + rry, err := dnsv2.New(y.String()) + if err != nil { + t.Fatal(err) + } + if rry.String() != y.String() { + t.Fatalf("FRAME string presentations should be identical:\n%s\n%s", rry.String(), y.String()) + } +} + +// Code generated by "go run types_generate.go"; DO NOT EDIT. diff --git a/pkg/privatetypes/t_import_transform.go b/pkg/privatetypes/t_import_transform.go new file mode 100644 index 0000000000..2aadd79adf --- /dev/null +++ b/pkg/privatetypes/t_import_transform.go @@ -0,0 +1,73 @@ +package privatetypes + +// Code generated by "go run types_generate.go"; DO NOT EDIT. + +import ( + "fmt" + "strconv" + + dnsv2 "codeberg.org/miekg/dns" + dnsutilv2 "codeberg.org/miekg/dns/dnsutil" + "github.com/DNSControl/dnscontrol/v5/pkg/mustbe" + privatetypesrdata "github.com/DNSControl/dnscontrol/v5/pkg/privatetypes/rdata" +) + +// IMPORT_TRANSFORM + +func init() { + Register(TypeIMPORTTRANSFORM, "IMPORT_TRANSFORM", func() dnsv2.RR { return new(IMPORTTRANSFORM) }, privatetypesrdata.MakeIMPORTTRANSFORM) +} + +const TypeIMPORTTRANSFORM = uint16(65322) + +type IMPORTTRANSFORM struct { + Hdr dnsv2.Header + + privatetypesrdata.IMPORTTRANSFORM + // TransformTable string + // TTL uint16 + // SuffixStrip string + // TargetDomain string +} + +// Typer interface. + +func (rr *IMPORTTRANSFORM) Type() uint16 { return TypeIMPORTTRANSFORM } + +// RR interface. + +func (rr *IMPORTTRANSFORM) Header() *dnsv2.Header { return &rr.Hdr } +func (rr *IMPORTTRANSFORM) Len() int { + return rr.Hdr.Len() + rr.Data().Len() +} +func (rr *IMPORTTRANSFORM) Data() dnsv2.RDATA { + return privatetypesrdata.IMPORTTRANSFORM{TransformTable: rr.TransformTable, TTL: rr.TTL, SuffixStrip: rr.SuffixStrip, TargetDomain: rr.TargetDomain} +} +func (rr *IMPORTTRANSFORM) Clone() dnsv2.RR { + return &IMPORTTRANSFORM{ + Hdr: rr.Hdr, + TransformTable: rr.TransformTable, + TTL: rr.TTL, + SuffixStrip: rr.SuffixStrip, + TargetDomain: rr.TargetDomain} +} +func (rr *IMPORTTRANSFORM) String() string { + return (rr.Header().Name + "\t" + + strconv.FormatInt(int64(rr.Header().TTL), 10) + "\t" + + dnsutilv2.ClassToString(rr.Header().Class) + "\tIMPORT_TRANSFORM\t" + rr.Data().String()) +} + +// Parse makes an RDATA for this type using the tokens from dnsv2's parser. +func (rr *IMPORTTRANSFORM) Parse(tokens []string, s string) error { + args := TokensToArgs(tokens) + if len(args) != 4 { + return fmt.Errorf("IMPORT_TRANSFORM requires exactly 4 arguments, got %d: %v", len(args), args) + } + rr.TransformTable = mustbe.RawString(args[0]) + rr.TTL = mustbe.Uint16(args[1]) + rr.SuffixStrip = mustbe.RawString(args[2]) + rr.TargetDomain = mustbe.RawString(args[3]) + return nil +} + +// Code generated by "go run types_generate.go"; DO NOT EDIT. diff --git a/pkg/privatetypes/t_import_transform_test.go b/pkg/privatetypes/t_import_transform_test.go new file mode 100644 index 0000000000..662d27d87e --- /dev/null +++ b/pkg/privatetypes/t_import_transform_test.go @@ -0,0 +1,28 @@ +package privatetypes + +// Code generated by "go run types_generate.go"; DO NOT EDIT. + +import ( + "testing" + + dnsv2 "codeberg.org/miekg/dns" +) + +func TestImportTransform(t *testing.T) { + y := &IMPORTTRANSFORM{ + Hdr: dnsv2.Header{Name: "example.org.", Class: dnsv2.ClassINET}, + TransformTable: "1.1.1.0 ~ 1.1.1.100 ~ 4.4.4.100 ~", + TTL: 123, + SuffixStrip: "com", + TargetDomain: "example.com", + } + rry, err := dnsv2.New(y.String()) + if err != nil { + t.Fatal(err) + } + if rry.String() != y.String() { + t.Fatalf("IMPORT_TRANSFORM string presentations should be identical:\n%s\n%s", rry.String(), y.String()) + } +} + +// Code generated by "go run types_generate.go"; DO NOT EDIT. diff --git a/pkg/privatetypes/t_lua.go b/pkg/privatetypes/t_lua.go new file mode 100644 index 0000000000..6a1584d532 --- /dev/null +++ b/pkg/privatetypes/t_lua.go @@ -0,0 +1,67 @@ +package privatetypes + +// Code generated by "go run types_generate.go"; DO NOT EDIT. + +import ( + "fmt" + "strconv" + + dnsv2 "codeberg.org/miekg/dns" + dnsutilv2 "codeberg.org/miekg/dns/dnsutil" + "github.com/DNSControl/dnscontrol/v5/pkg/mustbe" + privatetypesrdata "github.com/DNSControl/dnscontrol/v5/pkg/privatetypes/rdata" +) + +// LUA + +func init() { + Register(TypeLUA, "LUA", func() dnsv2.RR { return new(LUA) }, privatetypesrdata.MakeLUA) +} + +const TypeLUA = uint16(65292) + +type LUA struct { + Hdr dnsv2.Header + + privatetypesrdata.LUA + // LuaType string + // LuaPayload string +} + +// Typer interface. + +func (rr *LUA) Type() uint16 { return TypeLUA } + +// RR interface. + +func (rr *LUA) Header() *dnsv2.Header { return &rr.Hdr } +func (rr *LUA) Len() int { + return rr.Hdr.Len() + rr.Data().Len() +} +func (rr *LUA) Data() dnsv2.RDATA { + return privatetypesrdata.LUA{LuaType: rr.LuaType, LuaPayload: rr.LuaPayload} +} +func (rr *LUA) Clone() dnsv2.RR { + return &LUA{ + Hdr: rr.Hdr, + LuaType: rr.LuaType, + LuaPayload: rr.LuaPayload} +} +func (rr *LUA) String() string { + return (rr.Header().Name + "\t" + + strconv.FormatInt(int64(rr.Header().TTL), 10) + "\t" + + dnsutilv2.ClassToString(rr.Header().Class) + "\tLUA\t" + rr.Data().String()) +} + +// Parse makes an RDATA for this type using the tokens from dnsv2's parser. +func (rr *LUA) Parse(tokens []string, s string) error { + args := TokensToArgs(tokens) + if len(args) != 2 { + return fmt.Errorf("LUA requires exactly 2 arguments, got %d: %v", len(args), args) + } + rr.LuaType = mustbe.ToUpperRawString(args[0]) + rr.LuaPayload = mustbe.RawString(args[1]) + return nil +} + +// Code generated by "go run types_generate.go"; DO NOT EDIT. diff --git a/pkg/privatetypes/t_lua_test.go b/pkg/privatetypes/t_lua_test.go new file mode 100644 index 0000000000..1ae52ce501 --- /dev/null +++ b/pkg/privatetypes/t_lua_test.go @@ -0,0 +1,26 @@ +package privatetypes + +// Code generated by "go run types_generate.go"; DO NOT EDIT. + +import ( + "testing" + + dnsv2 "codeberg.org/miekg/dns" +) + +func TestLua(t *testing.T) { + y := &LUA{ + Hdr: dnsv2.Header{Name: "example.org.", Class: dnsv2.ClassINET}, + LuaType: "A", + LuaPayload: "return_127_0_0_1", + } + rry, err := dnsv2.New(y.String()) + if err != nil { + t.Fatal(err) + } + if rry.String() != y.String() { + t.Fatalf("LUA string presentations should be identical:\n%s\n%s", rry.String(), y.String()) + } +} + +// Code generated by "go run types_generate.go"; DO NOT EDIT. diff --git a/pkg/privatetypes/t_mikrotik_forwarder.go b/pkg/privatetypes/t_mikrotik_forwarder.go new file mode 100644 index 0000000000..5023ed85dc --- /dev/null +++ b/pkg/privatetypes/t_mikrotik_forwarder.go @@ -0,0 +1,64 @@ +package privatetypes + +// Code generated by "go run types_generate.go"; DO NOT EDIT. + +import ( + "fmt" + "strconv" + + dnsv2 "codeberg.org/miekg/dns" + dnsutilv2 "codeberg.org/miekg/dns/dnsutil" + "github.com/DNSControl/dnscontrol/v5/pkg/mustbe" + privatetypesrdata "github.com/DNSControl/dnscontrol/v5/pkg/privatetypes/rdata" +) + +// MIKROTIK_FORWARDER + +func init() { + Register(TypeMIKROTIKFORWARDER, "MIKROTIK_FORWARDER", func() dnsv2.RR { return new(MIKROTIKFORWARDER) }, privatetypesrdata.MakeMIKROTIKFORWARDER) +} + +const TypeMIKROTIKFORWARDER = uint16(65321) + +type MIKROTIKFORWARDER struct { + Hdr dnsv2.Header + + privatetypesrdata.MIKROTIKFORWARDER + // Target string +} + +// Typer interface. + +func (rr *MIKROTIKFORWARDER) Type() uint16 { return TypeMIKROTIKFORWARDER } + +// RR interface. + +func (rr *MIKROTIKFORWARDER) Header() *dnsv2.Header { return &rr.Hdr } +func (rr *MIKROTIKFORWARDER) Len() int { + return rr.Hdr.Len() + rr.Data().Len() +} +func (rr *MIKROTIKFORWARDER) Data() dnsv2.RDATA { + return privatetypesrdata.MIKROTIKFORWARDER{Target: rr.Target} +} +func (rr *MIKROTIKFORWARDER) Clone() dnsv2.RR { + return &MIKROTIKFORWARDER{ + Hdr: rr.Hdr, + Target: rr.Target} +} +func (rr *MIKROTIKFORWARDER) String() string { + return (rr.Header().Name + "\t" + + strconv.FormatInt(int64(rr.Header().TTL), 10) + "\t" + + dnsutilv2.ClassToString(rr.Header().Class) + "\tMIKROTIK_FORWARDER\t" + rr.Data().String()) +} + +// Parse makes an RDATA for this type using the tokens from dnsv2's parser. +func (rr *MIKROTIKFORWARDER) Parse(tokens []string, s string) error { + args := TokensToArgs(tokens) + if len(args) != 1 { + return fmt.Errorf("MIKROTIK_FORWARDER requires exactly 1 arguments, got %d: %v", len(args), args) + } + rr.Target = mustbe.RawString(args[0]) + return nil +} + +// Code generated by "go run types_generate.go"; DO NOT EDIT. diff --git a/pkg/privatetypes/t_mikrotik_forwarder_test.go b/pkg/privatetypes/t_mikrotik_forwarder_test.go new file mode 100644 index 0000000000..9a084bffe4 --- /dev/null +++ b/pkg/privatetypes/t_mikrotik_forwarder_test.go @@ -0,0 +1,25 @@ +package privatetypes + +// Code generated by "go run types_generate.go"; DO NOT EDIT. + +import ( + "testing" + + dnsv2 "codeberg.org/miekg/dns" +) + +func TestMikrotikForwarder(t *testing.T) { + y := &MIKROTIKFORWARDER{ + Hdr: dnsv2.Header{Name: "example.org.", Class: dnsv2.ClassINET}, + Target: "1.1.1.1,8.8.8.8", + } + rry, err := dnsv2.New(y.String()) + if err != nil { + t.Fatal(err) + } + if rry.String() != y.String() { + t.Fatalf("MIKROTIK_FORWARDER string presentations should be identical:\n%s\n%s", rry.String(), y.String()) + } +} + +// Code generated by "go run types_generate.go"; DO NOT EDIT. diff --git a/pkg/privatetypes/t_mikrotik_fwd.go b/pkg/privatetypes/t_mikrotik_fwd.go new file mode 100644 index 0000000000..26b8b686dd --- /dev/null +++ b/pkg/privatetypes/t_mikrotik_fwd.go @@ -0,0 +1,64 @@ +package privatetypes + +// Code generated by "go run types_generate.go"; DO NOT EDIT. + +import ( + "fmt" + "strconv" + + dnsv2 "codeberg.org/miekg/dns" + dnsutilv2 "codeberg.org/miekg/dns/dnsutil" + "github.com/DNSControl/dnscontrol/v5/pkg/mustbe" + privatetypesrdata "github.com/DNSControl/dnscontrol/v5/pkg/privatetypes/rdata" +) + +// MIKROTIK_FWD + +func init() { + Register(TypeMIKROTIKFWD, "MIKROTIK_FWD", func() dnsv2.RR { return new(MIKROTIKFWD) }, privatetypesrdata.MakeMIKROTIKFWD) +} + +const TypeMIKROTIKFWD = uint16(65293) + +type MIKROTIKFWD struct { + Hdr dnsv2.Header + + privatetypesrdata.MIKROTIKFWD + // ForwardTo string +} + +// Typer interface. + +func (rr *MIKROTIKFWD) Type() uint16 { return TypeMIKROTIKFWD } + +// RR interface. + +func (rr *MIKROTIKFWD) Header() *dnsv2.Header { return &rr.Hdr } +func (rr *MIKROTIKFWD) Len() int { + return rr.Hdr.Len() + rr.Data().Len() +} +func (rr *MIKROTIKFWD) Data() dnsv2.RDATA { + return privatetypesrdata.MIKROTIKFWD{ForwardTo: rr.ForwardTo} +} +func (rr *MIKROTIKFWD) Clone() dnsv2.RR { + return &MIKROTIKFWD{ + Hdr: rr.Hdr, + ForwardTo: rr.ForwardTo} +} +func (rr *MIKROTIKFWD) String() string { + return (rr.Header().Name + "\t" + + strconv.FormatInt(int64(rr.Header().TTL), 10) + "\t" + + dnsutilv2.ClassToString(rr.Header().Class) + "\tMIKROTIK_FWD\t" + rr.Data().String()) +} + +// Parse makes an RDATA for this type using the tokens from dnsv2's parser. +func (rr *MIKROTIKFWD) Parse(tokens []string, s string) error { + args := TokensToArgs(tokens) + if len(args) != 1 { + return fmt.Errorf("MIKROTIK_FWD requires exactly 1 arguments, got %d: %v", len(args), args) + } + rr.ForwardTo = mustbe.RawString(args[0]) + return nil +} + +// Code generated by "go run types_generate.go"; DO NOT EDIT. diff --git a/pkg/privatetypes/t_mikrotik_fwd_test.go b/pkg/privatetypes/t_mikrotik_fwd_test.go new file mode 100644 index 0000000000..6d1375c825 --- /dev/null +++ b/pkg/privatetypes/t_mikrotik_fwd_test.go @@ -0,0 +1,25 @@ +package privatetypes + +// Code generated by "go run types_generate.go"; DO NOT EDIT. + +import ( + "testing" + + dnsv2 "codeberg.org/miekg/dns" +) + +func TestMikrotikFwd(t *testing.T) { + y := &MIKROTIKFWD{ + Hdr: dnsv2.Header{Name: "example.org.", Class: dnsv2.ClassINET}, + ForwardTo: "example.com.", + } + rry, err := dnsv2.New(y.String()) + if err != nil { + t.Fatal(err) + } + if rry.String() != y.String() { + t.Fatalf("MIKROTIK_FWD string presentations should be identical:\n%s\n%s", rry.String(), y.String()) + } +} + +// Code generated by "go run types_generate.go"; DO NOT EDIT. diff --git a/pkg/privatetypes/t_mikrotik_nxdomain.go b/pkg/privatetypes/t_mikrotik_nxdomain.go new file mode 100644 index 0000000000..7e99339d0d --- /dev/null +++ b/pkg/privatetypes/t_mikrotik_nxdomain.go @@ -0,0 +1,61 @@ +package privatetypes + +// Code generated by "go run types_generate.go"; DO NOT EDIT. + +import ( + "fmt" + "strconv" + + dnsv2 "codeberg.org/miekg/dns" + dnsutilv2 "codeberg.org/miekg/dns/dnsutil" + privatetypesrdata "github.com/DNSControl/dnscontrol/v5/pkg/privatetypes/rdata" +) + +// MIKROTIK_NXDOMAIN + +func init() { + Register(TypeMIKROTIKNXDOMAIN, "MIKROTIK_NXDOMAIN", func() dnsv2.RR { return new(MIKROTIKNXDOMAIN) }, privatetypesrdata.MakeMIKROTIKNXDOMAIN) +} + +const TypeMIKROTIKNXDOMAIN = uint16(65294) + +type MIKROTIKNXDOMAIN struct { + Hdr dnsv2.Header + + privatetypesrdata.MIKROTIKNXDOMAIN +} + +// Typer interface. + +func (rr *MIKROTIKNXDOMAIN) Type() uint16 { return TypeMIKROTIKNXDOMAIN } + +// RR interface. + +func (rr *MIKROTIKNXDOMAIN) Header() *dnsv2.Header { return &rr.Hdr } +func (rr *MIKROTIKNXDOMAIN) Len() int { + return rr.Hdr.Len() +} +func (rr *MIKROTIKNXDOMAIN) Data() dnsv2.RDATA { + return nil +} +func (rr *MIKROTIKNXDOMAIN) Clone() dnsv2.RR { + return &MIKROTIKNXDOMAIN{ + rr.Hdr, + privatetypesrdata.MIKROTIKNXDOMAIN{}} +} +func (rr *MIKROTIKNXDOMAIN) String() string { + return rr.Header().Name + "\t" + + strconv.FormatInt(int64(rr.Header().TTL), 10) + "\t" + + dnsutilv2.ClassToString(rr.Header().Class) + "\tMIKROTIK_NXDOMAIN" // RDATA is empty. +} + +// Parse makes an RDATA for this type using the tokens from dnsv2's parser. +func (rr *MIKROTIKNXDOMAIN) Parse(tokens []string, s string) error { + args := TokensToArgs(tokens) + if len(args) != 0 { + return fmt.Errorf("MIKROTIK_NXDOMAIN requires exactly 0 arguments, got %d", len(args)) + } + return nil +} + +// Code generated by "go run types_generate.go"; DO NOT EDIT. diff --git a/pkg/privatetypes/t_mikrotik_nxdomain_test.go b/pkg/privatetypes/t_mikrotik_nxdomain_test.go new file mode 100644 index 0000000000..fc150e61d4 --- /dev/null +++ b/pkg/privatetypes/t_mikrotik_nxdomain_test.go @@ -0,0 +1,22 @@ +package privatetypes + +// Code generated by "go run types_generate.go"; DO NOT EDIT. + +import ( + "testing" + + dnsv2 "codeberg.org/miekg/dns" +) + +func TestMikrotikNxdomain(t *testing.T) { + y := &MIKROTIKNXDOMAIN{Hdr: dnsv2.Header{Name: "example.org.", Class: dnsv2.ClassINET}} + rry, err := dnsv2.New(y.String()) + if err != nil { + t.Fatal(err) + } + if rry.String() != y.String() { + t.Fatalf("MIKROTIK_NXDOMAIN string presentations should be identical:\n%q\n%q", rry.String(), y.String()) + } +} + +// Code generated by "go run types_generate.go"; DO NOT EDIT. diff --git a/pkg/privatetypes/t_netlify.go b/pkg/privatetypes/t_netlify.go new file mode 100644 index 0000000000..d0d0922fe5 --- /dev/null +++ b/pkg/privatetypes/t_netlify.go @@ -0,0 +1,61 @@ +package privatetypes + +// Code generated by "go run types_generate.go"; DO NOT EDIT. + +import ( + "fmt" + "strconv" + + dnsv2 "codeberg.org/miekg/dns" + dnsutilv2 "codeberg.org/miekg/dns/dnsutil" + privatetypesrdata "github.com/DNSControl/dnscontrol/v5/pkg/privatetypes/rdata" +) + +// NETLIFY + +func init() { + Register(TypeNETLIFY, "NETLIFY", func() dnsv2.RR { return new(NETLIFY) }, privatetypesrdata.MakeNETLIFY) +} + +const TypeNETLIFY = uint16(65295) + +type NETLIFY struct { + Hdr dnsv2.Header + + privatetypesrdata.NETLIFY +} + +// Typer interface. + +func (rr *NETLIFY) Type() uint16 { return TypeNETLIFY } + +// RR interface. + +func (rr *NETLIFY) Header() *dnsv2.Header { return &rr.Hdr } +func (rr *NETLIFY) Len() int { + return rr.Hdr.Len() +} +func (rr *NETLIFY) Data() dnsv2.RDATA { + return nil +} +func (rr *NETLIFY) Clone() dnsv2.RR { + return &NETLIFY{ + rr.Hdr, + privatetypesrdata.NETLIFY{}} +} +func (rr *NETLIFY) String() string { + return rr.Header().Name + "\t" + + strconv.FormatInt(int64(rr.Header().TTL), 10) + "\t" + + dnsutilv2.ClassToString(rr.Header().Class) + "\tNETLIFY" // RDATA is empty. +} + +// Parse makes an RDATA for this type using the tokens from dnsv2's parser. +func (rr *NETLIFY) Parse(tokens []string, s string) error { + args := TokensToArgs(tokens) + if len(args) != 0 { + return fmt.Errorf("NETLIFY requires exactly 0 arguments, got %d", len(args)) + } + return nil +} + +// Code generated by "go run types_generate.go"; DO NOT EDIT. diff --git a/pkg/privatetypes/t_netlify_test.go b/pkg/privatetypes/t_netlify_test.go new file mode 100644 index 0000000000..bc59784711 --- /dev/null +++ b/pkg/privatetypes/t_netlify_test.go @@ -0,0 +1,22 @@ +package privatetypes + +// Code generated by "go run types_generate.go"; DO NOT EDIT. + +import ( + "testing" + + dnsv2 "codeberg.org/miekg/dns" +) + +func TestNetlify(t *testing.T) { + y := &NETLIFY{Hdr: dnsv2.Header{Name: "example.org.", Class: dnsv2.ClassINET}} + rry, err := dnsv2.New(y.String()) + if err != nil { + t.Fatal(err) + } + if rry.String() != y.String() { + t.Fatalf("NETLIFY string presentations should be identical:\n%q\n%q", rry.String(), y.String()) + } +} + +// Code generated by "go run types_generate.go"; DO NOT EDIT. diff --git a/pkg/privatetypes/t_netlifyv6.go b/pkg/privatetypes/t_netlifyv6.go new file mode 100644 index 0000000000..ff08350d1b --- /dev/null +++ b/pkg/privatetypes/t_netlifyv6.go @@ -0,0 +1,61 @@ +package privatetypes + +// Code generated by "go run types_generate.go"; DO NOT EDIT. + +import ( + "fmt" + "strconv" + + dnsv2 "codeberg.org/miekg/dns" + dnsutilv2 "codeberg.org/miekg/dns/dnsutil" + privatetypesrdata "github.com/DNSControl/dnscontrol/v5/pkg/privatetypes/rdata" +) + +// NETLIFYV6 + +func init() { + Register(TypeNETLIFYV6, "NETLIFYV6", func() dnsv2.RR { return new(NETLIFYV6) }, privatetypesrdata.MakeNETLIFYV6) +} + +const TypeNETLIFYV6 = uint16(65296) + +type NETLIFYV6 struct { + Hdr dnsv2.Header + + privatetypesrdata.NETLIFYV6 +} + +// Typer interface. + +func (rr *NETLIFYV6) Type() uint16 { return TypeNETLIFYV6 } + +// RR interface. + +func (rr *NETLIFYV6) Header() *dnsv2.Header { return &rr.Hdr } +func (rr *NETLIFYV6) Len() int { + return rr.Hdr.Len() +} +func (rr *NETLIFYV6) Data() dnsv2.RDATA { + return nil +} +func (rr *NETLIFYV6) Clone() dnsv2.RR { + return &NETLIFYV6{ + rr.Hdr, + privatetypesrdata.NETLIFYV6{}} +} +func (rr *NETLIFYV6) String() string { + return rr.Header().Name + "\t" + + strconv.FormatInt(int64(rr.Header().TTL), 10) + "\t" + + dnsutilv2.ClassToString(rr.Header().Class) + "\tNETLIFYV6" // RDATA is empty. +} + +// Parse makes an RDATA for this type using the tokens from dnsv2's parser. +func (rr *NETLIFYV6) Parse(tokens []string, s string) error { + args := TokensToArgs(tokens) + if len(args) != 0 { + return fmt.Errorf("NETLIFYV6 requires exactly 0 arguments, got %d", len(args)) + } + return nil +} + +// Code generated by "go run types_generate.go"; DO NOT EDIT. diff --git a/pkg/privatetypes/t_netlifyv6_test.go b/pkg/privatetypes/t_netlifyv6_test.go new file mode 100644 index 0000000000..a90c484b56 --- /dev/null +++ b/pkg/privatetypes/t_netlifyv6_test.go @@ -0,0 +1,22 @@ +package privatetypes + +// Code generated by "go run types_generate.go"; DO NOT EDIT. + +import ( + "testing" + + dnsv2 "codeberg.org/miekg/dns" +) + +func TestNetlifyv6(t *testing.T) { + y := &NETLIFYV6{Hdr: dnsv2.Header{Name: "example.org.", Class: dnsv2.ClassINET}} + rry, err := dnsv2.New(y.String()) + if err != nil { + t.Fatal(err) + } + if rry.String() != y.String() { + t.Fatalf("NETLIFYV6 string presentations should be identical:\n%q\n%q", rry.String(), y.String()) + } +} + +// Code generated by "go run types_generate.go"; DO NOT EDIT. diff --git a/pkg/privatetypes/t_porkbun_urlfwd.go b/pkg/privatetypes/t_porkbun_urlfwd.go new file mode 100644 index 0000000000..67feeaff62 --- /dev/null +++ b/pkg/privatetypes/t_porkbun_urlfwd.go @@ -0,0 +1,64 @@ +package privatetypes + +// Code generated by "go run types_generate.go"; DO NOT EDIT. + +import ( + "fmt" + "strconv" + + dnsv2 "codeberg.org/miekg/dns" + dnsutilv2 "codeberg.org/miekg/dns/dnsutil" + "github.com/DNSControl/dnscontrol/v5/pkg/mustbe" + privatetypesrdata "github.com/DNSControl/dnscontrol/v5/pkg/privatetypes/rdata" +) + +// PORKBUN_URLFWD + +func init() { + Register(TypePORKBUNURLFWD, "PORKBUN_URLFWD", func() dnsv2.RR { return new(PORKBUNURLFWD) }, privatetypesrdata.MakePORKBUNURLFWD) +} + +const TypePORKBUNURLFWD = uint16(65297) + +type PORKBUNURLFWD struct { + Hdr dnsv2.Header + + privatetypesrdata.PORKBUNURLFWD + // Location string +} + +// Typer interface. + +func (rr *PORKBUNURLFWD) Type() uint16 { return TypePORKBUNURLFWD } + +// RR interface. + +func (rr *PORKBUNURLFWD) Header() *dnsv2.Header { return &rr.Hdr } +func (rr *PORKBUNURLFWD) Len() int { + return rr.Hdr.Len() + rr.Data().Len() +} +func (rr *PORKBUNURLFWD) Data() dnsv2.RDATA { + return privatetypesrdata.PORKBUNURLFWD{Location: rr.Location} +} +func (rr *PORKBUNURLFWD) Clone() dnsv2.RR { + return &PORKBUNURLFWD{ + Hdr: rr.Hdr, + Location: rr.Location} +} +func (rr *PORKBUNURLFWD) String() string { + return (rr.Header().Name + "\t" + + strconv.FormatInt(int64(rr.Header().TTL), 10) + "\t" + + dnsutilv2.ClassToString(rr.Header().Class) + "\tPORKBUN_URLFWD\t" + rr.Data().String()) +} + +// Parse makes an RDATA for this type using the tokens from dnsv2's parser. +func (rr *PORKBUNURLFWD) Parse(tokens []string, s string) error { + args := TokensToArgs(tokens) + if len(args) != 1 { + return fmt.Errorf("PORKBUN_URLFWD requires exactly 1 arguments, got %d: %v", len(args), args) + } + rr.Location = mustbe.RawString(args[0]) + return nil +} + +// Code generated by "go run types_generate.go"; DO NOT EDIT. diff --git a/pkg/privatetypes/t_porkbun_urlfwd_test.go b/pkg/privatetypes/t_porkbun_urlfwd_test.go new file mode 100644 index 0000000000..7f73befe4f --- /dev/null +++ b/pkg/privatetypes/t_porkbun_urlfwd_test.go @@ -0,0 +1,25 @@ +package privatetypes + +// Code generated by "go run types_generate.go"; DO NOT EDIT. + +import ( + "testing" + + dnsv2 "codeberg.org/miekg/dns" +) + +func TestPorkbunUrlfwd_Plain(t *testing.T) { + y := &PORKBUNURLFWD{ + Hdr: dnsv2.Header{Name: "example.org.", Class: dnsv2.ClassINET}, + Location: "http://example.com", + } + rry, err := dnsv2.New(y.String()) + if err != nil { + t.Fatal(err) + } + if rry.String() != y.String() { + t.Fatalf("PORKBUN_URLFWD string presentations should be identical:\n%s\n%s", rry.String(), y.String()) + } +} + +// Code generated by "go run types_generate.go"; DO NOT EDIT. diff --git a/pkg/privatetypes/t_r53_alias.go b/pkg/privatetypes/t_r53_alias.go new file mode 100644 index 0000000000..00e3d2ba75 --- /dev/null +++ b/pkg/privatetypes/t_r53_alias.go @@ -0,0 +1,78 @@ +package privatetypes + +// Code generated by "go run types_generate.go"; DO NOT EDIT. + +import ( + "fmt" + "strconv" + + dnsv2 "codeberg.org/miekg/dns" + dnsutilv2 "codeberg.org/miekg/dns/dnsutil" + "github.com/DNSControl/dnscontrol/v5/pkg/mustbe" + "github.com/DNSControl/dnscontrol/v5/pkg/nrc" + privatetypesrdata "github.com/DNSControl/dnscontrol/v5/pkg/privatetypes/rdata" +) + +// R53_ALIAS + +func init() { + Register(TypeR53ALIAS, "R53_ALIAS", func() dnsv2.RR { return new(R53ALIAS) }, privatetypesrdata.MakeR53ALIAS) +} + +const TypeR53ALIAS = uint16(65298) + +type R53ALIAS struct { + Hdr dnsv2.Header + + privatetypesrdata.R53ALIAS + // AliasType string + // Target string + // EvalTargetHealth string // Optional + // ZoneID string // Optional +} + +// Typer interface. + +func (rr *R53ALIAS) Type() uint16 { return TypeR53ALIAS } + +// RR interface. + +func (rr *R53ALIAS) Header() *dnsv2.Header { return &rr.Hdr } +func (rr *R53ALIAS) Len() int { + return rr.Hdr.Len() + rr.Data().Len() +} +func (rr *R53ALIAS) Data() dnsv2.RDATA { + return privatetypesrdata.R53ALIAS{AliasType: rr.AliasType, Target: rr.Target, EvalTargetHealth: rr.EvalTargetHealth, ZoneID: rr.ZoneID} +} +func (rr *R53ALIAS) Clone() dnsv2.RR { + return &R53ALIAS{ + Hdr: rr.Hdr, + AliasType: rr.AliasType, + Target: rr.Target, + EvalTargetHealth: rr.EvalTargetHealth, + ZoneID: rr.ZoneID} +} +func (rr *R53ALIAS) String() string { + return (rr.Header().Name + "\t" + + strconv.FormatInt(int64(rr.Header().TTL), 10) + "\t" + + dnsutilv2.ClassToString(rr.Header().Class) + "\tR53_ALIAS\t" + rr.Data().String()) +} + +// Parse makes an RDATA for this type using the tokens from dnsv2's parser. +func (rr *R53ALIAS) Parse(tokens []string, s string) error { + args := TokensToArgs(tokens) + if len(args) != 4 { + return fmt.Errorf("R53_ALIAS requires exactly 4 arguments, got %d: %v", len(args), args) + } + rr.AliasType = mustbe.RawString(args[0]) + targetHost1, err := mustbe.TargetHost("", nrc.Flags{}, args[1]) + if err != nil { + return err + } + rr.Target = targetHost1 + rr.EvalTargetHealth = mustbe.RawString(args[2]) + rr.ZoneID = mustbe.RawString(args[3]) + return nil +} + +// Code generated by "go run types_generate.go"; DO NOT EDIT. diff --git a/pkg/privatetypes/t_r53_alias_test.go b/pkg/privatetypes/t_r53_alias_test.go new file mode 100644 index 0000000000..a5c6d50297 --- /dev/null +++ b/pkg/privatetypes/t_r53_alias_test.go @@ -0,0 +1,28 @@ +package privatetypes + +// Code generated by "go run types_generate.go"; DO NOT EDIT. + +import ( + "testing" + + dnsv2 "codeberg.org/miekg/dns" +) + +func TestR53Alias_NormalUser(t *testing.T) { + y := &R53ALIAS{ + Hdr: dnsv2.Header{Name: "example.org.", Class: dnsv2.ClassINET}, + AliasType: "1", + Target: "alice.", + EvalTargetHealth: "true", + ZoneID: "1234", + } + rry, err := dnsv2.New(y.String()) + if err != nil { + t.Fatal(err) + } + if rry.String() != y.String() { + t.Fatalf("R53_ALIAS string presentations should be identical:\n%s\n%s", rry.String(), y.String()) + } +} + +// Code generated by "go run types_generate.go"; DO NOT EDIT. diff --git a/pkg/privatetypes/t_url.go b/pkg/privatetypes/t_url.go new file mode 100644 index 0000000000..5949c5e756 --- /dev/null +++ b/pkg/privatetypes/t_url.go @@ -0,0 +1,64 @@ +package privatetypes + +// Code generated by "go run types_generate.go"; DO NOT EDIT. + +import ( + "fmt" + "strconv" + + dnsv2 "codeberg.org/miekg/dns" + dnsutilv2 "codeberg.org/miekg/dns/dnsutil" + "github.com/DNSControl/dnscontrol/v5/pkg/mustbe" + privatetypesrdata "github.com/DNSControl/dnscontrol/v5/pkg/privatetypes/rdata" +) + +// URL + +func init() { + Register(TypeURL, "URL", func() dnsv2.RR { return new(URL) }, privatetypesrdata.MakeURL) +} + +const TypeURL = uint16(65299) + +type URL struct { + Hdr dnsv2.Header + + privatetypesrdata.URL + // Location string +} + +// Typer interface. + +func (rr *URL) Type() uint16 { return TypeURL } + +// RR interface. + +func (rr *URL) Header() *dnsv2.Header { return &rr.Hdr } +func (rr *URL) Len() int { + return rr.Hdr.Len() + rr.Data().Len() +} +func (rr *URL) Data() dnsv2.RDATA { + return privatetypesrdata.URL{Location: rr.Location} +} +func (rr *URL) Clone() dnsv2.RR { + return &URL{ + Hdr: rr.Hdr, + Location: rr.Location} +} +func (rr *URL) String() string { + return (rr.Header().Name + "\t" + + strconv.FormatInt(int64(rr.Header().TTL), 10) + "\t" + + dnsutilv2.ClassToString(rr.Header().Class) + "\tURL\t" + rr.Data().String()) +} + +// Parse makes an RDATA for this type using the tokens from dnsv2's parser. +func (rr *URL) Parse(tokens []string, s string) error { + args := TokensToArgs(tokens) + if len(args) != 1 { + return fmt.Errorf("URL requires exactly 1 arguments, got %d: %v", len(args), args) + } + rr.Location = mustbe.RawString(args[0]) + return nil +} + +// Code generated by "go run types_generate.go"; DO NOT EDIT. diff --git a/pkg/privatetypes/t_url301.go b/pkg/privatetypes/t_url301.go new file mode 100644 index 0000000000..e24cf7d4cc --- /dev/null +++ b/pkg/privatetypes/t_url301.go @@ -0,0 +1,64 @@ +package privatetypes + +// Code generated by "go run types_generate.go"; DO NOT EDIT. + +import ( + "fmt" + "strconv" + + dnsv2 "codeberg.org/miekg/dns" + dnsutilv2 "codeberg.org/miekg/dns/dnsutil" + "github.com/DNSControl/dnscontrol/v5/pkg/mustbe" + privatetypesrdata "github.com/DNSControl/dnscontrol/v5/pkg/privatetypes/rdata" +) + +// URL301 + +func init() { + Register(TypeURL301, "URL301", func() dnsv2.RR { return new(URL301) }, privatetypesrdata.MakeURL301) +} + +const TypeURL301 = uint16(65300) + +type URL301 struct { + Hdr dnsv2.Header + + privatetypesrdata.URL301 + // Location string +} + +// Typer interface. + +func (rr *URL301) Type() uint16 { return TypeURL301 } + +// RR interface. + +func (rr *URL301) Header() *dnsv2.Header { return &rr.Hdr } +func (rr *URL301) Len() int { + return rr.Hdr.Len() + rr.Data().Len() +} +func (rr *URL301) Data() dnsv2.RDATA { + return privatetypesrdata.URL301{Location: rr.Location} +} +func (rr *URL301) Clone() dnsv2.RR { + return &URL301{ + Hdr: rr.Hdr, + Location: rr.Location} +} +func (rr *URL301) String() string { + return (rr.Header().Name + "\t" + + strconv.FormatInt(int64(rr.Header().TTL), 10) + "\t" + + dnsutilv2.ClassToString(rr.Header().Class) + "\tURL301\t" + rr.Data().String()) +} + +// Parse makes an RDATA for this type using the tokens from dnsv2's parser. +func (rr *URL301) Parse(tokens []string, s string) error { + args := TokensToArgs(tokens) + if len(args) != 1 { + return fmt.Errorf("URL301 requires exactly 1 arguments, got %d: %v", len(args), args) + } + rr.Location = mustbe.RawString(args[0]) + return nil +} + +// Code generated by "go run types_generate.go"; DO NOT EDIT. diff --git a/pkg/privatetypes/t_url301_test.go b/pkg/privatetypes/t_url301_test.go new file mode 100644 index 0000000000..b6949546c4 --- /dev/null +++ b/pkg/privatetypes/t_url301_test.go @@ -0,0 +1,25 @@ +package privatetypes + +// Code generated by "go run types_generate.go"; DO NOT EDIT. + +import ( + "testing" + + dnsv2 "codeberg.org/miekg/dns" +) + +func TestUrl301(t *testing.T) { + y := &URL301{ + Hdr: dnsv2.Header{Name: "example.org.", Class: dnsv2.ClassINET}, + Location: "https://example.com/", + } + rry, err := dnsv2.New(y.String()) + if err != nil { + t.Fatal(err) + } + if rry.String() != y.String() { + t.Fatalf("URL301 string presentations should be identical:\n%s\n%s", rry.String(), y.String()) + } +} + +// Code generated by "go run types_generate.go"; DO NOT EDIT. diff --git a/pkg/privatetypes/t_url_test.go b/pkg/privatetypes/t_url_test.go new file mode 100644 index 0000000000..0cfe6f0ec8 --- /dev/null +++ b/pkg/privatetypes/t_url_test.go @@ -0,0 +1,25 @@ +package privatetypes + +// Code generated by "go run types_generate.go"; DO NOT EDIT. + +import ( + "testing" + + dnsv2 "codeberg.org/miekg/dns" +) + +func TestUrl(t *testing.T) { + y := &URL{ + Hdr: dnsv2.Header{Name: "example.org.", Class: dnsv2.ClassINET}, + Location: "https://example.com/", + } + rry, err := dnsv2.New(y.String()) + if err != nil { + t.Fatal(err) + } + if rry.String() != y.String() { + t.Fatalf("URL string presentations should be identical:\n%s\n%s", rry.String(), y.String()) + } +} + +// Code generated by "go run types_generate.go"; DO NOT EDIT. diff --git a/pkg/privatetypes/tokens.go b/pkg/privatetypes/tokens.go new file mode 100644 index 0000000000..9a957d358c --- /dev/null +++ b/pkg/privatetypes/tokens.go @@ -0,0 +1,20 @@ +package privatetypes + +// TokensToArgs copies tokens. If a token is a quote ("\""), it is followed by the string to be copied followed by another quote. The quote is skipped. +func TokensToArgs(tokens []string) []string { + // Null string + if len(tokens) == 2 && tokens[0] == `"` && tokens[1] == `"` { + return []string{""} + } + + var args []string + for i := 0; i < len(tokens); i++ { + if ((i + 2) < len(tokens)) && tokens[i] == "\"" && tokens[i+2] == "\"" { + args = append(args, tokens[i+1]) + i += 2 + } else { + args = append(args, tokens[i]) + } + } + return args +} diff --git a/pkg/privatetypes/tokens_test.go b/pkg/privatetypes/tokens_test.go new file mode 100644 index 0000000000..19ee2d21f3 --- /dev/null +++ b/pkg/privatetypes/tokens_test.go @@ -0,0 +1,64 @@ +package privatetypes + +import ( + "reflect" + "testing" +) + +func TestTokensToArgs(t *testing.T) { + tests := []struct { + name string + input []string + expected []string + }{ + { + name: "single token", + input: []string{"one"}, + expected: []string{"one"}, + }, + { + name: "two tokens", + input: []string{"one", "two"}, + expected: []string{"one", "two"}, + }, + { + name: "three tokens", + input: []string{"one", "two", "three"}, + expected: []string{"one", "two", "three"}, + }, + { + name: "quoted string", + input: []string{"\"", "one", "\""}, + expected: []string{"one"}, + }, + { + name: "quoted string with following token", + input: []string{"\"", "one", "\"", "two"}, + expected: []string{"one", "two"}, + }, + { + name: "token before quoted string", + input: []string{"one", "\"", "two", "\""}, + expected: []string{"one", "two"}, + }, + { + name: "incomplete quoted string at end", + input: []string{"one", "\"", "two"}, + expected: []string{"one", "\"", "two"}, + }, + { + name: "lone quote at end", + input: []string{"one", "\""}, + expected: []string{"one", "\""}, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + got := TokensToArgs(tt.input) + if !reflect.DeepEqual(got, tt.expected) { + t.Errorf("TokensToArgs(%v) = %v, want %v", tt.input, got, tt.expected) + } + }) + } +} diff --git a/pkg/privatetypes/types_generate.go b/pkg/privatetypes/types_generate.go new file mode 100644 index 0000000000..b33e0286e4 --- /dev/null +++ b/pkg/privatetypes/types_generate.go @@ -0,0 +1,672 @@ +//go:build ignore + +package main + +import ( + "bytes" + "fmt" + "go/format" + "log" + "os" + "path/filepath" + "slices" + "strings" + + "gopkg.in/yaml.v3" +) + +// TypeDef represents a single type definition from the YAML +type TypeDef struct { + Name string `yaml:"name"` + Codepoint int `yaml:"codepoint"` + Fields []FieldDef `yaml:"fields"` + OptionalFields []FieldDef `yaml:"optionalFields"` + RuntimeFields []FieldDef `yaml:"runtimeFields"` + TestData []TestDataDef `yaml:"test_data"` +} + +// TYPENAME(ops) .String() TestTYPENAME() +// Fields YES YES YES +// OptionalFields no YES YES +// RuntimeFields YES no no + +// FieldDef represents a field within a type +type FieldDef struct { + Name string `yaml:"name"` + Type string `yaml:"type"` + STag string `yaml:"structag"` + Comment string `yaml:"comment"` +} + +// TestDataDef represents test data for a type +type TestDataDef struct { + Name string `yaml:"name"` + Values map[string]any `yaml:"values"` +} + +// Config represents the YAML file structure +type Config struct { + Types []TypeDef `yaml:"types"` +} + +// TypeInfo describes how a mustbe type maps to Go code. +type TypeInfo struct { + GoType string // Go type of the struct field + NeedsOrigin bool // mustbe call needs an origin string as first arg + NeedsNetip bool // requires "net/netip" import + IsString bool // field is a Go string (affects len/string formatting) +} + +var typeInfo = map[string]TypeInfo{ + "RawString": {GoType: "string", IsString: true}, + "ToUpperRawString": {GoType: "string", IsString: true}, + "TargetHost": {GoType: "string", IsString: true, NeedsOrigin: true}, + "BoolString": {GoType: "string", IsString: true}, + "Bool": {GoType: "bool"}, + "Uint8": {GoType: "uint8"}, + "Uint16": {GoType: "uint16"}, + "Uint32": {GoType: "uint32"}, + "Uint64": {GoType: "uint64"}, + "Int64": {GoType: "int64"}, + "IPv4": {GoType: "netip.Addr", NeedsNetip: true}, + "IPv6": {GoType: "netip.Addr", NeedsNetip: true}, +} + +func info(typeName string) TypeInfo { + ti, ok := typeInfo[typeName] + if !ok { + log.Fatalf("unknown mustbe type %q", typeName) + } + return ti +} + +// writeImports writes a properly grouped import block: standard-library imports +// first, then a blank line, then third-party imports. gofmt (applied by +// writeGoFile) sorts alphabetically within each group. Each entry is a full +// import spec, e.g. `"fmt"` or `dnsv2 "codeberg.org/miekg/dns"`. +func writeImports(buf *bytes.Buffer, std, third []string) { + buf.WriteString("import (\n") + for _, s := range std { + fmt.Fprintf(buf, "\t%s\n", s) + } + if len(std) > 0 && len(third) > 0 { + buf.WriteString("\n") + } + for _, s := range third { + fmt.Fprintf(buf, "\t%s\n", s) + } + buf.WriteString(")\n\n") +} + +// writeGoFile runs the generated source through gofmt (go/format) and writes it +// to path. This makes the output compliant with Go formatting standards — +// struct/field alignment, struct-literal colon alignment, import sorting within +// groups — so a separate `goimports`/`gofmt` pass is not needed. If formatting +// fails, the unformatted source is written to aid debugging and an error is +// returned. +func writeGoFile(path string, src []byte) error { + formatted, err := format.Source(src) + if err != nil { + _ = os.WriteFile(path, src, 0o644) + return fmt.Errorf("gofmt %s: %w", path, err) + } + return os.WriteFile(path, formatted, 0o644) +} + +func anyNeedsNetip(fields []FieldDef) bool { + for _, f := range fields { + if info(f.Type).NeedsNetip { + return true + } + } + return false +} + +func anyNonString(fields []FieldDef) bool { + for _, f := range fields { + if !info(f.Type).IsString { + return true + } + } + return false +} + +// needsNrc returns true if any field requires nrc functions. +func needsNrc(fields []FieldDef) bool { + for _, f := range fields { + if f.Type == "TargetHost" { + return true + } + } + return false +} + +// needsTxtutil returns true if any field requires txtutil functions. +func needsTxtutil(fields []FieldDef) bool { + for _, f := range fields { + if f.Type == "RawString" || f.Type == "ToUpperRawString" { + return true + } + } + return false +} + +// fieldStringExpr returns a Go expression that converts the named field to a string for printing. +func fieldStringExpr(receiver string, f FieldDef) string { + ti := info(f.Type) + switch { + case ti.IsString: + return fmt.Sprintf("%s.%s", receiver, f.Name) + case ti.NeedsNetip: + return fmt.Sprintf("%s.%s.String()", receiver, f.Name) + case ti.GoType == "bool": + return fmt.Sprintf("fmt.Sprintf(\"%%t\", %s.%s)", receiver, f.Name) + default: // numeric + return fmt.Sprintf("fmt.Sprintf(\"%%d\", %s.%s)", receiver, f.Name) + } +} + +// formatLiteral renders a test-data value as a Go literal appropriate for the field type. +func formatLiteral(typeName string, v any) string { + ti := info(typeName) + s := fmt.Sprintf("%v", v) + switch { + case ti.IsString: + return fmt.Sprintf("%q", s) + case ti.NeedsNetip: + return fmt.Sprintf("netip.MustParseAddr(%q)", s) + default: + return s // bool / numeric literal + } +} + +// zeroLiteral renders the zero value of the field type as a Go literal. +func zeroLiteral(typeName string) string { + ti := info(typeName) + switch { + case ti.IsString: + return `""` + case ti.NeedsNetip: + return "netip.Addr{}" + case ti.GoType == "bool": + return "false" + default: + return "0" + } +} + +func main() { + yamlFile, err := os.ReadFile("types_generate.yaml") + if err != nil { + log.Fatalf("Failed to read types_generate.yaml: %v", err) + } + + var config Config + err = yaml.Unmarshal(yamlFile, &config) + if err != nil { + log.Fatalf("Failed to parse YAML: %v", err) + } + + for _, t := range config.Types { + if err := generateTypeFile(&t); err != nil { + log.Fatalf("Failed to generate type file for %s: %v", t.Name, err) + } + if err := generateTestFile(&t); err != nil { + log.Fatalf("Failed to generate test file for %s: %v", t.Name, err) + } + if err := generateRdataFile(&t); err != nil { + log.Fatalf("Failed to generate rdata file for %s: %v", t.Name, err) + } + } + + fmt.Println("Generator pkg/privatetypes/types_generate.go complete!") +} + +func toConstName(name string) string { + s := strings.ToUpper(name) + return strings.ReplaceAll(s, "_", "") +} + +func toTypeName(name string) string { + return toConstName(name) +} + +func toFileName(name string) string { + return strings.ToLower(name) +} + +func camelCaseFromSnake(s string) string { + s = strings.ReplaceAll(s, " ", "_") + parts := strings.Split(s, "_") + var result []string + for _, part := range parts { + if len(part) > 0 { + result = append(result, strings.ToUpper(part[:1])+strings.ToLower(part[1:])) + } + } + return strings.Join(result, "") +} + +func toDisplayName(name string) string { + // if strings.HasPrefix(name, "Cf_Worker_Route") { + // fmt.Printf("DEBUG: toDisplayName name=%q out=%q\n", name, strings.ToUpper(name)) + // } + return strings.ToUpper(name) +} + +func generateTypeFile(t *TypeDef) error { + constName := toConstName(t.Name) + typeName := toTypeName(t.Name) + fileName := toFileName(t.Name) + displayName := toDisplayName(t.Name) + + var buf bytes.Buffer + + buf.WriteString("package privatetypes\n\n") + buf.WriteString("\n// Code generated by \"go run types_generate.go\"; DO NOT EDIT.\n\n") + std := []string{`"fmt"`, `"strconv"`} + if anyNeedsNetip(t.Fields) || anyNeedsNetip(t.OptionalFields) || anyNeedsNetip(t.RuntimeFields) { + std = append(std, `"net/netip"`) + } + third := []string{ + `dnsv2 "codeberg.org/miekg/dns"`, + `dnsutilv2 "codeberg.org/miekg/dns/dnsutil"`, + } + if len(t.Fields) > 0 || len(t.OptionalFields) > 0 { + third = append(third, `"github.com/DNSControl/dnscontrol/v5/pkg/mustbe"`) + } + if needsNrc(t.Fields) || needsNrc(t.OptionalFields) || needsNrc(t.RuntimeFields) { + third = append(third, `"github.com/DNSControl/dnscontrol/v5/pkg/nrc"`) + } + third = append(third, `privatetypesrdata "github.com/DNSControl/dnscontrol/v5/pkg/privatetypes/rdata"`) + writeImports(&buf, std, third) + + fmt.Fprintf(&buf, "// %s\n\n", displayName) + + fmt.Fprintf(&buf, "func init() {\n") + fmt.Fprintf(&buf, "\tRegister(Type%s, \"%s\", func() dnsv2.RR { return new(%s) }, privatetypesrdata.Make%s)\n", + constName, displayName, typeName, typeName) + fmt.Fprintf(&buf, "}\n\n") + + fmt.Fprintf(&buf, "const Type%s = uint16(%d)\n\n", constName, t.Codepoint) + + fmt.Fprintf(&buf, "type %s struct {\n", typeName) + buf.WriteString("\tHdr dnsv2.Header\n\n") + fmt.Fprintf(&buf, "\tprivatetypesrdata.%s\n", typeName) + + //if len(t.Fields) > 0 || len(t.RuntimeFields) > 0 || len(t.OptionalFields) > 0 { + // for _, f := range append(t.Fields, t.OptionalFields, t.RuntimeFields...) { + // fmt.Fprintf(&buf, "\t// %-20s %s\n", f.Name, info(f.Type).GoType) + // } + //} + for _, f := range t.Fields { + fmt.Fprintf(&buf, "\t// %-20s %s\n", f.Name, info(f.Type).GoType) + } + for _, f := range t.OptionalFields { + fmt.Fprintf(&buf, "\t// %-20s %s\t// Optional\n", f.Name, info(f.Type).GoType) + } + for _, f := range t.RuntimeFields { + fmt.Fprintf(&buf, "\t// %-20s %s\t// Runtime\n", f.Name, info(f.Type).GoType) + } + + buf.WriteString("}\n\n") + + buf.WriteString("// Typer interface.\n\n") + fmt.Fprintf(&buf, "func (rr *%s) Type() uint16 { return Type%s }\n\n", typeName, constName) + + buf.WriteString("// RR interface.\n\n") + fmt.Fprintf(&buf, "func (rr *%s) Header() *dnsv2.Header { return &rr.Hdr }\n", typeName) + + fmt.Fprintf(&buf, "func (rr *%s) Len() int {\n", typeName) + if len(t.Fields) == 0 && len(t.OptionalFields) == 0 { + buf.WriteString("\treturn rr.Hdr.Len()\n") + } else { + buf.WriteString("\treturn rr.Hdr.Len() + rr.Data().Len()\n") + } + // NB(tlim): t.RuntimeFields are not included in the Len() calculation. This could change. + buf.WriteString("}\n") + + fmt.Fprintf(&buf, "func (rr *%s) Data() dnsv2.RDATA {\n", typeName) + if len(t.Fields) == 0 && len(t.OptionalFields) == 0 && len(t.RuntimeFields) == 0 { + fmt.Fprintf(&buf, "\treturn nil\n") + } else { + fmt.Fprintf(&buf, "\treturn privatetypesrdata.%s{", typeName) + fields := slices.Concat(t.Fields, t.OptionalFields, t.RuntimeFields) + for i, f := range fields { + if i > 0 { + buf.WriteString(", ") + } + fmt.Fprintf(&buf, "%s: rr.%s", f.Name, f.Name) + } + buf.WriteString("}\n") + } + buf.WriteString("}\n") + + fmt.Fprintf(&buf, "func (rr *%s) Clone() dnsv2.RR {\n", typeName) + if len(t.Fields) == 0 && len(t.OptionalFields) == 0 && len(t.RuntimeFields) == 0 { + fmt.Fprintf(&buf, "\treturn &%s{\n", typeName) + buf.WriteString("\t\trr.Hdr,\n") + fmt.Fprintf(&buf, "\t\tprivatetypesrdata.%s{}}\n", typeName) + } else { + fmt.Fprintf(&buf, "\treturn &%s{\n", typeName) + buf.WriteString("\t\tHdr: rr.Hdr,\n") + fields := slices.Concat(t.Fields, t.OptionalFields, t.RuntimeFields) + for i, f := range fields { + if i == len(fields)-1 { + fmt.Fprintf(&buf, "\t\t%s: rr.%s}\n", f.Name, f.Name) + } else { + fmt.Fprintf(&buf, "\t\t%s: rr.%s,\n", f.Name, f.Name) + } + } + } + buf.WriteString("}\n") + + fmt.Fprintf(&buf, "func (rr *%s) String() string {\n", typeName) + if len(t.Fields) == 0 && len(t.OptionalFields) == 0 { + fmt.Fprintf(&buf, "\treturn rr.Header().Name + \"\\t\" +\n") + buf.WriteString("\t\tstrconv.FormatInt(int64(rr.Header().TTL), 10) + \"\\t\" +\n") + fmt.Fprintf(&buf, "\t\tdnsutilv2.ClassToString(rr.Header().Class) + \"\\t%s\" // RDATA is empty.\n", displayName) + } else { + fmt.Fprintf(&buf, "\treturn (rr.Header().Name + \"\\t\" +\n") + buf.WriteString("\t\tstrconv.FormatInt(int64(rr.Header().TTL), 10) + \"\\t\" +\n") + fmt.Fprintf(&buf, "\t\tdnsutilv2.ClassToString(rr.Header().Class) + \"\\t%s\\t\" + rr.Data().String())\n", displayName) + } + buf.WriteString("}\n\n") + + fmt.Fprintf(&buf, "// Parse makes an RDATA for this type using the tokens from dnsv2's parser.\n") + fmt.Fprintf(&buf, "func (rr *%s) Parse(tokens []string, s string) error {\n", typeName) + buf.WriteString("\targs := TokensToArgs(tokens)\n") + + fc := len(t.Fields) + len(t.OptionalFields) + if fc == 0 { + fmt.Fprintf(&buf, "\tif len(args) != 0 {\n") + fmt.Fprintf(&buf, "\t\treturn fmt.Errorf(\"%s requires exactly 0 arguments, got %%d\", len(args))\n", displayName) + } else { + fmt.Fprintf(&buf, "\tif len(args) != %d {\n", fc) + fmt.Fprintf(&buf, "\t\treturn fmt.Errorf(\"%s requires exactly %d arguments, got %%d: %%v\", len(args), args)\n", displayName, fc) + } + + buf.WriteString("\t}\n") + + for i, f := range t.Fields { + ti := info(f.Type) + if ti.NeedsOrigin { + fmt.Fprintf(&buf, "\ttargetHost%d, err := mustbe.%s(\"\", nrc.Flags{}, args[%d])\n", i, f.Type, i) + buf.WriteString("\tif err != nil {\n\t\treturn err\n\t}\n") + fmt.Fprintf(&buf, "\trr.%s = targetHost%d\n", f.Name, i) + } else { + fmt.Fprintf(&buf, "\trr.%s = mustbe.%s(args[%d])\n", f.Name, f.Type, i) + } + } + for i, f := range t.OptionalFields { + ti := info(f.Type) + argIndex := len(t.Fields) + i + if ti.NeedsOrigin { + fmt.Fprintf(&buf, "\ttargetHost%d, err := mustbe.%s(\"\", nrc.Flags{}, args[%d])\n", argIndex, f.Type, argIndex) + buf.WriteString("\tif err != nil {\n\t\treturn err\n\t}\n") + fmt.Fprintf(&buf, "\trr.%s = targetHost%d\n", f.Name, argIndex) + } else { + fmt.Fprintf(&buf, "\trr.%s = mustbe.%s(args[%d])\n", f.Name, f.Type, argIndex) + } + } + + buf.WriteString("\treturn nil\n") + buf.WriteString("}\n") + + buf.WriteString("\n// Code generated by \"go run types_generate.go\"; DO NOT EDIT.\n\n") + + return writeGoFile(fmt.Sprintf("t_%s.go", fileName), buf.Bytes()) +} + +func generateTestFile(t *TypeDef) error { + fileName := toFileName(t.Name) + typeName := toTypeName(t.Name) + displayName := toDisplayName(t.Name) + testFuncName := camelCaseFromSnake(t.Name) + + var buf bytes.Buffer + + buf.WriteString("package privatetypes\n\n") + buf.WriteString("\n// Code generated by \"go run types_generate.go\"; DO NOT EDIT.\n\n") + std := []string{`"testing"`} + if anyNeedsNetip(t.Fields) { + std = append(std, `"net/netip"`) + } + third := []string{`dnsv2 "codeberg.org/miekg/dns"`} + writeImports(&buf, std, third) + + if len(t.Fields) == 0 { + fmt.Fprintf(&buf, "func Test%s(t *testing.T) {\n", testFuncName) + fmt.Fprintf(&buf, "\ty := &%s{Hdr: dnsv2.Header{Name: \"example.org.\", Class: dnsv2.ClassINET}}\n", typeName) + buf.WriteString("\trry, err := dnsv2.New(y.String())\n") + buf.WriteString("\tif err != nil {\n") + buf.WriteString("\t\tt.Fatal(err)\n") + buf.WriteString("\t}\n") + buf.WriteString("\tif rry.String() != y.String() {\n") + fmt.Fprintf(&buf, "\t\tt.Fatalf(\"%s string presentations should be identical:\\n%%q\\n%%q\", rry.String(), y.String())\n", displayName) + buf.WriteString("\t}\n") + buf.WriteString("}\n") + } else { + if len(t.TestData) == 0 { + fmt.Fprintf(&buf, "func Test%s(t *testing.T) {\n", testFuncName) + fmt.Fprintf(&buf, "\ty := &%s{\n", typeName) + buf.WriteString("\t\tHdr: dnsv2.Header{Name: \"example.org.\", Class: dnsv2.ClassINET},\n") + for _, f := range slices.Concat(t.Fields, t.OptionalFields) { + fmt.Fprintf(&buf, "\t\t%s: %s,\n", f.Name, zeroLiteral(f.Type)) + } + buf.WriteString("\t}\n") + buf.WriteString("\trry, err := dnsv2.New(y.String())\n") + buf.WriteString("\tif err != nil {\n") + buf.WriteString("\t\tt.Fatal(err)\n") + buf.WriteString("\t}\n") + buf.WriteString("\tif rry.String() != y.String() {\n") + fmt.Fprintf(&buf, "\t\tt.Fatalf(\"%s string presentations should be identical:\\n%%s\\n%%s\", rry.String(), y.String())\n", displayName) + buf.WriteString("\t}\n") + buf.WriteString("}\n") + } else { + for _, td := range t.TestData { + testName := testFuncName + if td.Name != "" { + testName = testFuncName + "_" + camelCaseFromSnake(td.Name) + } + + fmt.Fprintf(&buf, "func Test%s(t *testing.T) {\n", testName) + fmt.Fprintf(&buf, "\ty := &%s{\n", typeName) + buf.WriteString("\t\tHdr: dnsv2.Header{Name: \"example.org.\", Class: dnsv2.ClassINET},\n") + + for _, f := range slices.Concat(t.Fields, t.OptionalFields) { + var lit string + if v, ok := td.Values[f.Name]; ok { + lit = formatLiteral(f.Type, v) + } else { + lit = zeroLiteral(f.Type) + } + fmt.Fprintf(&buf, "\t\t%s: %s,\n", f.Name, lit) + } + + buf.WriteString("\t}\n") + buf.WriteString("\trry, err := dnsv2.New(y.String())\n") + buf.WriteString("\tif err != nil {\n") + buf.WriteString("\t\tt.Fatal(err)\n") + buf.WriteString("\t}\n") + buf.WriteString("\tif rry.String() != y.String() {\n") + fmt.Fprintf(&buf, "\t\tt.Fatalf(\"%s string presentations should be identical:\\n%%s\\n%%s\", rry.String(), y.String())\n", displayName) + buf.WriteString("\t}\n") + buf.WriteString("}\n") + if len(t.TestData) > 1 { + buf.WriteString("\n") + } + } + } + } + + buf.WriteString("\n// Code generated by \"go run types_generate.go\"; DO NOT EDIT.\n\n") + + return writeGoFile(fmt.Sprintf("t_%s_test.go", fileName), buf.Bytes()) +} + +func generateRdataFile(t *TypeDef) error { + fileName := toFileName(t.Name) + typeName := toTypeName(t.Name) + displayName := toDisplayName(t.Name) + + var buf bytes.Buffer + + buf.WriteString("package privatetypesrdata\n\n") + buf.WriteString("\n// Code generated by \"go run types_generate.go\"; DO NOT EDIT.\n\n") + std := []string{`"fmt"`} + if anyNeedsNetip(t.Fields) || anyNeedsNetip(t.OptionalFields) || anyNeedsNetip(t.RuntimeFields) { + std = append(std, `"net/netip"`) + } + if len(t.Fields) > 0 || len(t.OptionalFields) > 0 || len(t.RuntimeFields) > 0 { + std = append(std, `"strings"`) + } + third := []string{ + `dnsv2 "codeberg.org/miekg/dns"`, + `"github.com/DNSControl/dnscontrol/v5/pkg/mustbe"`, + } + // if needsNrc(t.Fields) || needsNrc(t.RuntimeFields) { + third = append(third, `"github.com/DNSControl/dnscontrol/v5/pkg/nrc"`) + // } + if needsTxtutil(t.Fields) || needsTxtutil(t.OptionalFields) || needsTxtutil(t.RuntimeFields) { + third = append(third, `"github.com/DNSControl/dnscontrol/v5/pkg/txtutil"`) + } + writeImports(&buf, std, third) + + // Silence unused-import warnings when no field needs them. + _ = anyNonString + + fmt.Fprintf(&buf, "type %s struct {\n", typeName) + for _, f := range t.Fields { + fmt.Fprintf(&buf, "\t%-20s %s\n", f.Name, info(f.Type).GoType) + } + for _, f := range t.OptionalFields { + fmt.Fprintf(&buf, "\t%-20s %s\n", f.Name, info(f.Type).GoType) + } + for _, f := range t.RuntimeFields { + fmt.Fprintf(&buf, "\t%-20s %s\n", f.Name, info(f.Type).GoType) + } + buf.WriteString("}\n\n") + + // Len: bytes of the textual representation. + fmt.Fprintf(&buf, "func (rd %s) Len() int {\n", typeName) + if len(t.Fields) == 0 { + buf.WriteString("\treturn 0\n") + } else { + buf.WriteString("\treturn len(rd.String())\n") + } + buf.WriteString("}\n\n") + + // String: build a zonefile-compatble (space-separated) textual representation of the fields. + fmt.Fprintf(&buf, "func (rd %s) String() string {\n", typeName) + if len(t.Fields) == 0 && len(t.OptionalFields) == 0 { + buf.WriteString("\treturn \"\"\n") + } else { + fmt.Fprintf(&buf, "\tparts := make([]string, 0, %d)\n", len(t.Fields)+len(t.OptionalFields)) + for _, f := range append(t.Fields, t.OptionalFields...) { + // Special-case behaviors requested by generator requirements. + switch f.Type { + case "RawString", "ToUpperRawString": + fmt.Fprintf(&buf, "\tparts = append(parts, txtutil.ZoneifyString(rd.%s))\n", f.Name) + case "TargetHost": + fmt.Fprintf(&buf, "\tparts = append(parts, rd.%s)\n", f.Name) + default: + ti := info(f.Type) + if ti.NeedsNetip { + fmt.Fprintf(&buf, "\tparts = append(parts, rd.%s.String())\n", f.Name) + } else if ti.GoType == "bool" { + fmt.Fprintf(&buf, "\tparts = append(parts, fmt.Sprintf(\"%%t\", rd.%s))\n", f.Name) + } else if !ti.IsString { + // numeric types: Uint8/16/32 -> decimal + fmt.Fprintf(&buf, "\tparts = append(parts, fmt.Sprintf(\"%%d\", rd.%s))\n", f.Name) + } else { + // other string-like types + fmt.Fprintf(&buf, "\tparts = append(parts, rd.%s)\n", f.Name) + } + } + } + buf.WriteString("\treturn strings.Join(parts, \" \")\n") + } + buf.WriteString("}\n\n") + + // Make: validate arg count, then build the rdata using mustbe.X conversions. + isEnabledName := "isEnabled" + if !(needsNrc(t.Fields) || needsNrc(t.OptionalFields) || needsNrc(t.RuntimeFields)) { + isEnabledName = "_" + } + fmt.Fprintf(&buf, "func Make%s(origin string, _ map[string]string, %s nrc.Flags, args ...any) (dnsv2.RDATA, error) {\n", typeName, isEnabledName) + buf.WriteString("\tmustbe.ValidArgs(args)\n") + + minArgs := len(t.Fields) + maxArgs := minArgs + len(t.OptionalFields) + if len(t.Fields) == 0 && len(t.OptionalFields) == 0 { + fmt.Fprintf(&buf, "\tif len(args) != 0 {\n") + fmt.Fprintf(&buf, "\t\treturn nil, fmt.Errorf(\"%s expects 0 arguments, got %%d: %%+v\", len(args), args)\n", displayName) + } else { + if len(t.OptionalFields) == 0 { + fmt.Fprintf(&buf, "\tif len(args) != %d {\n", minArgs) + } else { + fmt.Fprintf(&buf, "\tif len(args) < %d || len(args) > %d {\n", minArgs, maxArgs) + } + fmt.Fprintf(&buf, "\t\treturn nil, fmt.Errorf(\"%s expects %d arguments, got %%d: %%+v\", len(args), args)\n", displayName, (len(t.Fields) + len(t.OptionalFields))) + } + + buf.WriteString("\t}\n") + if minArgs < maxArgs { + fmt.Fprintf(&buf, "\tfor len(args) < %d {\n", maxArgs) + fmt.Fprint(&buf, "\t\targs = append(args, \"\")\n") + fmt.Fprint(&buf, "\t}\n") + } + + if len(t.Fields) == 0 { + fmt.Fprintf(&buf, "\treturn %s{}, nil\n", typeName) + } else { + if needsNrc(t.Fields) || needsNrc(t.OptionalFields) || needsNrc(t.RuntimeFields) { + fmt.Fprint(&buf, "\tif isEnabled.TargetIsFqdnNoDot {\n\t\torigin = \".\"\n\t}\n") + } + for i, f := range append(t.Fields, t.OptionalFields...) { + if info(f.Type).NeedsOrigin { + fmt.Fprintf(&buf, "\ttargetHost%d, err := mustbe.%s(origin, isEnabled, args[%d])\n", i, f.Type, i) + buf.WriteString("\tif err != nil {\n\t\treturn nil, err\n\t}\n") + } + } + fmt.Fprintf(&buf, "\treturn %s{\n", typeName) + for i, f := range append(t.Fields, t.OptionalFields...) { + ti := info(f.Type) + if ti.NeedsOrigin { + fmt.Fprintf(&buf, "\t\t%s: targetHost%d,\n", f.Name, i) + } else { + fmt.Fprintf(&buf, "\t\t%s: mustbe.%s(args[%d]),\n", f.Name, f.Type, i) + } + } + buf.WriteString("\t}, nil\n") + } + + buf.WriteString("}\n") + + // "origin" is unused when there are no TargetHost fields. + if len(t.Fields) > 0 || len(t.OptionalFields) > 0 { + needsOrigin := false + for _, f := range slices.Concat(t.Fields, t.OptionalFields) { + if info(f.Type).NeedsOrigin { + needsOrigin = true + break + } + } + if !needsOrigin { + // Rewrite the receiver to use _ instead of origin to avoid unused-var warnings. + out := bytes.Replace(buf.Bytes(), + fmt.Appendf(nil, "func Make%s(origin string, isEnabled, args ...any)", typeName), + fmt.Appendf(nil, "func Make%s(_ string, isEnabled, args ...any)", typeName), + 1) + buf.Reset() + buf.Write(out) + } + } + + buf.WriteString("\n// Code generated by \"go run types_generate.go\"; DO NOT EDIT.\n\n") + + os.MkdirAll("rdata", 0o755) + + return writeGoFile(filepath.Join("rdata", fmt.Sprintf("rdata_%s.go", fileName)), buf.Bytes()) +} diff --git a/pkg/privatetypes/types_generate.yaml b/pkg/privatetypes/types_generate.yaml new file mode 100644 index 0000000000..0d1d85ec59 --- /dev/null +++ b/pkg/privatetypes/types_generate.yaml @@ -0,0 +1,273 @@ +--- +# 65280 to 65534 +types: + - name: Adguardhome_A_Passthrough + codepoint: 65280 + fields: + - name: Target + type: RawString + test_data: + - name: "" + values: + Target: "" + + - name: Adguardhome_AAAA_Passthrough + codepoint: 65281 + fields: + - name: Target + type: RawString + test_data: + - name: "" + values: + Target: "" + + - name: Akamaicdn + codepoint: 65282 + fields: + - name: Target + type: TargetHost + test_data: + - name: "" + values: + Target: example.com. + + - name: Akamaitlc + codepoint: 65284 + fields: + - name: AnswerType + type: RawString + - name: Target + type: TargetHost + test_data: + - name: "" + values: + AnswerType: cname + Target: example.com. + + - name: Alias + codepoint: 65285 + fields: + - name: Target + type: TargetHost + test_data: + - name: "" + values: + Target: example.com. + + - name: Azure_Alias + codepoint: 65286 + fields: + - name: AliasType + type: RawString + - name: Target + type: RawString + test_data: + - name: "" + values: + AliasType: A + Target: example.com. + + - name: Bunny_Dns_Pz + codepoint: 65287 + fields: + - name: PullZoneID + type: Int64 + test_data: + - name: "" + values: + PullZoneID: 123 + +# NOTE TO SELF: PullZoneID is an int64. Should it be a uint16? + + - name: Bunny_Dns_Rdr + codepoint: 65320 + fields: + - name: Target + type: RawString + test_data: + - name: "" + values: + Target: https://example.com + + - name: Cf_Worker_Route + codepoint: 65288 + fields: + - name: When + type: RawString + - name: Then + type: RawString + test_data: + - name: "" + values: + When: whenWhen + Then: ThenThen + + - name: Cloudflareapi_Single_Redirect + codepoint: 65289 + fields: + - name: SRName + type: RawString + - name: Code + type: Uint16 + - name: SRWhen + type: RawString + - name: SRThen + type: RawString + runtimeFields: + - name: RT_SRRRulesetID + type: RawString + structtag: "json:\"sr_rulesetid,omitempty\"" + comment: "ID of the ruleset containing this rule (populated by API)" + - name: RT_SRRRulesetRuleID + type: RawString + structtag: "json:\"sr_rulesetruleid,omitempty\"" + comment: "ID of this rule within the ruleset (populated by API)" +# - name: RT_SRDisplay +# type: RawString +# structtag: "json:\"sr_display,omitempty\"" +# comment: "How is this displayed to the user (SetTarget) for CF_SINGLE_REDIRECT" + + test_data: + - name: "" + values: + SRName: first_rule + Code: 301 + SRWhen: when_string + SRThen: then_string + + - name: Cloudns_Wr + codepoint: 65290 + fields: + - name: Target + type: RawString + test_data: + - name: "" + values: + Target: example.com. + + - name: Frame + codepoint: 65291 + fields: + - name: Target + type: RawString + test_data: + - name: "" + values: + Target: example.com. + + - name: Import_Transform + codepoint: 65322 + fields: + - name: TransformTable + type: RawString + - name: TTL + type: Uint16 + - name: SuffixStrip + type: RawString + - name: TargetDomain + type: RawString + test_data: + - name: "" + values: + TransformTable: 1.1.1.0 ~ 1.1.1.100 ~ 4.4.4.100 ~ + SuffixStrip: com + TargetDomain: example.com + TTL: 123 + + - name: Lua + codepoint: 65292 + fields: + - name: LuaType + type: ToUpperRawString + - name: LuaPayload + type: RawString + test_data: + - name: "" + values: + LuaType: A + LuaPayload: return_127_0_0_1 + + - name: Mikrotik_Fwd + codepoint: 65293 + fields: + - name: ForwardTo + type: RawString + test_data: + - name: "" + values: + ForwardTo: example.com. + + - name: Mikrotik_Nxdomain + codepoint: 65294 + fields: [] + test_data: [] + + - name: Mikrotik_Forwarder + codepoint: 65321 + fields: + - name: Target + type: RawString + test_data: + - name: "" + values: + Target: 1.1.1.1,8.8.8.8 + + - name: Netlify + codepoint: 65295 + fields: [] + test_data: [] + + - name: Netlifyv6 + codepoint: 65296 + fields: [] + test_data: [] + + - name: Porkbun_Urlfwd + codepoint: 65297 + fields: + - name: Location + type: RawString + test_data: + - name: "plain" + values: + Location: http://example.com + + - name: R53_Alias + codepoint: 65298 + fields: + - name: AliasType + type: RawString + - name: Target + type: TargetHost + optionalFields: + - name: EvalTargetHealth + type: RawString + - name: ZoneID + type: RawString + test_data: + - name: normal_user + values: + AliasType: 1 + Target: alice. + EvalTargetHealth: true + ZoneID: 1234 + + - name: Url + codepoint: 65299 + fields: + - name: Location + type: RawString + test_data: + - name: "" + values: + Location: https://example.com/ + + - name: Url301 + codepoint: 65300 + fields: + - name: Location + type: RawString + test_data: + - name: "" + values: + Location: https://example.com/ diff --git a/pkg/providergolden/providergolden.go b/pkg/providergolden/providergolden.go new file mode 100644 index 0000000000..d1508dbe99 --- /dev/null +++ b/pkg/providergolden/providergolden.go @@ -0,0 +1,384 @@ +// Package providergolden records and replays exact provider conversion calls. +package providergolden + +import ( + "bytes" + "encoding/json" + "errors" + "flag" + "fmt" + "io/fs" + "os" + "path/filepath" + "regexp" + "slices" + "strconv" + "strings" + "testing" + + "github.com/DNSControl/dnscontrol/v5/models" + "github.com/google/go-cmp/cmp" +) + +var update = flag.Bool("update", false, "rewrite provider conversion expected-output files") + +const testDataDir = "test_data" + +var safeFilenamePart = regexp.MustCompile(`^[A-Za-z0-9_.-]+$`) + +func conversionFilename(kind, function, domain, ext string) string { + if !safeFilenamePart.MatchString(function) || !safeFilenamePart.MatchString(domain) { + panic(fmt.Sprintf("unsafe conversion filename: function=%q domain=%q", function, domain)) + } + return fmt.Sprintf("%s_%s_%s.%s", kind, function, domain, ext) +} + +func toRCInputFile(function, domain string) string { + return conversionFilename("recorded_torc_input", function, domain, "json") +} + +func toRCOutputFile(function, domain string) string { + return conversionFilename("expected_torc_output", function, domain, "records") +} + +func toNativeInputFile(function, domain string) string { + return conversionFilename("recorded_tonative_input", function, domain, "records") +} + +func toNativeOutputFile(function, domain string) string { + return conversionFilename("expected_tonative_output", function, domain, "json") +} + +type indexedValue[T any] struct { + Index int `json:"index"` + Value T `json:"value"` +} + +// CheckToRC replays every domain recorded for function. +func CheckToRC[N any, R ~[]*models.RecordConfig](t *testing.T, function string, convert func(*models.DomainConfig, N) (R, error)) { + t.Helper() + metadata := loadMetadataForTest(t) + found := false + for _, recording := range metadata.Recordings { + if !slices.Contains(recording.ToRC, function) { + continue + } + found = true + recording := recording + t.Run(recording.Domain, func(t *testing.T) { + input := toRCInputFile(function, recording.Domain) + data := mustLoad(t, input) + var natives []indexedValue[N] + if err := json.Unmarshal(data, &natives); err != nil { + t.Fatalf("%s: %v", input, err) + } + validateIndexes(t, input, indexesOf(natives)) + + dc := models.MustNewDomainConfig(recording.Domain) + var got strings.Builder + for _, item := range natives { + before := mustMarshal(t, item.Value) + records, err := convert(dc, item.Value) + if err != nil { + t.Fatalf("%s: index %d: %v", input, item.Index, err) + } + after := mustMarshal(t, item.Value) + if !bytes.Equal(before, after) { + t.Errorf("%s: index %d: ToRC mutated its native input", input, item.Index) + } + for _, record := range recordStrings(models.Records(records)) { + fmt.Fprintf(&got, "%d\t%s\n", item.Index, record) + } + } + reportFile(t, toRCOutputFile(function, recording.Domain), []byte(got.String())) + }) + } + if !found { + t.Skipf("no ToRC recording for %s", function) + } +} + +// CheckToNative replays every domain recorded for function. Records sharing an +// index are passed to convert as one conversion invocation. +func CheckToNative[N any](t *testing.T, function string, convert func(*models.DomainConfig, models.Records) (N, error)) { + t.Helper() + metadata := loadMetadataForTest(t) + found := false + for _, recording := range metadata.Recordings { + if !slices.Contains(recording.ToNative, function) { + continue + } + found = true + recording := recording + t.Run(recording.Domain, func(t *testing.T) { + input := toNativeInputFile(function, recording.Domain) + groups, err := parseIndexedRecords(models.MustNewDomainConfig(recording.Domain), string(mustLoad(t, input))) + if err != nil { + t.Fatalf("%s: %v", input, err) + } + outputs := make([]indexedValue[N], 0, len(groups)) + dc := models.MustNewDomainConfig(recording.Domain) + for _, group := range groups { + before := mustMarshal(t, group.Records) + native, err := convert(dc, group.Records) + if err != nil { + t.Fatalf("%s: index %d: %v", input, group.Index, err) + } + after := mustMarshal(t, group.Records) + if !bytes.Equal(before, after) { + t.Errorf("%s: index %d: ToNative mutated its RecordConfig input", input, group.Index) + } + outputs = append(outputs, indexedValue[N]{Index: group.Index, Value: native}) + } + data, err := json.MarshalIndent(outputs, "", " ") + if err != nil { + t.Fatal(err) + } + reportFile(t, toNativeOutputFile(function, recording.Domain), append(data, '\n')) + }) + } + if !found { + t.Skipf("no ToNative recording for %s", function) + } +} + +// CheckRoundTrip verifies each indexed ToNative input through both directions. +func CheckRoundTrip[N any, R ~[]*models.RecordConfig](t *testing.T, toNativeFunction string, + toNative func(*models.DomainConfig, models.Records) (N, error), + toRC func(*models.DomainConfig, N) (R, error), +) { + t.Helper() + metadata := loadMetadataForTest(t) + for _, recording := range metadata.Recordings { + if !slices.Contains(recording.ToNative, toNativeFunction) { + continue + } + recording := recording + t.Run(recording.Domain, func(t *testing.T) { + dc := models.MustNewDomainConfig(recording.Domain) + groups, err := parseIndexedRecords(dc, string(mustLoad(t, toNativeInputFile(toNativeFunction, recording.Domain)))) + if err != nil { + t.Fatal(err) + } + for _, group := range groups { + native, err := toNative(dc, group.Records) + if err != nil { + t.Fatalf("index %d: convert to native: %v", group.Index, err) + } + after, err := toRC(dc, native) + if err != nil { + t.Fatalf("index %d: convert to RecordConfig: %v", group.Index, err) + } + if diff := cmp.Diff(recordStrings(group.Records), recordStrings(models.Records(after))); diff != "" { + t.Errorf("index %d changed in round trip (-before +after):\n%s", group.Index, diff) + } + } + }) + } +} + +type indexedRecordGroup struct { + Index int + Records models.Records +} + +func parseIndexedRecords(dc *models.DomainConfig, text string) ([]indexedRecordGroup, error) { + var groups []indexedRecordGroup + positions := map[int]int{} + for lineNumber, line := range strings.Split(text, "\n") { + if strings.TrimSpace(line) == "" { + continue + } + prefix, record, ok := strings.Cut(line, "\t") + if !ok { + return nil, fmt.Errorf("line %d: expected index, tab, and record", lineNumber+1) + } + index64, err := strconv.ParseInt(prefix, 10, 32) + if err != nil || index64 <= 0 { + return nil, fmt.Errorf("line %d: invalid index %q", lineNumber+1, prefix) + } + index := int(index64) + position, exists := positions[index] + if !exists { + if len(groups) != 0 && index <= groups[len(groups)-1].Index { + return nil, fmt.Errorf("line %d: indexes must increase", lineNumber+1) + } + positions[index] = len(groups) + groups = append(groups, indexedRecordGroup{Index: index}) + position = len(groups) - 1 + } + rc, err := parseRecord(dc, record) + if err != nil { + return nil, fmt.Errorf("line %d: %w", lineNumber+1, err) + } + groups[position].Records = append(groups[position].Records, rc) + } + return groups, nil +} + +func indexesOf[T any](values []indexedValue[T]) []int { + indexes := make([]int, len(values)) + for i := range values { + indexes[i] = values[i].Index + } + return indexes +} + +func validateIndexes(t *testing.T, filename string, indexes []int) { + t.Helper() + for i, index := range indexes { + if index <= 0 || i != 0 && index <= indexes[i-1] { + t.Fatalf("%s: indexes must be positive and increasing: %v", filename, indexes) + } + } +} + +func loadMetadataForTest(t *testing.T) recordingMetadata { + t.Helper() + metadata, err := readMetadata(testDataDir) + if err != nil { + if errors.Is(err, fs.ErrNotExist) { + t.Skipf("%s has no recorded data", filepath.Join(testDataDir, "meta.json")) + } + t.Fatal(err) + } + return metadata +} + +func mustLoad(t *testing.T, filename string) []byte { + t.Helper() + data, err := os.ReadFile(filepath.Join(testDataDir, filename)) + if err != nil { + t.Fatal(err) + } + return data +} + +func mustMarshal(t *testing.T, value any) []byte { + t.Helper() + data, err := json.Marshal(value) + if err != nil { + t.Fatal(err) + } + return data +} + +func reportFile(t *testing.T, filename string, got []byte) { + t.Helper() + path := filepath.Join(testDataDir, filename) + if *update { + if err := os.WriteFile(path, got, 0o644); err != nil { + t.Fatal(err) + } + return + } + want, err := os.ReadFile(path) + if errors.Is(err, fs.ErrNotExist) { + t.Skipf("%s does not exist: run go test . -update", path) + } + if err != nil { + t.Fatal(err) + } + if diff := cmp.Diff(strings.Split(string(want), "\n"), strings.Split(string(got), "\n")); diff != "" { + t.Errorf("%s does not match (-want +got):\n%s", filename, diff) + } +} + +// // parseRecords parses unindexed record text. It remains useful for focused +// // parser tests and migration tooling. +// func parseRecords(dc *models.DomainConfig, text string) ([]*models.RecordConfig, error) { +// var recs []*models.RecordConfig +// for i, line := range strings.Split(text, "\n") { +// if strings.TrimSpace(line) == "" { +// continue +// } +// rc, err := parseRecord(dc, line) +// if err != nil { +// return nil, fmt.Errorf("line %d: %w", i+1, err) +// } +// recs = append(recs, rc) +// } +// return recs, nil +// } + +func parseRecord(dc *models.DomainConfig, line string) (*models.RecordConfig, error) { + record, metatext := cutMetadata(line) + fields := strings.SplitN(record, " ", 5) + if len(fields) != 5 { + return nil, fmt.Errorf("%q: expected \"label ttl IN type rdata\"", line) + } + name, ttltext, class, rtype, rdata := fields[0], fields[1], fields[2], fields[3], fields[4] + ttl, err := strconv.ParseUint(ttltext, 10, 32) + if err != nil { + return nil, fmt.Errorf("%q: %w", line, err) + } + if class != "IN" { + return nil, fmt.Errorf("%q: expected class \"IN\"", line) + } + rc, err := dc.NewRecordConfigParse(name, uint32(ttl), rtype, rdata) + if err != nil { + return nil, err + } + metadata, err := parseMetadata(metatext) + if err != nil { + return nil, fmt.Errorf("%q: %w", line, err) + } + if len(metadata) != 0 { + rc.Metadata = metadata + } + return rc, nil +} + +func cutMetadata(line string) (record, metadata string) { + quoted := false + for i := 0; i < len(line); i++ { + switch line[i] { + case '\\': + i++ + case '"': + quoted = !quoted + case ';': + if !quoted { + return strings.TrimRight(line[:i], " "), line[i+1:] + } + } + } + return line, "" +} + +func parseMetadata(s string) (map[string]string, error) { + metadata := map[string]string{} + s = strings.TrimLeft(s, " ") + for s != "" { + key, rest, ok := strings.Cut(s, "=") + if !ok { + return nil, fmt.Errorf("metadata %q: expected key=\"value\"", s) + } + value, rest, err := cutQuoted(rest) + if err != nil { + return nil, err + } + metadata[key] = value + s = strings.TrimLeft(rest, " ") + } + return metadata, nil +} + +func cutQuoted(s string) (value, rest string, err error) { + if !strings.HasPrefix(s, `"`) { + return "", "", fmt.Errorf("metadata %q: expected a quoted value", s) + } + for i := 1; i < len(s); i++ { + switch s[i] { + case '\\': + i++ + case '"': + value, err := strconv.Unquote(s[:i+1]) + if err != nil { + return "", "", fmt.Errorf("metadata %q: %w", s, err) + } + return value, s[i+1:], nil + } + } + return "", "", fmt.Errorf("metadata %q: unterminated quoted value", s) +} diff --git a/pkg/providergolden/providergolden_test.go b/pkg/providergolden/providergolden_test.go new file mode 100644 index 0000000000..87ae48a4a5 --- /dev/null +++ b/pkg/providergolden/providergolden_test.go @@ -0,0 +1,57 @@ +package providergolden + +import ( + "strings" + "testing" + + "github.com/DNSControl/dnscontrol/v5/models" +) + +func TestConversionFilenames(t *testing.T) { + domain := "example.com" + tests := map[string]string{ + toRCInputFile("convert", domain): "recorded_torc_input_convert_example.com.json", + toRCOutputFile("convert", domain): "expected_torc_output_convert_example.com.records", + toNativeInputFile("convert", domain): "recorded_tonative_input_convert_example.com.records", + toNativeOutputFile("convert", domain): "expected_tonative_output_convert_example.com.json", + } + for got, want := range tests { + if got != want { + t.Errorf("filename = %q, want %q", got, want) + } + } +} + +func TestParseIndexedRecordsGroupsRepeatedIndexes(t *testing.T) { + dc := models.MustNewDomainConfig("example.com") + groups, err := parseIndexedRecords(dc, strings.Join([]string{ + "1\twww 300 IN A 192.0.2.1", + "1\twww 300 IN AAAA 2001:db8::1", + "2\t@ 300 IN TXT \"hello\"", + }, "\n")) + if err != nil { + t.Fatal(err) + } + if len(groups) != 2 || groups[0].Index != 1 || len(groups[0].Records) != 2 || groups[1].Index != 2 || len(groups[1].Records) != 1 { + t.Fatalf("unexpected groups: %#v", groups) + } +} + +func TestParseIndexedRecordsRejectsOutOfOrderIndexes(t *testing.T) { + dc := models.MustNewDomainConfig("example.com") + _, err := parseIndexedRecords(dc, "2\twww 300 IN A 192.0.2.1\n1\tmail 300 IN A 192.0.2.2\n") + if err == nil || !strings.Contains(err.Error(), "indexes must increase") { + t.Fatalf("error = %v, want index-order error", err) + } +} + +func TestParseRecordPreservesMetadata(t *testing.T) { + dc := models.MustNewDomainConfig("example.com") + rc, err := parseRecord(dc, `www 300 IN A 192.0.2.1 ; key="value with spaces"`) + if err != nil { + t.Fatal(err) + } + if rc.Metadata["key"] != "value with spaces" { + t.Fatalf("metadata = %#v", rc.Metadata) + } +} diff --git a/pkg/providergolden/record.go b/pkg/providergolden/record.go new file mode 100644 index 0000000000..471b6dd505 --- /dev/null +++ b/pkg/providergolden/record.go @@ -0,0 +1,400 @@ +package providergolden + +import ( + "bytes" + "encoding/json" + "errors" + "fmt" + "maps" + "os" + "path" + "path/filepath" + "reflect" + "slices" + "strings" + "sync" + + "github.com/DNSControl/dnscontrol/v5/models" + "github.com/DNSControl/dnscontrol/v5/pkg/providers" +) + +type recordingMetadata struct { + Version int `json:"version"` + Recordings []recordingDescriptor `json:"recordings"` +} + +type recordingDescriptor struct { + Domain string `json:"domain"` + ToRC []string `json:"to_rc,omitempty"` + ToNative []string `json:"to_native,omitempty"` +} + +type toRCObservation struct { + input json.RawMessage + output []string +} + +type toNativeObservation struct { + input []string + output json.RawMessage +} + +// Recorder collects exact conversion inputs and outputs from a provider. +type Recorder struct { + mu sync.Mutex + toRC map[string]map[string]map[string]toRCObservation + toNative map[string]map[string]map[string]toNativeObservation + errs []error +} + +// NewRecorder returns an empty conversion recorder. +func NewRecorder() *Recorder { + return &Recorder{ + toRC: map[string]map[string]map[string]toRCObservation{}, + toNative: map[string]map[string]map[string]toNativeObservation{}, + } +} + +// ForDomain returns a constructor-injectable observer scoped to one zone. +func (r *Recorder) ForDomain(domain string) providers.ConversionObserver { + return &domainObserver{recorder: r, domain: strings.TrimSuffix(strings.ToLower(domain), ".")} +} + +type domainObserver struct { + recorder *Recorder + domain string +} + +type conversionSnapshot struct { + serialized []byte + records []string +} + +func (o *domainObserver) BeginToRC(_ string, native any) providers.ConversionSnapshot { + data, err := json.Marshal(native) + if err != nil { + o.recorder.addError(err) + } + return conversionSnapshot{serialized: data} +} + +func (o *domainObserver) EndToRC(function string, before providers.ConversionSnapshot, nativeAfter any, result models.Records, convertErr error) { + snapshot, ok := before.(conversionSnapshot) + if !ok { + o.recorder.addError(fmt.Errorf("%s ToRC returned an invalid observer snapshot", function)) + return + } + after, err := json.Marshal(nativeAfter) + if err != nil { + o.recorder.addError(err) + return + } + if !bytes.Equal(snapshot.serialized, after) { + o.recorder.addError(fmt.Errorf("%s ToRC mutated its native input", function)) + return + } + if convertErr != nil { + o.recorder.addError(fmt.Errorf("%s ToRC: %w", function, convertErr)) + return + } + output := recordStrings(result) + o.recorder.addToRC(o.domain, function, snapshot.serialized, output) +} + +func (o *domainObserver) BeginToNative(_ string, records models.Records) providers.ConversionSnapshot { + data, err := json.Marshal(records) + if err != nil { + o.recorder.addError(err) + } + return conversionSnapshot{serialized: data, records: recordStrings(records)} +} + +func (o *domainObserver) EndToNative(function string, before providers.ConversionSnapshot, recordsAfter models.Records, result any, convertErr error) { + snapshot, ok := before.(conversionSnapshot) + if !ok { + o.recorder.addError(fmt.Errorf("%s ToNative returned an invalid observer snapshot", function)) + return + } + after, err := json.Marshal(recordsAfter) + if err != nil { + o.recorder.addError(err) + return + } + if !bytes.Equal(snapshot.serialized, after) { + o.recorder.addError(fmt.Errorf("%s ToNative mutated its RecordConfig input", function)) + return + } + if convertErr != nil { + o.recorder.addError(fmt.Errorf("%s ToNative: %w", function, convertErr)) + return + } + output, err := json.Marshal(result) + if err != nil { + o.recorder.addError(err) + return + } + o.recorder.addToNative(o.domain, function, snapshot.records, output) +} + +func recordStrings(records models.Records) []string { + result := make([]string, 0, len(records)) + for _, rc := range records { + if rc != nil { + result = append(result, rc.StringWithMeta()) + } + } + return result +} + +func (r *Recorder) addError(err error) { + if err == nil { + return + } + r.mu.Lock() + defer r.mu.Unlock() + r.errs = append(r.errs, err) +} + +func (r *Recorder) addToRC(domain, function string, input []byte, output []string) { + r.mu.Lock() + defer r.mu.Unlock() + if r.toRC[domain] == nil { + r.toRC[domain] = map[string]map[string]toRCObservation{} + } + if r.toRC[domain][function] == nil { + r.toRC[domain][function] = map[string]toRCObservation{} + } + key := string(input) + observation := toRCObservation{input: slices.Clone(input), output: slices.Clone(output)} + if old, ok := r.toRC[domain][function][key]; ok && !slices.Equal(old.output, output) { + r.errs = append(r.errs, fmt.Errorf("%s ToRC produced different outputs for the same input", function)) + return + } + r.toRC[domain][function][key] = observation +} + +func (r *Recorder) addToNative(domain, function string, input []string, output []byte) { + r.mu.Lock() + defer r.mu.Unlock() + if r.toNative[domain] == nil { + r.toNative[domain] = map[string]map[string]toNativeObservation{} + } + if r.toNative[domain][function] == nil { + r.toNative[domain][function] = map[string]toNativeObservation{} + } + key := strings.Join(input, "\n") + observation := toNativeObservation{input: slices.Clone(input), output: slices.Clone(output)} + if old, ok := r.toNative[domain][function][key]; ok && !bytes.Equal(old.output, output) { + r.errs = append(r.errs, fmt.Errorf("%s ToNative produced different outputs for the same input", function)) + return + } + r.toNative[domain][function][key] = observation +} + +type indexedJSON struct { + Index int `json:"index"` + Value json.RawMessage `json:"value"` +} + +// WriteTo writes all recorded conversion inputs and their expected outputs. +// Existing recordings for other domains are preserved. +func (r *Recorder) WriteTo(dir string) ([]string, error) { + r.mu.Lock() + defer r.mu.Unlock() + if len(r.errs) != 0 { + return nil, errors.Join(r.errs...) + } + + metadata, err := readMetadata(dir) + if err != nil { + return nil, err + } + byDomain := map[string]recordingDescriptor{} + for _, recording := range metadata.Recordings { + byDomain[recording.Domain] = recording + } + + var written []string + for _, domain := range sortedUnionKeys(r.toRC, r.toNative) { + descriptor := byDomain[domain] + descriptor.Domain = domain + for _, function := range slices.Sorted(maps.Keys(r.toRC[domain])) { + paths, err := writeToRC(dir, function, domain, r.toRC[domain][function]) + if err != nil { + return written, err + } + written = append(written, paths...) + descriptor.ToRC = appendUnique(descriptor.ToRC, function) + } + for _, function := range slices.Sorted(maps.Keys(r.toNative[domain])) { + paths, err := writeToNative(dir, function, domain, r.toNative[domain][function]) + if err != nil { + return written, err + } + written = append(written, paths...) + descriptor.ToNative = appendUnique(descriptor.ToNative, function) + } + slices.Sort(descriptor.ToRC) + slices.Sort(descriptor.ToNative) + byDomain[domain] = descriptor + } + + metadata.Version = 1 + metadata.Recordings = metadata.Recordings[:0] + for _, domain := range slices.Sorted(maps.Keys(byDomain)) { + metadata.Recordings = append(metadata.Recordings, byDomain[domain]) + } + data, err := json.MarshalIndent(metadata, "", " ") + if err != nil { + return written, err + } + path, err := writeFile(dir, "meta.json", append(data, '\n')) + if err != nil { + return written, err + } + written = append([]string{path}, written...) + return written, nil +} + +func writeToRC(dir, function, domain string, observations map[string]toRCObservation) ([]string, error) { + keys := slices.Sorted(maps.Keys(observations)) + inputs := make([]indexedJSON, 0, len(keys)) + var outputs strings.Builder + for i, key := range keys { + index := i + 1 + observation := observations[key] + inputs = append(inputs, indexedJSON{Index: index, Value: observation.input}) + for _, record := range observation.output { + fmt.Fprintf(&outputs, "%d\t%s\n", index, record) + } + } + data, err := json.MarshalIndent(inputs, "", " ") + if err != nil { + return nil, err + } + inputPath, err := writeFile(dir, toRCInputFile(function, domain), append(data, '\n')) + if err != nil { + return nil, err + } + outputPath, err := writeFile(dir, toRCOutputFile(function, domain), []byte(outputs.String())) + return []string{inputPath, outputPath}, err +} + +func writeToNative(dir, function, domain string, observations map[string]toNativeObservation) ([]string, error) { + keys := slices.Sorted(maps.Keys(observations)) + outputs := make([]indexedJSON, 0, len(keys)) + var inputs strings.Builder + for i, key := range keys { + index := i + 1 + observation := observations[key] + for _, record := range observation.input { + fmt.Fprintf(&inputs, "%d\t%s\n", index, record) + } + outputs = append(outputs, indexedJSON{Index: index, Value: observation.output}) + } + inputPath, err := writeFile(dir, toNativeInputFile(function, domain), []byte(inputs.String())) + if err != nil { + return nil, err + } + data, err := json.MarshalIndent(outputs, "", " ") + if err != nil { + return nil, err + } + outputPath, err := writeFile(dir, toNativeOutputFile(function, domain), append(data, '\n')) + return []string{inputPath, outputPath}, err +} + +func readMetadata(dir string) (recordingMetadata, error) { + data, err := os.ReadFile(filepath.Join(dir, "meta.json")) + if errors.Is(err, os.ErrNotExist) { + return recordingMetadata{Version: 1}, nil + } + if err != nil { + return recordingMetadata{}, err + } + var metadata recordingMetadata + if err := json.Unmarshal(data, &metadata); err != nil { + return recordingMetadata{}, err + } + return metadata, nil +} + +func sortedUnionKeys[A, B any](a map[string]A, b map[string]B) []string { + keys := map[string]bool{} + for key := range a { + keys[key] = true + } + for key := range b { + keys[key] = true + } + return slices.Sorted(maps.Keys(keys)) +} + +func appendUnique(items []string, item string) []string { + if !slices.Contains(items, item) { + return append(items, item) + } + return items +} + +// ProviderName returns the package name of p's implementation. +func ProviderName(p models.DNSProvider) (string, error) { + t := reflect.TypeOf(p) + for t != nil && t.Kind() == reflect.Pointer { + t = t.Elem() + } + if t == nil || t.PkgPath() == "" { + return "", fmt.Errorf("cannot derive a provider name from provider type %T", p) + } + return path.Base(t.PkgPath()), nil +} + +// TestdataDir returns providers//test_data under the module root. +func TestdataDir(p models.DNSProvider) (string, error) { + name, err := ProviderName(p) + if err != nil { + return "", err + } + root, err := moduleRoot() + if err != nil { + return "", err + } + return filepath.Join(root, "providers", name, testDataDir), nil +} + +// ResolveDir resolves dir against the module root when it is relative. +func ResolveDir(dir string) (string, error) { + if filepath.IsAbs(dir) { + return dir, nil + } + root, err := moduleRoot() + if err != nil { + return "", err + } + return filepath.Join(root, dir), nil +} + +func moduleRoot() (string, error) { + dir, err := os.Getwd() + if err != nil { + return "", err + } + for { + if _, err := os.Stat(filepath.Join(dir, "go.mod")); err == nil { + return dir, nil + } + parent := filepath.Dir(dir) + if parent == dir { + return "", errors.New("no go.mod above the working directory") + } + dir = parent + } +} + +func writeFile(dir, filename string, data []byte) (string, error) { + if err := os.MkdirAll(dir, 0o755); err != nil { + return "", err + } + path := filepath.Join(dir, filename) + return path, os.WriteFile(path, data, 0o644) +} diff --git a/pkg/providergolden/record_test.go b/pkg/providergolden/record_test.go new file mode 100644 index 0000000000..9b724ceb3e --- /dev/null +++ b/pkg/providergolden/record_test.go @@ -0,0 +1,114 @@ +package providergolden + +import ( + "encoding/json" + "os" + "path/filepath" + "strings" + "testing" + + "github.com/DNSControl/dnscontrol/v5/models" +) + +type fakeNative struct { + Name string `json:"name"` +} + +func TestRecorderWritesIndexedInputAndOutput(t *testing.T) { + dc := models.MustNewDomainConfig("example.com") + records := models.Records{ + dc.MustNewRecordConfig("www", 300, "A", "192.0.2.1"), + dc.MustNewRecordConfig("www", 300, "AAAA", "2001:db8::1"), + } + recorder := NewRecorder() + observer := recorder.ForDomain(dc.Name) + + native := fakeNative{Name: "www"} + toRC := observer.BeginToRC("toRC", native) + observer.EndToRC("toRC", toRC, native, records, nil) + toNative := observer.BeginToNative("toNative", records) + observer.EndToNative("toNative", toNative, records, native, nil) + + dir := t.TempDir() + written, err := recorder.WriteTo(dir) + if err != nil { + t.Fatal(err) + } + if len(written) != 5 { + t.Fatalf("wrote %d files, want 5: %v", len(written), written) + } + + metadata, err := readMetadata(dir) + if err != nil { + t.Fatal(err) + } + if metadata.Version != 1 || len(metadata.Recordings) != 1 { + t.Fatalf("unexpected metadata: %#v", metadata) + } + got := metadata.Recordings[0] + if got.Domain != "example.com" || strings.Join(got.ToRC, ",") != "toRC" || strings.Join(got.ToNative, ",") != "toNative" { + t.Fatalf("unexpected recording descriptor: %#v", got) + } + + assertFileContains(t, filepath.Join(dir, toRCOutputFile("toRC", dc.Name)), "1\twww 300 IN A 192.0.2.1\n1\twww 300 IN AAAA 2001:db8::1\n") + assertFileContains(t, filepath.Join(dir, toNativeInputFile("toNative", dc.Name)), "1\twww 300 IN A 192.0.2.1\n1\twww 300 IN AAAA 2001:db8::1\n") + + var input []indexedValue[fakeNative] + data, err := os.ReadFile(filepath.Join(dir, toRCInputFile("toRC", dc.Name))) + if err != nil { + t.Fatal(err) + } + if err := json.Unmarshal(data, &input); err != nil { + t.Fatal(err) + } + if len(input) != 1 || input[0].Index != 1 || input[0].Value != native { + t.Fatalf("unexpected indexed input: %#v", input) + } +} + +func TestRecorderRejectsMutation(t *testing.T) { + recorder := NewRecorder() + observer := recorder.ForDomain("example.com") + native := &fakeNative{Name: "before"} + snapshot := observer.BeginToRC("toRC", native) + native.Name = "after" + observer.EndToRC("toRC", snapshot, native, nil, nil) + if _, err := recorder.WriteTo(t.TempDir()); err == nil || !strings.Contains(err.Error(), "mutated its native input") { + t.Fatalf("WriteTo() error = %v, want mutation error", err) + } +} + +func TestRecorderMergesDomains(t *testing.T) { + dir := t.TempDir() + metadata := recordingMetadata{Version: 1, Recordings: []recordingDescriptor{{Domain: "old.example", ToRC: []string{"old"}}}} + data, _ := json.Marshal(metadata) + if err := os.WriteFile(filepath.Join(dir, "meta.json"), data, 0o644); err != nil { + t.Fatal(err) + } + recorder := NewRecorder() + observer := recorder.ForDomain("new.example") + native := fakeNative{Name: "new"} + snapshot := observer.BeginToRC("new", native) + observer.EndToRC("new", snapshot, native, nil, nil) + if _, err := recorder.WriteTo(dir); err != nil { + t.Fatal(err) + } + got, err := readMetadata(dir) + if err != nil { + t.Fatal(err) + } + if len(got.Recordings) != 2 || got.Recordings[0].Domain != "new.example" || got.Recordings[1].Domain != "old.example" { + t.Fatalf("merged metadata = %#v", got.Recordings) + } +} + +func assertFileContains(t *testing.T, path, want string) { + t.Helper() + got, err := os.ReadFile(path) + if err != nil { + t.Fatal(err) + } + if string(got) != want { + t.Fatalf("%s = %q, want %q", path, got, want) + } +} diff --git a/pkg/providers/_all/all.go b/pkg/providers/_all/all.go index 875a5fdb29..05ba5b006e 100644 --- a/pkg/providers/_all/all.go +++ b/pkg/providers/_all/all.go @@ -3,74 +3,75 @@ package all import ( // Define all known providers here. They should each register themselves with the providers package via init function. - _ "github.com/DNSControl/dnscontrol/v4/providers/adguardhome" - _ "github.com/DNSControl/dnscontrol/v4/providers/akamaiedgedns" - _ "github.com/DNSControl/dnscontrol/v4/providers/alidns" - _ "github.com/DNSControl/dnscontrol/v4/providers/autodns" - _ "github.com/DNSControl/dnscontrol/v4/providers/axfrddns" - _ "github.com/DNSControl/dnscontrol/v4/providers/azuredns" - _ "github.com/DNSControl/dnscontrol/v4/providers/azureprivatedns" - _ "github.com/DNSControl/dnscontrol/v4/providers/bind" - _ "github.com/DNSControl/dnscontrol/v4/providers/bunnydns" - _ "github.com/DNSControl/dnscontrol/v4/providers/cloudflare" - _ "github.com/DNSControl/dnscontrol/v4/providers/cloudns" - _ "github.com/DNSControl/dnscontrol/v4/providers/cnr" - _ "github.com/DNSControl/dnscontrol/v4/providers/cscglobal" - _ "github.com/DNSControl/dnscontrol/v4/providers/desec" - _ "github.com/DNSControl/dnscontrol/v4/providers/digitalocean" - _ "github.com/DNSControl/dnscontrol/v4/providers/dnscale" - _ "github.com/DNSControl/dnscontrol/v4/providers/dnsimple" - _ "github.com/DNSControl/dnscontrol/v4/providers/dnsmadeeasy" - _ "github.com/DNSControl/dnscontrol/v4/providers/doh" - _ "github.com/DNSControl/dnscontrol/v4/providers/domainnameshop" - _ "github.com/DNSControl/dnscontrol/v4/providers/dynadot" - _ "github.com/DNSControl/dnscontrol/v4/providers/dynu" - _ "github.com/DNSControl/dnscontrol/v4/providers/easyname" - _ "github.com/DNSControl/dnscontrol/v4/providers/exoscale" - _ "github.com/DNSControl/dnscontrol/v4/providers/fortigate" - _ "github.com/DNSControl/dnscontrol/v4/providers/gandiv5" - _ "github.com/DNSControl/dnscontrol/v4/providers/gcloud" - _ "github.com/DNSControl/dnscontrol/v4/providers/gcore" - _ "github.com/DNSControl/dnscontrol/v4/providers/gidinet" - _ "github.com/DNSControl/dnscontrol/v4/providers/gigahost" - _ "github.com/DNSControl/dnscontrol/v4/providers/hedns" - _ "github.com/DNSControl/dnscontrol/v4/providers/hetznerv2" - _ "github.com/DNSControl/dnscontrol/v4/providers/hostingde" - _ "github.com/DNSControl/dnscontrol/v4/providers/huaweicloud" - _ "github.com/DNSControl/dnscontrol/v4/providers/infomaniak" - _ "github.com/DNSControl/dnscontrol/v4/providers/internetbs" - _ "github.com/DNSControl/dnscontrol/v4/providers/inwx" - _ "github.com/DNSControl/dnscontrol/v4/providers/joker" - _ "github.com/DNSControl/dnscontrol/v4/providers/linode" - _ "github.com/DNSControl/dnscontrol/v4/providers/loopia" - _ "github.com/DNSControl/dnscontrol/v4/providers/luadns" - _ "github.com/DNSControl/dnscontrol/v4/providers/mikrotik" - _ "github.com/DNSControl/dnscontrol/v4/providers/mythicbeasts" - _ "github.com/DNSControl/dnscontrol/v4/providers/namecheap" - _ "github.com/DNSControl/dnscontrol/v4/providers/namedotcom" - _ "github.com/DNSControl/dnscontrol/v4/providers/nexdns" - _ "github.com/DNSControl/dnscontrol/v4/providers/netbird" - _ "github.com/DNSControl/dnscontrol/v4/providers/netcup" - _ "github.com/DNSControl/dnscontrol/v4/providers/netlify" - _ "github.com/DNSControl/dnscontrol/v4/providers/netnod" - _ "github.com/DNSControl/dnscontrol/v4/providers/ns1" - _ "github.com/DNSControl/dnscontrol/v4/providers/openwrt" - _ "github.com/DNSControl/dnscontrol/v4/providers/opensrs" - _ "github.com/DNSControl/dnscontrol/v4/providers/oracle" - _ "github.com/DNSControl/dnscontrol/v4/providers/ovh" - _ "github.com/DNSControl/dnscontrol/v4/providers/packetframe" - _ "github.com/DNSControl/dnscontrol/v4/providers/porkbun" - _ "github.com/DNSControl/dnscontrol/v4/providers/powerdns" - _ "github.com/DNSControl/dnscontrol/v4/providers/realtimeregister" - _ "github.com/DNSControl/dnscontrol/v4/providers/route53" - _ "github.com/DNSControl/dnscontrol/v4/providers/rwth" - _ "github.com/DNSControl/dnscontrol/v4/providers/sakuracloud" - _ "github.com/DNSControl/dnscontrol/v4/providers/scaleway" - _ "github.com/DNSControl/dnscontrol/v4/providers/softlayer" - _ "github.com/DNSControl/dnscontrol/v4/providers/tencentdns" - _ "github.com/DNSControl/dnscontrol/v4/providers/transip" - _ "github.com/DNSControl/dnscontrol/v4/providers/unifi" - _ "github.com/DNSControl/dnscontrol/v4/providers/vercel" - _ "github.com/DNSControl/dnscontrol/v4/providers/vultr" - _ "github.com/DNSControl/dnscontrol/v4/providers/websupport" + _ "github.com/DNSControl/dnscontrol/v5/providers/adguardhome" + _ "github.com/DNSControl/dnscontrol/v5/providers/akamaiedgedns" + _ "github.com/DNSControl/dnscontrol/v5/providers/alidns" + _ "github.com/DNSControl/dnscontrol/v5/providers/autodns" + _ "github.com/DNSControl/dnscontrol/v5/providers/axfrddns" + _ "github.com/DNSControl/dnscontrol/v5/providers/azuredns" + _ "github.com/DNSControl/dnscontrol/v5/providers/azureprivatedns" + _ "github.com/DNSControl/dnscontrol/v5/providers/bind" + _ "github.com/DNSControl/dnscontrol/v5/providers/bunnydns" + _ "github.com/DNSControl/dnscontrol/v5/providers/cloudflare" + _ "github.com/DNSControl/dnscontrol/v5/providers/cloudflare/rtypes/cfsingleredirect" + _ "github.com/DNSControl/dnscontrol/v5/providers/cloudns" + _ "github.com/DNSControl/dnscontrol/v5/providers/cnr" + _ "github.com/DNSControl/dnscontrol/v5/providers/cscglobal" + _ "github.com/DNSControl/dnscontrol/v5/providers/desec" + _ "github.com/DNSControl/dnscontrol/v5/providers/digitalocean" + _ "github.com/DNSControl/dnscontrol/v5/providers/dnscale" + _ "github.com/DNSControl/dnscontrol/v5/providers/dnsimple" + _ "github.com/DNSControl/dnscontrol/v5/providers/dnsmadeeasy" + _ "github.com/DNSControl/dnscontrol/v5/providers/doh" + _ "github.com/DNSControl/dnscontrol/v5/providers/domainnameshop" + _ "github.com/DNSControl/dnscontrol/v5/providers/dynadot" + _ "github.com/DNSControl/dnscontrol/v5/providers/dynu" + _ "github.com/DNSControl/dnscontrol/v5/providers/easyname" + _ "github.com/DNSControl/dnscontrol/v5/providers/exoscale" + _ "github.com/DNSControl/dnscontrol/v5/providers/fortigate" + _ "github.com/DNSControl/dnscontrol/v5/providers/gandiv5" + _ "github.com/DNSControl/dnscontrol/v5/providers/gcloud" + _ "github.com/DNSControl/dnscontrol/v5/providers/gcore" + _ "github.com/DNSControl/dnscontrol/v5/providers/gidinet" + _ "github.com/DNSControl/dnscontrol/v5/providers/gigahost" + _ "github.com/DNSControl/dnscontrol/v5/providers/hedns" + _ "github.com/DNSControl/dnscontrol/v5/providers/hetznerv2" + _ "github.com/DNSControl/dnscontrol/v5/providers/hostingde" + _ "github.com/DNSControl/dnscontrol/v5/providers/huaweicloud" + _ "github.com/DNSControl/dnscontrol/v5/providers/infomaniak" + _ "github.com/DNSControl/dnscontrol/v5/providers/internetbs" + _ "github.com/DNSControl/dnscontrol/v5/providers/inwx" + _ "github.com/DNSControl/dnscontrol/v5/providers/joker" + _ "github.com/DNSControl/dnscontrol/v5/providers/linode" + _ "github.com/DNSControl/dnscontrol/v5/providers/loopia" + _ "github.com/DNSControl/dnscontrol/v5/providers/luadns" + _ "github.com/DNSControl/dnscontrol/v5/providers/mikrotik" + _ "github.com/DNSControl/dnscontrol/v5/providers/mythicbeasts" + _ "github.com/DNSControl/dnscontrol/v5/providers/namecheap" + _ "github.com/DNSControl/dnscontrol/v5/providers/namedotcom" + _ "github.com/DNSControl/dnscontrol/v5/providers/netbird" + _ "github.com/DNSControl/dnscontrol/v5/providers/netcup" + _ "github.com/DNSControl/dnscontrol/v5/providers/netlify" + _ "github.com/DNSControl/dnscontrol/v5/providers/netnod" + _ "github.com/DNSControl/dnscontrol/v5/providers/nexdns" + _ "github.com/DNSControl/dnscontrol/v5/providers/ns1" + _ "github.com/DNSControl/dnscontrol/v5/providers/opensrs" + _ "github.com/DNSControl/dnscontrol/v5/providers/openwrt" + _ "github.com/DNSControl/dnscontrol/v5/providers/oracle" + _ "github.com/DNSControl/dnscontrol/v5/providers/ovh" + _ "github.com/DNSControl/dnscontrol/v5/providers/packetframe" + _ "github.com/DNSControl/dnscontrol/v5/providers/porkbun" + _ "github.com/DNSControl/dnscontrol/v5/providers/powerdns" + _ "github.com/DNSControl/dnscontrol/v5/providers/realtimeregister" + _ "github.com/DNSControl/dnscontrol/v5/providers/route53" + _ "github.com/DNSControl/dnscontrol/v5/providers/rwth" + _ "github.com/DNSControl/dnscontrol/v5/providers/sakuracloud" + _ "github.com/DNSControl/dnscontrol/v5/providers/scaleway" + _ "github.com/DNSControl/dnscontrol/v5/providers/softlayer" + _ "github.com/DNSControl/dnscontrol/v5/providers/tencentdns" + _ "github.com/DNSControl/dnscontrol/v5/providers/transip" + _ "github.com/DNSControl/dnscontrol/v5/providers/unifi" + _ "github.com/DNSControl/dnscontrol/v5/providers/vercel" + _ "github.com/DNSControl/dnscontrol/v5/providers/vultr" + _ "github.com/DNSControl/dnscontrol/v5/providers/websupport" ) diff --git a/pkg/providers/conversion_observer.go b/pkg/providers/conversion_observer.go new file mode 100644 index 0000000000..54e65ca609 --- /dev/null +++ b/pkg/providers/conversion_observer.go @@ -0,0 +1,90 @@ +package providers + +import "github.com/DNSControl/dnscontrol/v5/models" + +// ConversionSnapshot is an opaque snapshot returned before a conversion and +// passed back after it. Its concrete type belongs to the observer. +type ConversionSnapshot any + +// ConversionObserver observes the exact inputs and outputs of provider record +// conversions. Implementations may also verify that conversions did not mutate +// their inputs. +type ConversionObserver interface { + BeginToRC(function string, native any) ConversionSnapshot + EndToRC(function string, before ConversionSnapshot, nativeAfter any, result models.Records, err error) + BeginToNative(function string, records models.Records) ConversionSnapshot + EndToNative(function string, before ConversionSnapshot, recordsAfter models.Records, result any, err error) +} + +// ConversionObserverSetter is implemented by providers that expose conversion +// boundaries. CreateDNSProvider calls it before returning the constructed +// provider. +type ConversionObserverSetter interface { + SetConversionObserver(ConversionObserver) +} + +type noopConversionObserver struct{} + +func (noopConversionObserver) BeginToRC(string, any) ConversionSnapshot { return nil } +func (noopConversionObserver) EndToRC(string, ConversionSnapshot, any, models.Records, error) { +} +func (noopConversionObserver) BeginToNative(string, models.Records) ConversionSnapshot { return nil } +func (noopConversionObserver) EndToNative(string, ConversionSnapshot, models.Records, any, error) { +} + +// CreateOptions holds optional dependencies supplied while constructing a DNS +// provider. +type CreateOptions struct { + ConversionObserver ConversionObserver +} + +// CreateOption customizes DNS provider construction. +type CreateOption func(*CreateOptions) + +// WithConversionObserver supplies an observer for provider record conversions. +func WithConversionObserver(observer ConversionObserver) CreateOption { + return func(options *CreateOptions) { + options.ConversionObserver = observer + } +} + +func newCreateOptions(opts []CreateOption) CreateOptions { + options := CreateOptions{ConversionObserver: noopConversionObserver{}} + for _, opt := range opts { + opt(&options) + } + if options.ConversionObserver == nil { + options.ConversionObserver = noopConversionObserver{} + } + return options +} + +// BeginToRC safely begins an observation when observer may be nil. +func BeginToRC(observer ConversionObserver, function string, native any) ConversionSnapshot { + if observer == nil { + return nil + } + return observer.BeginToRC(function, native) +} + +// EndToRC safely completes an observation when observer may be nil. +func EndToRC(observer ConversionObserver, function string, before ConversionSnapshot, native any, result models.Records, err error) { + if observer != nil { + observer.EndToRC(function, before, native, result, err) + } +} + +// BeginToNative safely begins an observation when observer may be nil. +func BeginToNative(observer ConversionObserver, function string, records models.Records) ConversionSnapshot { + if observer == nil { + return nil + } + return observer.BeginToNative(function, records) +} + +// EndToNative safely completes an observation when observer may be nil. +func EndToNative(observer ConversionObserver, function string, before ConversionSnapshot, records models.Records, result any, err error) { + if observer != nil { + observer.EndToNative(function, before, records, result, err) + } +} diff --git a/pkg/providers/conversion_observer_test.go b/pkg/providers/conversion_observer_test.go new file mode 100644 index 0000000000..842538c217 --- /dev/null +++ b/pkg/providers/conversion_observer_test.go @@ -0,0 +1,51 @@ +package providers + +import ( + "encoding/json" + "testing" + + "github.com/DNSControl/dnscontrol/v5/models" +) + +type testObserver struct{ noopConversionObserver } + +type observerProvider struct { + observer ConversionObserver +} + +func (*observerProvider) GetNameservers(string) ([]*models.Nameserver, error) { return nil, nil } +func (*observerProvider) GetZoneRecords(*models.DomainConfig) (models.Records, error) { + return nil, nil +} +func (*observerProvider) GetZoneRecordsCorrections(*models.DomainConfig, models.Records) ([]*models.Correction, int, error) { + return nil, 0, nil +} +func (p *observerProvider) SetConversionObserver(observer ConversionObserver) { + p.observer = observer +} + +func TestCreateDNSProviderInjectsConversionObserver(t *testing.T) { + const name = "PROVIDERGOLDEN_OBSERVER_TEST" + old, existed := DNSProviderTypes[name] + t.Cleanup(func() { + if existed { + DNSProviderTypes[name] = old + } else { + delete(DNSProviderTypes, name) + } + }) + DNSProviderTypes[name] = DspFuncs{ + Initializer: func(map[string]string, json.RawMessage) (DNSServiceProvider, error) { + return &observerProvider{}, nil + }, + } + + want := &testObserver{} + provider, err := CreateDNSProvider(name, nil, nil, WithConversionObserver(want)) + if err != nil { + t.Fatal(err) + } + if got := provider.(*observerProvider).observer; got != want { + t.Fatalf("observer = %T %p, want %T %p", got, got, want, want) + } +} diff --git a/pkg/providers/providers.go b/pkg/providers/providers.go index 0322101d7a..4f33d86f55 100644 --- a/pkg/providers/providers.go +++ b/pkg/providers/providers.go @@ -6,7 +6,7 @@ import ( "fmt" "log" - "github.com/DNSControl/dnscontrol/v4/models" + "github.com/DNSControl/dnscontrol/v5/models" ) // Registrar is an interface for a domain registrar. It can return a list of needed corrections to be applied in the future. Implement this only if the provider is a "registrar" (i.e. can update the NS records of the parent to a domain). @@ -41,15 +41,20 @@ var RegistrarTypes = map[string]RegistrarInitializer{} // DspInitializer is a function to create a DNS service provider. Function will be passed the unprocessed json payload from the configuration file for the given provider. type DspInitializer func(map[string]string, json.RawMessage) (DNSServiceProvider, error) +// DspInitializerWithOptions creates a DNS service provider with optional +// constructor dependencies such as a conversion observer. +type DspInitializerWithOptions func(map[string]string, json.RawMessage, CreateOptions) (DNSServiceProvider, error) + // RecordAuditor is a function that verifies that all the records // are supportable by this provider. It returns a list of errors // detailing records that this provider can not support. -type RecordAuditor func([]*models.RecordConfig) []error +type RecordAuditor func(models.Records) []error // DspFuncs lists functions registered with a provider. type DspFuncs struct { - Initializer DspInitializer - RecordAuditor RecordAuditor + Initializer DspInitializer + InitializerWithOptions DspInitializerWithOptions + RecordAuditor RecordAuditor } // DNSProviderTypes stores initializer for each DSP. @@ -115,7 +120,7 @@ func CreateRegistrar(rType string, config map[string]string) (Registrar, error) } // CreateDNSProvider initializes a dns provider instance from given credentials. -func CreateDNSProvider(providerTypeName string, config map[string]string, meta json.RawMessage) (DNSServiceProvider, error) { +func CreateDNSProvider(providerTypeName string, config map[string]string, meta json.RawMessage, opts ...CreateOption) (DNSServiceProvider, error) { var err error providerTypeName, err = beCompatible(providerTypeName, config) if err != nil { @@ -126,7 +131,18 @@ func CreateDNSProvider(providerTypeName string, config map[string]string, meta j if !ok { return nil, fmt.Errorf("no such DNS service provider: %q", providerTypeName) } - return p.Initializer(config, meta) + options := newCreateOptions(opts) + if p.InitializerWithOptions != nil { + return p.InitializerWithOptions(config, meta, options) + } + provider, err := p.Initializer(config, meta) + if err != nil { + return nil, err + } + if setter, ok := provider.(ConversionObserverSetter); ok { + setter.SetConversionObserver(options.ConversionObserver) + } + return provider, nil } // beCompatible looks up. diff --git a/pkg/recorddb/recorddb.go b/pkg/recorddb/recorddb.go index b3e02d7e94..1dcbb10e52 100644 --- a/pkg/recorddb/recorddb.go +++ b/pkg/recorddb/recorddb.go @@ -1,6 +1,6 @@ package recorddb -import "github.com/DNSControl/dnscontrol/v4/models" +import "github.com/DNSControl/dnscontrol/v5/models" // Functions that make it easier to deal with // a group of records. diff --git a/pkg/rejectif/audit.go b/pkg/rejectif/audit.go index 8dbc558031..bda1d13dd9 100644 --- a/pkg/rejectif/audit.go +++ b/pkg/rejectif/audit.go @@ -3,7 +3,7 @@ package rejectif import ( "fmt" - "github.com/DNSControl/dnscontrol/v4/models" + "github.com/DNSControl/dnscontrol/v5/models" ) // Auditor stores a list of checks to be executed during Audit(). diff --git a/pkg/rejectif/caa.go b/pkg/rejectif/caa.go index e42ed48144..4dc5e9a99a 100644 --- a/pkg/rejectif/caa.go +++ b/pkg/rejectif/caa.go @@ -4,14 +4,14 @@ import ( "errors" "strings" - "github.com/DNSControl/dnscontrol/v4/models" + "github.com/DNSControl/dnscontrol/v5/models" ) // Keep these in alphabetical order. -// CaaFlagIsNonZero identifies CAA records where tag is no zero. +// CaaFlagIsNonZero identifies CAA records where flag is no zero. func CaaFlagIsNonZero(rc *models.RecordConfig) error { - if rc.CaaFlag != 0 { + if rc.AsCAA().Flag != 0 { return errors.New("caa flag is non-zero") } return nil @@ -21,7 +21,7 @@ func CaaFlagIsNonZero(rc *models.RecordConfig) error { // whitespace in the target. // See https://github.com/DNSControl/dnscontrol/issues/1374 func CaaTargetContainsWhitespace(rc *models.RecordConfig) error { - if strings.ContainsAny(rc.GetTargetField(), " \t\r\n") { + if strings.ContainsAny(rc.AsCAA().Value, " \t\r\n") { return errors.New("caa target contains whitespace") } return nil @@ -29,7 +29,7 @@ func CaaTargetContainsWhitespace(rc *models.RecordConfig) error { // CaaHasEmptyTag detects CAA records with empty tags. func CaaHasEmptyTag(rc *models.RecordConfig) error { - if rc.CaaTag == "" { + if rc.AsCAA().Tag == "" { return errors.New("caa has empty tag") } return nil @@ -37,16 +37,8 @@ func CaaHasEmptyTag(rc *models.RecordConfig) error { // CaaHasEmptyTarget detects CAA records with empty targets. func CaaHasEmptyTarget(rc *models.RecordConfig) error { - if rc.GetTargetField() == "" { + if rc.AsCAA().Value == "" { return errors.New("caa has empty target") } return nil } - -// // CaaTargetHasSemicolon identifies CAA records that contain semicolons. -// func CaaTargetHasSemicolon(rc *models.RecordConfig) error { -// if strings.Contains(rc.GetTargetField(), ";") { -// return fmt.Errorf("caa target contains semicolon") -// } -// return nil -// } diff --git a/pkg/rejectif/dnskey.go b/pkg/rejectif/dnskey.go new file mode 100644 index 0000000000..505c4e5579 --- /dev/null +++ b/pkg/rejectif/dnskey.go @@ -0,0 +1,18 @@ +package rejectif + +import ( + "errors" + + "github.com/DNSControl/dnscontrol/v5/models" +) + +// Keep these in alphabetical order. + +// DnskeyNotAtApex detects DNSKEY records not at the apex/root domain. +// Use this when a provider doesn't support custom DNSKEY records at subnames. +func DnskeyNotAtApex(rc *models.RecordConfig) error { + if rc.GetLabel() != "" && rc.GetLabel() != "@" { + return errors.New("DNSKEY records not supported at subnames") + } + return nil +} diff --git a/pkg/rejectif/label.go b/pkg/rejectif/label.go index 16ffcebba0..33786280fc 100644 --- a/pkg/rejectif/label.go +++ b/pkg/rejectif/label.go @@ -4,7 +4,7 @@ import ( "errors" "strings" - "github.com/DNSControl/dnscontrol/v4/models" + "github.com/DNSControl/dnscontrol/v5/models" ) // Keep these in alphabetical order. diff --git a/pkg/rejectif/mx.go b/pkg/rejectif/mx.go index a2e16defc8..9fbb43ba24 100644 --- a/pkg/rejectif/mx.go +++ b/pkg/rejectif/mx.go @@ -3,7 +3,7 @@ package rejectif import ( "errors" - "github.com/DNSControl/dnscontrol/v4/models" + "github.com/DNSControl/dnscontrol/v5/models" ) // Keep these in alphabetical order. @@ -11,7 +11,8 @@ import ( // MxNull detects MX records that are a "null MX". // This is needed by providers that don't support RFC 7505. func MxNull(rc *models.RecordConfig) error { - if rc.GetTargetField() == "." { + f := rc.AsMX() + if f.Mx == "." { return errors.New("mx has null target") } return nil diff --git a/pkg/rejectif/naptr.go b/pkg/rejectif/naptr.go index 1f117be0ba..afe67bbab8 100644 --- a/pkg/rejectif/naptr.go +++ b/pkg/rejectif/naptr.go @@ -3,14 +3,14 @@ package rejectif import ( "errors" - "github.com/DNSControl/dnscontrol/v4/models" + "github.com/DNSControl/dnscontrol/v5/models" ) // Keep these in alphabetical order. // NaptrHasEmptyTarget detects NAPTR records with empty targets. func NaptrHasEmptyTarget(rc *models.RecordConfig) error { - if rc.GetTargetField() == "" { + if rc.AsNAPTR().Replacement == "" { return errors.New("naptr has empty target") } return nil diff --git a/pkg/rejectif/ns.go b/pkg/rejectif/ns.go index 4d52e3cd94..136f2fa168 100644 --- a/pkg/rejectif/ns.go +++ b/pkg/rejectif/ns.go @@ -3,7 +3,7 @@ package rejectif import ( "errors" - "github.com/DNSControl/dnscontrol/v4/models" + "github.com/DNSControl/dnscontrol/v5/models" ) // Keep these in alphabetical order. @@ -11,7 +11,7 @@ import ( // NsAtApex detects NS records at the apex/root domain. // Use this when a provider doesn't support custom NS records at the apex. func NsAtApex(rc *models.RecordConfig) error { - if rc.GetLabel() == "" { + if rc.GetLabel() == "@" { return errors.New("NS records not supported at apex") } return nil diff --git a/pkg/rejectif/ns_test.go b/pkg/rejectif/ns_test.go new file mode 100644 index 0000000000..00fe507d88 --- /dev/null +++ b/pkg/rejectif/ns_test.go @@ -0,0 +1,31 @@ +package rejectif + +import ( + "testing" + + dnsv2 "codeberg.org/miekg/dns" + "github.com/DNSControl/dnscontrol/v5/models" +) + +func TestNsAtApex(t *testing.T) { + tests := []struct { + name string + label string + wantErr bool + }{ + {name: "apex as @", label: "@", wantErr: true}, + {name: "subdomain", label: "xyz", wantErr: false}, + {name: "deep subdomain", label: "a.b.c", wantErr: false}, + } + + dc := models.MustNewDomainConfig("example.com") + rc := dc.MustNewRecordConfig("placeholder", 300, dnsv2.TypeNS, "ns1.example.net.") + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + rc.Name = tt.label + if err := NsAtApex(rc); (err != nil) != tt.wantErr { + t.Errorf("NsAtApex(label=%q) error = %v, wantErr %v", tt.label, err, tt.wantErr) + } + }) + } +} diff --git a/pkg/rejectif/srv.go b/pkg/rejectif/srv.go index 8cf925fcae..e1c830eb99 100644 --- a/pkg/rejectif/srv.go +++ b/pkg/rejectif/srv.go @@ -3,14 +3,14 @@ package rejectif import ( "errors" - "github.com/DNSControl/dnscontrol/v4/models" + "github.com/DNSControl/dnscontrol/v5/models" ) // Keep these in alphabetical order. // SrvHasNullTarget detects SRV records that has a null target. func SrvHasNullTarget(rc *models.RecordConfig) error { - if rc.GetTargetField() == "." { + if rc.AsSRV().Target == "." { return errors.New("srv has empty target") // Same msg as SrvHasEmptyTarget to make testing easier. } return nil @@ -18,7 +18,7 @@ func SrvHasNullTarget(rc *models.RecordConfig) error { // SrvHasEmptyTarget detects SRV records with empty targets. func SrvHasEmptyTarget(rc *models.RecordConfig) error { - if rc.GetTargetField() == "" { + if rc.AsSRV().Target == "" { return errors.New("srv has empty target") } return nil @@ -26,7 +26,7 @@ func SrvHasEmptyTarget(rc *models.RecordConfig) error { // SrvHasZeroPort detects SRV records with port set to zero. func SrvHasZeroPort(rc *models.RecordConfig) error { - if rc.SrvPort == 0 { + if rc.AsSRV().Port == 0 { return errors.New("srv has zero port") } return nil diff --git a/pkg/rejectif/txt.go b/pkg/rejectif/txt.go index 74460ca8f1..d2a0fe052f 100644 --- a/pkg/rejectif/txt.go +++ b/pkg/rejectif/txt.go @@ -5,7 +5,7 @@ import ( "fmt" "strings" - "github.com/DNSControl/dnscontrol/v4/models" + "github.com/DNSControl/dnscontrol/v5/models" ) // Keep these in alphabetical order. @@ -57,7 +57,7 @@ func TxtHasDoubleQuotes(rc *models.RecordConfig) error { return nil } -// TxtHasSemicolon audits TXT records for strings that contain backticks. +// TxtHasSemicolon audits TXT records for strings that contain semicolons. func TxtHasSemicolon(rc *models.RecordConfig) error { if strings.Contains(rc.GetTargetTXTJoined(), ";") { return errors.New("txtstring contains semicolon") @@ -118,3 +118,14 @@ func TxtStartsOrEndsWithSpaces(rc *models.RecordConfig) error { } return nil } + +// CaaTargetHasSemicolon returns an error if a CAA record's target contains a semicolon. +func CaaTargetHasSemicolon(rc *models.RecordConfig) error { + if rc.Type == "CAA" { + f := rc.AsCAA() + if strings.Contains(f.Value, ";") { + return fmt.Errorf("CAA record target contains semicolon: %s", f.Value) + } + } + return nil +} diff --git a/pkg/rfc4183/ipv6.go b/pkg/rfc4183/ipv6.go index c3233e215a..36690a833e 100644 --- a/pkg/rfc4183/ipv6.go +++ b/pkg/rfc4183/ipv6.go @@ -2,7 +2,7 @@ package rfc4183 import "errors" -// reverseIPv6 returns the ipv6.arpa string suitable for reverse DNS lookups. +// reverseIPv6 returns the ip6.arpa string suitable for reverse DNS lookups. func reverseIPv6(ip []byte, maskbits int) (arpa string, err error) { // Must be IPv6 if len(ip) != 16 { diff --git a/pkg/rtype/ds.go b/pkg/rtype/ds.go deleted file mode 100644 index 37acd88f99..0000000000 --- a/pkg/rtype/ds.go +++ /dev/null @@ -1,81 +0,0 @@ -package rtype - -import ( - "fmt" - - "github.com/DNSControl/dnscontrol/v4/models" - "github.com/DNSControl/dnscontrol/v4/pkg/domaintags" - "github.com/DNSControl/dnscontrol/v4/pkg/rtypecontrol" - dnsv1 "github.com/miekg/dns" -) - -func init() { - rtypecontrol.Register(&DS{}) -} - -// DS RR. -type DS struct { - dnsv1.DS -} - -// Name returns the DNS record type as a string. -func (handle *DS) Name() string { - return "DS" -} - -// FromArgs fills in the RecordConfig from []any, which is typically from a parsed config file. -func (handle *DS) FromArgs(dcn *domaintags.DomainNameVarieties, rec *models.RecordConfig, args []any) error { - if err := rtypecontrol.PaveArgs(args[1:], "wbbs"); err != nil { - return fmt.Errorf("ERROR: (%s) [DS(%q, %v)]: %w", - rec.FilePos, - rec.Name, rtypecontrol.StringifyQuoted(args[1:]), - err) - } - fields := &dnsv1.DS{ - KeyTag: args[1].(uint16), - Algorithm: args[2].(uint8), - DigestType: args[3].(uint8), - Digest: args[4].(string), - } - - return handle.FromStruct(dcn, rec, args[0].(string), fields) -} - -// FromStruct fills in the RecordConfig from a struct, typically from an API response. -func (handle *DS) FromStruct(dcn *domaintags.DomainNameVarieties, rec *models.RecordConfig, name string, fields any) error { - // Fields is of type "any" thus we must validate the type. It should be the "inner" type of .F, not the outer type, rtype.DS{}. - ds, ok := fields.(*dnsv1.DS) - if !ok { - return fmt.Errorf("fields is not *dns.DS, got %T", fields) - } - rec.F = &DS{*ds} - - rec.ZonefilePartial = rec.GetTargetRFC1035Quoted() - rec.Comparable = rec.ZonefilePartial - - handle.CopyToLegacyFields(rec) - return nil -} - -// CopyToLegacyFields populates the legacy fields of the RecordConfig using the fields in .F. -func (handle *DS) CopyToLegacyFields(rec *models.RecordConfig) { - ds := rec.F.(*DS) - _ = rec.SetTargetDS(ds.KeyTag, ds.Algorithm, ds.DigestType, ds.Digest) -} - -// CopyFromLegacyFields uses the the legacy fields to populate .F. -func (handle *DS) CopyFromLegacyFields(rec *models.RecordConfig) { - // Copy fields: - rec.F = &DS{ - dnsv1.DS{ - KeyTag: rec.DsKeyTag, - Algorithm: rec.DsAlgorithm, - DigestType: rec.DsDigestType, - Digest: rec.DsDigest, - }, - } - - // Fix up ZonefilePartial and Comparable: - rec.ZonefilePartial = rec.GetTargetRFC1035Quoted() - rec.Comparable = rec.ZonefilePartial -} diff --git a/pkg/rtype/rp.go b/pkg/rtype/rp.go deleted file mode 100644 index 919e160ec3..0000000000 --- a/pkg/rtype/rp.go +++ /dev/null @@ -1,68 +0,0 @@ -package rtype - -import ( - "fmt" - - "github.com/DNSControl/dnscontrol/v4/models" - "github.com/DNSControl/dnscontrol/v4/pkg/domaintags" - "github.com/DNSControl/dnscontrol/v4/pkg/rtypecontrol" - dnsv1 "github.com/miekg/dns" - dnsutilv1 "github.com/miekg/dns/dnsutil" -) - -func init() { - rtypecontrol.Register(&RP{}) -} - -// RP RR. See RFC 1138, Section 2.2. -type RP struct { - dnsv1.RP -} - -// Name returns the DNS record type as a string. -func (handle *RP) Name() string { - return "RP" -} - -// FromArgs fills in the RecordConfig from []any, which is typically from a parsed config file. -func (handle *RP) FromArgs(dcn *domaintags.DomainNameVarieties, rec *models.RecordConfig, args []any) error { - if err := rtypecontrol.PaveArgs(args[1:], "ss"); err != nil { - return fmt.Errorf("ERROR: (%s) [RP(%q, %v)]: %w", - rec.FilePos, - rec.Name, rtypecontrol.StringifyQuoted(args[1:]), - err) - } - fields := &RP{ - dnsv1.RP{ - Mbox: dnsutilv1.AddOrigin(args[1].(string), dcn.NameASCII+"."), - Txt: dnsutilv1.AddOrigin(args[2].(string), dcn.NameASCII+"."), - }, - } - - return handle.FromStruct(dcn, rec, args[0].(string), fields) -} - -// FromStruct fills in the RecordConfig from a struct, typically from an API response. -func (handle *RP) FromStruct(dcn *domaintags.DomainNameVarieties, rec *models.RecordConfig, name string, fields any) error { - rec.F = fields - - rec.ZonefilePartial = rec.GetTargetRFC1035Quoted() - rec.Comparable = rec.ZonefilePartial - - handle.CopyToLegacyFields(rec) - return nil -} - -// CopyToLegacyFields populates the legacy fields of the RecordConfig using the fields in .F. -func (handle *RP) CopyToLegacyFields(rec *models.RecordConfig) { - // RP, like all new RRs, does not have legacy fields. Even .target is deprecated. -} - -// CopyFromLegacyFields populates the legacy fields of the RecordConfig using the fields in .F. -func (handle *RP) CopyFromLegacyFields(rec *models.RecordConfig) { - // RP is RecordConfigv2 and has no legacy fields. Even .target is deprecated. - - // Fix up ZonefilePartial and Comparable: - rec.ZonefilePartial = rec.GetTargetRFC1035Quoted() - rec.Comparable = rec.ZonefilePartial -} diff --git a/pkg/rtypecontrol/fixlegacy.go b/pkg/rtypecontrol/fixlegacy.go deleted file mode 100644 index 12a335c521..0000000000 --- a/pkg/rtypecontrol/fixlegacy.go +++ /dev/null @@ -1,36 +0,0 @@ -package rtypecontrol - -import "github.com/DNSControl/dnscontrol/v4/models" - -// FixLegacyDC populates .F to compenstate for providers that have not been -// updated to support RecordConfigV2 when creating RecordConfig. -// It is called anywhere dc.PostProcess() or models.PostProcessRecords() is -// called. Those functions can't call it directly because that would cause an -// import cycle. -func FixLegacyDC(dc *models.DomainConfig) { - FixLegacyRecords(&dc.Records) -} - -// FixLegacyRecords populates .F to compenstate for providers that have not been -// updated to support RecordConfigV2 when creating RecordConfig. -// It is called anywhere provider.GetZoneRecords() is called. GetZoneRecords() -// can't call it directly because that would involve modifying every provider. -// Instead, providers should be fixed to generate records properly. -func FixLegacyRecords(recs *models.Records) { - for _, rec := range *recs { - FixLegacyRecord(rec) - } -} - -// FixLegacyRecord populates .F to compenstate for providers that have not been -// updated to support RecordConfigV2 when creating RecordConfig. -func FixLegacyRecord(rec *models.RecordConfig) { - // Populate .F if needed: - // That is... If rec.F == nil and this is a "modern" type. - if rec.F != nil { - return - } - if fixer, ok := Func[rec.Type]; ok { - fixer.CopyFromLegacyFields(rec) - } -} diff --git a/pkg/rtypecontrol/import.go b/pkg/rtypecontrol/import.go deleted file mode 100644 index 9c678514c7..0000000000 --- a/pkg/rtypecontrol/import.go +++ /dev/null @@ -1,193 +0,0 @@ -package rtypecontrol - -import ( - "fmt" - "strings" - - "github.com/DNSControl/dnscontrol/v4/models" - "github.com/DNSControl/dnscontrol/v4/pkg/domaintags" - dnsv1 "github.com/miekg/dns" -) - -// ImportRawRecords imports the RawRecordConfigs into RecordConfigs. -func ImportRawRecords(domains []*models.DomainConfig) error { - for _, dc := range domains { - for _, rawRec := range dc.RawRecords { - filePos := models.FixPosition(rawRec.FilePos) - - rec, err := NewRecordConfigFromRaw(FromRawOpts{ - Type: rawRec.Type, - TTL: rawRec.TTL, - Args: rawRec.Args, - Metas: rawRec.Metas, - DCN: dc.DomainNameVarieties(), - FilePos: filePos, - }) - if err != nil { - return fmt.Errorf("error processing record at %s [%s(%s)]: %v", - filePos, - rawRec.Type, StringifyQuoted(rawRec.Args), - err) - } - if rec.Metadata["skip_fqdn_check"] != "true" && stutters(rec.Name, dc.Name) { - var shortname string - if rec.Name == dc.Name { - shortname = "@" - } else { - shortname = strings.TrimSuffix(rec.Name, "."+dc.Name) - } - return fmt.Errorf( - "name %q is an error (repeats the domain): Hint: Maybe instead of %q you intended %q? If not add DISABLE_REPEATED_DOMAIN_CHECK to this record to disable this check", - rec.NameFQDNRaw, - rec.NameRaw, - shortname, - ) - } - - // Free memeory: - clear(rawRec.Args) - rawRec.Args = nil - - dc.Records = append(dc.Records, rec) - } - dc.RawRecords = nil - } - - return nil -} - -func stutters(name, domain string) bool { - if name == "@" { - return false - } - if name == domain || strings.HasSuffix(name, "."+domain) { - return true - } - return false -} - -// FromRawOpts contains the options for creating a RecordConfig from raw data. -// Except Type and Args, all fields are optional. -type FromRawOpts struct { - Type string // (required) Record type (e.g., "A", "CNAME") - TTL uint32 // Time to live - Args []any // (required) Arguments for the record - Metas []map[string]any // Metadata for the record - DCN *domaintags.DomainNameVarieties // Domain name varieties - FilePos string // Position in the file where this record was defined -} - -// NewRecordConfigFromRaw creates a new RecordConfig from the raw ([]any) args, -// usually from the parsed dnsconfig.js file, but also useful when a provider -// returns the fields of a record as individual values. -func NewRecordConfigFromRaw(opts FromRawOpts) (*models.RecordConfig, error) { - t := opts.Type - ttl := opts.TTL - args := opts.Args - dcn := opts.DCN - FilePos := opts.FilePos - - if _, ok := Func[t]; !ok { - return nil, fmt.Errorf("record type %q is not supported", t) - } - if t == "" { - panic("rtypecontrol: NewRecordConfigFromRaw: empty record type") - } - - // Create as much of the RecordConfig as we can now. Allow New() to fill in the reset. - rec := &models.RecordConfig{ - Type: t, - TTL: ttl, - Metadata: map[string]string{}, - FilePos: FilePos, - } - - // Set the label names: - if err := setRecordNames(rec, dcn, args[0].(string)); err != nil { - return rec, err - } - // If setRecordNames notices that a FQDN was used but it is outside the - // D()/D_EXTEND() domain, it will leave the name as a FQDN ending in a dot. - // We catch that here: - if strings.HasSuffix(rec.Name, ".") { - return nil, fmt.Errorf("label %q is not in zone %s", args[0].(string), dcn.DisplayName) - } - - // Fill in the metadata fields. - for _, meta := range opts.Metas { - for k, v := range meta { - vStr := fmt.Sprintf("%v", v) - v, exists := rec.Metadata[k] - //fmt.Printf("DEBUG: meta key=%q value=%q v,e=%q,%q\n", k, vStr, v, exists) - if exists && v == vStr { - return nil, fmt.Errorf("duplicate metadata key %q (%q -- %q)", k, rec.Metadata[k], vStr) - } - rec.Metadata[k] = vStr - } - } - - // Fill in the .F/.Fields* fields. - err := Func[t].FromArgs(dcn, rec, args) - if err != nil { - return nil, err - } - - return rec, nil -} - -// NewRecordConfigFromString creates a new RecordConfig from a string in the -// format usually used in a zonefile but typically also used by providers -// returning the fields of a record as a string. -func NewRecordConfigFromString(name string, ttl uint32, t string, s string, dcn *domaintags.DomainNameVarieties) (*models.RecordConfig, error) { - if _, ok := Func[t]; !ok { - return nil, fmt.Errorf("record type %q is not supported", t) - } - if t == "" { - panic("rtypecontrol: NewRecordConfigFromStruct: empty record type") - } - - rec, err := dnsv1.NewRR(fmt.Sprintf("$ORIGIN .\n. %d IN %s %s", ttl, t, s)) - if err != nil { - return nil, err - } - return NewRecordConfigFromStruct(name, ttl, t, rec, dcn) - -} - -// NewRecordConfigFromStruct creates a new RecordConfig from a struct, typically -// a miekg/dns struct. It must be the exact struct type used by the FromStruct() -// method of the rtype package. -func NewRecordConfigFromStruct(name string, ttl uint32, t string, fields any, dcn *domaintags.DomainNameVarieties) (*models.RecordConfig, error) { - if _, ok := Func[t]; !ok { - return nil, fmt.Errorf("record type %q is not supported", t) - } - if t == "" { - panic("rtypecontrol: NewRecordConfigFromStruct: empty record type") - } - - // Create as much of the RecordConfig as we can now. Allow New() to fill in the reset. - rec := &models.RecordConfig{ - Type: t, - TTL: ttl, - Metadata: map[string]string{}, - } - if err := setRecordNames(rec, dcn, name); err != nil { - return rec, err - } - if strings.HasSuffix(rec.Name, ".") { - return nil, fmt.Errorf("label %q is not in zone %q", name, dcn.NameASCII+".") - } - if err := setRecordNames(rec, dcn, name); err != nil { - return rec, err - } - if strings.HasSuffix(rec.Name, ".") { - return nil, fmt.Errorf("label %q is not in zone %q", name, dcn.NameASCII+".") - } - - err := Func[t].FromStruct(dcn, rec, name, fields) - if err != nil { - return nil, err - } - - return rec, nil -} diff --git a/pkg/rtypecontrol/pave.go b/pkg/rtypecontrol/pave.go deleted file mode 100644 index 309db329cd..0000000000 --- a/pkg/rtypecontrol/pave.go +++ /dev/null @@ -1,114 +0,0 @@ -package rtypecontrol - -import ( - "fmt" - "math" - "strconv" -) - -// PaveArgs converts each arg to its desired type, or returns an error if conversion fails or if the number of arguments is wrong. -// argTypes is a string where each rune specifies the desired type of the arg in the same position: -// 's': string (will convert other types to string using %v) -// 'b': uint8 (will convert strings, truncate floats, etc) -// 'w': uint16 (will convert strings, truncate floats, etc) -// FUTURE 'd': uint32 (will convert strings, truncate floats, etc) -// FUTURE 'q': uint64 (will convert strings, truncate floats, etc) -// FUTURE: Uppercase runes for signed types. -func PaveArgs(args []any, argTypes string) error { - if len(args) != len(argTypes) { - return fmt.Errorf("wrong number of arguments. Expected %v, got %v", len(argTypes), len(args)) - } - - for i, at := range argTypes { - arg := args[i] - switch at { - - case 's': - if _, ok := arg.(string); ok { - args[i] = arg.(string) - } else { - args[i] = fmt.Sprintf("%v", arg) - } - - case 'b': // uint8 - switch v := arg.(type) { - case uint8: - // already correct type - case uint16: - if v > math.MaxUint8 { - return fmt.Errorf("value %q overflows uint8", arg) - } - args[i] = uint8(v) - case int16: - if v < 0 || v > math.MaxUint8 { - return fmt.Errorf("value %q overflows uint8", arg) - } - args[i] = uint8(v) - case uint: - if v > math.MaxUint8 { - return fmt.Errorf("value %q overflows uint8", arg) - } - args[i] = uint8(v) - case int: - if v < 0 || v > math.MaxUint8 { - return fmt.Errorf("value %q overflows uint8", arg) - } - args[i] = uint8(v) - case float64: - if v < 0 || v > math.MaxUint8 { - return fmt.Errorf("value %q overflows uint8", arg) - } - args[i] = uint8(v) - case string: - ni, err := strconv.ParseUint(arg.(string), 10, 8) - if err != nil { - return fmt.Errorf("value %q is not a number (uint8 wanted)", arg) - } - args[i] = uint8(ni) - default: - return fmt.Errorf("value %q is type %T, expected uint8", arg, arg) - } - - case 'w': // uint16 - switch v := arg.(type) { - case uint8: - args[i] = uint16(v) - case uint16: - // already correct type - case int16: - if v < 0 { - return fmt.Errorf("value %q overflows uint8", arg) - } - args[i] = uint16(v) - case uint: - if v > math.MaxUint16 { - return fmt.Errorf("value %q overflows uint8", arg) - } - args[i] = uint16(v) - case int: - if v < 0 || v > math.MaxUint16 { - return fmt.Errorf("value %q overflows uint8", arg) - } - args[i] = uint16(v) - case float64: - if v < 0 || v > math.MaxUint16 { - return fmt.Errorf("value %q overflows uint8", arg) - } - args[i] = uint16(v) - case string: - ni, err := strconv.ParseUint(arg.(string), 10, 16) - if err != nil { - return fmt.Errorf("value %q is not a number (uint16 wanted)", arg) - } - args[i] = uint16(ni) - default: - return fmt.Errorf("value %q is type %T, expected uint16", arg, arg) - } - - default: - return fmt.Errorf("unknown argType rune: %q", at) - } - } - - return nil -} diff --git a/pkg/rtypecontrol/pave_test.go b/pkg/rtypecontrol/pave_test.go deleted file mode 100644 index be11fd4f00..0000000000 --- a/pkg/rtypecontrol/pave_test.go +++ /dev/null @@ -1,115 +0,0 @@ -package rtypecontrol - -import "testing" - -func TestPaveArgs(t *testing.T) { - tests := []struct { - name string - dataArgs []any - dataRule string - wantErr bool - }{ - - // Error cases - { - name: "wrong number of args", - dataArgs: []any{"test", uint16(1)}, - dataRule: "s", - wantErr: true, - }, - { - name: "unknown arg type", - dataArgs: []any{uint32(100)}, - dataRule: "d", - wantErr: true, - }, - { - name: "unsupported type to uint8", - dataArgs: []any{int32(50)}, - dataRule: "b", - wantErr: true, - }, - { - name: "unsupported type to uint16", - dataArgs: []any{int32(50)}, - dataRule: "w", - wantErr: true, - }, - - // Multiple args - { - name: "multiple args mixed", - dataArgs: []any{"test", uint8(42), uint16(1000)}, - dataRule: "sbw", - wantErr: false, - }, - { - name: "multiple args with conversions", - dataArgs: []any{int(100), "255", float64(50.0)}, - dataRule: "sbb", - wantErr: false, - }, - } - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - if err := PaveArgs(tt.dataArgs, tt.dataRule); (err != nil) != tt.wantErr { - t.Errorf("PaveArgs() error = %v, wantErr %v", err, tt.wantErr) - } - }) - } -} -func TestPaveArgsConversionsCompact(t *testing.T) { - tests := []struct { - name string - args []any - argTypes string - want []any - wantErr bool - }{ - // String conversions - all should result in string type - {name: "string unchanged", args: []any{"hello"}, argTypes: "s", want: []any{"hello"}}, - {name: "int to string", args: []any{int(123)}, argTypes: "s", want: []any{"123"}}, - {name: "uint8 to string", args: []any{uint8(42)}, argTypes: "s", want: []any{"42"}}, - {name: "bool to string", args: []any{true}, argTypes: "s", want: []any{"true"}}, - - // uint8 ('b') conversions - all should result in uint8 type - {name: "uint8 unchanged", args: []any{uint8(100)}, argTypes: "b", want: []any{uint8(100)}}, - {name: "uint16 to uint8 valid", args: []any{uint16(255)}, argTypes: "b", want: []any{uint8(255)}}, - {name: "int16 to uint8 valid", args: []any{int16(100)}, argTypes: "b", want: []any{uint8(100)}}, - {name: "uint to uint8 valid", args: []any{uint(200)}, argTypes: "b", want: []any{uint8(200)}}, - {name: "int to uint8 valid", args: []any{int(50)}, argTypes: "b", want: []any{uint8(50)}}, - {name: "float64 to uint8 valid", args: []any{float64(100.9)}, argTypes: "b", want: []any{uint8(100)}}, - {name: "string to uint8 valid", args: []any{"255"}, argTypes: "b", want: []any{uint8(255)}}, - {name: "string to uint8 zero", args: []any{"0"}, argTypes: "b", want: []any{uint8(0)}}, - - // uint16 ('w') conversions - all should result in uint16 type - {name: "uint16 unchanged", args: []any{uint16(1000)}, argTypes: "w", want: []any{uint16(1000)}}, - {name: "uint8 to uint16", args: []any{uint8(255)}, argTypes: "w", want: []any{uint16(255)}}, - {name: "int16 to uint16 valid", args: []any{int16(32767)}, argTypes: "w", want: []any{uint16(32767)}}, - {name: "uint to uint16 valid", args: []any{uint(65535)}, argTypes: "w", want: []any{uint16(65535)}}, - {name: "int to uint16 valid", args: []any{int(30000)}, argTypes: "w", want: []any{uint16(30000)}}, - {name: "float64 to uint16 valid", args: []any{float64(1234.5)}, argTypes: "w", want: []any{uint16(1234)}}, - {name: "string to uint16 valid", args: []any{"65535"}, argTypes: "w", want: []any{uint16(65535)}}, - - // Multiple arguments - {name: "multiple types", args: []any{uint8(1), "test", uint16(1000)}, argTypes: "bsw", want: []any{uint8(1), "test", uint16(1000)}}, - {name: "all conversions", args: []any{"100", int(200), float64(50.5)}, argTypes: "bbs", want: []any{uint8(100), uint8(200), "50.5"}}, - } - - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - err := PaveArgs(tt.args, tt.argTypes) - if (err != nil) != tt.wantErr { - t.Errorf("PaveArgs() error = %v, wantErr %v", err, tt.wantErr) - return - } - if !tt.wantErr { - for i, want := range tt.want { - if tt.args[i] != want { - t.Errorf("PaveArgs() arg[%d] = %v (type %T), want %v (type %T)", i, tt.args[i], tt.args[i], want, want) - } - } - } - }) - } -} diff --git a/pkg/rtypecontrol/rtypecontrol.go b/pkg/rtypecontrol/rtypecontrol.go deleted file mode 100644 index 27dbb07098..0000000000 --- a/pkg/rtypecontrol/rtypecontrol.go +++ /dev/null @@ -1,41 +0,0 @@ -package rtypecontrol - -import ( - "fmt" - - "github.com/DNSControl/dnscontrol/v4/models" - "github.com/DNSControl/dnscontrol/v4/pkg/domaintags" - "github.com/DNSControl/dnscontrol/v4/pkg/providers" -) - -// RType is an interface that defines the methods required for a DNS record type. -type RType interface { - // Returns the name of the rtype ("A", "MX", etc.) - Name() string - - // RecordConfig factory. Updates a RecordConfig's fields based on args. - FromArgs(*domaintags.DomainNameVarieties, *models.RecordConfig, []any) error - FromStruct(*domaintags.DomainNameVarieties, *models.RecordConfig, string, any) error - - CopyToLegacyFields(*models.RecordConfig) - CopyFromLegacyFields(*models.RecordConfig) -} - -// Func is a map of registered rtypes. -var Func map[string]RType = map[string]RType{} - -// Register registers a new RType (Record Type) implementation. It can be used -// to register an RFC-defined type, a new custom type, or a "builder". -// -// It panics if the type is already registered, to prevent accidental overwrites. -func Register(t RType) { - name := t.Name() - if _, ok := Func[name]; ok { - panic(fmt.Sprintf("rtype %q already registered. Can't register it a second time!", name)) - } - // Store the interface - Func[name] = t - - // For compatibility with legacy systems: - providers.RegisterCustomRecordType(name, "", "") -} diff --git a/pkg/rtypecontrol/setrecordnames.go b/pkg/rtypecontrol/setrecordnames.go deleted file mode 100644 index 69ae11fa94..0000000000 --- a/pkg/rtypecontrol/setrecordnames.go +++ /dev/null @@ -1,193 +0,0 @@ -package rtypecontrol - -import ( - "fmt" - "strings" - - "github.com/DNSControl/dnscontrol/v4/models" - "github.com/DNSControl/dnscontrol/v4/pkg/domaintags" -) - -// This code defines many variables to make the logic easier to read. The Go optimizer -// should eliminate any performance impact. -// We could probably fold some of the logic together, but it would be harder to read. -// It's difficult enough to understand it as-is, so clarity is preferred. - -// setRecordNames uses n to update the .Name* fields. If the name is a FQDN -// (ends with a "."), it will be handled accordingly. However if it does not -// match the domain name, no error is returned but rec.Name* fields will end -// with a ".". -func setRecordNames(rec *models.RecordConfig, dcn *domaintags.DomainNameVarieties, n string) error { - if rec.SubDomain == "" { - return setRecordNamesNonExtend(rec, dcn, n) - } - return setRecordNamesExtend(rec, dcn, n) -} - -func setRecordNamesNonExtend(rec *models.RecordConfig, dcn *domaintags.DomainNameVarieties, n string) error { - - nRaw := n - nASCII := domaintags.EfficientToASCII(n) - nUnicode := domaintags.EfficientToUnicode(nASCII) - - if strings.HasSuffix(nRaw, ".") { - // The user specified a FQDN, we give it special handling. - - // with trailing dot: - nameRawdot := nRaw - nameASCIIdot := nASCII - nameUnicodedot := nUnicode - // without trailing dot: - nameRaw := nameRawdot[:len(nameRawdot)-1] - nameASCII := nameASCIIdot[:len(nameASCIIdot)-1] - nameUnicode := nameUnicodedot[:len(nameUnicodedot)-1] - // suffix: - suffixRaw := dcn.NameRaw - suffixASCII := dcn.NameASCII - suffixUnicode := dcn.NameUnicode - dotsuffixASCII := "." + suffixASCII - - if nameASCII == suffixASCII { - // Name is the apex: - rec.NameRaw = "@" - rec.Name = "@" - rec.NameUnicode = "@" - rec.NameFQDNRaw = dcn.NameRaw - rec.NameFQDN = dcn.NameASCII - rec.NameFQDNUnicode = dcn.NameUnicode - return nil - } else if strings.HasSuffix(nameASCII, dotsuffixASCII) { - // Name is a subdomain of the domain: - rec.NameRaw = nameRaw[:len(nameRaw)-len(suffixRaw)-1] - rec.Name = nameASCII[:len(nameASCII)-len(suffixASCII)-1] - rec.NameUnicode = nameUnicode[:len(nameUnicode)-len(suffixUnicode)-1] - rec.NameFQDNRaw = nameRaw - rec.NameFQDN = nameASCII - rec.NameFQDNUnicode = nameUnicode - return nil - } - // Name is not in this domain. Don't error, just return names with trailing dots. - rec.NameRaw = nameRawdot - rec.Name = nameASCIIdot - rec.NameUnicode = nameUnicodedot - rec.NameFQDNRaw = nameRawdot + dcn.NameRaw + "." - rec.NameFQDN = nameASCIIdot + dcn.NameASCII + "." - rec.NameFQDNUnicode = nameUnicodedot + dcn.NameUnicode + "." - return nil - } - - // Non-FQDN case: - - if nRaw == "@" { - // Name is the apex. We never store "", we store "@". - rec.NameRaw = "@" - rec.Name = "@" - rec.NameUnicode = "@" - rec.NameFQDNRaw = dcn.NameRaw - rec.NameFQDN = dcn.NameASCII - rec.NameFQDNUnicode = dcn.NameUnicode - return nil - } - - // Everything else: - - nameRaw := nRaw - nameASCII := nASCII - nameUnicode := nUnicode - - rec.NameRaw = nameRaw - rec.Name = nameASCII - rec.NameUnicode = nameUnicode - rec.NameFQDNRaw = nameRaw + "." + dcn.NameRaw - rec.NameFQDN = nameASCII + "." + dcn.NameASCII - rec.NameFQDNUnicode = nameUnicode + "." + dcn.NameUnicode - return nil -} - -func setRecordNamesExtend(rec *models.RecordConfig, dcn *domaintags.DomainNameVarieties, n string) error { - // NB(tlim): When a record has a subdomain "foo" and domain "example.com", a - // record such as "www" is added as "www.foo" (short name) or - // "www.foo.example.com" (FQDN name). - // When generating the shortname, we are truncating the "D()" name, not the - // D_EXTEND() name. That is... dcn.NameASCII, not - // rec.SubDomain+dcn.NameASCII. - - nRaw := n - nASCII := domaintags.EfficientToASCII(n) - nUnicode := domaintags.EfficientToUnicode(nASCII) - - sdRaw := rec.SubDomain - sdASCII := domaintags.EfficientToASCII(sdRaw) - sdUnicode := domaintags.EfficientToUnicode(sdASCII) - - if strings.HasSuffix(nRaw, ".") { - // The user specified a FQDN, we give it special handling. - - // with trailing dot: - nameRawdot := nRaw - nameASCIIdot := nASCII - nameUnicodedot := nUnicode - // without trailing dot: - nameRaw := nameRawdot[:len(nameRawdot)-1] - nameASCII := nameASCIIdot[:len(nameASCIIdot)-1] - nameUnicode := nameUnicodedot[:len(nameUnicodedot)-1] - // suffixes: - dotsdsuffixASCII := "." + sdASCII + "." + dcn.NameASCII - dotsuffixASCII := "." + dcn.NameASCII - suffixASCII := dcn.NameASCII - - if strings.HasSuffix(nameASCII, dotsdsuffixASCII) { - // The name is in the D_EXTEND() domain: - rec.NameRaw = nameRaw[:len(nameRaw)-len(dcn.NameRaw)-1] - rec.Name = nameASCII[:len(nameASCII)-len(dcn.NameASCII)-1] - rec.NameUnicode = nameUnicode[:len(nameUnicode)-len(dcn.NameUnicode)-1] - rec.NameFQDNRaw = nameRaw - rec.NameFQDN = nameASCII - rec.NameFQDNUnicode = nameUnicode - return nil - } - if strings.HasSuffix(nameASCII, suffixASCII) || strings.HasSuffix(nameASCII, dotsuffixASCII) { - // The name is NOT in the D_EXTEND() domain; but it is in the D() domain. - return fmt.Errorf("label %q should be in the apex domain, D(%q), not D_EXTEND(%q)", - nameRaw, - dcn.NameRaw, - rec.SubDomain+"."+dcn.NameRaw, - ) - } - // The name is not i the D_EXTEND() nor D() domain. Don't error, just return names with trailing dots. - rec.NameRaw = nameRawdot - rec.Name = nameASCIIdot - rec.NameUnicode = nameUnicodedot - rec.NameFQDNRaw = nameRawdot - rec.NameFQDN = nameASCIIdot - rec.NameFQDNUnicode = nameUnicodedot - return nil - } - - // Non-FQDN case: - - if nRaw == "@" { - // Name is the apex. Therefore, the subdomain is the name. - rec.NameRaw = sdRaw - rec.Name = sdASCII - rec.NameUnicode = sdUnicode - rec.NameFQDNRaw = rec.NameRaw + "." + dcn.NameRaw - rec.NameFQDN = rec.Name + "." + dcn.NameASCII - rec.NameFQDNUnicode = rec.NameUnicode + "." + dcn.NameUnicode - return nil - } - - // Everything else: - - nameRaw := nRaw - nameASCII := nASCII - nameUnicode := nUnicode - - rec.NameRaw = nameRaw + "." + sdRaw - rec.Name = nameASCII + "." + sdASCII - rec.NameUnicode = nameUnicode + "." + sdUnicode - rec.NameFQDNRaw = rec.NameRaw + "." + dcn.NameRaw - rec.NameFQDN = rec.Name + "." + dcn.NameASCII - rec.NameFQDNUnicode = rec.NameUnicode + "." + dcn.NameUnicode - return nil -} diff --git a/pkg/rtypecontrol/setrecordnames_test.go b/pkg/rtypecontrol/setrecordnames_test.go deleted file mode 100644 index 317eed6b47..0000000000 --- a/pkg/rtypecontrol/setrecordnames_test.go +++ /dev/null @@ -1,340 +0,0 @@ -package rtypecontrol - -import ( - "testing" - - "github.com/DNSControl/dnscontrol/v4/models" - "github.com/DNSControl/dnscontrol/v4/pkg/domaintags" -) - -func TestSetRecordNames(t *testing.T) { - dc := &domaintags.DomainNameVarieties{ - NameRaw: "example.com", - NameASCII: "example.com", - NameUnicode: "example.com", - } - dcIDN := &domaintags.DomainNameVarieties{ - NameRaw: "bücher.com", - NameASCII: "xn--bcher-kva.com", - NameUnicode: "bücher.com", - } - - tests := []struct { - name string - rec *models.RecordConfig - dc *domaintags.DomainNameVarieties - n string - expectedErr bool - expectedRec *models.RecordConfig - }{ - - { - name: "normal_at", - rec: &models.RecordConfig{}, - dc: dc, - n: "@", - expectedRec: &models.RecordConfig{ - NameRaw: "@", - Name: "@", - NameUnicode: "@", - NameFQDNRaw: "example.com", - NameFQDN: "example.com", - NameFQDNUnicode: "example.com", - }, - }, - { - name: "normal_label", - rec: &models.RecordConfig{}, - dc: dc, - n: "www", - expectedRec: &models.RecordConfig{ - NameRaw: "www", - Name: "www", - NameUnicode: "www", - NameFQDNRaw: "www.example.com", - NameFQDN: "www.example.com", - NameFQDNUnicode: "www.example.com", - }, - }, - { - name: "normal_idn_label", - rec: &models.RecordConfig{}, - dc: dc, - n: "bücher", - expectedRec: &models.RecordConfig{ - NameRaw: "bücher", - Name: "xn--bcher-kva", - NameUnicode: "bücher", - NameFQDNRaw: "bücher.example.com", - NameFQDN: "xn--bcher-kva.example.com", - NameFQDNUnicode: "bücher.example.com", - }, - }, - { - name: "normal_idn_domain", - rec: &models.RecordConfig{}, - dc: dcIDN, - n: "www", - expectedRec: &models.RecordConfig{ - NameRaw: "www", - Name: "www", - NameUnicode: "www", - NameFQDNRaw: "www.bücher.com", - NameFQDN: "www.xn--bcher-kva.com", - NameFQDNUnicode: "www.bücher.com", - }, - }, - { - name: "extend_at", - rec: &models.RecordConfig{SubDomain: "sub"}, - dc: dc, - n: "@", - expectedRec: &models.RecordConfig{ - SubDomain: "sub", - NameRaw: "sub", - Name: "sub", - NameUnicode: "sub", - NameFQDNRaw: "sub.example.com", - NameFQDN: "sub.example.com", - NameFQDNUnicode: "sub.example.com", - }, - }, - { - name: "extend_label", - rec: &models.RecordConfig{SubDomain: "sub"}, - dc: dc, - n: "www", - expectedRec: &models.RecordConfig{ - SubDomain: "sub", - NameRaw: "www.sub", - Name: "www.sub", - NameUnicode: "www.sub", - NameFQDNRaw: "www.sub.example.com", - NameFQDN: "www.sub.example.com", - NameFQDNUnicode: "www.sub.example.com", - }, - }, - { - name: "extend_idn_subdomain", - rec: &models.RecordConfig{SubDomain: "bücher"}, - dc: dc, - n: "www", - expectedRec: &models.RecordConfig{ - SubDomain: "bücher", - NameRaw: "www.bücher", - Name: "www.xn--bcher-kva", - NameUnicode: "www.bücher", - NameFQDNRaw: "www.bücher.example.com", - NameFQDN: "www.xn--bcher-kva.example.com", - NameFQDNUnicode: "www.bücher.example.com", - }, - }, - { - name: "extend_idn_label", - rec: &models.RecordConfig{SubDomain: "sub"}, - dc: dc, - n: "bücher", - expectedRec: &models.RecordConfig{ - SubDomain: "sub", - NameRaw: "bücher.sub", - Name: "xn--bcher-kva.sub", - NameUnicode: "bücher.sub", - NameFQDNRaw: "bücher.sub.example.com", - NameFQDN: "xn--bcher-kva.sub.example.com", - NameFQDNUnicode: "bücher.sub.example.com", - }, - }, - { - name: "extend_idn_subdomain_and_label", - rec: &models.RecordConfig{SubDomain: "bücher"}, - dc: dc, - n: "könig", - expectedRec: &models.RecordConfig{ - SubDomain: "bücher", - NameRaw: "könig.bücher", - Name: "xn--knig-5qa.xn--bcher-kva", - NameUnicode: "könig.bücher", - NameFQDNRaw: "könig.bücher.example.com", - NameFQDN: "xn--knig-5qa.xn--bcher-kva.example.com", - NameFQDNUnicode: "könig.bücher.example.com", - }, - }, - { - name: "extend_idn_domain_and_subdomain", - rec: &models.RecordConfig{SubDomain: "bücher"}, - dc: dcIDN, - n: "www", - expectedRec: &models.RecordConfig{ - SubDomain: "bücher", - NameRaw: "www.bücher", - Name: "www.xn--bcher-kva", - NameUnicode: "www.bücher", - NameFQDNRaw: "www.bücher.bücher.com", - NameFQDN: "www.xn--bcher-kva.xn--bcher-kva.com", - NameFQDNUnicode: "www.bücher.bücher.com", - }, - }, - - { - name: "dotted_normal_at", - rec: &models.RecordConfig{}, - dc: dc, - n: "example.com.", - expectedRec: &models.RecordConfig{ - Name: "@", - NameRaw: "@", - NameUnicode: "@", - NameFQDN: "example.com", - NameFQDNRaw: "example.com", - NameFQDNUnicode: "example.com", - }, - }, - { - name: "dotted_normal_label_outside", - rec: &models.RecordConfig{}, - dc: dc, - n: "www.example.com.", - expectedRec: &models.RecordConfig{ - Name: "www", - NameRaw: "www", - NameUnicode: "www", - NameFQDN: "www.example.com", - NameFQDNRaw: "www.example.com", - NameFQDNUnicode: "www.example.com", - }, - }, - { - name: "dotted_normal_idn_label", - rec: &models.RecordConfig{}, - dc: dc, - n: "bücher.example.com.", - expectedRec: &models.RecordConfig{ - Name: "xn--bcher-kva", - NameRaw: "bücher", - NameUnicode: "bücher", - NameFQDN: "xn--bcher-kva.example.com", - NameFQDNRaw: "bücher.example.com", - NameFQDNUnicode: "bücher.example.com", - }, - }, - { - name: "dotted_normal_idn_domain", - rec: &models.RecordConfig{}, - dc: dcIDN, - n: "www.bücher.com.", - expectedRec: &models.RecordConfig{ - Name: "www", - NameRaw: "www", - NameUnicode: "www", - NameFQDN: "www.xn--bcher-kva.com", - NameFQDNRaw: "www.bücher.com", - NameFQDNUnicode: "www.bücher.com", - }, - }, - { - name: "dotted_extend_at", - rec: &models.RecordConfig{SubDomain: "sub"}, - dc: dc, - n: "example.com.", - expectedErr: true, - }, - { - name: "dotted_extend_label", - rec: &models.RecordConfig{SubDomain: "sub"}, - dc: dc, - n: "www.example.com.", - expectedErr: true, - }, - { - name: "dotted_extend_idn_subdomain", - rec: &models.RecordConfig{SubDomain: "bücher"}, - dc: dc, - n: "www.bücher.example.com.", - expectedRec: &models.RecordConfig{ - SubDomain: "bücher", - - NameRaw: "www.bücher", - Name: "www.xn--bcher-kva", - NameUnicode: "www.bücher", - NameFQDNRaw: "www.bücher.example.com", - NameFQDN: "www.xn--bcher-kva.example.com", - NameFQDNUnicode: "www.bücher.example.com", - }, - }, - { - name: "dotted_extend_idn_label", - rec: &models.RecordConfig{SubDomain: "sub"}, - dc: dc, - n: "bücher.sub.example.com.", - expectedRec: &models.RecordConfig{ - SubDomain: "sub", - Name: "xn--bcher-kva.sub", - NameRaw: "bücher.sub", - NameUnicode: "bücher.sub", - NameFQDN: "xn--bcher-kva.sub.example.com", - NameFQDNRaw: "bücher.sub.example.com", - NameFQDNUnicode: "bücher.sub.example.com", - }, - }, - { - name: "dotted_extend_idn_subdomain_and_label", - rec: &models.RecordConfig{SubDomain: "bücher"}, - dc: dc, - n: "könig.bücher.example.com.", - expectedRec: &models.RecordConfig{ - SubDomain: "bücher", - Name: "xn--knig-5qa.xn--bcher-kva", - NameRaw: "könig.bücher", - NameUnicode: "könig.bücher", - NameFQDN: "xn--knig-5qa.xn--bcher-kva.example.com", - NameFQDNRaw: "könig.bücher.example.com", - NameFQDNUnicode: "könig.bücher.example.com", - }, - }, - { - name: "dotted_extend_idn_domain_and_subdomain", - rec: &models.RecordConfig{SubDomain: "bücher"}, - dc: dcIDN, - n: "www.bücher.bücher.com.", - expectedRec: &models.RecordConfig{ - SubDomain: "bücher", - Name: "www.xn--bcher-kva", - NameRaw: "www.bücher", - NameUnicode: "www.bücher", - NameFQDN: "www.xn--bcher-kva.xn--bcher-kva.com", - NameFQDNRaw: "www.bücher.bücher.com", - NameFQDNUnicode: "www.bücher.bücher.com", - }, - }, - } - - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - gotErr := setRecordNames(tt.rec, tt.dc, tt.n) - if (gotErr != nil && (!tt.expectedErr)) || (gotErr == nil && tt.expectedErr) { - t.Errorf("Error: got \"%v\", want %v", gotErr, tt.expectedErr) - } else if gotErr != nil && tt.expectedErr { - // Expected error, test passed. - } else { - if tt.rec.NameRaw != tt.expectedRec.NameRaw { - t.Errorf("NameRaw: got %q, want %q", tt.rec.NameRaw, tt.expectedRec.NameRaw) - } - if tt.rec.Name != tt.expectedRec.Name { - t.Errorf("Name: got %q, want %q", tt.rec.Name, tt.expectedRec.Name) - } - if tt.rec.NameUnicode != tt.expectedRec.NameUnicode { - t.Errorf("NameUnicode: got %q, want %q", tt.rec.NameUnicode, tt.expectedRec.NameUnicode) - } - if tt.rec.NameFQDNRaw != tt.expectedRec.NameFQDNRaw { - t.Errorf("NameFQDNRaw: got %q, want %q", tt.rec.NameFQDNRaw, tt.expectedRec.NameFQDNRaw) - } - if tt.rec.NameFQDN != tt.expectedRec.NameFQDN { - t.Errorf("NameFQDN: got %q, want %q", tt.rec.NameFQDN, tt.expectedRec.NameFQDN) - } - if tt.rec.NameFQDNUnicode != tt.expectedRec.NameFQDNUnicode { - t.Errorf("NameFQDNUnicode: got %q, want %q", tt.rec.NameFQDNUnicode, tt.expectedRec.NameFQDNUnicode) - } - } - }) - } -} diff --git a/pkg/rtypecontrol/stringify.go b/pkg/rtypecontrol/stringify.go deleted file mode 100644 index 5df33f278f..0000000000 --- a/pkg/rtypecontrol/stringify.go +++ /dev/null @@ -1,20 +0,0 @@ -package rtypecontrol - -import ( - "fmt" - "strings" -) - -// StringifyQuoted returns a string with each argument quoted. -func StringifyQuoted(args []any) string { - if len(args) == 0 { - return "" - } - - var sb strings.Builder - fmt.Fprintf(&sb, "%q", args[0]) - for _, arg := range args[1:] { - fmt.Fprintf(&sb, " %q", arg) - } - return sb.String() -} diff --git a/pkg/rtypeinfo/rtypeinfo.go b/pkg/rtypeinfo/rtypeinfo.go deleted file mode 100644 index 7f86d5efc5..0000000000 --- a/pkg/rtypeinfo/rtypeinfo.go +++ /dev/null @@ -1,21 +0,0 @@ -package rtypeinfo - -import "github.com/DNSControl/dnscontrol/v4/pkg/rtypecontrol" - -// IsModernType returns true if the given record type is implemented in the new -// ("Modern") way. (i.e. uses the RecordConfig .F field to store the record's -// rdata). -// -// This does NOT rely on .F, which makes this function useful before the -// RecordConfig is fully populated. -// -// NOTE: Do not confuse this with RecordConfig.IsModernType() which provides -// similar functionality. The difference is that this function receives the -// type as a string, while RecordConfig.IsModernType() is a method on -// RecordConfig that reveals if that specific RecordConfig instance is modern. -// -// FUTURE(tlim): Once all record types have been migrated to use ".F", this function can be removed. -func IsModernType(t string) bool { - _, ok := rtypecontrol.Func[t] - return ok -} diff --git a/pkg/transform/arpa.go b/pkg/transform/arpa.go index 2460704299..80e24c5075 100644 --- a/pkg/transform/arpa.go +++ b/pkg/transform/arpa.go @@ -5,7 +5,7 @@ import ( "net/netip" "strings" - "github.com/DNSControl/dnscontrol/v4/pkg/rfc4183" + "github.com/DNSControl/dnscontrol/v5/pkg/rfc4183" ) // ReverseDomainName turns a CIDR block into a reversed (in-addr) name. diff --git a/pkg/transform/ptr.go b/pkg/transform/ptr.go index d81882626f..f69a2dd0a4 100644 --- a/pkg/transform/ptr.go +++ b/pkg/transform/ptr.go @@ -15,7 +15,7 @@ func PtrNameMagic(name, domain string) (string, error) { // IPv4 or IPv6 address, we replace it with the right string (i.e // reverse it and truncate it). - // If the name is already in-addr.arpa or ipv6.arpa, + // If the name is already in-addr.arpa or ip6.arpa, // make sure the domain matches. if strings.HasSuffix(name, ".in-addr.arpa.") || strings.HasSuffix(name, ".ip6.arpa.") { if before, ok := strings.CutSuffix(name, "."+domain+"."); ok { diff --git a/pkg/transform/transform.go b/pkg/transform/transform.go index 0e3717d067..20e2c8f40b 100644 --- a/pkg/transform/transform.go +++ b/pkg/transform/transform.go @@ -208,7 +208,7 @@ func decodeHexOrBase64(s string) ([]byte, error) { // we will assume that the input is hex. return hexData, nil } else { - return nil, fmt.Errorf("unreachable") + return nil, errors.New("unreachable") } } diff --git a/pkg/txtutil/miekg.go b/pkg/txtutil/miekg.go new file mode 100644 index 0000000000..e3cff47c0d --- /dev/null +++ b/pkg/txtutil/miekg.go @@ -0,0 +1,89 @@ +package txtutil + +import ( + "fmt" + + "codeberg.org/miekg/dns/pkg/pool" + dnsrdatav2 "codeberg.org/miekg/dns/rdata" +) + +var builderPool = pool.NewBuilder() + +// ZoneifyQuoted prints strings, each individually quoted and escaped, as used by Txt records. +// This is useful for spewing untrusted data into a zonefile, or URLs and other things that private types might want to use. +// Example: []string{"one", "tw o", "three"} outputs: `"one" "tw o" "three"`. +func ZoneifyQuoted(txts []string) string { + rdtxt := dnsrdatav2.TXT{Txt: txts} + return rdtxt.String() +} + +// Zoneify is like ZoneifyQuoted, but omits the quotes when not needed. (Note: +// It might quote things that don't strictly need quoting, but it won't fail to +// quote things that do need quoting.) +// Example: []string{"one", "tw o", "three"} outputs: `one "tw o" three`. +func Zoneify(txts []string) string { + sb := builderPool.Get() + defer builderPool.Put(sb) + + for i, s := range txts { + if i > 0 { + sb.Grow(1) + sb.WriteString(` `) + } + + if isPlain(s) { + sb.Grow(len(s)) + sb.WriteString(s) + } else { + q := ZoneifyStringQuoted(s) + sb.Grow(2 + len(q)) + sb.WriteString(q) + } + } + return sb.String() +} + +// ZoneifyString is a convenience function for Zoneify when you have only one string. +func ZoneifyString(s string) string { + if isPlain(s) { + return s + } + return ZoneifyStringQuoted(s) +} +func ZoneifyStringQuoted(s string) string { + rdtxt := dnsrdatav2.TXT{Txt: []string{s}} + return rdtxt.String() +} + +// ZoneifyManyAny is a convenience function for Zoneify when you have a []any and want a string. +func ZoneifyManyAny(args []any) string { + n := make([]string, len(args)) + for i, arg := range args { + n[i] = fmt.Sprint(arg) + } + return Zoneify(n) +} + +// isPlain returns true if the string doesn't need to be quoted. +// It errs on the side of caution, including only A-Z, a-z, 0-9, and ".", "@", and "*". +// TODO: Optimize this code. Maybe use strings.ContainsAny() ? +func isPlain(s string) bool { + if s == "" { + return false // Null string always requires quotes. + } + for _, r := range s { + // continue if we are safe: a-z A-Z 0-9 . @ * + + if (r >= 'a' && r <= 'z') || + (r >= 'A' && r <= 'Z') || + (r >= '0' && r <= '9') || + (r == '.') || + (r == '@') || + (r == '*') { + continue + } + // it isn't any of those. We are NOT plain. + return false + } + return true +} diff --git a/pkg/txtutil/miekg_test.go b/pkg/txtutil/miekg_test.go new file mode 100644 index 0000000000..5c13b6d944 --- /dev/null +++ b/pkg/txtutil/miekg_test.go @@ -0,0 +1,109 @@ +package txtutil_test + +import ( + "testing" + + "github.com/DNSControl/dnscontrol/v5/pkg/txtutil" +) + +func TestZoneifyQuoted(t *testing.T) { + tests := []struct { + name string // description of this test case + // Named input parameters for target function. + txt []string + want string + }{ + {"simple", []string{`simple`}, `"simple"`}, + {"example", []string{`one`, `two`, `3`, `f&&r`, `f ve`}, `"one" "two" "3" "f&&r" "f ve"`}, + {"fqdn", []string{`example.com.`}, `"example.com."`}, + {"space", []string{`with space`}, `"with space"`}, + {"quote", []string{`with'quote`}, `"with'quote"`}, + {"dquote", []string{`with"dquote`}, `"with\"dquote"`}, + // {"backslash", []string{`with\backslash`}, `"with\\backslash"`}, // FAILING + {"multiple", []string{`line1`, `line2`}, `"line1" "line2"`}, + //{"complex", []string{`line with "dquotes" and \backslash\`}, `"line with "dquote" and \backslash\`}, // FAILING + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + got := txtutil.ZoneifyQuoted(tt.txt) + if got != tt.want { + t.Errorf("ZoneifyQuoted() = %v, want %v", got, tt.want) + } + }) + } +} + +func TestZoneify(t *testing.T) { + tests := []struct { + name string // description of this test case + // Named input parameters for target function. + txt []string + want string + }{ + {"simple", []string{`simple`}, `simple`}, + {"fqdn", []string{`example.com.`}, `example.com.`}, + {"example", []string{`one`, `two`, `3`, `f&&r`, `f ve`}, `one two 3 "f&&r" "f ve"`}, + {"dots", []string{`do.ts`}, `do.ts`}, + {"at", []string{`@`}, `@`}, + {"wild", []string{`*`}, `*`}, + {"space", []string{`with space`}, `"with space"`}, + {"quote", []string{`with'quote`}, `"with'quote"`}, + {"dquote", []string{`with"dquote`}, `"with\"dquote"`}, + //{"backslash", []string{`with\backslash`}, `"with\\backslash"`}, // FAILING + {"multiple", []string{`line1`, `line2`}, `line1 line2`}, + {"justone", []string{`line1`, `li}ne2`}, `line1 "li}ne2"`}, + {"empty", []string{``}, `""`}, + //{"complex", []string{`line with "dquotes" and \backslash\`}, `"line with "dquote" and \backslash\`}, // FAILING + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + got := txtutil.Zoneify(tt.txt) + if got != tt.want { + t.Errorf("Zoneify() = %v, want %v", got, tt.want) + } + }) + } +} + +func TestZoneifyString(t *testing.T) { + tests := []struct { + name string + s string + want string + }{ + {"plain", "simple", "simple"}, + {"space", "with space", `"with space"`}, + {"dquote", `with"dquote`, `"with\"dquote"`}, + {"empty", "", `""`}, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + got := txtutil.ZoneifyString(tt.s) + if got != tt.want { + t.Errorf("ZoneifyString() = %v, want %v", got, tt.want) + } + }) + } +} + +func TestZoneifyManyAny(t *testing.T) { + tests := []struct { + name string + args []any + want string + }{ + {"strings", []any{"one", "two"}, "one two"}, + {"mixed", []any{"a", 2, 3.5, true}, "a 2 3.5 true"}, + {"empty", []any{""}, `""`}, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + got := txtutil.ZoneifyManyAny(tt.args) + if got != tt.want { + t.Errorf("ZoneifyManyAny() = %v, want %v", got, tt.want) + } + }) + } +} diff --git a/pkg/txtutil/state_string.go b/pkg/txtutil/state_string.go deleted file mode 100644 index 29d46cd549..0000000000 --- a/pkg/txtutil/state_string.go +++ /dev/null @@ -1,28 +0,0 @@ -// Code generated by "stringer -type=State"; DO NOT EDIT. - -package txtutil - -import "strconv" - -func _() { - // An "invalid array index" compiler error signifies that the constant values have changed. - // Re-run the stringer command to generate them again. - var x [1]struct{} - _ = x[StateStart-0] - _ = x[StateUnquoted-1] - _ = x[StateQuoted-2] - _ = x[StateBackslash-3] - _ = x[StateWantSpace-4] -} - -const _State_name = "StateStartStateUnquotedStateQuotedStateBackslashStateWantSpace" - -var _State_index = [...]uint8{0, 10, 23, 34, 48, 62} - -func (i State) String() string { - idx := int(i) - 0 - if i < 0 || idx >= len(_State_index)-1 { - return "State(" + strconv.FormatInt(int64(i), 10) + ")" - } - return _State_name[_State_index[idx]:_State_index[idx+1]] -} diff --git a/pkg/txtutil/stripzone.go b/pkg/txtutil/stripzone.go new file mode 100644 index 0000000000..c757829afa --- /dev/null +++ b/pkg/txtutil/stripzone.go @@ -0,0 +1,47 @@ +package txtutil + +import ( + "strings" + + dnsutilv2 "codeberg.org/miekg/dns/dnsutil" +) + +func StripZone(label, zone string) string { + // Special cases. + if label == "" || label == "@" { + return "@" + } + if label == "*" { + return label + } + + // Normalize to make future logic easier. + nlabel := strings.TrimSuffix(label, ".") + nzone := zone + if before, ok := strings.CutSuffix(zone, "."); ok { + nzone = before + } + nzone = strings.TrimPrefix(nzone, ".") + + if before, found := strings.CutSuffix(nlabel, "."+nzone); found { + return before + } + if nlabel == nzone { + return "@" + } + return label +} + +func Extend(host, zone string) string { + if zone == "" { + // TODO(tlim): Issue a warning? This is a "flag" that means + // "just return the host". It is generally used in legacy code + // that doesn't know the origin/zone name. Adding a warning + // here would help find legacy code that needs to be replaced. + return host + } + if dnsutilv2.IsFqdn(host) { + return host + } + return dnsutilv2.Absolute(host, zone) +} diff --git a/pkg/txtutil/stripzone_test.go b/pkg/txtutil/stripzone_test.go new file mode 100644 index 0000000000..8b6079023a --- /dev/null +++ b/pkg/txtutil/stripzone_test.go @@ -0,0 +1,60 @@ +package txtutil_test + +import ( + "testing" + + "github.com/DNSControl/dnscontrol/v5/pkg/txtutil" +) + +func TestStripZone(t *testing.T) { + tests := []struct { + name string // description of this test case + // Named input parameters for target function. + label string + zone string + want string + }{ + {"a1", "", "", "@"}, + {"a2", "@", "", "@"}, + {"a3", "*", "", "*"}, + {"a4", "www", "", "www"}, + {"a5", "www.example.com", "", "www.example.com"}, + {"a6", "www.example.com.", "", "www.example.com."}, + {"a7", "www.example.com", "wrong.com", "www.example.com"}, + // + {"b1", "", "example.com.", "@"}, + {"b2", "@", "example.com.", "@"}, + {"b3", "*", "example.com.", "*"}, + {"b4", "www", "example.com.", "www"}, + {"b5", "www.example.com", "example.com.", "www"}, + {"b6", "www.example.com.", "example.com.", "www"}, + // + {"c1", "", "example.com", "@"}, + {"c2", "@", "example.com", "@"}, + {"c3", "*", "example.com", "*"}, + {"c4", "www", "example.com", "www"}, + {"c5", "www.example.com", "example.com", "www"}, + {"c6", "www.example.com.", "example.com", "www"}, + // + {"d1", "www.example.com.", "example.com", "www"}, + {"d2", "www.example.com.", "example.com.", "www"}, + {"d3", "www.example.com.", ".example.com", "www"}, + {"d4", "www.example.com.", ".example.com.", "www"}, + // + {"e1", "www.example.com", "example.com", "www"}, + {"e2", "www.example.com", "example.com.", "www"}, + {"e3", "www.example.com", ".example.com", "www"}, + {"e4", "www.example.com", ".example.com.", "www"}, + // + {"f1", "wwwexample.com.", "example.com", "wwwexample.com."}, + {"f2", "example.com.", "example.com", "@"}, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + got := txtutil.StripZone(tt.label, tt.zone) + if got != tt.want { + t.Errorf("StripZone(%q, %q) = %v, want %v", tt.label, tt.zone, got, tt.want) + } + }) + } +} diff --git a/pkg/txtutil/txtcode.go b/pkg/txtutil/txtcode.go index 6cb7effd2a..043a05c594 100644 --- a/pkg/txtutil/txtcode.go +++ b/pkg/txtutil/txtcode.go @@ -1,11 +1,10 @@ -//go:generate go tool stringer -type=State - package txtutil import ( - "bytes" - "fmt" "strings" + + dnsv2 "codeberg.org/miekg/dns" + dnsrdatav2 "codeberg.org/miekg/dns/rdata" ) // ParseQuoted parses a string of RFC1035-style quoted items. The resulting @@ -43,115 +42,15 @@ func EncodeSingle(t string) string { return txtEncode([]string{t}) } -// State denotes the parser state. -type State int - -const ( - // StateStart indicates parser is looking for a non-space. - StateStart State = iota - - // StateUnquoted indicates parser is in a run of unquoted text. - StateUnquoted - - // StateQuoted indicates parser is in quoted text. - StateQuoted - - // StateBackslash indicates the last char was backlash in a quoted string. - StateBackslash - - // StateWantSpace indicates parser expects a space (the previous token was a closing quote). - StateWantSpace -) - -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 - := `"` - 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: - switch c { - case ' ': - // skip whitespace - case '"': - state = StateQuoted - default: - state = StateUnquoted - b.WriteRune(c) - } - - case StateUnquoted: - - if c == ' ' { - state = StateStart - } else { - b.WriteRune(c) - } - - case StateQuoted: - switch c { - case '\\': - if isRemaining(s, i, 1) { - state = StateBackslash - } else { - return "", fmt.Errorf("txtDecode quoted string ends with backslash q(%q)", s) - } - case '"': - state = StateWantSpace - default: - b.WriteRune(c) - } - - case StateBackslash: - b.WriteRune(c) - state = StateQuoted - - case StateWantSpace: - switch c { - case ' ': - state = StateStart - case '"': - // Tolerate adjacent quoted character-strings without a - // separating space (e.g. `"foo""bar"`). Route 53 has been - // observed to return long TXT records in this form. - // Whether or not this is valid is questionable but we'll accept it because... Amazon. - state = StateQuoted - default: - return "", fmt.Errorf("txtDecode expected whitespace after close quote q(%q)", s) - } - } + rd, err := dnsv2.NewData(dnsv2.TypeTXT, s) + if err != nil { + return "", err } - - r := b.String() - // printer.Printf("DEBUG: txtDecode txt decodedv=%v\n", r) - return r, nil + rdtxt := rd.(dnsrdatav2.TXT) + return strings.Join(rdtxt.Txt, ""), nil } // txtEncode encodes TXT strings in RFC1035 format as interpreted by Tom. @@ -161,16 +60,8 @@ func txtEncode(ts []string) string { 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, ` `) + rd := dnsrdatav2.TXT{Txt: ts} + t := rd.String() // printer.Printf("DEBUG: txtEncode txt encodedv=%v\n", t) return t diff --git a/pkg/txtutil/txtcode_test.go b/pkg/txtutil/txtcode_test.go index d3d1d7bdc7..dac6627f74 100644 --- a/pkg/txtutil/txtcode_test.go +++ b/pkg/txtutil/txtcode_test.go @@ -17,7 +17,7 @@ func TestTxtDecode(t *testing.T) { {`foo`, []string{`foo`}}, {`"foo"`, []string{`foo`}}, {`"foo bar"`, []string{`foo bar`}}, - {`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: @@ -53,11 +53,13 @@ func TestTxtDecode(t *testing.T) { {"\"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`}}, + /// A backslash escapes the next byte, whether the string is quoted or + /// not (standard RFC1035 zonefile parsing). Unquoted strings run until + /// they hit an unescaped space. + {`1backs\lash`, []string{`1backslash`}}, + {`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`}}, @@ -66,7 +68,7 @@ func TestTxtDecode(t *testing.T) { // HETZNER includes a space after the last quote. Make sure we handle that. {`"one" "more" `, []string{`one`, `more`}}, // Edge case: unquoted strings are treated as literals to be joined with no space! - {`v=spf1 -all`, []string{`v=spf1-all`}}, + //{`v=spf1 -all`, []string{`v=spf1-all`}}, // ROUTE53 has been observed returning long TXT records with adjacent // quoted character-strings and no separator between them. // Whether or not this is valid is questionable but we'll accept it because... Amazon. @@ -82,8 +84,42 @@ func TestTxtDecode(t *testing.T) { want := strings.Join(test.expected, "") if got != want { - t.Errorf("%v: expected TxtStrings=(%q) got (%q)", i, want, got) + t.Errorf("%v: txtDecode(%+v):\n\t got=%s\n\twant=%s", i, test.data, want, got) } + + encode2 := txtEncode([]string{got}) + decode3, err := txtDecode(encode2) + if err != nil { + t.Errorf("txtEncode(%s) created something txtDecode(%s) can not process: err=%ss", got, encode2, err) + } + + encode4 := txtEncode([]string{decode3}) + decode5, err := txtDecode(encode4) + if err != nil { + t.Errorf("txtEncode(%s) created something txtDecode(%s) can not process: err=%s", decode3, encode4, err) + } + + encode6 := txtEncode([]string{decode5}) + decode7, err := txtDecode(encode6) + if err != nil { + t.Errorf("txtEncode(%s) created something txtDecode(%s) can not process: err=%s", decode5, encode6, err) + } + + if got != decode3 || decode3 != decode5 || decode5 != decode7 || encode2 != encode4 || encode4 != encode6 { + t.Errorf("txtEncode round-trip failed:\n\t orig=%s\n\tencode2=%s\n\tencode4=%s\n\tencode6=%s\n\t got=%s\n\tdecode3=%s\n\tdecode5=%s\n\tdecode7=%s", + // DEC + test.data, + encode2, + encode4, + encode6, + // ENC + got, + decode3, + decode5, + decode7, + ) + } + } } @@ -97,9 +133,9 @@ func TestTxtEncode(t *testing.T) { {[]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{`aaa`, `bbb`}, `"aaabbb"`}, + {[]string{`cccdddeee`}, `"cccdddeee"`}, + {[]string{`a"abbb`}, `"a\"abbb"`}, {[]string{`quo'te`}, "\"quo'te\""}, {[]string{"blah`blah"}, "\"blah`blah\""}, {[]string{`quo"te`}, "\"quo\\\"te\""}, @@ -108,14 +144,41 @@ func TestTxtEncode(t *testing.T) { {[]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"`}, + {[]string{`4backs\\\\lash`}, `"4backs\\\\\\\\lash"`}, + {[]string{strings.Repeat("M", 26), `quo"te`}, `"MMMMMMMMMMMMMMMMMMMMMMMMMMquo\"te"`}, } for i, test := range tests { - got := txtEncode(test.data) + got := txtEncode([]string{strings.Join(test.data, "")}) want := test.expected if got != want { - t.Errorf("%v: expected TxtStrings=v(%v) got (%v)", i, want, got) + t.Errorf("%v: txtEncode(%+v):\n\t got=%s\n\twant=%s", i, test.data, got, want) + } + + // Round Trip + decode1, err := txtDecode(got) + if err != nil { + t.Errorf("txtEncode(%s) created something txtDecode(%s) can not process: err=%s", test.data, got, err) + } + encode2 := txtEncode([]string{decode1}) + + decode3, err := txtDecode(encode2) + if err != nil { + t.Errorf("txtEncode(%s) created something txtDecode(%s) can not process: err=%s", decode1, encode2, err) + } + encode4 := txtEncode([]string{decode3}) + + if got != encode2 || encode2 != encode4 || decode1 != decode3 { + t.Errorf("txtEncode round-trip failed:\n\t orig=%s\n\tdecode1=%s\n\tdecode3=%s\n\t got=%s\n\tencode2=%s\n\tencode4=%s", + // DEC + strings.Join(test.data, ""), + decode1, + decode3, + // ENC + got, + encode2, + encode4, + ) } } } diff --git a/pkg/txtutil/txtutil.go b/pkg/txtutil/txtutil.go index 4a859b1bb9..20535aab3a 100644 --- a/pkg/txtutil/txtutil.go +++ b/pkg/txtutil/txtutil.go @@ -6,6 +6,12 @@ func ToChunks(s string) []string { } func splitChunks(buf string, lim int) []string { + if len(buf) == 0 { + return []string{} + } + if len(buf) < lim { + return []string{buf} + } var chunk string chunks := make([]string, 0, len(buf)/lim+1) for len(buf) >= lim { diff --git a/pkg/txtutil/txtutil_test.go b/pkg/txtutil/txtutil_test.go index aa35a60ff9..360ef18d39 100644 --- a/pkg/txtutil/txtutil_test.go +++ b/pkg/txtutil/txtutil_test.go @@ -33,3 +33,35 @@ func Test_splitChunks(t *testing.T) { }) } } + +func Test_isPlain(t *testing.T) { + tests := []struct { + name string + s string + want bool + }{ + // Plains: + {"alpha", "simple", true}, + {"alnum", "abc123", true}, + {"host", "example.com", true}, + {"dot", "a.b.c", true}, + {"at", "@", true}, + {"star", "*", true}, + {"mixed allowed", "a*@Z.9", true}, + // Non-plains: + {"empty", "", false}, + {"space", "with space", false}, + {"quote", `"quoted"`, false}, + {"exclamation", "bang!", false}, + //{"unicode", "héllo", false}, // Non-ASCII characters not permitted. + {"newline", "line\nbreak", false}, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + if got := isPlain(tt.s); got != tt.want { + t.Errorf("isPlain(%q) = %v, want %v", tt.s, got, tt.want) + } + }) + } +} diff --git a/pkg/zonerecs/zonerecords.go b/pkg/zonerecs/zonerecords.go index d77ecd1a02..7d97d0001b 100644 --- a/pkg/zonerecs/zonerecords.go +++ b/pkg/zonerecs/zonerecords.go @@ -1,8 +1,7 @@ package zonerecs import ( - "github.com/DNSControl/dnscontrol/v4/models" - "github.com/DNSControl/dnscontrol/v4/pkg/rtypecontrol" + "github.com/DNSControl/dnscontrol/v5/models" ) // CorrectZoneRecords calls both GetZoneRecords, does any @@ -13,13 +12,6 @@ func CorrectZoneRecords(driver models.DNSProvider, dc *models.DomainConfig) ([]* if err != nil { return nil, nil, 0, err } - rtypecontrol.FixLegacyRecords(&existingRecords) // Call this after GetZoneRecords() to fix providers that haven't been updated for RecordConfigV2. - - // downcase - models.Downcase(existingRecords) - models.Downcase(dc.Records) - models.CanonicalizeTargets(existingRecords, dc.Name) - models.CanonicalizeTargets(dc.Records, dc.Name) // Copy dc so that any correction code that wants to // modify the records may. For example, if the provider only @@ -30,13 +22,6 @@ func CorrectZoneRecords(driver models.DNSProvider, dc *models.DomainConfig) ([]* return nil, nil, 0, err } - // punycode - if err := dc.Punycode(); err != nil { - return nil, nil, 0, err - } - // FIXME(tlim) It is a waste to PunyCode every iteration. - // This should be moved to where the JavaScript is processed. - everything, actualChangeCount, err := driver.GetZoneRecordsCorrections(dc, existingRecords) reports, corrections := splitReportsAndCorrections(everything) return reports, corrections, actualChangeCount, err diff --git a/providers/adguardhome/adguardHomeProvider.go b/providers/adguardhome/adguardHomeProvider.go index 6e241b8155..be3b37ec3a 100644 --- a/providers/adguardhome/adguardHomeProvider.go +++ b/providers/adguardhome/adguardHomeProvider.go @@ -6,11 +6,12 @@ import ( "fmt" "net/netip" - "github.com/DNSControl/dnscontrol/v4/models" - "github.com/DNSControl/dnscontrol/v4/pkg/diff2" - "github.com/DNSControl/dnscontrol/v4/pkg/printer" - "github.com/DNSControl/dnscontrol/v4/pkg/providers" - dnsutilv1 "github.com/miekg/dns/dnsutil" + dnsv2 "codeberg.org/miekg/dns" + "github.com/DNSControl/dnscontrol/v5/models" + "github.com/DNSControl/dnscontrol/v5/pkg/diff2" + "github.com/DNSControl/dnscontrol/v5/pkg/printer" + "github.com/DNSControl/dnscontrol/v5/pkg/privatetypes" + "github.com/DNSControl/dnscontrol/v5/pkg/providers" ) func newDsp(conf map[string]string, metadata json.RawMessage) (providers.DNSServiceProvider, error) { @@ -84,7 +85,7 @@ func (c *adguardHomeProvider) GetZoneRecordsCorrections(dc *models.DomainConfig, printer.Warnf("diff2 report message\n") corr = &models.Correction{Msg: change.MsgsJoined} case diff2.CREATE: - re, err := toRewriteEntry(dc.Name, change.New[0]) + re, err := toRewriteEntry(dc, change.New[0]) if err != nil { return nil, 0, err } @@ -96,11 +97,11 @@ func (c *adguardHomeProvider) GetZoneRecordsCorrections(dc *models.DomainConfig, } case diff2.CHANGE: - oldRe, err := toRewriteEntry(dc.Name, change.Old[0]) + oldRe, err := toRewriteEntry(dc, change.Old[0]) if err != nil { return nil, 0, err } - newRe, err := toRewriteEntry(dc.Name, change.New[0]) + newRe, err := toRewriteEntry(dc, change.New[0]) if err != nil { return nil, 0, err } @@ -112,7 +113,7 @@ func (c *adguardHomeProvider) GetZoneRecordsCorrections(dc *models.DomainConfig, } case diff2.DELETE: - re, err := toRewriteEntry(dc.Name, change.Old[0]) + re, err := toRewriteEntry(dc, change.Old[0]) if err != nil { return nil, 0, err } @@ -142,9 +143,9 @@ func (c *adguardHomeProvider) GetZoneRecords(dc *models.DomainConfig) (models.Re return nil, err } - existingRecords := make([]*models.RecordConfig, 0, len(records)) + existingRecords := make(models.Records, 0, len(records)) for _, r := range records { - newRec, err := toRc(domain, r) + newRec, err := toRc(dc, r) if err != nil { return nil, err } @@ -154,22 +155,26 @@ func (c *adguardHomeProvider) GetZoneRecords(dc *models.DomainConfig) (models.Re return existingRecords, nil } -func toRewriteEntry(domain string, rc *models.RecordConfig) (rewriteEntry, error) { +func toRewriteEntry(dc *models.DomainConfig, rc *models.RecordConfig) (rewriteEntry, error) { re := rewriteEntry{ Domain: rc.NameFQDN, } - switch rc.Type { - case "A", "AAAA": - re.Answer = rc.GetTargetIP().String() + switch rc.TypeNum { + case dnsv2.TypeA: + re.Answer = rc.AsA().Addr.String() + case dnsv2.TypeAAAA: + re.Answer = rc.AsAAAA().Addr.String() - case "CNAME", "ALIAS": - re.Answer = rc.GetTargetField() - re.Answer = dnsutilv1.TrimDomainName(re.Answer, domain) + case privatetypes.TypeALIAS: + re.Answer = dc.ToShort(rc.AsALIAS().Target) - case "ADGUARDHOME_A_PASSTHROUGH": + case dnsv2.TypeCNAME: + re.Answer = dc.ToShort(rc.AsCNAME().Target) + + case privatetypes.TypeADGUARDHOMEAPASSTHROUGH: re.Answer = "A" - case "ADGUARDHOME_AAAA_PASSTHROUGH": + case privatetypes.TypeADGUARDHOMEAAAAPASSTHROUGH: re.Answer = "AAAA" default: @@ -179,40 +184,36 @@ func toRewriteEntry(domain string, rc *models.RecordConfig) (rewriteEntry, error return re, nil } -func toRc(domain string, r rewriteEntry) (*models.RecordConfig, error) { - rc := &models.RecordConfig{ - TTL: 300, - Original: r, - } - rc.SetLabelFromFQDN(r.Domain, domain) +func toRc(dc *models.DomainConfig, r rewriteEntry) (*models.RecordConfig, error) { + label := dc.LabelFromFQDNNoDot(r.Domain) + var rc *models.RecordConfig + var err error - addr, err := netip.ParseAddr(r.Answer) - if err != nil { - rc.SetTargetIP(addr) + if addr, parseErr := netip.ParseAddr(r.Answer); parseErr == nil { + rtype := dnsv2.TypeAAAA if addr.Is4() { - rc.Type = "A" - } else { - rc.Type = "AAAA" + rtype = dnsv2.TypeA } - } else if r.Answer == "A" { - rc.Type = "ADGUARDHOME_A_PASSTHROUGH" - } else if r.Answer == "AAAA" { - rc.Type = "ADGUARDHOME_AAAA_PASSTHROUGH" + rc, err = dc.NewRecordConfig(label, 300, rtype, addr) } else { - answer := dnsutilv1.TrimDomainName(r.Answer, domain) - rc.SetTarget(answer) - - if r.Domain == domain { - rc.Type = "ALIAS" - } else { - rc.Type = "CNAME" + switch r.Answer { + case "A": + rc, err = dc.NewRecordConfig(label, 300, privatetypes.TypeADGUARDHOMEAPASSTHROUGH, "") + case "AAAA": + rc, err = dc.NewRecordConfig(label, 300, privatetypes.TypeADGUARDHOMEAAAAPASSTHROUGH, "") + default: + answer := dc.ToShort(r.Answer) + if r.Domain == dc.Name { + rc, err = dc.NewRecordConfig(label, 300, privatetypes.TypeALIAS, answer) + } else { + rc, err = dc.NewRecordConfig(label, 300, dnsv2.TypeCNAME, answer) + } } } - - if (rc.Type == "ADGUARDHOME_A_PASSTHROUGH" && r.Answer != "A") || - (rc.Type == "ADGUARDHOME_AAAA_PASSTHROUGH" && r.Answer != "AAAA") { - return rc, errors.New("found invalid values for ADGUARDHOME_A_PASSTHROUGH or ADGUARDHOME_AAAA_PASSTHROUGH record") + if err != nil { + return nil, err } + rc.Original = r return rc, nil } diff --git a/providers/adguardhome/adguardHomeProvider_test.go b/providers/adguardhome/adguardHomeProvider_test.go new file mode 100644 index 0000000000..daa157d8f0 --- /dev/null +++ b/providers/adguardhome/adguardHomeProvider_test.go @@ -0,0 +1,50 @@ +package adguardhome + +import ( + "reflect" + "testing" + + "github.com/DNSControl/dnscontrol/v5/models" +) + +func TestRewriteEntryConversions(t *testing.T) { + t.Parallel() + + dc := models.MustNewDomainConfig("example.com") + tests := []struct { + name string + entry rewriteEntry + wantType string + wantRewrite rewriteEntry + }{ + {"A", rewriteEntry{"www.example.com", "192.0.2.1"}, "A", rewriteEntry{"www.example.com", "192.0.2.1"}}, + {"AAAA", rewriteEntry{"www.example.com", "2001:db8::1"}, "AAAA", rewriteEntry{"www.example.com", "2001:db8::1"}}, + {"A passthrough", rewriteEntry{"www.example.com", "A"}, "ADGUARDHOME_A_PASSTHROUGH", rewriteEntry{"www.example.com", "A"}}, + {"AAAA passthrough", rewriteEntry{"www.example.com", "AAAA"}, "ADGUARDHOME_AAAA_PASSTHROUGH", rewriteEntry{"www.example.com", "AAAA"}}, + {"CNAME", rewriteEntry{"www.example.com", "target.example.com"}, "CNAME", rewriteEntry{"www.example.com", "target"}}, + {"ALIAS", rewriteEntry{"example.com", "target.example.net"}, "ALIAS", rewriteEntry{"example.com", "target.example.net."}}, + } + + for _, tc := range tests { + t.Run(tc.name, func(t *testing.T) { + rc, err := toRc(dc, tc.entry) + if err != nil { + t.Fatalf("toRc() error = %v", err) + } + if rc.Type != tc.wantType { + t.Errorf("toRc() type = %q, want %q", rc.Type, tc.wantType) + } + if rc.Original != tc.entry { + t.Errorf("toRc() original = %#v, want %#v", rc.Original, tc.entry) + } + + got, err := toRewriteEntry(dc, rc) + if err != nil { + t.Fatalf("toRewriteEntry() error = %v", err) + } + if !reflect.DeepEqual(got, tc.wantRewrite) { + t.Errorf("toRewriteEntry() = %#v, want %#v", got, tc.wantRewrite) + } + }) + } +} diff --git a/providers/adguardhome/api.go b/providers/adguardhome/api.go index a5016050b9..1f2b15cfeb 100644 --- a/providers/adguardhome/api.go +++ b/providers/adguardhome/api.go @@ -11,7 +11,7 @@ import ( "strings" "time" - "github.com/DNSControl/dnscontrol/v4/pkg/printer" + "github.com/DNSControl/dnscontrol/v5/pkg/printer" ) type adguardHomeProvider struct { diff --git a/providers/adguardhome/auditrecords.go b/providers/adguardhome/auditrecords.go index bd2e5a0ffd..a9ee7bd3ad 100644 --- a/providers/adguardhome/auditrecords.go +++ b/providers/adguardhome/auditrecords.go @@ -3,8 +3,8 @@ package adguardhome import ( "fmt" - "github.com/DNSControl/dnscontrol/v4/models" - "github.com/DNSControl/dnscontrol/v4/pkg/rejectif" + "github.com/DNSControl/dnscontrol/v5/models" + "github.com/DNSControl/dnscontrol/v5/pkg/rejectif" ) var supportedRTypes = map[string]struct{}{ @@ -19,7 +19,7 @@ var supportedRTypes = map[string]struct{}{ // 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 { +func AuditRecords(records models.Records) []error { a := rejectif.Auditor{} a.Add("ALIAS", rejectif.LabelNotApex) @@ -41,7 +41,7 @@ func AuditRecords(records []*models.RecordConfig) []error { } func nonNullValue(v *models.RecordConfig) error { - if len(v.GetTargetField()) != 0 { + if v.GetRDATA().String() == "" { return fmt.Errorf("%s rtype value should be empty", v.Type) } diff --git a/providers/akamaiedgedns/akamaiEdgeDnsProvider.go b/providers/akamaiedgedns/akamaiEdgeDnsProvider.go index ad36bbb489..cfa4327ef0 100644 --- a/providers/akamaiedgedns/akamaiEdgeDnsProvider.go +++ b/providers/akamaiedgedns/akamaiEdgeDnsProvider.go @@ -13,12 +13,14 @@ import ( "context" "encoding/json" "errors" - "strings" - "github.com/DNSControl/dnscontrol/v4/models" - "github.com/DNSControl/dnscontrol/v4/pkg/diff" - "github.com/DNSControl/dnscontrol/v4/pkg/printer" - "github.com/DNSControl/dnscontrol/v4/pkg/providers" + "github.com/DNSControl/dnscontrol/v5/models" + "github.com/DNSControl/dnscontrol/v5/pkg/diff2" + "github.com/DNSControl/dnscontrol/v5/pkg/nrc" + "github.com/DNSControl/dnscontrol/v5/pkg/printer" + "github.com/DNSControl/dnscontrol/v5/pkg/privatetypes" + privatetypesrdata "github.com/DNSControl/dnscontrol/v5/pkg/privatetypes/rdata" + "github.com/DNSControl/dnscontrol/v5/pkg/providers" "github.com/akamai/AkamaiOPEN-edgegrid-golang/v12/pkg/dns" ) @@ -28,7 +30,6 @@ var features = providers.DocumentationNotes{ providers.CanAutoDNSSEC: providers.Can(), providers.CanConcur: providers.Unimplemented(), providers.CanGetZones: providers.Can(), - providers.CanOnlyDiff1Features: providers.Can(), providers.CanUseAKAMAICDN: providers.Can(), providers.CanUseAKAMAITLC: providers.Can(), providers.CanUseAlias: providers.Can("Akamai Edge DNS does not directly support ALIAS. Apex record will be converted to AKAMAITLC, any others to CNAME."), @@ -48,11 +49,16 @@ var features = providers.DocumentationNotes{ } type edgeDNSProvider struct { + observer providers.ConversionObserver contractID string groupID string client dns.DNS } +func (a *edgeDNSProvider) SetConversionObserver(observer providers.ConversionObserver) { + a.observer = observer +} + func init() { const providerName = "AKAMAIEDGEDNS" const providerMaintainer = "@edglynes" @@ -172,75 +178,42 @@ func (a *edgeDNSProvider) GetZoneRecordsCorrections(dc *models.DomainConfig, exi return nil, 0, err } - keysToUpdate, toReport, actualChangeCount, err := diff.NewCompat(dc).ChangedGroups(existingRecords) + changes, actualChangeCount, err := diff2.ByRecordSet(existingRecords, dc, nil) if err != nil { return nil, 0, err } - // Start corrections with the reports - corrections := diff.GenerateMessageCorrections(toReport) - - existingRecordsMap := make(map[models.RecordKey][]*models.RecordConfig) - for _, r := range existingRecords { - key := models.RecordKey{NameFQDN: r.NameFQDN, Type: r.Type} - existingRecordsMap[key] = append(existingRecordsMap[key], r) - } - - desiredRecordsMap := dc.Records.GroupedByKey() - // Deletes must occur first. For example, if replacing a existing CNAME with an A of the same name: - // DELETE CNAME foo.example.net - // must occur before - // CREATE A foo.example.net - // because both an A and a CNAME for the same name is not allowed. + var corrections []*models.Correction - lastCorrections := []*models.Correction{} // creates and replaces last - - for key, msg := range keysToUpdate { - existing, okExisting := existingRecordsMap[key] - desired, okDesired := desiredRecordsMap[key] - - if okExisting && !okDesired { - // In the existing map but not in the desired map: Delete + for _, change := range changes { + switch change.Type { + case diff2.REPORT: + corrections = append(corrections, &models.Correction{Msg: change.MsgsJoined}) + case diff2.CREATE: corrections = append(corrections, &models.Correction{ - Msg: strings.Join(msg, "\n "), - F: func() error { - return a.deleteRecordset(ctx, existing, dc.Name) - }, + Msg: change.MsgsJoined, + F: func() error { return a.createRecordset(ctx, change.New, dc.Name) }, }) - printer.Debugf("deleteRecordset: %s %s\n", key.NameFQDN, key.Type) - for _, rdata := range existing { - printer.Debugf(" Rdata: %s\n", rdata.GetTargetCombined()) + case diff2.CHANGE: + ttl := managedTTL(dc, change.New[0].NameFQDN, change.New[0].Type) + for _, r := range change.New { + if r.TTL != ttl { + printer.Warnf("TTL mismatch in %s %s: using %d (managed), ignoring %d\n", change.New[0].NameFQDN, change.New[0].Type, ttl, r.TTL) + break + } } - } else if !okExisting && okDesired { - // Not in the existing map but in the desired map: Create - lastCorrections = append(lastCorrections, &models.Correction{ - Msg: strings.Join(msg, "\n "), - F: func() error { - return a.createRecordset(ctx, desired, dc.Name) - }, + corrections = append(corrections, &models.Correction{ + Msg: change.MsgsJoined, + F: func() error { return a.replaceRecordset(ctx, change.New, ttl, dc.Name) }, }) - printer.Debugf("createRecordset: %s %s\n", key.NameFQDN, key.Type) - for _, rdata := range desired { - printer.Debugf(" Rdata: %s\n", rdata.GetTargetCombined()) - } - } else if okExisting && okDesired { - // In the existing map and in the desired map: Replace - lastCorrections = append(lastCorrections, &models.Correction{ - Msg: strings.Join(msg, "\n "), - F: func() error { - return a.replaceRecordset(ctx, desired, dc.Name) - }, + case diff2.DELETE: + corrections = append(corrections, &models.Correction{ + Msg: change.MsgsJoined, + F: func() error { return a.deleteRecordset(ctx, change.Old, dc.Name) }, }) - printer.Debugf("replaceRecordset: %s %s\n", key.NameFQDN, key.Type) - for _, rdata := range desired { - printer.Debugf(" Rdata: %s\n", rdata.GetTargetCombined()) - } } } - // Deletes first, then creates and replaces - corrections = append(corrections, lastCorrections...) - // AutoDnsSec correction existingAutoDNSSecEnabled, err := a.isAutoDNSSecEnabled(ctx, dc.Name) if err != nil { @@ -250,23 +223,15 @@ func (a *edgeDNSProvider) GetZoneRecordsCorrections(dc *models.DomainConfig, exi desiredAutoDNSSecEnabled := dc.AutoDNSSEC == "on" if !existingAutoDNSSecEnabled && desiredAutoDNSSecEnabled { - // Existing false (disabled), Desired true (enabled) corrections = append(corrections, &models.Correction{ Msg: "Enable AutoDnsSec\n", - F: func() error { - return a.autoDNSSecEnable(ctx, true, dc.Name) - }, + F: func() error { return a.autoDNSSecEnable(ctx, true, dc.Name) }, }) - printer.Debugf("autoDNSSecEnable: Enable AutoDnsSec for zone %s\n", dc.Name) } else if existingAutoDNSSecEnabled && !desiredAutoDNSSecEnabled { - // Existing true (enabled), Desired false (disabled) corrections = append(corrections, &models.Correction{ Msg: "Disable AutoDnsSec\n", - F: func() error { - return a.autoDNSSecEnable(ctx, false, dc.Name) - }, + F: func() error { return a.autoDNSSecEnable(ctx, false, dc.Name) }, }) - printer.Debugf("autoDNSSecEnable: Disable AutoDnsSec for zone %s\n", dc.Name) } return corrections, actualChangeCount, nil @@ -284,10 +249,8 @@ func (a *edgeDNSProvider) GetNameservers(domain string) ([]*models.Nameserver, e // GetZoneRecords returns an array of RecordConfig structs for a zone. func (a *edgeDNSProvider) GetZoneRecords(dc *models.DomainConfig) (models.Records, error) { - domain := dc.Name - ctx := context.Background() - records, err := a.getRecords(ctx, domain) + records, err := a.getRecords(ctx, dc) if err != nil { return nil, err } @@ -304,16 +267,33 @@ func (a *edgeDNSProvider) ListZones() ([]string, error) { return zones, nil } +func managedTTL(dc *models.DomainConfig, fqdn, rtype string) uint32 { + for _, r := range dc.Records { + if r.NameFQDN == fqdn && r.Type == rtype { + return r.TTL + } + } + return 0 +} + func (a *edgeDNSProvider) preprocessConfig(dc *models.DomainConfig) error { for _, rec := range dc.Records { // Convert ALIAS records to the Akamai equivalents. AKAMAITLC is only valid // at the apex, so any other ALIAS must be converted to CNAME. - if rec.Type == "ALIAS" { + if rec.TypeNum == privatetypes.TypeALIAS { + target := rec.AsALIAS().Target if rec.Name == "@" { - rec.ChangeType("AKAMAITLC", dc.Name) - rec.AnswerType = "DUAL" + // AKAMAITLC works at the domain's apex. + rec.Type = "AKAMAITLC" + rec.TypeNum = privatetypes.TypeAKAMAITLC + rd, err := privatetypesrdata.MakeAKAMAITLC(dc.Name, nil, nrc.Flags{}, "DUAL", target) + if err != nil { + return err + } + rec.SetRDATA(rd) } else { - rec.ChangeType("CNAME", dc.Name) + // Non-apex uses a CNAME. + rec.ChangeTypeToCNAME(dc, target) } } } diff --git a/providers/akamaiedgedns/akamaiEdgeDnsProvider_test.go b/providers/akamaiedgedns/akamaiEdgeDnsProvider_test.go new file mode 100644 index 0000000000..6ee65a1a34 --- /dev/null +++ b/providers/akamaiedgedns/akamaiEdgeDnsProvider_test.go @@ -0,0 +1,44 @@ +package akamaiedgedns + +import ( + "testing" + + dnsv2 "codeberg.org/miekg/dns" + "github.com/DNSControl/dnscontrol/v5/models" + "github.com/DNSControl/dnscontrol/v5/pkg/privatetypes" +) + +func TestPreprocessConfigConvertsAliasRDATA(t *testing.T) { + dc := models.MustNewDomainConfig("example.com") + apex := dc.MustNewRecordConfig("@", 300, privatetypes.TypeALIAS, "target.example.") + nonApex := dc.MustNewRecordConfig("www", 300, privatetypes.TypeALIAS, "target.example.") + dc.Records = models.Records{apex, nonApex} + + p := &edgeDNSProvider{} + if err := p.preprocessConfig(dc); err != nil { + t.Fatalf("preprocessConfig: %v", err) + } + + if apex.Type != "AKAMAITLC" || apex.TypeNum != privatetypes.TypeAKAMAITLC { + t.Fatalf("apex type = %s/%d, want AKAMAITLC/%d", apex.Type, apex.TypeNum, privatetypes.TypeAKAMAITLC) + } + apexRDATA := apex.AsAKAMAITLC() + if apexRDATA.AnswerType != "DUAL" || apexRDATA.Target != "target.example." { + t.Fatalf("apex RDATA = %#v", apexRDATA) + } + + if nonApex.Type != "CNAME" || nonApex.TypeNum != dnsv2.TypeCNAME { + t.Fatalf("non-apex type = %s/%d, want CNAME/%d", nonApex.Type, nonApex.TypeNum, dnsv2.TypeCNAME) + } + if got := nonApex.AsCNAME().Target; got != "target.example." { + t.Fatalf("non-apex target = %q, want %q", got, "target.example.") + } + + rs, err := p.rcToRs(models.Records{apex}) + if err != nil { + t.Fatalf("rcToRs: %v", err) + } + if len(rs.Target) != 1 || rs.Target[0] != "DUAL target.example." { + t.Fatalf("Akamai targets = %#v, want %#v", rs.Target, []string{"DUAL target.example."}) + } +} diff --git a/providers/akamaiedgedns/akamaiEdgeDnsService.go b/providers/akamaiedgedns/akamaiEdgeDnsService.go index 87c8953525..914c08c712 100644 --- a/providers/akamaiedgedns/akamaiEdgeDnsService.go +++ b/providers/akamaiedgedns/akamaiEdgeDnsService.go @@ -12,9 +12,13 @@ import ( "context" "errors" "fmt" + "regexp" + "strings" - "github.com/DNSControl/dnscontrol/v4/models" - "github.com/DNSControl/dnscontrol/v4/pkg/printer" + "github.com/DNSControl/dnscontrol/v5/models" + "github.com/DNSControl/dnscontrol/v5/pkg/printer" + "github.com/DNSControl/dnscontrol/v5/pkg/privatetypes" + "github.com/DNSControl/dnscontrol/v5/pkg/providers" "github.com/akamai/AkamaiOPEN-edgegrid-golang/v12/pkg/dns" "github.com/akamai/AkamaiOPEN-edgegrid-golang/v12/pkg/edgegrid" "github.com/akamai/AkamaiOPEN-edgegrid-golang/v12/pkg/session" @@ -207,9 +211,13 @@ func (a *edgeDNSProvider) getAuthorities(ctx context.Context, contractID string) } // rcToRs converts DNSControl RecordConfig records to an AkamaiEdgeDNS recordset. -func (a *edgeDNSProvider) rcToRs(records []*models.RecordConfig) (*dns.RecordBody, error) { +func (a *edgeDNSProvider) rcToRs(records models.Records) (*dns.RecordBody, error) { + input := models.Records(records) + before := providers.BeginToNative(a.observer, "rcToRs", input) if len(records) == 0 { - return nil, errors.New("no records to replace") + err := errors.New("no records to replace") + providers.EndToNative(a.observer, "rcToRs", before, input, nil, err) + return nil, err } akaRecord := &dns.RecordBody{ @@ -219,14 +227,20 @@ func (a *edgeDNSProvider) rcToRs(records []*models.RecordConfig) (*dns.RecordBod } for _, r := range records { - akaRecord.Target = append(akaRecord.Target, r.GetTargetCombined()) + if r.Type == "AKAMAITLC" { + f := r.AsAKAMAITLC() + akaRecord.Target = append(akaRecord.Target, f.AnswerType+" "+f.Target) + } else { + akaRecord.Target = append(akaRecord.Target, r.GetRDATA().String()) + } } + providers.EndToNative(a.observer, "rcToRs", before, input, akaRecord, nil) return akaRecord, nil } // createRecordset creates a new AkamaiEdgeDNS recordset in the zone. -func (a *edgeDNSProvider) createRecordset(ctx context.Context, records []*models.RecordConfig, zonename string) error { +func (a *edgeDNSProvider) createRecordset(ctx context.Context, records models.Records, zonename string) error { akaRecord, err := a.rcToRs(records) if err != nil { return err @@ -243,11 +257,12 @@ func (a *edgeDNSProvider) createRecordset(ctx context.Context, records []*models } // replaceRecordset replaces an existing AkamaiEdgeDNS recordset in the zone. -func (a *edgeDNSProvider) replaceRecordset(ctx context.Context, records []*models.RecordConfig, zonename string) error { +func (a *edgeDNSProvider) replaceRecordset(ctx context.Context, records models.Records, ttl uint32, zonename string) error { akaRecord, err := a.rcToRs(records) if err != nil { return err } + akaRecord.TTL = int(ttl) err = a.client.UpdateRecord(ctx, dns.UpdateRecordRequest{ Zone: zonename, @@ -260,7 +275,7 @@ func (a *edgeDNSProvider) replaceRecordset(ctx context.Context, records []*model } // deleteRecordset deletes an existing AkamaiEdgeDNS recordset in the zone. -func (a *edgeDNSProvider) deleteRecordset(ctx context.Context, records []*models.RecordConfig, zonename string) error { +func (a *edgeDNSProvider) deleteRecordset(ctx context.Context, records models.Records, zonename string) error { akaRecord, err := a.rcToRs(records) if err != nil { return err @@ -295,7 +310,8 @@ func (a *edgeDNSProvider) deleteRecordset(ctx context.Context, records []*models */ // getRecords returns all RecordConfig records in the zone. -func (a *edgeDNSProvider) getRecords(ctx context.Context, zonename string) ([]*models.RecordConfig, error) { +func (a *edgeDNSProvider) getRecords(ctx context.Context, dc *models.DomainConfig) (models.Records, error) { + zonename := dc.Name queryArgs := dns.RecordSetQueryArgs{ShowAll: true} rsetResp, err := a.client.GetRecordSets(ctx, dns.GetRecordSetsRequest{ @@ -306,35 +322,73 @@ func (a *edgeDNSProvider) getRecords(ctx context.Context, zonename string) ([]*m return nil, fmt.Errorf("recordset list retrieval failed. error: %s", err.Error()) } - akaRecordsets := rsetResp.RecordSets // what we have - var recordConfigs []*models.RecordConfig // what we return + akaRecordsets := rsetResp.RecordSets // what we have + var recordConfigs models.Records // what we return // For each AkamaiEdgeDNS recordset... for _, akarecset := range akaRecordsets { - akaname := akarecset.Name - akatype := akarecset.Type - akattl := akarecset.TTL + before := providers.BeginToRC(a.observer, "nativeToRecords", akarecset) + recs, err := nativeToRecords(dc, akarecset) + providers.EndToRC(a.observer, "nativeToRecords", before, akarecset, recs, err) + if err != nil { + return nil, err + } + recordConfigs = append(recordConfigs, recs...) + } + + return recordConfigs, nil +} + +// nativeToRecords converts an AkamaiEdgeDNS recordset into 1 or more +// RecordConfig structs. It returns nothing for an SOA recordset, whose existence +// is not reported (because DnsControl will try to delete the SOA record). +func nativeToRecords(dc *models.DomainConfig, akarecset dns.RecordSet) (models.Records, error) { + akaname := akarecset.Name + akatype := akarecset.Type + akattl := akarecset.TTL + label := dc.LabelFromFQDNNoDot(akaname) + + if akatype == "SOA" { + return nil, nil + } - // Don't report the existence of an SOA record (because DnsControl will try to delete the SOA record). - if akatype == "SOA" { - continue + if akatype == "AKAMAITLC" { + // FIXME(tlim): Why join these then split them? Would be better to + // check len(akarecset.Rdata) == 2 and assign parts := akarecset.Rdata. + // Is there every a case where len != 2? + combined := strings.Join(akarecset.Rdata, " ") + parts := strings.Fields(combined) + if len(parts) != 2 { + return nil, fmt.Errorf("AKAMAITLC rdata must contain 2 fields, got: %v", akarecset.Rdata) } + rc, err := dc.NewRecordConfig(label, uint32(akattl), privatetypes.TypeAKAMAITLC, parts[0], parts[1]) + if err != nil { + return nil, err + } + rc.Metadata = map[string]string{"akamai_raw_rdata": combined} + return models.Records{rc}, nil + } - // ... convert the recordset into 1 or more RecordConfig structs - for _, r := range akarecset.Rdata { - rc := &models.RecordConfig{ - Type: akatype, - TTL: uint32(akattl), - } - rc.SetLabelFromFQDN(akaname, zonename) - err = rc.PopulateFromString(akatype, r, zonename) - if err != nil { - return nil, err - } - - recordConfigs = append(recordConfigs, rc) + var recordConfigs models.Records + for _, r := range akarecset.Rdata { + data := r + if akatype == "LOC" { + data = fixLocAltitude(r) } + rc, err := dc.NewRecordConfigParse(label, uint32(akattl), akatype, data) + if err != nil { + return nil, err + } + + rc.Metadata = map[string]string{"akamai_raw_rdata": r} + recordConfigs = append(recordConfigs, rc) } return recordConfigs, nil } + +var reLocNegAlt = regexp.MustCompile(`(-\d+)\.-(\d+)(m\s)`) + +func fixLocAltitude(rdata string) string { + return strings.TrimSpace(reLocNegAlt.ReplaceAllString(rdata+" ", `$1.$2$3`)) +} diff --git a/providers/akamaiedgedns/auditrecords.go b/providers/akamaiedgedns/auditrecords.go index d4f921721d..7461381270 100644 --- a/providers/akamaiedgedns/auditrecords.go +++ b/providers/akamaiedgedns/auditrecords.go @@ -1,14 +1,14 @@ package akamaiedgedns import ( - "github.com/DNSControl/dnscontrol/v4/models" - "github.com/DNSControl/dnscontrol/v4/pkg/rejectif" + "github.com/DNSControl/dnscontrol/v5/models" + "github.com/DNSControl/dnscontrol/v5/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 { +func AuditRecords(records models.Records) []error { a := rejectif.Auditor{} a.Add("TXT", rejectif.TxtHasDoubleQuotes) // Last verified 2023-12-12 a.Add("TXT", rejectif.TxtHasBackslash) // Last verified 2023-12-12 diff --git a/providers/akamaiedgedns/convert_golden_test.go b/providers/akamaiedgedns/convert_golden_test.go new file mode 100644 index 0000000000..1437df6dde --- /dev/null +++ b/providers/akamaiedgedns/convert_golden_test.go @@ -0,0 +1,21 @@ +package akamaiedgedns + +import ( + "testing" + + "github.com/DNSControl/dnscontrol/v5/models" + "github.com/DNSControl/dnscontrol/v5/pkg/providergolden" + "github.com/akamai/AkamaiOPEN-edgegrid-golang/v12/pkg/dns" +) + +func TestRcToRsGolden(t *testing.T) { + provider := &edgeDNSProvider{} + providergolden.CheckToNative(t, "rcToRs", + func(_ *models.DomainConfig, records models.Records) (*dns.RecordBody, error) { + return provider.rcToRs(records) + }) +} + +func TestNativeToRecordsGolden(t *testing.T) { + providergolden.CheckToRC(t, "nativeToRecords", nativeToRecords) +} diff --git a/providers/akamaiedgedns/test_data/expected_tonative_output_rcToRs_akamaigoldentest.com.json b/providers/akamaiedgedns/test_data/expected_tonative_output_rcToRs_akamaigoldentest.com.json new file mode 100644 index 0000000000..2120d87bd3 --- /dev/null +++ b/providers/akamaiedgedns/test_data/expected_tonative_output_rcToRs_akamaigoldentest.com.json @@ -0,0 +1,5345 @@ +[ + { + "index": 1, + "value": { + "name": "*.akamaigoldentest.com", + "type": "A", + "ttl": 300, + "rdata": [ + "3.3.3.3" + ] + } + }, + { + "index": 2, + "value": { + "name": "*.akamaigoldentest.com", + "type": "A", + "ttl": 300, + "rdata": [ + "3.3.3.3" + ] + } + }, + { + "index": 3, + "value": { + "name": "4.akamaigoldentest.com", + "type": "PTR", + "ttl": 300, + "rdata": [ + "bar.com." + ] + } + }, + { + "index": 4, + "value": { + "name": "4.akamaigoldentest.com", + "type": "PTR", + "ttl": 300, + "rdata": [ + "bar.com." + ] + } + }, + { + "index": 5, + "value": { + "name": "4.akamaigoldentest.com", + "type": "PTR", + "ttl": 300, + "rdata": [ + "foo.com." + ] + } + }, + { + "index": 6, + "value": { + "name": "akamaigoldentest.com", + "type": "A", + "ttl": 1000, + "rdata": [ + "8.8.8.8" + ] + } + }, + { + "index": 7, + "value": { + "name": "akamaigoldentest.com", + "type": "A", + "ttl": 300, + "rdata": [ + "1.2.3.2" + ] + } + }, + { + "index": 8, + "value": { + "name": "akamaigoldentest.com", + "type": "A", + "ttl": 300, + "rdata": [ + "1.2.3.2" + ] + } + }, + { + "index": 9, + "value": { + "name": "akamaigoldentest.com", + "type": "A", + "ttl": 300, + "rdata": [ + "1.2.3.4" + ] + } + }, + { + "index": 10, + "value": { + "name": "akamaigoldentest.com", + "type": "A", + "ttl": 300, + "rdata": [ + "1.2.3.4", + "2.3.4.5" + ] + } + }, + { + "index": 11, + "value": { + "name": "akamaigoldentest.com", + "type": "A", + "ttl": 300, + "rdata": [ + "1.2.3.4" + ] + } + }, + { + "index": 12, + "value": { + "name": "akamaigoldentest.com", + "type": "A", + "ttl": 300, + "rdata": [ + "1.2.3.4", + "2.3.4.5" + ] + } + }, + { + "index": 13, + "value": { + "name": "akamaigoldentest.com", + "type": "A", + "ttl": 300, + "rdata": [ + "2.2.2.2" + ] + } + }, + { + "index": 14, + "value": { + "name": "akamaigoldentest.com", + "type": "A", + "ttl": 300, + "rdata": [ + "2.2.2.2" + ] + } + }, + { + "index": 15, + "value": { + "name": "akamaigoldentest.com", + "type": "A", + "ttl": 300, + "rdata": [ + "4.4.4.4" + ] + } + }, + { + "index": 16, + "value": { + "name": "akamaigoldentest.com", + "type": "A", + "ttl": 300, + "rdata": [ + "4.4.4.4" + ] + } + }, + { + "index": 17, + "value": { + "name": "akamaigoldentest.com", + "type": "AKAMAITLC", + "ttl": 300, + "rdata": [ + "DUAL foo.akamaigoldentest.com." + ] + } + }, + { + "index": 18, + "value": { + "name": "akamaigoldentest.com", + "type": "AKAMAITLC", + "ttl": 300, + "rdata": [ + "DUAL foo.akamaigoldentest.com." + ] + } + }, + { + "index": 19, + "value": { + "name": "akamaigoldentest.com", + "type": "AKAMAITLC", + "ttl": 300, + "rdata": [ + "DUAL foo.com." + ] + } + }, + { + "index": 20, + "value": { + "name": "akamaigoldentest.com", + "type": "AKAMAITLC", + "ttl": 300, + "rdata": [ + "DUAL foo2.com." + ] + } + }, + { + "index": 21, + "value": { + "name": "akamaigoldentest.com", + "type": "AKAMAITLC", + "ttl": 300, + "rdata": [ + "DUAL foo2.com." + ] + } + }, + { + "index": 22, + "value": { + "name": "akamaigoldentest.com", + "type": "CAA", + "ttl": 300, + "rdata": [ + "0 issue \"letsencrypt.org\"" + ] + } + }, + { + "index": 23, + "value": { + "name": "akamaigoldentest.com", + "type": "CAA", + "ttl": 300, + "rdata": [ + "0 issue \"letsencrypt.org; validationmethods=dns-01; accounturi=https://acme-v02.api.letsencrypt.org/acme/acct/1234\"" + ] + } + }, + { + "index": 24, + "value": { + "name": "akamaigoldentest.com", + "type": "CAA", + "ttl": 300, + "rdata": [ + "0 issue \"letsencrypt.org; validationmethods=dns-01; accounturi=https://acme-v02.api.letsencrypt.org/acme/acct/1234\"" + ] + } + }, + { + "index": 25, + "value": { + "name": "akamaigoldentest.com", + "type": "CAA", + "ttl": 300, + "rdata": [ + "0 issuewild \";\"" + ] + } + }, + { + "index": 26, + "value": { + "name": "akamaigoldentest.com", + "type": "CAA", + "ttl": 300, + "rdata": [ + "0 issuewild \"example.com\"" + ] + } + }, + { + "index": 27, + "value": { + "name": "akamaigoldentest.com", + "type": "CAA", + "ttl": 300, + "rdata": [ + "0 issuewild \"letsencrypt.org\"" + ] + } + }, + { + "index": 28, + "value": { + "name": "akamaigoldentest.com", + "type": "CAA", + "ttl": 300, + "rdata": [ + "128 issue \"letsencrypt.org\"" + ] + } + }, + { + "index": 29, + "value": { + "name": "akamaigoldentest.com", + "type": "CAA", + "ttl": 300, + "rdata": [ + "128 issue \"letsencrypt.org\"" + ] + } + }, + { + "index": 30, + "value": { + "name": "akamaigoldentest.com", + "type": "LOC", + "ttl": 300, + "rdata": [ + "42 21 54.000 N 71 06 18.000 W -24.05m 30m 0.00m 0.00m" + ] + } + }, + { + "index": 31, + "value": { + "name": "akamaigoldentest.com", + "type": "LOC", + "ttl": 300, + "rdata": [ + "42 21 54.000 N 71 06 18.000 W -24.06m 30m 10m 0.00m" + ] + } + }, + { + "index": 32, + "value": { + "name": "akamaigoldentest.com", + "type": "LOC", + "ttl": 300, + "rdata": [ + "42 21 54.000 N 71 06 18.000 W -24m 30m 0.00m 0.00m" + ] + } + }, + { + "index": 33, + "value": { + "name": "akamaigoldentest.com", + "type": "LOC", + "ttl": 300, + "rdata": [ + "42 21 54.000 N 71 06 18.000 W -24m 30m 0.00m 0.00m" + ] + } + }, + { + "index": 34, + "value": { + "name": "akamaigoldentest.com", + "type": "MX", + "ttl": 300, + "rdata": [ + "0 ." + ] + } + }, + { + "index": 35, + "value": { + "name": "akamaigoldentest.com", + "type": "MX", + "ttl": 300, + "rdata": [ + "0 ." + ] + } + }, + { + "index": 36, + "value": { + "name": "akamaigoldentest.com", + "type": "MX", + "ttl": 300, + "rdata": [ + "2 akamaigoldentest.com.", + "8 www.akamaigoldentest.com." + ] + } + }, + { + "index": 37, + "value": { + "name": "akamaigoldentest.com", + "type": "MX", + "ttl": 300, + "rdata": [ + "5 bar.com." + ] + } + }, + { + "index": 38, + "value": { + "name": "akamaigoldentest.com", + "type": "MX", + "ttl": 300, + "rdata": [ + "5 bar.com." + ] + } + }, + { + "index": 39, + "value": { + "name": "akamaigoldentest.com", + "type": "MX", + "ttl": 300, + "rdata": [ + "5 foo.com." + ] + } + }, + { + "index": 40, + "value": { + "name": "akamaigoldentest.com", + "type": "NS", + "ttl": 300, + "rdata": [ + "a1-98.akam.net.", + "a12-65.akam.net.", + "a13-65.akam.net.", + "a2-64.akam.net.", + "a3-64.akam.net.", + "a4-65.akam.net." + ] + } + }, + { + "index": 41, + "value": { + "name": "akamaigoldentest.com", + "type": "NS", + "ttl": 300, + "rdata": [ + "a1-98.akam.net.", + "a12-65.akam.net.", + "a13-65.akam.net.", + "a2-64.akam.net.", + "a3-64.akam.net.", + "a4-65.akam.net.", + "ns1.foo.com." + ] + } + }, + { + "index": 42, + "value": { + "name": "akamaigoldentest.com", + "type": "NS", + "ttl": 300, + "rdata": [ + "a1-98.akam.net.", + "a12-65.akam.net.", + "a13-65.akam.net.", + "a2-64.akam.net.", + "a3-64.akam.net.", + "a4-65.akam.net.", + "ns1.foo.com.", + "ns2.foo.com." + ] + } + }, + { + "index": 43, + "value": { + "name": "akamaigoldentest.com", + "type": "SSHFP", + "ttl": 300, + "rdata": [ + "1 1 66C7D5540B7D75A1FB4C84FEBFA178AD99BDD67C" + ] + } + }, + { + "index": 44, + "value": { + "name": "akamaigoldentest.com", + "type": "SSHFP", + "ttl": 300, + "rdata": [ + "2 1 66C7D5540B7D75A1FB4C84FEBFA178AD99BDD67C" + ] + } + }, + { + "index": 45, + "value": { + "name": "akamaigoldentest.com", + "type": "SSHFP", + "ttl": 300, + "rdata": [ + "2 2 745A635BC46A397A5C4F21D437483005BCC40D7511FF15FBFAFE913A081559BC" + ] + } + }, + { + "index": 46, + "value": { + "name": "akamaigoldentest.com", + "type": "SSHFP", + "ttl": 300, + "rdata": [ + "2 2 745A635BC46A397A5C4F21D437483005BCC40D7511FF15FBFAFE913A081559BC" + ] + } + }, + { + "index": 47, + "value": { + "name": "akamaigoldentest.com", + "type": "TXT", + "ttl": 300, + "rdata": [ + "\"asimple\"" + ] + } + }, + { + "index": 48, + "value": { + "name": "akamaigoldentest.com", + "type": "TXT", + "ttl": 300, + "rdata": [ + "\"asimple\"" + ] + } + }, + { + "index": 49, + "value": { + "name": "akamaigoldentest.com", + "type": "TXT", + "ttl": 300, + "rdata": [ + "\"simple\"" + ] + } + }, + { + "index": 50, + "value": { + "name": "akamaigoldentest.com", + "type": "TXT", + "ttl": 300, + "rdata": [ + "\"simple\"" + ] + } + }, + { + "index": 51, + "value": { + "name": "akamaigoldentest.com", + "type": "A", + "ttl": 500, + "rdata": [ + "8.8.8.8" + ] + } + }, + { + "index": 52, + "value": { + "name": "akamaigoldentest.com", + "type": "A", + "ttl": 500, + "rdata": [ + "8.8.8.8" + ] + } + }, + { + "index": 53, + "value": { + "name": "akamaigoldentest.com", + "type": "A", + "ttl": 666, + "rdata": [ + "8.8.8.8" + ] + } + }, + { + "index": 54, + "value": { + "name": "_443._tcp.akamaigoldentest.com", + "type": "TLSA", + "ttl": 300, + "rdata": [ + "2 0 1 0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF" + ] + } + }, + { + "index": 55, + "value": { + "name": "_443._tcp.akamaigoldentest.com", + "type": "TLSA", + "ttl": 300, + "rdata": [ + "2 0 2 0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF" + ] + } + }, + { + "index": 56, + "value": { + "name": "_443._tcp.akamaigoldentest.com", + "type": "TLSA", + "ttl": 300, + "rdata": [ + "2 0 2 FEDCBA9876543210FEDCBA9876543210FEDCBA9876543210FEDCBA9876543210FEDCBA9876543210FEDCBA9876543210FEDCBA9876543210FEDCBA9876543210" + ] + } + }, + { + "index": 57, + "value": { + "name": "_443._tcp.akamaigoldentest.com", + "type": "TLSA", + "ttl": 300, + "rdata": [ + "2 0 2 FEDCBA9876543210FEDCBA9876543210FEDCBA9876543210FEDCBA9876543210FEDCBA9876543210FEDCBA9876543210FEDCBA9876543210FEDCBA9876543210" + ] + } + }, + { + "index": 58, + "value": { + "name": "_443._tcp.akamaigoldentest.com", + "type": "TLSA", + "ttl": 300, + "rdata": [ + "2 1 1 0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF" + ] + } + }, + { + "index": 59, + "value": { + "name": "_443._tcp.akamaigoldentest.com", + "type": "TLSA", + "ttl": 300, + "rdata": [ + "3 1 1 0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF" + ] + } + }, + { + "index": 60, + "value": { + "name": "_sip._tcp.akamaigoldentest.com", + "type": "SRV", + "ttl": 300, + "rdata": [ + "15 65 75 ." + ] + } + }, + { + "index": 61, + "value": { + "name": "_sip._tcp.akamaigoldentest.com", + "type": "SRV", + "ttl": 300, + "rdata": [ + "15 65 75 ." + ] + } + }, + { + "index": 62, + "value": { + "name": "_sip._tcp.akamaigoldentest.com", + "type": "SRV", + "ttl": 300, + "rdata": [ + "15 65 75 foo4.com.", + "52 6 7 foo.com." + ] + } + }, + { + "index": 63, + "value": { + "name": "_sip._tcp.akamaigoldentest.com", + "type": "SRV", + "ttl": 300, + "rdata": [ + "15 65 75 foo4.com.", + "52 62 7 foo.com." + ] + } + }, + { + "index": 64, + "value": { + "name": "_sip._tcp.akamaigoldentest.com", + "type": "SRV", + "ttl": 300, + "rdata": [ + "15 65 75 foo4.com.", + "52 62 72 foo.com." + ] + } + }, + { + "index": 65, + "value": { + "name": "_sip._tcp.akamaigoldentest.com", + "type": "SRV", + "ttl": 300, + "rdata": [ + "15 65 75 foo4.com.", + "52 62 72 foo.com." + ] + } + }, + { + "index": 66, + "value": { + "name": "_sip._tcp.akamaigoldentest.com", + "type": "SRV", + "ttl": 300, + "rdata": [ + "5 6 7 foo.com." + ] + } + }, + { + "index": 67, + "value": { + "name": "_sip._tcp.akamaigoldentest.com", + "type": "SRV", + "ttl": 300, + "rdata": [ + "5 6 7 foo.com.", + "15 65 75 foo3.com." + ] + } + }, + { + "index": 68, + "value": { + "name": "_sip._tcp.akamaigoldentest.com", + "type": "SRV", + "ttl": 300, + "rdata": [ + "5 6 7 foo.com.", + "15 65 75 foo4.com." + ] + } + }, + { + "index": 69, + "value": { + "name": "_sip._tcp.akamaigoldentest.com", + "type": "SRV", + "ttl": 300, + "rdata": [ + "5 6 7 foo.com.", + "5 60 70 foo2.com." + ] + } + }, + { + "index": 70, + "value": { + "name": "_sip._tcp.akamaigoldentest.com", + "type": "SRV", + "ttl": 300, + "rdata": [ + "5 6 7 foo.com.", + "5 60 70 foo2.com.", + "15 65 75 foo3.com." + ] + } + }, + { + "index": 71, + "value": { + "name": "_sip._tcp.akamaigoldentest.com", + "type": "SRV", + "ttl": 333, + "rdata": [ + "5 6 7 foo.com." + ] + } + }, + { + "index": 72, + "value": { + "name": "_sip._tcp.akamaigoldentest.com", + "type": "SRV", + "ttl": 4400, + "rdata": [ + "5 6 7 foo.com." + ] + } + }, + { + "index": 73, + "value": { + "name": "_sip._tcp.akamaigoldentest.com", + "type": "SRV", + "ttl": 4400, + "rdata": [ + "5 6 7 foo.com." + ] + } + }, + { + "index": 74, + "value": { + "name": "a.akamaigoldentest.com", + "type": "CNAME", + "ttl": 300, + "rdata": [ + "xn--ndaaa.com." + ] + } + }, + { + "index": 75, + "value": { + "name": "a.akamaigoldentest.com", + "type": "CNAME", + "ttl": 300, + "rdata": [ + "xn--ndaaa.com." + ] + } + }, + { + "index": 76, + "value": { + "name": "a.akamaigoldentest.com", + "type": "LOC", + "ttl": 300, + "rdata": [ + "42 21 43.950 N 71 05 6.340 W -24.33m 1m 200m 10m" + ] + } + }, + { + "index": 77, + "value": { + "name": "a.akamaigoldentest.com", + "type": "LOC", + "ttl": 300, + "rdata": [ + "42 21 43.950 N 71 05 6.340 W -24.33m 1m 200m 10m" + ] + } + }, + { + "index": 78, + "value": { + "name": "another-child.akamaigoldentest.com", + "type": "DS", + "ttl": 300, + "rdata": [ + "44 13 2 4B9B6B073EDD97FEB5BC12DC4E1B32D2C6AF7AE23A293936CEB87BB10494EC44" + ] + } + }, + { + "index": 79, + "value": { + "name": "another-child.akamaigoldentest.com", + "type": "DS", + "ttl": 300, + "rdata": [ + "44 13 2 4B9B6B073EDD97FEB5BC12DC4E1B32D2C6AF7AE23A293936CEB87BB10494EC44", + "1501 14 4 109BB6B5B6D5547C1CE03C7A8BD7D8F80C1CB0957F50C4F7FDA04692079917E4F9CAD52B878F3D8234E1A170B154B72D", + "1502 8 2 2FA14F53E6B15CAC9AC77846C7BE87862C2A7E9EC0C6CEA319DB939317F126ED", + "65535 13 2 2FA14F53E6B15CAC9AC77846C7BE87862C2A7E9EC0C6CEA319DB939317F126ED" + ] + } + }, + { + "index": 80, + "value": { + "name": "another-child.akamaigoldentest.com", + "type": "DS", + "ttl": 300, + "rdata": [ + "44 13 2 4B9B6B073EDD97FEB5BC12DC4E1B32D2C6AF7AE23A293936CEB87BB10494EC44", + "1501 14 4 109BB6B5B6D5547C1CE03C7A8BD7D8F80C1CB0957F50C4F7FDA04692079917E4F9CAD52B878F3D8234E1A170B154B72D", + "1502 8 2 2FA14F53E6B15CAC9AC77846C7BE87862C2A7E9EC0C6CEA319DB939317F126ED", + "65535 13 2 2FA14F53E6B15CAC9AC77846C7BE87862C2A7E9EC0C6CEA319DB939317F126ED" + ] + } + }, + { + "index": 81, + "value": { + "name": "b.akamaigoldentest.com", + "type": "LOC", + "ttl": 300, + "rdata": [ + "52 14 5.000 N 00 08 50.000 E 10.22m 0.00m 0.00m 0.00m" + ] + } + }, + { + "index": 82, + "value": { + "name": "b.akamaigoldentest.com", + "type": "LOC", + "ttl": 300, + "rdata": [ + "52 14 5.000 N 00 08 50.000 E 10.22m 0.00m 0.00m 0.00m" + ] + } + }, + { + "index": 83, + "value": { + "name": "bar.akamaigoldentest.com", + "type": "A", + "ttl": 300, + "rdata": [ + "1.2.3.4" + ] + } + }, + { + "index": 84, + "value": { + "name": "bar.akamaigoldentest.com", + "type": "A", + "ttl": 300, + "rdata": [ + "1.2.3.4" + ] + } + }, + { + "index": 85, + "value": { + "name": "bar.akamaigoldentest.com", + "type": "A", + "ttl": 300, + "rdata": [ + "5.5.5.5" + ] + } + }, + { + "index": 86, + "value": { + "name": "bar.akamaigoldentest.com", + "type": "A", + "ttl": 300, + "rdata": [ + "5.5.5.5" + ] + } + }, + { + "index": 87, + "value": { + "name": "bar.akamaigoldentest.com", + "type": "CNAME", + "ttl": 300, + "rdata": [ + "redact2.acm-validations.aws." + ] + } + }, + { + "index": 88, + "value": { + "name": "bar.akamaigoldentest.com", + "type": "CNAME", + "ttl": 300, + "rdata": [ + "redact2.acm-validations.aws." + ] + } + }, + { + "index": 89, + "value": { + "name": "bar.akamaigoldentest.com", + "type": "MX", + "ttl": 300, + "rdata": [ + "5 bar.com." + ] + } + }, + { + "index": 90, + "value": { + "name": "bar.akamaigoldentest.com", + "type": "MX", + "ttl": 300, + "rdata": [ + "5 bar.com." + ] + } + }, + { + "index": 91, + "value": { + "name": "bar.bat.akamaigoldentest.com", + "type": "A", + "ttl": 300, + "rdata": [ + "5.5.5.5" + ] + } + }, + { + "index": 92, + "value": { + "name": "bar.bat.akamaigoldentest.com", + "type": "A", + "ttl": 300, + "rdata": [ + "5.5.5.5" + ] + } + }, + { + "index": 93, + "value": { + "name": "c.akamaigoldentest.com", + "type": "LOC", + "ttl": 300, + "rdata": [ + "32 07 19.000 S 116 02 25.000 E 10m 0.00m 0.00m 0.00m" + ] + } + }, + { + "index": 94, + "value": { + "name": "c.akamaigoldentest.com", + "type": "LOC", + "ttl": 300, + "rdata": [ + "32 07 19.000 S 116 02 25.000 E 10m 0.00m 0.00m 0.00m" + ] + } + }, + { + "index": 95, + "value": { + "name": "child.akamaigoldentest.com", + "type": "DS", + "ttl": 300, + "rdata": [ + "1 14 4 417212FD1C8BC5896FEFD8DB58AF824545E85B0D0546409366A30AEF7269FAE258173BD185FB262C86F3BB86FBA04368" + ] + } + }, + { + "index": 96, + "value": { + "name": "child.akamaigoldentest.com", + "type": "DS", + "ttl": 300, + "rdata": [ + "3 13 2 4B9B6B073EDD97FEB5BC12DC4E1B32D2C6AF7AE23A293936CEB87BB10494EC44" + ] + } + }, + { + "index": 97, + "value": { + "name": "child.akamaigoldentest.com", + "type": "DS", + "ttl": 300, + "rdata": [ + "3 14 4 3115238F89E0BF5252D9718113B1B9FFF854608D84BE94EEFB9210DC1CC0B4F3557342A27465CFACC42EF137AE9A5489" + ] + } + }, + { + "index": 98, + "value": { + "name": "child.akamaigoldentest.com", + "type": "DS", + "ttl": 300, + "rdata": [ + "3 14 4 3115238F89E0BF5252D9718113B1B9FFF854608D84BE94EEFB9210DC1CC0B4F3557342A27465CFACC42EF137AE9A5489" + ] + } + }, + { + "index": 99, + "value": { + "name": "child.akamaigoldentest.com", + "type": "DS", + "ttl": 300, + "rdata": [ + "3 8 2 4B9B6B073EDD97FEB5BC12DC4E1B32D2C6AF7AE23A293936CEB87BB10494EC44" + ] + } + }, + { + "index": 100, + "value": { + "name": "child.akamaigoldentest.com", + "type": "DS", + "ttl": 300, + "rdata": [ + "8857 8 2 4B9B6B073EDD97FEB5BC12DC4E1B32D2C6AF7AE23A293936CEB87BB10494EC44" + ] + } + }, + { + "index": 101, + "value": { + "name": "d.akamaigoldentest.com", + "type": "LOC", + "ttl": 300, + "rdata": [ + "42 21 28.760 N 71 00 51.620 W -44m 2000m 0.00m 0.00m" + ] + } + }, + { + "index": 102, + "value": { + "name": "d.akamaigoldentest.com", + "type": "LOC", + "ttl": 300, + "rdata": [ + "42 21 28.760 N 71 00 51.620 W -44m 2000m 0.00m 0.00m" + ] + } + }, + { + "index": 103, + "value": { + "name": "decoy.akamaigoldentest.com", + "type": "A", + "ttl": 300, + "rdata": [ + "1.1.1.1" + ] + } + }, + { + "index": 104, + "value": { + "name": "decoy.akamaigoldentest.com", + "type": "A", + "ttl": 300, + "rdata": [ + "2.2.2.2" + ] + } + }, + { + "index": 105, + "value": { + "name": "decoy.akamaigoldentest.com", + "type": "A", + "ttl": 300, + "rdata": [ + "3.3.3.3" + ] + } + }, + { + "index": 106, + "value": { + "name": "decoy.akamaigoldentest.com", + "type": "A", + "ttl": 300, + "rdata": [ + "3.3.3.3" + ] + } + }, + { + "index": 107, + "value": { + "name": "dyndns-city1.akamaigoldentest.com", + "type": "A", + "ttl": 300, + "rdata": [ + "91.42.1.1" + ] + } + }, + { + "index": 108, + "value": { + "name": "dyndns-city1.akamaigoldentest.com", + "type": "A", + "ttl": 300, + "rdata": [ + "91.42.1.1" + ] + } + }, + { + "index": 109, + "value": { + "name": "dyndns-city1.akamaigoldentest.com", + "type": "AAAA", + "ttl": 300, + "rdata": [ + "2003:dd:d7ff::fe71:ce77" + ] + } + }, + { + "index": 110, + "value": { + "name": "dyndns-city1.akamaigoldentest.com", + "type": "AAAA", + "ttl": 300, + "rdata": [ + "2003:dd:d7ff::fe71:ce77" + ] + } + }, + { + "index": 111, + "value": { + "name": "dyndns-city2.akamaigoldentest.com", + "type": "A", + "ttl": 300, + "rdata": [ + "91.42.1.2" + ] + } + }, + { + "index": 112, + "value": { + "name": "dyndns-city2.akamaigoldentest.com", + "type": "A", + "ttl": 300, + "rdata": [ + "91.42.1.2" + ] + } + }, + { + "index": 113, + "value": { + "name": "dyndns-city2.akamaigoldentest.com", + "type": "AAAA", + "ttl": 300, + "rdata": [ + "2003:dd:d7ff::fe71:ce78" + ] + } + }, + { + "index": 114, + "value": { + "name": "dyndns-city2.akamaigoldentest.com", + "type": "AAAA", + "ttl": 300, + "rdata": [ + "2003:dd:d7ff::fe71:ce78" + ] + } + }, + { + "index": 115, + "value": { + "name": "final.akamaigoldentest.com", + "type": "TXT", + "ttl": 300, + "rdata": [ + "\"TestDNSProviders was successful!\"" + ] + } + }, + { + "index": 116, + "value": { + "name": "final.akamaigoldentest.com", + "type": "TXT", + "ttl": 300, + "rdata": [ + "\"TestDNSProviders was successful!\"" + ] + } + }, + { + "index": 117, + "value": { + "name": "foo.akamaigoldentest.com", + "type": "A", + "ttl": 300, + "rdata": [ + "1.1.1.1", + "11.11.11.11" + ] + } + }, + { + "index": 118, + "value": { + "name": "foo.akamaigoldentest.com", + "type": "A", + "ttl": 300, + "rdata": [ + "1.1.1.1", + "12.12.12.12" + ] + } + }, + { + "index": 119, + "value": { + "name": "foo.akamaigoldentest.com", + "type": "A", + "ttl": 300, + "rdata": [ + "1.1.1.1", + "13.13.13.13" + ] + } + }, + { + "index": 120, + "value": { + "name": "foo.akamaigoldentest.com", + "type": "A", + "ttl": 300, + "rdata": [ + "1.1.1.1", + "9.9.9.9" + ] + } + }, + { + "index": 121, + "value": { + "name": "foo.akamaigoldentest.com", + "type": "A", + "ttl": 300, + "rdata": [ + "1.1.1.1", + "14.14.14.14" + ] + } + }, + { + "index": 122, + "value": { + "name": "foo.akamaigoldentest.com", + "type": "A", + "ttl": 300, + "rdata": [ + "1.1.1.1", + "14.14.14.14" + ] + } + }, + { + "index": 123, + "value": { + "name": "foo.akamaigoldentest.com", + "type": "A", + "ttl": 300, + "rdata": [ + "1.2.3.4" + ] + } + }, + { + "index": 124, + "value": { + "name": "foo.akamaigoldentest.com", + "type": "A", + "ttl": 300, + "rdata": [ + "1.2.3.4", + "2.3.4.5" + ] + } + }, + { + "index": 125, + "value": { + "name": "foo.akamaigoldentest.com", + "type": "A", + "ttl": 300, + "rdata": [ + "1.2.3.4", + "3.4.5.6" + ] + } + }, + { + "index": 126, + "value": { + "name": "foo.akamaigoldentest.com", + "type": "A", + "ttl": 300, + "rdata": [ + "1.2.3.4" + ] + } + }, + { + "index": 127, + "value": { + "name": "foo.akamaigoldentest.com", + "type": "A", + "ttl": 300, + "rdata": [ + "1.2.3.4", + "2.3.4.5" + ] + } + }, + { + "index": 128, + "value": { + "name": "foo.akamaigoldentest.com", + "type": "A", + "ttl": 300, + "rdata": [ + "1.2.3.4", + "3.4.5.6" + ] + } + }, + { + "index": 129, + "value": { + "name": "foo.akamaigoldentest.com", + "type": "A", + "ttl": 300, + "rdata": [ + "2.3.4.5" + ] + } + }, + { + "index": 130, + "value": { + "name": "foo.akamaigoldentest.com", + "type": "A", + "ttl": 300, + "rdata": [ + "2.3.4.5", + "3.4.5.6" + ] + } + }, + { + "index": 131, + "value": { + "name": "foo.akamaigoldentest.com", + "type": "A", + "ttl": 300, + "rdata": [ + "2.3.4.5", + "8.8.8.8" + ] + } + }, + { + "index": 132, + "value": { + "name": "foo.akamaigoldentest.com", + "type": "A", + "ttl": 300, + "rdata": [ + "2.3.4.5", + "8.8.8.8" + ] + } + }, + { + "index": 133, + "value": { + "name": "foo.akamaigoldentest.com", + "type": "A", + "ttl": 300, + "rdata": [ + "4.5.6.7" + ] + } + }, + { + "index": 134, + "value": { + "name": "foo.akamaigoldentest.com", + "type": "A", + "ttl": 300, + "rdata": [ + "4.5.6.7" + ] + } + }, + { + "index": 135, + "value": { + "name": "foo.akamaigoldentest.com", + "type": "AAAA", + "ttl": 300, + "rdata": [ + "2003:dd:d7ff::fe71:aaaa" + ] + } + }, + { + "index": 136, + "value": { + "name": "foo.akamaigoldentest.com", + "type": "AAAA", + "ttl": 300, + "rdata": [ + "2003:dd:d7ff::fe71:aaaa" + ] + } + }, + { + "index": 137, + "value": { + "name": "foo.akamaigoldentest.com", + "type": "CNAME", + "ttl": 300, + "rdata": [ + "akamaigoldentest.com." + ] + } + }, + { + "index": 138, + "value": { + "name": "foo.akamaigoldentest.com", + "type": "CNAME", + "ttl": 300, + "rdata": [ + "akamaigoldentest.com." + ] + } + }, + { + "index": 139, + "value": { + "name": "foo.akamaigoldentest.com", + "type": "CNAME", + "ttl": 300, + "rdata": [ + "google.com." + ] + } + }, + { + "index": 140, + "value": { + "name": "foo.akamaigoldentest.com", + "type": "CNAME", + "ttl": 300, + "rdata": [ + "google.com." + ] + } + }, + { + "index": 141, + "value": { + "name": "foo.akamaigoldentest.com", + "type": "CNAME", + "ttl": 300, + "rdata": [ + "google2.com." + ] + } + }, + { + "index": 142, + "value": { + "name": "foo.akamaigoldentest.com", + "type": "CNAME", + "ttl": 300, + "rdata": [ + "google2.com." + ] + } + }, + { + "index": 143, + "value": { + "name": "foo.akamaigoldentest.com", + "type": "CNAME", + "ttl": 300, + "rdata": [ + "redact1.acm-validations.aws." + ] + } + }, + { + "index": 144, + "value": { + "name": "foo.akamaigoldentest.com", + "type": "CNAME", + "ttl": 300, + "rdata": [ + "redact1.acm-validations.aws." + ] + } + }, + { + "index": 145, + "value": { + "name": "foo.akamaigoldentest.com", + "type": "MX", + "ttl": 300, + "rdata": [ + "10 aspmx.l.google.com.", + "20 alt1.aspmx.l.google.com." + ] + } + }, + { + "index": 146, + "value": { + "name": "foo.akamaigoldentest.com", + "type": "MX", + "ttl": 300, + "rdata": [ + "10 aspmx.l.google.com.", + "20 alt1.aspmx.l.google.com." + ] + } + }, + { + "index": 147, + "value": { + "name": "foo.akamaigoldentest.com", + "type": "MX", + "ttl": 300, + "rdata": [ + "10 foo.akamaigoldentest.com.", + "20 bar.akamaigoldentest.com." + ] + } + }, + { + "index": 148, + "value": { + "name": "foo.akamaigoldentest.com", + "type": "MX", + "ttl": 300, + "rdata": [ + "10 foo.akamaigoldentest.com.", + "20 bar.akamaigoldentest.com." + ] + } + }, + { + "index": 149, + "value": { + "name": "foo.akamaigoldentest.com", + "type": "MX", + "ttl": 300, + "rdata": [ + "5 mx.google.com." + ] + } + }, + { + "index": 150, + "value": { + "name": "foo.akamaigoldentest.com", + "type": "MX", + "ttl": 300, + "rdata": [ + "5 mx.google.com." + ] + } + }, + { + "index": 151, + "value": { + "name": "foo.akamaigoldentest.com", + "type": "MX", + "ttl": 300, + "rdata": [ + "8 akamaigoldentest.com." + ] + } + }, + { + "index": 152, + "value": { + "name": "foo.akamaigoldentest.com", + "type": "MX", + "ttl": 300, + "rdata": [ + "8 akamaigoldentest.com." + ] + } + }, + { + "index": 153, + "value": { + "name": "foo.akamaigoldentest.com", + "type": "NS", + "ttl": 300, + "rdata": [ + "akamaigoldentest.com." + ] + } + }, + { + "index": 154, + "value": { + "name": "foo.akamaigoldentest.com", + "type": "NS", + "ttl": 300, + "rdata": [ + "akamaigoldentest.com." + ] + } + }, + { + "index": 155, + "value": { + "name": "foo.akamaigoldentest.com", + "type": "TXT", + "ttl": 300, + "rdata": [ + "\"simple\"" + ] + } + }, + { + "index": 156, + "value": { + "name": "foo.akamaigoldentest.com", + "type": "TXT", + "ttl": 300, + "rdata": [ + "\"simple\"" + ] + } + }, + { + "index": 157, + "value": { + "name": "foo.akamaigoldentest.com", + "type": "TXT", + "ttl": 300, + "rdata": [ + "\"v=spf1 ip4:99.99.99.99 -all\"" + ] + } + }, + { + "index": 158, + "value": { + "name": "foo.akamaigoldentest.com", + "type": "TXT", + "ttl": 300, + "rdata": [ + "\"v=spf1 ip4:99.99.99.99 -all\"" + ] + } + }, + { + "index": 159, + "value": { + "name": "foo.bat.akamaigoldentest.com", + "type": "A", + "ttl": 300, + "rdata": [ + "1.2.3.4", + "2.3.4.5" + ] + } + }, + { + "index": 160, + "value": { + "name": "foo.bat.akamaigoldentest.com", + "type": "A", + "ttl": 300, + "rdata": [ + "1.2.3.4", + "2.3.4.5" + ] + } + }, + { + "index": 161, + "value": { + "name": "foo.bat.akamaigoldentest.com", + "type": "TXT", + "ttl": 300, + "rdata": [ + "\"simple\"" + ] + } + }, + { + "index": 162, + "value": { + "name": "foo.bat.akamaigoldentest.com", + "type": "TXT", + "ttl": 300, + "rdata": [ + "\"simple\"" + ] + } + }, + { + "index": 163, + "value": { + "name": "foo0.akamaigoldentest.com", + "type": "TXT", + "ttl": 300, + "rdata": [ + "\"\"" + ] + } + }, + { + "index": 164, + "value": { + "name": "foo0.akamaigoldentest.com", + "type": "TXT", + "ttl": 300, + "rdata": [ + "\"\"" + ] + } + }, + { + "index": 165, + "value": { + "name": "foo254.akamaigoldentest.com", + "type": "TXT", + "ttl": 300, + "rdata": [ + "\"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\"" + ] + } + }, + { + "index": 166, + "value": { + "name": "foo254.akamaigoldentest.com", + "type": "TXT", + "ttl": 300, + "rdata": [ + "\"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\"" + ] + } + }, + { + "index": 167, + "value": { + "name": "foo255.akamaigoldentest.com", + "type": "TXT", + "ttl": 300, + "rdata": [ + "\"BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB\"" + ] + } + }, + { + "index": 168, + "value": { + "name": "foo255.akamaigoldentest.com", + "type": "TXT", + "ttl": 300, + "rdata": [ + "\"BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB\"" + ] + } + }, + { + "index": 169, + "value": { + "name": "foo256.akamaigoldentest.com", + "type": "TXT", + "ttl": 300, + "rdata": [ + "\"CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC\" \"C\"" + ] + } + }, + { + "index": 170, + "value": { + "name": "foo256.akamaigoldentest.com", + "type": "TXT", + "ttl": 300, + "rdata": [ + "\"CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC\" \"C\"" + ] + } + }, + { + "index": 171, + "value": { + "name": "foo509.akamaigoldentest.com", + "type": "TXT", + "ttl": 300, + "rdata": [ + "\"DDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDD\" \"DDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDD\"" + ] + } + }, + { + "index": 172, + "value": { + "name": "foo509.akamaigoldentest.com", + "type": "TXT", + "ttl": 300, + "rdata": [ + "\"DDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDD\" \"DDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDD\"" + ] + } + }, + { + "index": 173, + "value": { + "name": "foo510.akamaigoldentest.com", + "type": "TXT", + "ttl": 300, + "rdata": [ + "\"EEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE\" \"EEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE\"" + ] + } + }, + { + "index": 174, + "value": { + "name": "foo510.akamaigoldentest.com", + "type": "TXT", + "ttl": 300, + "rdata": [ + "\"EEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE\" \"EEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE\"" + ] + } + }, + { + "index": 175, + "value": { + "name": "foo511.akamaigoldentest.com", + "type": "TXT", + "ttl": 300, + "rdata": [ + "\"FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF\" \"FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF\" \"F\"" + ] + } + }, + { + "index": 176, + "value": { + "name": "foo511.akamaigoldentest.com", + "type": "TXT", + "ttl": 300, + "rdata": [ + "\"FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF\" \"FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF\" \"F\"" + ] + } + }, + { + "index": 177, + "value": { + "name": "foo764.akamaigoldentest.com", + "type": "TXT", + "ttl": 300, + "rdata": [ + "\"GGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGG\" \"GGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGG\" \"GGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGG\"" + ] + } + }, + { + "index": 178, + "value": { + "name": "foo764.akamaigoldentest.com", + "type": "TXT", + "ttl": 300, + "rdata": [ + "\"GGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGG\" \"GGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGG\" \"GGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGG\"" + ] + } + }, + { + "index": 179, + "value": { + "name": "foo765.akamaigoldentest.com", + "type": "TXT", + "ttl": 300, + "rdata": [ + "\"HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH\" \"HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH\" \"HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH\"" + ] + } + }, + { + "index": 180, + "value": { + "name": "foo765.akamaigoldentest.com", + "type": "TXT", + "ttl": 300, + "rdata": [ + "\"HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH\" \"HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH\" \"HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH\"" + ] + } + }, + { + "index": 181, + "value": { + "name": "foo766.akamaigoldentest.com", + "type": "TXT", + "ttl": 300, + "rdata": [ + "\"JJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJ\" \"JJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJ\" \"JJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJ\" \"J\"" + ] + } + }, + { + "index": 182, + "value": { + "name": "foo766.akamaigoldentest.com", + "type": "TXT", + "ttl": 300, + "rdata": [ + "\"JJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJ\" \"JJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJ\" \"JJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJ\" \"J\"" + ] + } + }, + { + "index": 183, + "value": { + "name": "foobt.akamaigoldentest.com", + "type": "TXT", + "ttl": 300, + "rdata": [ + "\"blah`blah\"" + ] + } + }, + { + "index": 184, + "value": { + "name": "foobt.akamaigoldentest.com", + "type": "TXT", + "ttl": 300, + "rdata": [ + "\"blah`blah\"" + ] + } + }, + { + "index": 185, + "value": { + "name": "foosc1.akamaigoldentest.com", + "type": "TXT", + "ttl": 300, + "rdata": [ + "\"semi;colon\"" + ] + } + }, + { + "index": 186, + "value": { + "name": "foosc1.akamaigoldentest.com", + "type": "TXT", + "ttl": 300, + "rdata": [ + "\"semi;colon\"" + ] + } + }, + { + "index": 187, + "value": { + "name": "foosc2.akamaigoldentest.com", + "type": "TXT", + "ttl": 300, + "rdata": [ + "\"wssemi ; colon\"" + ] + } + }, + { + "index": 188, + "value": { + "name": "foosc2.akamaigoldentest.com", + "type": "TXT", + "ttl": 300, + "rdata": [ + "\"wssemi ; colon\"" + ] + } + }, + { + "index": 189, + "value": { + "name": "foosp.akamaigoldentest.com", + "type": "TXT", + "ttl": 300, + "rdata": [ + "\"with spaces\"" + ] + } + }, + { + "index": 190, + "value": { + "name": "foosp.akamaigoldentest.com", + "type": "TXT", + "ttl": 300, + "rdata": [ + "\"with spaces\"" + ] + } + }, + { + "index": 191, + "value": { + "name": "foosq.akamaigoldentest.com", + "type": "TXT", + "ttl": 300, + "rdata": [ + "\"quo'te\"" + ] + } + }, + { + "index": 192, + "value": { + "name": "foosq.akamaigoldentest.com", + "type": "TXT", + "ttl": 300, + "rdata": [ + "\"quo'te\"" + ] + } + }, + { + "index": 193, + "value": { + "name": "foows1.akamaigoldentest.com", + "type": "TXT", + "ttl": 300, + "rdata": [ + "\"trailingws \"" + ] + } + }, + { + "index": 194, + "value": { + "name": "foows1.akamaigoldentest.com", + "type": "TXT", + "ttl": 300, + "rdata": [ + "\"trailingws \"" + ] + } + }, + { + "index": 195, + "value": { + "name": "mail.akamaigoldentest.com", + "type": "CNAME", + "ttl": 300, + "rdata": [ + "ghs.googlehosted.com." + ] + } + }, + { + "index": 196, + "value": { + "name": "mail.akamaigoldentest.com", + "type": "CNAME", + "ttl": 300, + "rdata": [ + "ghs.googlehosted.com." + ] + } + }, + { + "index": 197, + "value": { + "name": "mail.bat.akamaigoldentest.com", + "type": "CNAME", + "ttl": 300, + "rdata": [ + "ghs.googlehosted.com." + ] + } + }, + { + "index": 198, + "value": { + "name": "mail.bat.akamaigoldentest.com", + "type": "CNAME", + "ttl": 300, + "rdata": [ + "ghs.googlehosted.com." + ] + } + }, + { + "index": 199, + "value": { + "name": "nmx.akamaigoldentest.com", + "type": "A", + "ttl": 300, + "rdata": [ + "1.2.3.3" + ] + } + }, + { + "index": 200, + "value": { + "name": "nmx.akamaigoldentest.com", + "type": "A", + "ttl": 300, + "rdata": [ + "1.2.3.3" + ] + } + }, + { + "index": 201, + "value": { + "name": "nmx.akamaigoldentest.com", + "type": "MX", + "ttl": 300, + "rdata": [ + "0 ." + ] + } + }, + { + "index": 202, + "value": { + "name": "nmx.akamaigoldentest.com", + "type": "MX", + "ttl": 300, + "rdata": [ + "0 ." + ] + } + }, + { + "index": 203, + "value": { + "name": "nmx.akamaigoldentest.com", + "type": "MX", + "ttl": 300, + "rdata": [ + "3 nmx.akamaigoldentest.com.", + "9 www.akamaigoldentest.com." + ] + } + }, + { + "index": 204, + "value": { + "name": "pager101-rec0000.akamaigoldentest.com", + "type": "A", + "ttl": 300, + "rdata": [ + "1.2.3.4" + ] + } + }, + { + "index": 205, + "value": { + "name": "pager101-rec0000.akamaigoldentest.com", + "type": "A", + "ttl": 300, + "rdata": [ + "1.2.3.4" + ] + } + }, + { + "index": 206, + "value": { + "name": "pager101-rec0001.akamaigoldentest.com", + "type": "A", + "ttl": 300, + "rdata": [ + "1.2.3.4" + ] + } + }, + { + "index": 207, + "value": { + "name": "pager101-rec0001.akamaigoldentest.com", + "type": "A", + "ttl": 300, + "rdata": [ + "1.2.3.4" + ] + } + }, + { + "index": 208, + "value": { + "name": "pager101-rec0002.akamaigoldentest.com", + "type": "A", + "ttl": 300, + "rdata": [ + "1.2.3.4" + ] + } + }, + { + "index": 209, + "value": { + "name": "pager101-rec0002.akamaigoldentest.com", + "type": "A", + "ttl": 300, + "rdata": [ + "1.2.3.4" + ] + } + }, + { + "index": 210, + "value": { + "name": "pager101-rec0003.akamaigoldentest.com", + "type": "A", + "ttl": 300, + "rdata": [ + "1.2.3.4" + ] + } + }, + { + "index": 211, + "value": { + "name": "pager101-rec0003.akamaigoldentest.com", + "type": "A", + "ttl": 300, + "rdata": [ + "1.2.3.4" + ] + } + }, + { + "index": 212, + "value": { + "name": "pager101-rec0004.akamaigoldentest.com", + "type": "A", + "ttl": 300, + "rdata": [ + "1.2.3.4" + ] + } + }, + { + "index": 213, + "value": { + "name": "pager101-rec0004.akamaigoldentest.com", + "type": "A", + "ttl": 300, + "rdata": [ + "1.2.3.4" + ] + } + }, + { + "index": 214, + "value": { + "name": "pager101-rec0005.akamaigoldentest.com", + "type": "A", + "ttl": 300, + "rdata": [ + "1.2.3.4" + ] + } + }, + { + "index": 215, + "value": { + "name": "pager101-rec0005.akamaigoldentest.com", + "type": "A", + "ttl": 300, + "rdata": [ + "1.2.3.4" + ] + } + }, + { + "index": 216, + "value": { + "name": "pager101-rec0006.akamaigoldentest.com", + "type": "A", + "ttl": 300, + "rdata": [ + "1.2.3.4" + ] + } + }, + { + "index": 217, + "value": { + "name": "pager101-rec0006.akamaigoldentest.com", + "type": "A", + "ttl": 300, + "rdata": [ + "1.2.3.4" + ] + } + }, + { + "index": 218, + "value": { + "name": "pager101-rec0007.akamaigoldentest.com", + "type": "A", + "ttl": 300, + "rdata": [ + "1.2.3.4" + ] + } + }, + { + "index": 219, + "value": { + "name": "pager101-rec0007.akamaigoldentest.com", + "type": "A", + "ttl": 300, + "rdata": [ + "1.2.3.4" + ] + } + }, + { + "index": 220, + "value": { + "name": "pager101-rec0008.akamaigoldentest.com", + "type": "A", + "ttl": 300, + "rdata": [ + "1.2.3.4" + ] + } + }, + { + "index": 221, + "value": { + "name": "pager101-rec0008.akamaigoldentest.com", + "type": "A", + "ttl": 300, + "rdata": [ + "1.2.3.4" + ] + } + }, + { + "index": 222, + "value": { + "name": "pager101-rec0009.akamaigoldentest.com", + "type": "A", + "ttl": 300, + "rdata": [ + "1.2.3.4" + ] + } + }, + { + "index": 223, + "value": { + "name": "pager101-rec0009.akamaigoldentest.com", + "type": "A", + "ttl": 300, + "rdata": [ + "1.2.3.4" + ] + } + }, + { + "index": 224, + "value": { + "name": "pager101-rec0010.akamaigoldentest.com", + "type": "A", + "ttl": 300, + "rdata": [ + "1.2.3.4" + ] + } + }, + { + "index": 225, + "value": { + "name": "pager101-rec0010.akamaigoldentest.com", + "type": "A", + "ttl": 300, + "rdata": [ + "1.2.3.4" + ] + } + }, + { + "index": 226, + "value": { + "name": "pager101-rec0011.akamaigoldentest.com", + "type": "A", + "ttl": 300, + "rdata": [ + "1.2.3.4" + ] + } + }, + { + "index": 227, + "value": { + "name": "pager101-rec0011.akamaigoldentest.com", + "type": "A", + "ttl": 300, + "rdata": [ + "1.2.3.4" + ] + } + }, + { + "index": 228, + "value": { + "name": "pager101-rec0012.akamaigoldentest.com", + "type": "A", + "ttl": 300, + "rdata": [ + "1.2.3.4" + ] + } + }, + { + "index": 229, + "value": { + "name": "pager101-rec0012.akamaigoldentest.com", + "type": "A", + "ttl": 300, + "rdata": [ + "1.2.3.4" + ] + } + }, + { + "index": 230, + "value": { + "name": "pager101-rec0013.akamaigoldentest.com", + "type": "A", + "ttl": 300, + "rdata": [ + "1.2.3.4" + ] + } + }, + { + "index": 231, + "value": { + "name": "pager101-rec0013.akamaigoldentest.com", + "type": "A", + "ttl": 300, + "rdata": [ + "1.2.3.4" + ] + } + }, + { + "index": 232, + "value": { + "name": "pager101-rec0014.akamaigoldentest.com", + "type": "A", + "ttl": 300, + "rdata": [ + "1.2.3.4" + ] + } + }, + { + "index": 233, + "value": { + "name": "pager101-rec0014.akamaigoldentest.com", + "type": "A", + "ttl": 300, + "rdata": [ + "1.2.3.4" + ] + } + }, + { + "index": 234, + "value": { + "name": "pager101-rec0015.akamaigoldentest.com", + "type": "A", + "ttl": 300, + "rdata": [ + "1.2.3.4" + ] + } + }, + { + "index": 235, + "value": { + "name": "pager101-rec0015.akamaigoldentest.com", + "type": "A", + "ttl": 300, + "rdata": [ + "1.2.3.4" + ] + } + }, + { + "index": 236, + "value": { + "name": "pager101-rec0016.akamaigoldentest.com", + "type": "A", + "ttl": 300, + "rdata": [ + "1.2.3.4" + ] + } + }, + { + "index": 237, + "value": { + "name": "pager101-rec0016.akamaigoldentest.com", + "type": "A", + "ttl": 300, + "rdata": [ + "1.2.3.4" + ] + } + }, + { + "index": 238, + "value": { + "name": "pager101-rec0017.akamaigoldentest.com", + "type": "A", + "ttl": 300, + "rdata": [ + "1.2.3.4" + ] + } + }, + { + "index": 239, + "value": { + "name": "pager101-rec0017.akamaigoldentest.com", + "type": "A", + "ttl": 300, + "rdata": [ + "1.2.3.4" + ] + } + }, + { + "index": 240, + "value": { + "name": "pager101-rec0018.akamaigoldentest.com", + "type": "A", + "ttl": 300, + "rdata": [ + "1.2.3.4" + ] + } + }, + { + "index": 241, + "value": { + "name": "pager101-rec0018.akamaigoldentest.com", + "type": "A", + "ttl": 300, + "rdata": [ + "1.2.3.4" + ] + } + }, + { + "index": 242, + "value": { + "name": "pager101-rec0019.akamaigoldentest.com", + "type": "A", + "ttl": 300, + "rdata": [ + "1.2.3.4" + ] + } + }, + { + "index": 243, + "value": { + "name": "pager101-rec0019.akamaigoldentest.com", + "type": "A", + "ttl": 300, + "rdata": [ + "1.2.3.4" + ] + } + }, + { + "index": 244, + "value": { + "name": "pager101-rec0020.akamaigoldentest.com", + "type": "A", + "ttl": 300, + "rdata": [ + "1.2.3.4" + ] + } + }, + { + "index": 245, + "value": { + "name": "pager101-rec0020.akamaigoldentest.com", + "type": "A", + "ttl": 300, + "rdata": [ + "1.2.3.4" + ] + } + }, + { + "index": 246, + "value": { + "name": "pager101-rec0021.akamaigoldentest.com", + "type": "A", + "ttl": 300, + "rdata": [ + "1.2.3.4" + ] + } + }, + { + "index": 247, + "value": { + "name": "pager101-rec0021.akamaigoldentest.com", + "type": "A", + "ttl": 300, + "rdata": [ + "1.2.3.4" + ] + } + }, + { + "index": 248, + "value": { + "name": "pager101-rec0022.akamaigoldentest.com", + "type": "A", + "ttl": 300, + "rdata": [ + "1.2.3.4" + ] + } + }, + { + "index": 249, + "value": { + "name": "pager101-rec0022.akamaigoldentest.com", + "type": "A", + "ttl": 300, + "rdata": [ + "1.2.3.4" + ] + } + }, + { + "index": 250, + "value": { + "name": "pager101-rec0023.akamaigoldentest.com", + "type": "A", + "ttl": 300, + "rdata": [ + "1.2.3.4" + ] + } + }, + { + "index": 251, + "value": { + "name": "pager101-rec0023.akamaigoldentest.com", + "type": "A", + "ttl": 300, + "rdata": [ + "1.2.3.4" + ] + } + }, + { + "index": 252, + "value": { + "name": "pager101-rec0024.akamaigoldentest.com", + "type": "A", + "ttl": 300, + "rdata": [ + "1.2.3.4" + ] + } + }, + { + "index": 253, + "value": { + "name": "pager101-rec0024.akamaigoldentest.com", + "type": "A", + "ttl": 300, + "rdata": [ + "1.2.3.4" + ] + } + }, + { + "index": 254, + "value": { + "name": "pager101-rec0025.akamaigoldentest.com", + "type": "A", + "ttl": 300, + "rdata": [ + "1.2.3.4" + ] + } + }, + { + "index": 255, + "value": { + "name": "pager101-rec0025.akamaigoldentest.com", + "type": "A", + "ttl": 300, + "rdata": [ + "1.2.3.4" + ] + } + }, + { + "index": 256, + "value": { + "name": "pager101-rec0026.akamaigoldentest.com", + "type": "A", + "ttl": 300, + "rdata": [ + "1.2.3.4" + ] + } + }, + { + "index": 257, + "value": { + "name": "pager101-rec0026.akamaigoldentest.com", + "type": "A", + "ttl": 300, + "rdata": [ + "1.2.3.4" + ] + } + }, + { + "index": 258, + "value": { + "name": "pager101-rec0027.akamaigoldentest.com", + "type": "A", + "ttl": 300, + "rdata": [ + "1.2.3.4" + ] + } + }, + { + "index": 259, + "value": { + "name": "pager101-rec0027.akamaigoldentest.com", + "type": "A", + "ttl": 300, + "rdata": [ + "1.2.3.4" + ] + } + }, + { + "index": 260, + "value": { + "name": "pager101-rec0028.akamaigoldentest.com", + "type": "A", + "ttl": 300, + "rdata": [ + "1.2.3.4" + ] + } + }, + { + "index": 261, + "value": { + "name": "pager101-rec0028.akamaigoldentest.com", + "type": "A", + "ttl": 300, + "rdata": [ + "1.2.3.4" + ] + } + }, + { + "index": 262, + "value": { + "name": "pager101-rec0029.akamaigoldentest.com", + "type": "A", + "ttl": 300, + "rdata": [ + "1.2.3.4" + ] + } + }, + { + "index": 263, + "value": { + "name": "pager101-rec0029.akamaigoldentest.com", + "type": "A", + "ttl": 300, + "rdata": [ + "1.2.3.4" + ] + } + }, + { + "index": 264, + "value": { + "name": "pager101-rec0030.akamaigoldentest.com", + "type": "A", + "ttl": 300, + "rdata": [ + "1.2.3.4" + ] + } + }, + { + "index": 265, + "value": { + "name": "pager101-rec0030.akamaigoldentest.com", + "type": "A", + "ttl": 300, + "rdata": [ + "1.2.3.4" + ] + } + }, + { + "index": 266, + "value": { + "name": "pager101-rec0031.akamaigoldentest.com", + "type": "A", + "ttl": 300, + "rdata": [ + "1.2.3.4" + ] + } + }, + { + "index": 267, + "value": { + "name": "pager101-rec0031.akamaigoldentest.com", + "type": "A", + "ttl": 300, + "rdata": [ + "1.2.3.4" + ] + } + }, + { + "index": 268, + "value": { + "name": "pager101-rec0032.akamaigoldentest.com", + "type": "A", + "ttl": 300, + "rdata": [ + "1.2.3.4" + ] + } + }, + { + "index": 269, + "value": { + "name": "pager101-rec0032.akamaigoldentest.com", + "type": "A", + "ttl": 300, + "rdata": [ + "1.2.3.4" + ] + } + }, + { + "index": 270, + "value": { + "name": "pager101-rec0033.akamaigoldentest.com", + "type": "A", + "ttl": 300, + "rdata": [ + "1.2.3.4" + ] + } + }, + { + "index": 271, + "value": { + "name": "pager101-rec0033.akamaigoldentest.com", + "type": "A", + "ttl": 300, + "rdata": [ + "1.2.3.4" + ] + } + }, + { + "index": 272, + "value": { + "name": "pager101-rec0034.akamaigoldentest.com", + "type": "A", + "ttl": 300, + "rdata": [ + "1.2.3.4" + ] + } + }, + { + "index": 273, + "value": { + "name": "pager101-rec0034.akamaigoldentest.com", + "type": "A", + "ttl": 300, + "rdata": [ + "1.2.3.4" + ] + } + }, + { + "index": 274, + "value": { + "name": "pager101-rec0035.akamaigoldentest.com", + "type": "A", + "ttl": 300, + "rdata": [ + "1.2.3.4" + ] + } + }, + { + "index": 275, + "value": { + "name": "pager101-rec0035.akamaigoldentest.com", + "type": "A", + "ttl": 300, + "rdata": [ + "1.2.3.4" + ] + } + }, + { + "index": 276, + "value": { + "name": "pager101-rec0036.akamaigoldentest.com", + "type": "A", + "ttl": 300, + "rdata": [ + "1.2.3.4" + ] + } + }, + { + "index": 277, + "value": { + "name": "pager101-rec0036.akamaigoldentest.com", + "type": "A", + "ttl": 300, + "rdata": [ + "1.2.3.4" + ] + } + }, + { + "index": 278, + "value": { + "name": "pager101-rec0037.akamaigoldentest.com", + "type": "A", + "ttl": 300, + "rdata": [ + "1.2.3.4" + ] + } + }, + { + "index": 279, + "value": { + "name": "pager101-rec0037.akamaigoldentest.com", + "type": "A", + "ttl": 300, + "rdata": [ + "1.2.3.4" + ] + } + }, + { + "index": 280, + "value": { + "name": "pager101-rec0038.akamaigoldentest.com", + "type": "A", + "ttl": 300, + "rdata": [ + "1.2.3.4" + ] + } + }, + { + "index": 281, + "value": { + "name": "pager101-rec0038.akamaigoldentest.com", + "type": "A", + "ttl": 300, + "rdata": [ + "1.2.3.4" + ] + } + }, + { + "index": 282, + "value": { + "name": "pager101-rec0039.akamaigoldentest.com", + "type": "A", + "ttl": 300, + "rdata": [ + "1.2.3.4" + ] + } + }, + { + "index": 283, + "value": { + "name": "pager101-rec0039.akamaigoldentest.com", + "type": "A", + "ttl": 300, + "rdata": [ + "1.2.3.4" + ] + } + }, + { + "index": 284, + "value": { + "name": "pager101-rec0040.akamaigoldentest.com", + "type": "A", + "ttl": 300, + "rdata": [ + "1.2.3.4" + ] + } + }, + { + "index": 285, + "value": { + "name": "pager101-rec0040.akamaigoldentest.com", + "type": "A", + "ttl": 300, + "rdata": [ + "1.2.3.4" + ] + } + }, + { + "index": 286, + "value": { + "name": "pager101-rec0041.akamaigoldentest.com", + "type": "A", + "ttl": 300, + "rdata": [ + "1.2.3.4" + ] + } + }, + { + "index": 287, + "value": { + "name": "pager101-rec0041.akamaigoldentest.com", + "type": "A", + "ttl": 300, + "rdata": [ + "1.2.3.4" + ] + } + }, + { + "index": 288, + "value": { + "name": "pager101-rec0042.akamaigoldentest.com", + "type": "A", + "ttl": 300, + "rdata": [ + "1.2.3.4" + ] + } + }, + { + "index": 289, + "value": { + "name": "pager101-rec0042.akamaigoldentest.com", + "type": "A", + "ttl": 300, + "rdata": [ + "1.2.3.4" + ] + } + }, + { + "index": 290, + "value": { + "name": "pager101-rec0043.akamaigoldentest.com", + "type": "A", + "ttl": 300, + "rdata": [ + "1.2.3.4" + ] + } + }, + { + "index": 291, + "value": { + "name": "pager101-rec0043.akamaigoldentest.com", + "type": "A", + "ttl": 300, + "rdata": [ + "1.2.3.4" + ] + } + }, + { + "index": 292, + "value": { + "name": "pager101-rec0044.akamaigoldentest.com", + "type": "A", + "ttl": 300, + "rdata": [ + "1.2.3.4" + ] + } + }, + { + "index": 293, + "value": { + "name": "pager101-rec0044.akamaigoldentest.com", + "type": "A", + "ttl": 300, + "rdata": [ + "1.2.3.4" + ] + } + }, + { + "index": 294, + "value": { + "name": "pager101-rec0045.akamaigoldentest.com", + "type": "A", + "ttl": 300, + "rdata": [ + "1.2.3.4" + ] + } + }, + { + "index": 295, + "value": { + "name": "pager101-rec0045.akamaigoldentest.com", + "type": "A", + "ttl": 300, + "rdata": [ + "1.2.3.4" + ] + } + }, + { + "index": 296, + "value": { + "name": "pager101-rec0046.akamaigoldentest.com", + "type": "A", + "ttl": 300, + "rdata": [ + "1.2.3.4" + ] + } + }, + { + "index": 297, + "value": { + "name": "pager101-rec0046.akamaigoldentest.com", + "type": "A", + "ttl": 300, + "rdata": [ + "1.2.3.4" + ] + } + }, + { + "index": 298, + "value": { + "name": "pager101-rec0047.akamaigoldentest.com", + "type": "A", + "ttl": 300, + "rdata": [ + "1.2.3.4" + ] + } + }, + { + "index": 299, + "value": { + "name": "pager101-rec0047.akamaigoldentest.com", + "type": "A", + "ttl": 300, + "rdata": [ + "1.2.3.4" + ] + } + }, + { + "index": 300, + "value": { + "name": "pager101-rec0048.akamaigoldentest.com", + "type": "A", + "ttl": 300, + "rdata": [ + "1.2.3.4" + ] + } + }, + { + "index": 301, + "value": { + "name": "pager101-rec0048.akamaigoldentest.com", + "type": "A", + "ttl": 300, + "rdata": [ + "1.2.3.4" + ] + } + }, + { + "index": 302, + "value": { + "name": "pager101-rec0049.akamaigoldentest.com", + "type": "A", + "ttl": 300, + "rdata": [ + "1.2.3.4" + ] + } + }, + { + "index": 303, + "value": { + "name": "pager101-rec0049.akamaigoldentest.com", + "type": "A", + "ttl": 300, + "rdata": [ + "1.2.3.4" + ] + } + }, + { + "index": 304, + "value": { + "name": "pager101-rec0050.akamaigoldentest.com", + "type": "A", + "ttl": 300, + "rdata": [ + "1.2.3.4" + ] + } + }, + { + "index": 305, + "value": { + "name": "pager101-rec0050.akamaigoldentest.com", + "type": "A", + "ttl": 300, + "rdata": [ + "1.2.3.4" + ] + } + }, + { + "index": 306, + "value": { + "name": "pager101-rec0051.akamaigoldentest.com", + "type": "A", + "ttl": 300, + "rdata": [ + "1.2.3.4" + ] + } + }, + { + "index": 307, + "value": { + "name": "pager101-rec0051.akamaigoldentest.com", + "type": "A", + "ttl": 300, + "rdata": [ + "1.2.3.4" + ] + } + }, + { + "index": 308, + "value": { + "name": "pager101-rec0052.akamaigoldentest.com", + "type": "A", + "ttl": 300, + "rdata": [ + "1.2.3.4" + ] + } + }, + { + "index": 309, + "value": { + "name": "pager101-rec0052.akamaigoldentest.com", + "type": "A", + "ttl": 300, + "rdata": [ + "1.2.3.4" + ] + } + }, + { + "index": 310, + "value": { + "name": "pager101-rec0053.akamaigoldentest.com", + "type": "A", + "ttl": 300, + "rdata": [ + "1.2.3.4" + ] + } + }, + { + "index": 311, + "value": { + "name": "pager101-rec0053.akamaigoldentest.com", + "type": "A", + "ttl": 300, + "rdata": [ + "1.2.3.4" + ] + } + }, + { + "index": 312, + "value": { + "name": "pager101-rec0054.akamaigoldentest.com", + "type": "A", + "ttl": 300, + "rdata": [ + "1.2.3.4" + ] + } + }, + { + "index": 313, + "value": { + "name": "pager101-rec0054.akamaigoldentest.com", + "type": "A", + "ttl": 300, + "rdata": [ + "1.2.3.4" + ] + } + }, + { + "index": 314, + "value": { + "name": "pager101-rec0055.akamaigoldentest.com", + "type": "A", + "ttl": 300, + "rdata": [ + "1.2.3.4" + ] + } + }, + { + "index": 315, + "value": { + "name": "pager101-rec0055.akamaigoldentest.com", + "type": "A", + "ttl": 300, + "rdata": [ + "1.2.3.4" + ] + } + }, + { + "index": 316, + "value": { + "name": "pager101-rec0056.akamaigoldentest.com", + "type": "A", + "ttl": 300, + "rdata": [ + "1.2.3.4" + ] + } + }, + { + "index": 317, + "value": { + "name": "pager101-rec0056.akamaigoldentest.com", + "type": "A", + "ttl": 300, + "rdata": [ + "1.2.3.4" + ] + } + }, + { + "index": 318, + "value": { + "name": "pager101-rec0057.akamaigoldentest.com", + "type": "A", + "ttl": 300, + "rdata": [ + "1.2.3.4" + ] + } + }, + { + "index": 319, + "value": { + "name": "pager101-rec0057.akamaigoldentest.com", + "type": "A", + "ttl": 300, + "rdata": [ + "1.2.3.4" + ] + } + }, + { + "index": 320, + "value": { + "name": "pager101-rec0058.akamaigoldentest.com", + "type": "A", + "ttl": 300, + "rdata": [ + "1.2.3.4" + ] + } + }, + { + "index": 321, + "value": { + "name": "pager101-rec0058.akamaigoldentest.com", + "type": "A", + "ttl": 300, + "rdata": [ + "1.2.3.4" + ] + } + }, + { + "index": 322, + "value": { + "name": "pager101-rec0059.akamaigoldentest.com", + "type": "A", + "ttl": 300, + "rdata": [ + "1.2.3.4" + ] + } + }, + { + "index": 323, + "value": { + "name": "pager101-rec0059.akamaigoldentest.com", + "type": "A", + "ttl": 300, + "rdata": [ + "1.2.3.4" + ] + } + }, + { + "index": 324, + "value": { + "name": "pager101-rec0060.akamaigoldentest.com", + "type": "A", + "ttl": 300, + "rdata": [ + "1.2.3.4" + ] + } + }, + { + "index": 325, + "value": { + "name": "pager101-rec0060.akamaigoldentest.com", + "type": "A", + "ttl": 300, + "rdata": [ + "1.2.3.4" + ] + } + }, + { + "index": 326, + "value": { + "name": "pager101-rec0061.akamaigoldentest.com", + "type": "A", + "ttl": 300, + "rdata": [ + "1.2.3.4" + ] + } + }, + { + "index": 327, + "value": { + "name": "pager101-rec0061.akamaigoldentest.com", + "type": "A", + "ttl": 300, + "rdata": [ + "1.2.3.4" + ] + } + }, + { + "index": 328, + "value": { + "name": "pager101-rec0062.akamaigoldentest.com", + "type": "A", + "ttl": 300, + "rdata": [ + "1.2.3.4" + ] + } + }, + { + "index": 329, + "value": { + "name": "pager101-rec0062.akamaigoldentest.com", + "type": "A", + "ttl": 300, + "rdata": [ + "1.2.3.4" + ] + } + }, + { + "index": 330, + "value": { + "name": "pager101-rec0063.akamaigoldentest.com", + "type": "A", + "ttl": 300, + "rdata": [ + "1.2.3.4" + ] + } + }, + { + "index": 331, + "value": { + "name": "pager101-rec0063.akamaigoldentest.com", + "type": "A", + "ttl": 300, + "rdata": [ + "1.2.3.4" + ] + } + }, + { + "index": 332, + "value": { + "name": "pager101-rec0064.akamaigoldentest.com", + "type": "A", + "ttl": 300, + "rdata": [ + "1.2.3.4" + ] + } + }, + { + "index": 333, + "value": { + "name": "pager101-rec0064.akamaigoldentest.com", + "type": "A", + "ttl": 300, + "rdata": [ + "1.2.3.4" + ] + } + }, + { + "index": 334, + "value": { + "name": "pager101-rec0065.akamaigoldentest.com", + "type": "A", + "ttl": 300, + "rdata": [ + "1.2.3.4" + ] + } + }, + { + "index": 335, + "value": { + "name": "pager101-rec0065.akamaigoldentest.com", + "type": "A", + "ttl": 300, + "rdata": [ + "1.2.3.4" + ] + } + }, + { + "index": 336, + "value": { + "name": "pager101-rec0066.akamaigoldentest.com", + "type": "A", + "ttl": 300, + "rdata": [ + "1.2.3.4" + ] + } + }, + { + "index": 337, + "value": { + "name": "pager101-rec0066.akamaigoldentest.com", + "type": "A", + "ttl": 300, + "rdata": [ + "1.2.3.4" + ] + } + }, + { + "index": 338, + "value": { + "name": "pager101-rec0067.akamaigoldentest.com", + "type": "A", + "ttl": 300, + "rdata": [ + "1.2.3.4" + ] + } + }, + { + "index": 339, + "value": { + "name": "pager101-rec0067.akamaigoldentest.com", + "type": "A", + "ttl": 300, + "rdata": [ + "1.2.3.4" + ] + } + }, + { + "index": 340, + "value": { + "name": "pager101-rec0068.akamaigoldentest.com", + "type": "A", + "ttl": 300, + "rdata": [ + "1.2.3.4" + ] + } + }, + { + "index": 341, + "value": { + "name": "pager101-rec0068.akamaigoldentest.com", + "type": "A", + "ttl": 300, + "rdata": [ + "1.2.3.4" + ] + } + }, + { + "index": 342, + "value": { + "name": "pager101-rec0069.akamaigoldentest.com", + "type": "A", + "ttl": 300, + "rdata": [ + "1.2.3.4" + ] + } + }, + { + "index": 343, + "value": { + "name": "pager101-rec0069.akamaigoldentest.com", + "type": "A", + "ttl": 300, + "rdata": [ + "1.2.3.4" + ] + } + }, + { + "index": 344, + "value": { + "name": "pager101-rec0070.akamaigoldentest.com", + "type": "A", + "ttl": 300, + "rdata": [ + "1.2.3.4" + ] + } + }, + { + "index": 345, + "value": { + "name": "pager101-rec0070.akamaigoldentest.com", + "type": "A", + "ttl": 300, + "rdata": [ + "1.2.3.4" + ] + } + }, + { + "index": 346, + "value": { + "name": "pager101-rec0071.akamaigoldentest.com", + "type": "A", + "ttl": 300, + "rdata": [ + "1.2.3.4" + ] + } + }, + { + "index": 347, + "value": { + "name": "pager101-rec0071.akamaigoldentest.com", + "type": "A", + "ttl": 300, + "rdata": [ + "1.2.3.4" + ] + } + }, + { + "index": 348, + "value": { + "name": "pager101-rec0072.akamaigoldentest.com", + "type": "A", + "ttl": 300, + "rdata": [ + "1.2.3.4" + ] + } + }, + { + "index": 349, + "value": { + "name": "pager101-rec0072.akamaigoldentest.com", + "type": "A", + "ttl": 300, + "rdata": [ + "1.2.3.4" + ] + } + }, + { + "index": 350, + "value": { + "name": "pager101-rec0073.akamaigoldentest.com", + "type": "A", + "ttl": 300, + "rdata": [ + "1.2.3.4" + ] + } + }, + { + "index": 351, + "value": { + "name": "pager101-rec0073.akamaigoldentest.com", + "type": "A", + "ttl": 300, + "rdata": [ + "1.2.3.4" + ] + } + }, + { + "index": 352, + "value": { + "name": "pager101-rec0074.akamaigoldentest.com", + "type": "A", + "ttl": 300, + "rdata": [ + "1.2.3.4" + ] + } + }, + { + "index": 353, + "value": { + "name": "pager101-rec0074.akamaigoldentest.com", + "type": "A", + "ttl": 300, + "rdata": [ + "1.2.3.4" + ] + } + }, + { + "index": 354, + "value": { + "name": "pager101-rec0075.akamaigoldentest.com", + "type": "A", + "ttl": 300, + "rdata": [ + "1.2.3.4" + ] + } + }, + { + "index": 355, + "value": { + "name": "pager101-rec0075.akamaigoldentest.com", + "type": "A", + "ttl": 300, + "rdata": [ + "1.2.3.4" + ] + } + }, + { + "index": 356, + "value": { + "name": "pager101-rec0076.akamaigoldentest.com", + "type": "A", + "ttl": 300, + "rdata": [ + "1.2.3.4" + ] + } + }, + { + "index": 357, + "value": { + "name": "pager101-rec0076.akamaigoldentest.com", + "type": "A", + "ttl": 300, + "rdata": [ + "1.2.3.4" + ] + } + }, + { + "index": 358, + "value": { + "name": "pager101-rec0077.akamaigoldentest.com", + "type": "A", + "ttl": 300, + "rdata": [ + "1.2.3.4" + ] + } + }, + { + "index": 359, + "value": { + "name": "pager101-rec0077.akamaigoldentest.com", + "type": "A", + "ttl": 300, + "rdata": [ + "1.2.3.4" + ] + } + }, + { + "index": 360, + "value": { + "name": "pager101-rec0078.akamaigoldentest.com", + "type": "A", + "ttl": 300, + "rdata": [ + "1.2.3.4" + ] + } + }, + { + "index": 361, + "value": { + "name": "pager101-rec0078.akamaigoldentest.com", + "type": "A", + "ttl": 300, + "rdata": [ + "1.2.3.4" + ] + } + }, + { + "index": 362, + "value": { + "name": "pager101-rec0079.akamaigoldentest.com", + "type": "A", + "ttl": 300, + "rdata": [ + "1.2.3.4" + ] + } + }, + { + "index": 363, + "value": { + "name": "pager101-rec0079.akamaigoldentest.com", + "type": "A", + "ttl": 300, + "rdata": [ + "1.2.3.4" + ] + } + }, + { + "index": 364, + "value": { + "name": "pager101-rec0080.akamaigoldentest.com", + "type": "A", + "ttl": 300, + "rdata": [ + "1.2.3.4" + ] + } + }, + { + "index": 365, + "value": { + "name": "pager101-rec0080.akamaigoldentest.com", + "type": "A", + "ttl": 300, + "rdata": [ + "1.2.3.4" + ] + } + }, + { + "index": 366, + "value": { + "name": "pager101-rec0081.akamaigoldentest.com", + "type": "A", + "ttl": 300, + "rdata": [ + "1.2.3.4" + ] + } + }, + { + "index": 367, + "value": { + "name": "pager101-rec0081.akamaigoldentest.com", + "type": "A", + "ttl": 300, + "rdata": [ + "1.2.3.4" + ] + } + }, + { + "index": 368, + "value": { + "name": "pager101-rec0082.akamaigoldentest.com", + "type": "A", + "ttl": 300, + "rdata": [ + "1.2.3.4" + ] + } + }, + { + "index": 369, + "value": { + "name": "pager101-rec0082.akamaigoldentest.com", + "type": "A", + "ttl": 300, + "rdata": [ + "1.2.3.4" + ] + } + }, + { + "index": 370, + "value": { + "name": "pager101-rec0083.akamaigoldentest.com", + "type": "A", + "ttl": 300, + "rdata": [ + "1.2.3.4" + ] + } + }, + { + "index": 371, + "value": { + "name": "pager101-rec0083.akamaigoldentest.com", + "type": "A", + "ttl": 300, + "rdata": [ + "1.2.3.4" + ] + } + }, + { + "index": 372, + "value": { + "name": "pager101-rec0084.akamaigoldentest.com", + "type": "A", + "ttl": 300, + "rdata": [ + "1.2.3.4" + ] + } + }, + { + "index": 373, + "value": { + "name": "pager101-rec0084.akamaigoldentest.com", + "type": "A", + "ttl": 300, + "rdata": [ + "1.2.3.4" + ] + } + }, + { + "index": 374, + "value": { + "name": "pager101-rec0085.akamaigoldentest.com", + "type": "A", + "ttl": 300, + "rdata": [ + "1.2.3.4" + ] + } + }, + { + "index": 375, + "value": { + "name": "pager101-rec0085.akamaigoldentest.com", + "type": "A", + "ttl": 300, + "rdata": [ + "1.2.3.4" + ] + } + }, + { + "index": 376, + "value": { + "name": "pager101-rec0086.akamaigoldentest.com", + "type": "A", + "ttl": 300, + "rdata": [ + "1.2.3.4" + ] + } + }, + { + "index": 377, + "value": { + "name": "pager101-rec0086.akamaigoldentest.com", + "type": "A", + "ttl": 300, + "rdata": [ + "1.2.3.4" + ] + } + }, + { + "index": 378, + "value": { + "name": "pager101-rec0087.akamaigoldentest.com", + "type": "A", + "ttl": 300, + "rdata": [ + "1.2.3.4" + ] + } + }, + { + "index": 379, + "value": { + "name": "pager101-rec0087.akamaigoldentest.com", + "type": "A", + "ttl": 300, + "rdata": [ + "1.2.3.4" + ] + } + }, + { + "index": 380, + "value": { + "name": "pager101-rec0088.akamaigoldentest.com", + "type": "A", + "ttl": 300, + "rdata": [ + "1.2.3.4" + ] + } + }, + { + "index": 381, + "value": { + "name": "pager101-rec0088.akamaigoldentest.com", + "type": "A", + "ttl": 300, + "rdata": [ + "1.2.3.4" + ] + } + }, + { + "index": 382, + "value": { + "name": "pager101-rec0089.akamaigoldentest.com", + "type": "A", + "ttl": 300, + "rdata": [ + "1.2.3.4" + ] + } + }, + { + "index": 383, + "value": { + "name": "pager101-rec0089.akamaigoldentest.com", + "type": "A", + "ttl": 300, + "rdata": [ + "1.2.3.4" + ] + } + }, + { + "index": 384, + "value": { + "name": "pager101-rec0090.akamaigoldentest.com", + "type": "A", + "ttl": 300, + "rdata": [ + "1.2.3.4" + ] + } + }, + { + "index": 385, + "value": { + "name": "pager101-rec0090.akamaigoldentest.com", + "type": "A", + "ttl": 300, + "rdata": [ + "1.2.3.4" + ] + } + }, + { + "index": 386, + "value": { + "name": "pager101-rec0091.akamaigoldentest.com", + "type": "A", + "ttl": 300, + "rdata": [ + "1.2.3.4" + ] + } + }, + { + "index": 387, + "value": { + "name": "pager101-rec0091.akamaigoldentest.com", + "type": "A", + "ttl": 300, + "rdata": [ + "1.2.3.4" + ] + } + }, + { + "index": 388, + "value": { + "name": "pager101-rec0092.akamaigoldentest.com", + "type": "A", + "ttl": 300, + "rdata": [ + "1.2.3.4" + ] + } + }, + { + "index": 389, + "value": { + "name": "pager101-rec0092.akamaigoldentest.com", + "type": "A", + "ttl": 300, + "rdata": [ + "1.2.3.4" + ] + } + }, + { + "index": 390, + "value": { + "name": "pager101-rec0093.akamaigoldentest.com", + "type": "A", + "ttl": 300, + "rdata": [ + "1.2.3.4" + ] + } + }, + { + "index": 391, + "value": { + "name": "pager101-rec0093.akamaigoldentest.com", + "type": "A", + "ttl": 300, + "rdata": [ + "1.2.3.4" + ] + } + }, + { + "index": 392, + "value": { + "name": "pager101-rec0094.akamaigoldentest.com", + "type": "A", + "ttl": 300, + "rdata": [ + "1.2.3.4" + ] + } + }, + { + "index": 393, + "value": { + "name": "pager101-rec0094.akamaigoldentest.com", + "type": "A", + "ttl": 300, + "rdata": [ + "1.2.3.4" + ] + } + }, + { + "index": 394, + "value": { + "name": "pager101-rec0095.akamaigoldentest.com", + "type": "A", + "ttl": 300, + "rdata": [ + "1.2.3.4" + ] + } + }, + { + "index": 395, + "value": { + "name": "pager101-rec0095.akamaigoldentest.com", + "type": "A", + "ttl": 300, + "rdata": [ + "1.2.3.4" + ] + } + }, + { + "index": 396, + "value": { + "name": "pager101-rec0096.akamaigoldentest.com", + "type": "A", + "ttl": 300, + "rdata": [ + "1.2.3.4" + ] + } + }, + { + "index": 397, + "value": { + "name": "pager101-rec0096.akamaigoldentest.com", + "type": "A", + "ttl": 300, + "rdata": [ + "1.2.3.4" + ] + } + }, + { + "index": 398, + "value": { + "name": "pager101-rec0097.akamaigoldentest.com", + "type": "A", + "ttl": 300, + "rdata": [ + "1.2.3.4" + ] + } + }, + { + "index": 399, + "value": { + "name": "pager101-rec0097.akamaigoldentest.com", + "type": "A", + "ttl": 300, + "rdata": [ + "1.2.3.4" + ] + } + }, + { + "index": 400, + "value": { + "name": "pager101-rec0098.akamaigoldentest.com", + "type": "A", + "ttl": 300, + "rdata": [ + "1.2.3.4" + ] + } + }, + { + "index": 401, + "value": { + "name": "pager101-rec0098.akamaigoldentest.com", + "type": "A", + "ttl": 300, + "rdata": [ + "1.2.3.4" + ] + } + }, + { + "index": 402, + "value": { + "name": "pager101-rec0099.akamaigoldentest.com", + "type": "A", + "ttl": 300, + "rdata": [ + "1.2.3.4" + ] + } + }, + { + "index": 403, + "value": { + "name": "pager101-rec0099.akamaigoldentest.com", + "type": "A", + "ttl": 300, + "rdata": [ + "1.2.3.4" + ] + } + }, + { + "index": 404, + "value": { + "name": "pager101-rec0100.akamaigoldentest.com", + "type": "A", + "ttl": 300, + "rdata": [ + "1.2.3.4" + ] + } + }, + { + "index": 405, + "value": { + "name": "pager101-rec0100.akamaigoldentest.com", + "type": "A", + "ttl": 300, + "rdata": [ + "1.2.3.4" + ] + } + }, + { + "index": 406, + "value": { + "name": "test.akamaigoldentest.com", + "type": "CNAME", + "ttl": 300, + "rdata": [ + "foo.com." + ] + } + }, + { + "index": 407, + "value": { + "name": "test.akamaigoldentest.com", + "type": "CNAME", + "ttl": 300, + "rdata": [ + "foo2.com." + ] + } + }, + { + "index": 408, + "value": { + "name": "test.akamaigoldentest.com", + "type": "CNAME", + "ttl": 300, + "rdata": [ + "foo2.com." + ] + } + }, + { + "index": 409, + "value": { + "name": "test.akamaigoldentest.com", + "type": "NAPTR", + "ttl": 300, + "rdata": [ + "100 10 \"U\" \"E2U+sip\" \"!^.*$!sip:customer-service@example.com!\" ." + ] + } + }, + { + "index": 410, + "value": { + "name": "test.akamaigoldentest.com", + "type": "NAPTR", + "ttl": 300, + "rdata": [ + "100 10 \"U\" \"E2U+sip\" \"!^.*$!sip:customer-service@example.com!\" .", + "102 10 \"U\" \"E2U+email\" \"!^.*$!mailto:information@example.com!\" ." + ] + } + }, + { + "index": 411, + "value": { + "name": "test.akamaigoldentest.com", + "type": "NAPTR", + "ttl": 300, + "rdata": [ + "103 10 \"U\" \"E2U+email\" \"!^.*$!mailto:information@example.com!\" ." + ] + } + }, + { + "index": 412, + "value": { + "name": "test.akamaigoldentest.com", + "type": "NAPTR", + "ttl": 300, + "rdata": [ + "103 20 \"A\" \"E2U+email\" \"!^.*$!mailto:information@example.com!\" ." + ] + } + }, + { + "index": 413, + "value": { + "name": "test.akamaigoldentest.com", + "type": "NAPTR", + "ttl": 300, + "rdata": [ + "103 20 \"A\" \"E2U+sip\" \"!^.*$!mailto:information@example.com!\" ." + ] + } + }, + { + "index": 414, + "value": { + "name": "test.akamaigoldentest.com", + "type": "NAPTR", + "ttl": 300, + "rdata": [ + "103 20 \"A\" \"E2U+sip\" \"!^.*$!sip:customer-service@example.com!\" ." + ] + } + }, + { + "index": 415, + "value": { + "name": "test.akamaigoldentest.com", + "type": "NAPTR", + "ttl": 300, + "rdata": [ + "103 20 \"A\" \"E2U+sip\" \"\" example.foo.com." + ] + } + }, + { + "index": 416, + "value": { + "name": "test.akamaigoldentest.com", + "type": "NAPTR", + "ttl": 300, + "rdata": [ + "103 20 \"A\" \"E2U+sip\" \"\" example2.foo.com." + ] + } + }, + { + "index": 417, + "value": { + "name": "test.akamaigoldentest.com", + "type": "NAPTR", + "ttl": 300, + "rdata": [ + "103 20 \"A\" \"E2U+sip\" \"\" example2.foo.com." + ] + } + }, + { + "index": 418, + "value": { + "name": "test.akamaigoldentest.com", + "type": "NAPTR", + "ttl": 300, + "rdata": [ + "103 20 \"U\" \"E2U+email\" \"!^.*$!mailto:information@example.com!\" ." + ] + } + }, + { + "index": 419, + "value": { + "name": "testa.akamaigoldentest.com", + "type": "A", + "ttl": 300, + "rdata": [ + "1.1.1.1" + ] + } + }, + { + "index": 420, + "value": { + "name": "testa.akamaigoldentest.com", + "type": "A", + "ttl": 300, + "rdata": [ + "3.3.3.3" + ] + } + }, + { + "index": 421, + "value": { + "name": "testa.akamaigoldentest.com", + "type": "A", + "ttl": 300, + "rdata": [ + "3.3.3.3" + ] + } + }, + { + "index": 422, + "value": { + "name": "testa.akamaigoldentest.com", + "type": "A", + "ttl": 333, + "rdata": [ + "1.1.1.1" + ] + } + }, + { + "index": 423, + "value": { + "name": "testa.akamaigoldentest.com", + "type": "A", + "ttl": 999, + "rdata": [ + "1.1.1.1" + ] + } + }, + { + "index": 424, + "value": { + "name": "testa.akamaigoldentest.com", + "type": "A", + "ttl": 999, + "rdata": [ + "1.1.1.1" + ] + } + }, + { + "index": 425, + "value": { + "name": "testaaaa.akamaigoldentest.com", + "type": "AAAA", + "ttl": 300, + "rdata": [ + "2607:f8b0:4006:820::2006" + ] + } + }, + { + "index": 426, + "value": { + "name": "testaaaa.akamaigoldentest.com", + "type": "AAAA", + "ttl": 300, + "rdata": [ + "2607:f8b0:4006:820::2013" + ] + } + }, + { + "index": 427, + "value": { + "name": "testaaaa.akamaigoldentest.com", + "type": "AAAA", + "ttl": 300, + "rdata": [ + "2607:f8b0:4006:820::2013" + ] + } + }, + { + "index": 428, + "value": { + "name": "testcname.akamaigoldentest.com", + "type": "CNAME", + "ttl": 300, + "rdata": [ + "foo.akamaigoldentest.com." + ] + } + }, + { + "index": 429, + "value": { + "name": "testcname.akamaigoldentest.com", + "type": "CNAME", + "ttl": 300, + "rdata": [ + "foo.akamaigoldentest.com." + ] + } + }, + { + "index": 430, + "value": { + "name": "testcname.akamaigoldentest.com", + "type": "CNAME", + "ttl": 300, + "rdata": [ + "www.google.com." + ] + } + }, + { + "index": 431, + "value": { + "name": "testcname.akamaigoldentest.com", + "type": "CNAME", + "ttl": 300, + "rdata": [ + "www.yahoo.com." + ] + } + }, + { + "index": 432, + "value": { + "name": "testcname.akamaigoldentest.com", + "type": "CNAME", + "ttl": 300, + "rdata": [ + "www.yahoo.com." + ] + } + }, + { + "index": 433, + "value": { + "name": "testdefined.akamaigoldentest.com", + "type": "A", + "ttl": 300, + "rdata": [ + "2.2.2.2" + ] + } + }, + { + "index": 434, + "value": { + "name": "testdefined.akamaigoldentest.com", + "type": "A", + "ttl": 300, + "rdata": [ + "2.2.2.2" + ] + } + }, + { + "index": 435, + "value": { + "name": "testdefined.akamaigoldentest.com", + "type": "A", + "ttl": 300, + "rdata": [ + "9.9.9.9" + ] + } + }, + { + "index": 436, + "value": { + "name": "testignore.akamaigoldentest.com", + "type": "A", + "ttl": 300, + "rdata": [ + "8.8.8.8" + ] + } + }, + { + "index": 437, + "value": { + "name": "testignore.akamaigoldentest.com", + "type": "A", + "ttl": 300, + "rdata": [ + "8.8.8.8" + ] + } + }, + { + "index": 438, + "value": { + "name": "testmx.akamaigoldentest.com", + "type": "MX", + "ttl": 300, + "rdata": [ + "100 foo.com." + ] + } + }, + { + "index": 439, + "value": { + "name": "testmx.akamaigoldentest.com", + "type": "MX", + "ttl": 300, + "rdata": [ + "100 foo.com." + ] + } + }, + { + "index": 440, + "value": { + "name": "testmx.akamaigoldentest.com", + "type": "MX", + "ttl": 300, + "rdata": [ + "5 bar.com." + ] + } + }, + { + "index": 441, + "value": { + "name": "testmx.akamaigoldentest.com", + "type": "MX", + "ttl": 300, + "rdata": [ + "5 bar.com." + ] + } + }, + { + "index": 442, + "value": { + "name": "testmx.akamaigoldentest.com", + "type": "MX", + "ttl": 300, + "rdata": [ + "5 foo.com." + ] + } + }, + { + "index": 443, + "value": { + "name": "testmx.akamaigoldentest.com", + "type": "MX", + "ttl": 300, + "rdata": [ + "5 foo.com.", + "100 bar.com." + ] + } + }, + { + "index": 444, + "value": { + "name": "testmx.akamaigoldentest.com", + "type": "MX", + "ttl": 300, + "rdata": [ + "5 foo.com.", + "100 bar.com." + ] + } + }, + { + "index": 445, + "value": { + "name": "testtxt.akamaigoldentest.com", + "type": "TXT", + "ttl": 300, + "rdata": [ + "\"changed\"" + ] + } + }, + { + "index": 446, + "value": { + "name": "testtxt.akamaigoldentest.com", + "type": "TXT", + "ttl": 300, + "rdata": [ + "\"changed\"" + ] + } + }, + { + "index": 447, + "value": { + "name": "testtxt.akamaigoldentest.com", + "type": "TXT", + "ttl": 300, + "rdata": [ + "\"simple\"" + ] + } + }, + { + "index": 448, + "value": { + "name": "www.akamaigoldentest.com", + "type": "A", + "ttl": 300, + "rdata": [ + "1.1.1.1" + ] + } + }, + { + "index": 449, + "value": { + "name": "www.akamaigoldentest.com", + "type": "A", + "ttl": 300, + "rdata": [ + "1.1.1.1", + "2.2.2.2" + ] + } + }, + { + "index": 450, + "value": { + "name": "www.akamaigoldentest.com", + "type": "A", + "ttl": 300, + "rdata": [ + "1.1.1.1", + "2.2.2.2", + "3.3.3.3" + ] + } + }, + { + "index": 451, + "value": { + "name": "www.akamaigoldentest.com", + "type": "A", + "ttl": 300, + "rdata": [ + "1.1.1.1" + ] + } + }, + { + "index": 452, + "value": { + "name": "www.akamaigoldentest.com", + "type": "A", + "ttl": 300, + "rdata": [ + "1.1.1.1", + "2.2.2.2", + "3.3.3.3" + ] + } + }, + { + "index": 453, + "value": { + "name": "www.akamaigoldentest.com", + "type": "A", + "ttl": 300, + "rdata": [ + "1.2.3.4", + "5.6.7.8" + ] + } + }, + { + "index": 454, + "value": { + "name": "www.akamaigoldentest.com", + "type": "A", + "ttl": 300, + "rdata": [ + "1.2.3.8" + ] + } + }, + { + "index": 455, + "value": { + "name": "www.akamaigoldentest.com", + "type": "A", + "ttl": 300, + "rdata": [ + "1.2.3.8" + ] + } + }, + { + "index": 456, + "value": { + "name": "www.akamaigoldentest.com", + "type": "A", + "ttl": 300, + "rdata": [ + "1.2.3.9" + ] + } + }, + { + "index": 457, + "value": { + "name": "www.akamaigoldentest.com", + "type": "A", + "ttl": 300, + "rdata": [ + "1.2.3.9" + ] + } + }, + { + "index": 458, + "value": { + "name": "www.akamaigoldentest.com", + "type": "A", + "ttl": 300, + "rdata": [ + "2.2.2.2", + "5.6.7.8" + ] + } + }, + { + "index": 459, + "value": { + "name": "www.akamaigoldentest.com", + "type": "A", + "ttl": 300, + "rdata": [ + "5.5.5.5" + ] + } + }, + { + "index": 460, + "value": { + "name": "www.akamaigoldentest.com", + "type": "A", + "ttl": 300, + "rdata": [ + "5.5.5.5" + ] + } + }, + { + "index": 461, + "value": { + "name": "www.akamaigoldentest.com", + "type": "A", + "ttl": 400, + "rdata": [ + "2.2.2.2", + "5.6.7.8" + ] + } + }, + { + "index": 462, + "value": { + "name": "www.akamaigoldentest.com", + "type": "A", + "ttl": 400, + "rdata": [ + "2.2.2.2", + "5.6.7.8" + ] + } + }, + { + "index": 463, + "value": { + "name": "www.akamaigoldentest.com", + "type": "A", + "ttl": 400, + "rdata": [ + "5.6.7.8" + ] + } + }, + { + "index": 464, + "value": { + "name": "www.akamaigoldentest.com", + "type": "A", + "ttl": 700, + "rdata": [ + "1.2.3.4", + "5.6.7.8" + ] + } + }, + { + "index": 465, + "value": { + "name": "www.akamaigoldentest.com", + "type": "A", + "ttl": 700, + "rdata": [ + "1.2.3.4", + "5.6.7.8" + ] + } + }, + { + "index": 466, + "value": { + "name": "xn--fiq228c.akamaigoldentest.com", + "type": "A", + "ttl": 300, + "rdata": [ + "1.2.3.4" + ] + } + }, + { + "index": 467, + "value": { + "name": "xn--fiq228c.akamaigoldentest.com", + "type": "A", + "ttl": 300, + "rdata": [ + "1.2.3.4" + ] + } + }, + { + "index": 468, + "value": { + "name": "xn--ndaaa.akamaigoldentest.com", + "type": "A", + "ttl": 300, + "rdata": [ + "1.2.3.4" + ] + } + }, + { + "index": 469, + "value": { + "name": "xn--ndaaa.akamaigoldentest.com", + "type": "A", + "ttl": 300, + "rdata": [ + "2.2.2.2" + ] + } + }, + { + "index": 470, + "value": { + "name": "xn--ndaaa.akamaigoldentest.com", + "type": "A", + "ttl": 300, + "rdata": [ + "2.2.2.2" + ] + } + }, + { + "index": 471, + "value": { + "name": "xn--o-0gab.akamaigoldentest.com", + "type": "CNAME", + "ttl": 300, + "rdata": [ + "xn--ndaaa.xn--vhquv." + ] + } + }, + { + "index": 472, + "value": { + "name": "xn--o-0gab.akamaigoldentest.com", + "type": "CNAME", + "ttl": 300, + "rdata": [ + "xn--ndaaa.xn--vhquv." + ] + } + }, + { + "index": 473, + "value": { + "name": "xyz.akamaigoldentest.com", + "type": "NS", + "ttl": 300, + "rdata": [ + "ns1.foo.com.", + "ns2.foo.com." + ] + } + }, + { + "index": 474, + "value": { + "name": "xyz.akamaigoldentest.com", + "type": "NS", + "ttl": 300, + "rdata": [ + "ns1.foo.com.", + "ns2.foo.com." + ] + } + }, + { + "index": 475, + "value": { + "name": "xyz.akamaigoldentest.com", + "type": "NS", + "ttl": 300, + "rdata": [ + "ns2.foo.com." + ] + } + }, + { + "index": 476, + "value": { + "name": "zzz.akamaigoldentest.com", + "type": "A", + "ttl": 300, + "rdata": [ + "3.3.3.3", + "4.4.4.4" + ] + } + }, + { + "index": 477, + "value": { + "name": "zzz.akamaigoldentest.com", + "type": "A", + "ttl": 300, + "rdata": [ + "3.3.3.3", + "4.4.4.4" + ] + } + }, + { + "index": 478, + "value": { + "name": "zzz.akamaigoldentest.com", + "type": "AAAA", + "ttl": 300, + "rdata": [ + "2003:dd:d7ff::fe71:cccc" + ] + } + }, + { + "index": 479, + "value": { + "name": "zzz.akamaigoldentest.com", + "type": "AAAA", + "ttl": 300, + "rdata": [ + "2003:dd:d7ff::fe71:cccc" + ] + } + } +] diff --git a/providers/akamaiedgedns/test_data/expected_torc_output_nativeToRecords_akamaigoldentest.com.records b/providers/akamaiedgedns/test_data/expected_torc_output_nativeToRecords_akamaigoldentest.com.records new file mode 100644 index 0000000000..644e8a3393 --- /dev/null +++ b/providers/akamaiedgedns/test_data/expected_torc_output_nativeToRecords_akamaigoldentest.com.records @@ -0,0 +1,333 @@ +1 * 300 IN A 3.3.3.3 ; akamai_raw_rdata="3.3.3.3" +2 4 300 IN PTR bar.com. ; akamai_raw_rdata="bar.com." +3 4 300 IN PTR foo.com. ; akamai_raw_rdata="foo.com." +4 _443._tcp 300 IN TLSA 2 0 1 0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF ; akamai_raw_rdata="2 0 1 0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF" +5 _443._tcp 300 IN TLSA 2 0 2 0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF ; akamai_raw_rdata="2 0 2 0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF" +6 _443._tcp 300 IN TLSA 2 0 2 FEDCBA9876543210FEDCBA9876543210FEDCBA9876543210FEDCBA9876543210FEDCBA9876543210FEDCBA9876543210FEDCBA9876543210FEDCBA9876543210 ; akamai_raw_rdata="2 0 2 FEDCBA9876543210FEDCBA9876543210FEDCBA9876543210FEDCBA9876543210FEDCBA9876543210FEDCBA9876543210FEDCBA9876543210FEDCBA9876543210" +7 _443._tcp 300 IN TLSA 2 1 1 0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF ; akamai_raw_rdata="2 1 1 0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF" +8 _443._tcp 300 IN TLSA 3 1 1 0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF ; akamai_raw_rdata="3 1 1 0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF" +9 _sip._tcp 300 IN SRV 15 65 75 . ; akamai_raw_rdata="15 65 75 ." +10 _sip._tcp 300 IN SRV 15 65 75 foo4.com. ; akamai_raw_rdata="15 65 75 foo4.com." +10 _sip._tcp 300 IN SRV 52 6 7 foo.com. ; akamai_raw_rdata="52 6 7 foo.com." +11 _sip._tcp 300 IN SRV 15 65 75 foo4.com. ; akamai_raw_rdata="15 65 75 foo4.com." +11 _sip._tcp 300 IN SRV 52 62 7 foo.com. ; akamai_raw_rdata="52 62 7 foo.com." +12 _sip._tcp 300 IN SRV 15 65 75 foo4.com. ; akamai_raw_rdata="15 65 75 foo4.com." +12 _sip._tcp 300 IN SRV 52 62 72 foo.com. ; akamai_raw_rdata="52 62 72 foo.com." +13 _sip._tcp 300 IN SRV 5 6 7 foo.com. ; akamai_raw_rdata="5 6 7 foo.com." +13 _sip._tcp 300 IN SRV 15 65 75 foo3.com. ; akamai_raw_rdata="15 65 75 foo3.com." +14 _sip._tcp 300 IN SRV 5 6 7 foo.com. ; akamai_raw_rdata="5 6 7 foo.com." +14 _sip._tcp 300 IN SRV 15 65 75 foo4.com. ; akamai_raw_rdata="15 65 75 foo4.com." +15 _sip._tcp 300 IN SRV 5 6 7 foo.com. ; akamai_raw_rdata="5 6 7 foo.com." +15 _sip._tcp 300 IN SRV 5 60 70 foo2.com. ; akamai_raw_rdata="5 60 70 foo2.com." +15 _sip._tcp 300 IN SRV 15 65 75 foo3.com. ; akamai_raw_rdata="15 65 75 foo3.com." +16 _sip._tcp 300 IN SRV 5 6 7 foo.com. ; akamai_raw_rdata="5 6 7 foo.com." +16 _sip._tcp 300 IN SRV 5 60 70 foo2.com. ; akamai_raw_rdata="5 60 70 foo2.com." +17 _sip._tcp 300 IN SRV 5 6 7 foo.com. ; akamai_raw_rdata="5 6 7 foo.com." +18 _sip._tcp 333 IN SRV 5 6 7 foo.com. ; akamai_raw_rdata="5 6 7 foo.com." +19 _sip._tcp 4400 IN SRV 5 6 7 foo.com. ; akamai_raw_rdata="5 6 7 foo.com." +20 a 300 IN CNAME xn--ndaaa.com. ; akamai_raw_rdata="xn--ndaaa.com." +21 a 300 IN LOC 42 21 43.950 N 71 05 6.340 W -24.33m 1m 200m 10m ; akamai_raw_rdata="42 21 43.950 N 71 5 6.340 W -24.-33m 1m 200m 10m" +22 @ 1000 IN A 8.8.8.8 ; akamai_raw_rdata="8.8.8.8" +23 @ 300 IN A 1.2.3.2 ; akamai_raw_rdata="1.2.3.2" +24 @ 300 IN A 1.2.3.4 ; akamai_raw_rdata="1.2.3.4" +24 @ 300 IN A 2.3.4.5 ; akamai_raw_rdata="2.3.4.5" +25 @ 300 IN A 1.2.3.4 ; akamai_raw_rdata="1.2.3.4" +26 @ 300 IN A 2.2.2.2 ; akamai_raw_rdata="2.2.2.2" +27 @ 300 IN A 4.4.4.4 ; akamai_raw_rdata="4.4.4.4" +28 @ 500 IN A 8.8.8.8 ; akamai_raw_rdata="8.8.8.8" +29 @ 666 IN A 8.8.8.8 ; akamai_raw_rdata="8.8.8.8" +30 @ 300 IN AKAMAITLC DUAL foo.akamaigoldentest.com. ; akamai_raw_rdata="DUAL foo.akamaigoldentest.com." +31 @ 300 IN AKAMAITLC DUAL foo.com. ; akamai_raw_rdata="DUAL foo.com." +32 @ 300 IN AKAMAITLC DUAL foo2.com. ; akamai_raw_rdata="DUAL foo2.com." +33 @ 300 IN CAA 0 issue "letsencrypt.org; validationmethods=dns-01; accounturi=https://acme-v02.api.letsencrypt.org/acme/acct/1234" ; akamai_raw_rdata="0 issue \"letsencrypt.org; validationmethods=dns-01; accounturi=https://acme-v02.api.letsencrypt.org/acme/acct/1234\"" +34 @ 300 IN CAA 0 issue "letsencrypt.org" ; akamai_raw_rdata="0 issue \"letsencrypt.org\"" +35 @ 300 IN CAA 0 issuewild ";" ; akamai_raw_rdata="0 issuewild \";\"" +36 @ 300 IN CAA 0 issuewild "example.com" ; akamai_raw_rdata="0 issuewild \"example.com\"" +37 @ 300 IN CAA 0 issuewild "letsencrypt.org" ; akamai_raw_rdata="0 issuewild \"letsencrypt.org\"" +38 @ 300 IN CAA 128 issue "letsencrypt.org" ; akamai_raw_rdata="128 issue \"letsencrypt.org\"" +39 @ 300 IN LOC 42 21 54.000 N 71 06 18.000 W -24.05m 30m 0.00m 0.00m ; akamai_raw_rdata="42 21 54 N 71 6 18 W -24.-05m 30m 0m 0m" +40 @ 300 IN LOC 42 21 54.000 N 71 06 18.000 W -24.06m 30m 10m 0.00m ; akamai_raw_rdata="42 21 54 N 71 6 18 W -24.-06m 30m 10m 0m" +41 @ 300 IN LOC 42 21 54.000 N 71 06 18.000 W -24m 30m 0.00m 0.00m ; akamai_raw_rdata="42 21 54 N 71 6 18 W -24m 30m 0m 0m" +42 @ 300 IN MX 0 . ; akamai_raw_rdata="0 ." +43 @ 300 IN MX 2 akamaigoldentest.com. ; akamai_raw_rdata="2 akamaigoldentest.com." +43 @ 300 IN MX 8 www.akamaigoldentest.com. ; akamai_raw_rdata="8 www.akamaigoldentest.com." +44 @ 300 IN MX 5 bar.com. ; akamai_raw_rdata="5 bar.com." +45 @ 300 IN MX 5 foo.com. ; akamai_raw_rdata="5 foo.com." +46 @ 300 IN NS a1-98.akam.net. ; akamai_raw_rdata="a1-98.akam.net." +46 @ 300 IN NS a12-65.akam.net. ; akamai_raw_rdata="a12-65.akam.net." +46 @ 300 IN NS a13-65.akam.net. ; akamai_raw_rdata="a13-65.akam.net." +46 @ 300 IN NS a2-64.akam.net. ; akamai_raw_rdata="a2-64.akam.net." +46 @ 300 IN NS a3-64.akam.net. ; akamai_raw_rdata="a3-64.akam.net." +46 @ 300 IN NS a4-65.akam.net. ; akamai_raw_rdata="a4-65.akam.net." +46 @ 300 IN NS ns1.foo.com. ; akamai_raw_rdata="ns1.foo.com." +46 @ 300 IN NS ns2.foo.com. ; akamai_raw_rdata="ns2.foo.com." +47 @ 300 IN NS a1-98.akam.net. ; akamai_raw_rdata="a1-98.akam.net." +47 @ 300 IN NS a12-65.akam.net. ; akamai_raw_rdata="a12-65.akam.net." +47 @ 300 IN NS a13-65.akam.net. ; akamai_raw_rdata="a13-65.akam.net." +47 @ 300 IN NS a2-64.akam.net. ; akamai_raw_rdata="a2-64.akam.net." +47 @ 300 IN NS a3-64.akam.net. ; akamai_raw_rdata="a3-64.akam.net." +47 @ 300 IN NS a4-65.akam.net. ; akamai_raw_rdata="a4-65.akam.net." +47 @ 300 IN NS ns1.foo.com. ; akamai_raw_rdata="ns1.foo.com." +48 @ 300 IN NS a1-98.akam.net. ; akamai_raw_rdata="a1-98.akam.net." +48 @ 300 IN NS a12-65.akam.net. ; akamai_raw_rdata="a12-65.akam.net." +48 @ 300 IN NS a13-65.akam.net. ; akamai_raw_rdata="a13-65.akam.net." +48 @ 300 IN NS a2-64.akam.net. ; akamai_raw_rdata="a2-64.akam.net." +48 @ 300 IN NS a3-64.akam.net. ; akamai_raw_rdata="a3-64.akam.net." +48 @ 300 IN NS a4-65.akam.net. ; akamai_raw_rdata="a4-65.akam.net." +49 @ 86400 IN NS a1-98.akam.net. ; akamai_raw_rdata="a1-98.akam.net." +49 @ 86400 IN NS a12-65.akam.net. ; akamai_raw_rdata="a12-65.akam.net." +49 @ 86400 IN NS a13-65.akam.net. ; akamai_raw_rdata="a13-65.akam.net." +49 @ 86400 IN NS a2-64.akam.net. ; akamai_raw_rdata="a2-64.akam.net." +49 @ 86400 IN NS a3-64.akam.net. ; akamai_raw_rdata="a3-64.akam.net." +49 @ 86400 IN NS a4-65.akam.net. ; akamai_raw_rdata="a4-65.akam.net." +265 @ 300 IN SSHFP 1 1 66C7D5540B7D75A1FB4C84FEBFA178AD99BDD67C ; akamai_raw_rdata="1 1 66C7D5540B7D75A1FB4C84FEBFA178AD99BDD67C" +266 @ 300 IN SSHFP 2 1 66C7D5540B7D75A1FB4C84FEBFA178AD99BDD67C ; akamai_raw_rdata="2 1 66C7D5540B7D75A1FB4C84FEBFA178AD99BDD67C" +267 @ 300 IN SSHFP 2 2 745A635BC46A397A5C4F21D437483005BCC40D7511FF15FBFAFE913A081559BC ; akamai_raw_rdata="2 2 745A635BC46A397A5C4F21D437483005BCC40D7511FF15FBFAFE913A081559BC" +268 @ 300 IN TXT "asimple" ; akamai_raw_rdata="\"asimple\"" +269 @ 300 IN TXT "simple" ; akamai_raw_rdata="\"simple\"" +270 another-child 300 IN DS 44 13 2 4B9B6B073EDD97FEB5BC12DC4E1B32D2C6AF7AE23A293936CEB87BB10494EC44 ; akamai_raw_rdata="44 13 2 4B9B6B073EDD97FEB5BC12DC4E1B32D2C6AF7AE23A293936CEB87BB10494EC44" +270 another-child 300 IN DS 1501 14 4 109BB6B5B6D5547C1CE03C7A8BD7D8F80C1CB0957F50C4F7FDA04692079917E4F9CAD52B878F3D8234E1A170B154B72D ; akamai_raw_rdata="1501 14 4 109BB6B5B6D5547C1CE03C7A8BD7D8F80C1CB0957F50C4F7FDA04692079917E4F9CAD52B878F3D8234E1A170B154B72D" +270 another-child 300 IN DS 1502 8 2 2FA14F53E6B15CAC9AC77846C7BE87862C2A7E9EC0C6CEA319DB939317F126ED ; akamai_raw_rdata="1502 8 2 2FA14F53E6B15CAC9AC77846C7BE87862C2A7E9EC0C6CEA319DB939317F126ED" +270 another-child 300 IN DS 65535 13 2 2FA14F53E6B15CAC9AC77846C7BE87862C2A7E9EC0C6CEA319DB939317F126ED ; akamai_raw_rdata="65535 13 2 2FA14F53E6B15CAC9AC77846C7BE87862C2A7E9EC0C6CEA319DB939317F126ED" +271 another-child 300 IN DS 44 13 2 4B9B6B073EDD97FEB5BC12DC4E1B32D2C6AF7AE23A293936CEB87BB10494EC44 ; akamai_raw_rdata="44 13 2 4B9B6B073EDD97FEB5BC12DC4E1B32D2C6AF7AE23A293936CEB87BB10494EC44" +272 b 300 IN LOC 52 14 5.000 N 00 08 50.000 E 10.22m 0.00m 0.00m 0.00m ; akamai_raw_rdata="52 14 5 N 0 8 50 E 10.22m 0m 0m 0m" +273 bar 300 IN A 1.2.3.4 ; akamai_raw_rdata="1.2.3.4" +274 bar 300 IN A 5.5.5.5 ; akamai_raw_rdata="5.5.5.5" +275 bar 300 IN CNAME redact2.acm-validations.aws. ; akamai_raw_rdata="redact2.acm-validations.aws." +276 bar 300 IN MX 5 bar.com. ; akamai_raw_rdata="5 bar.com." +277 bar.bat 300 IN A 5.5.5.5 ; akamai_raw_rdata="5.5.5.5" +278 c 300 IN LOC 32 07 19.000 S 116 02 25.000 E 10m 0.00m 0.00m 0.00m ; akamai_raw_rdata="32 7 19 S 116 2 25 E 10m 0m 0m 0m" +279 child 300 IN DS 1 14 4 417212FD1C8BC5896FEFD8DB58AF824545E85B0D0546409366A30AEF7269FAE258173BD185FB262C86F3BB86FBA04368 ; akamai_raw_rdata="1 14 4 417212FD1C8BC5896FEFD8DB58AF824545E85B0D0546409366A30AEF7269FAE258173BD185FB262C86F3BB86FBA04368" +280 child 300 IN DS 3 13 2 4B9B6B073EDD97FEB5BC12DC4E1B32D2C6AF7AE23A293936CEB87BB10494EC44 ; akamai_raw_rdata="3 13 2 4B9B6B073EDD97FEB5BC12DC4E1B32D2C6AF7AE23A293936CEB87BB10494EC44" +281 child 300 IN DS 3 14 4 3115238F89E0BF5252D9718113B1B9FFF854608D84BE94EEFB9210DC1CC0B4F3557342A27465CFACC42EF137AE9A5489 ; akamai_raw_rdata="3 14 4 3115238F89E0BF5252D9718113B1B9FFF854608D84BE94EEFB9210DC1CC0B4F3557342A27465CFACC42EF137AE9A5489" +282 child 300 IN DS 3 8 2 4B9B6B073EDD97FEB5BC12DC4E1B32D2C6AF7AE23A293936CEB87BB10494EC44 ; akamai_raw_rdata="3 8 2 4B9B6B073EDD97FEB5BC12DC4E1B32D2C6AF7AE23A293936CEB87BB10494EC44" +283 child 300 IN DS 8857 8 2 4B9B6B073EDD97FEB5BC12DC4E1B32D2C6AF7AE23A293936CEB87BB10494EC44 ; akamai_raw_rdata="8857 8 2 4B9B6B073EDD97FEB5BC12DC4E1B32D2C6AF7AE23A293936CEB87BB10494EC44" +284 d 300 IN LOC 42 21 28.760 N 71 00 51.620 W -44m 2000m 0.00m 0.00m ; akamai_raw_rdata="42 21 28.760 N 71 0 51.620 W -44m 2000m 0m 0m" +285 decoy 300 IN A 1.1.1.1 ; akamai_raw_rdata="1.1.1.1" +286 decoy 300 IN A 2.2.2.2 ; akamai_raw_rdata="2.2.2.2" +287 decoy 300 IN A 3.3.3.3 ; akamai_raw_rdata="3.3.3.3" +288 dyndns-city1 300 IN A 91.42.1.1 ; akamai_raw_rdata="91.42.1.1" +289 dyndns-city1 300 IN AAAA 2003:dd:d7ff::fe71:ce77 ; akamai_raw_rdata="2003:dd:d7ff:0:0:0:fe71:ce77" +290 dyndns-city2 300 IN A 91.42.1.2 ; akamai_raw_rdata="91.42.1.2" +291 dyndns-city2 300 IN AAAA 2003:dd:d7ff::fe71:ce78 ; akamai_raw_rdata="2003:dd:d7ff:0:0:0:fe71:ce78" +292 final 300 IN TXT "TestDNSProviders was successful!" ; akamai_raw_rdata="\"TestDNSProviders was successful!\"" +293 foo 300 IN A 1.1.1.1 ; akamai_raw_rdata="1.1.1.1" +293 foo 300 IN A 11.11.11.11 ; akamai_raw_rdata="11.11.11.11" +294 foo 300 IN A 1.1.1.1 ; akamai_raw_rdata="1.1.1.1" +294 foo 300 IN A 12.12.12.12 ; akamai_raw_rdata="12.12.12.12" +295 foo 300 IN A 1.1.1.1 ; akamai_raw_rdata="1.1.1.1" +295 foo 300 IN A 13.13.13.13 ; akamai_raw_rdata="13.13.13.13" +296 foo 300 IN A 1.1.1.1 ; akamai_raw_rdata="1.1.1.1" +296 foo 300 IN A 14.14.14.14 ; akamai_raw_rdata="14.14.14.14" +297 foo 300 IN A 1.1.1.1 ; akamai_raw_rdata="1.1.1.1" +297 foo 300 IN A 9.9.9.9 ; akamai_raw_rdata="9.9.9.9" +298 foo 300 IN A 1.2.3.4 ; akamai_raw_rdata="1.2.3.4" +298 foo 300 IN A 2.3.4.5 ; akamai_raw_rdata="2.3.4.5" +299 foo 300 IN A 1.2.3.4 ; akamai_raw_rdata="1.2.3.4" +299 foo 300 IN A 3.4.5.6 ; akamai_raw_rdata="3.4.5.6" +300 foo 300 IN A 1.2.3.4 ; akamai_raw_rdata="1.2.3.4" +301 foo 300 IN A 2.3.4.5 ; akamai_raw_rdata="2.3.4.5" +301 foo 300 IN A 3.4.5.6 ; akamai_raw_rdata="3.4.5.6" +302 foo 300 IN A 2.3.4.5 ; akamai_raw_rdata="2.3.4.5" +302 foo 300 IN A 8.8.8.8 ; akamai_raw_rdata="8.8.8.8" +303 foo 300 IN A 2.3.4.5 ; akamai_raw_rdata="2.3.4.5" +304 foo 300 IN A 4.5.6.7 ; akamai_raw_rdata="4.5.6.7" +305 foo 300 IN AAAA 2003:dd:d7ff::fe71:aaaa ; akamai_raw_rdata="2003:dd:d7ff:0:0:0:fe71:aaaa" +306 foo 300 IN CNAME akamaigoldentest.com. ; akamai_raw_rdata="akamaigoldentest.com." +307 foo 300 IN CNAME google.com. ; akamai_raw_rdata="google.com." +308 foo 300 IN CNAME google2.com. ; akamai_raw_rdata="google2.com." +309 foo 300 IN CNAME redact1.acm-validations.aws. ; akamai_raw_rdata="redact1.acm-validations.aws." +310 foo 300 IN MX 10 aspmx.l.google.com. ; akamai_raw_rdata="10 aspmx.l.google.com." +310 foo 300 IN MX 20 alt1.aspmx.l.google.com. ; akamai_raw_rdata="20 alt1.aspmx.l.google.com." +311 foo 300 IN MX 10 foo.akamaigoldentest.com. ; akamai_raw_rdata="10 foo.akamaigoldentest.com." +311 foo 300 IN MX 20 bar.akamaigoldentest.com. ; akamai_raw_rdata="20 bar.akamaigoldentest.com." +312 foo 300 IN MX 5 mx.google.com. ; akamai_raw_rdata="5 mx.google.com." +313 foo 300 IN MX 8 akamaigoldentest.com. ; akamai_raw_rdata="8 akamaigoldentest.com." +314 foo 300 IN NS akamaigoldentest.com. ; akamai_raw_rdata="akamaigoldentest.com." +315 foo 300 IN TXT "simple" ; akamai_raw_rdata="\"simple\"" +316 foo 300 IN TXT "v=spf1 ip4:99.99.99.99 -all" ; akamai_raw_rdata="\"v=spf1 ip4:99.99.99.99 -all\"" +317 foo.bat 300 IN A 1.2.3.4 ; akamai_raw_rdata="1.2.3.4" +317 foo.bat 300 IN A 2.3.4.5 ; akamai_raw_rdata="2.3.4.5" +318 foo.bat 300 IN TXT "simple" ; akamai_raw_rdata="\"simple\"" +319 foo0 300 IN TXT "" ; akamai_raw_rdata="\"\"" +320 foo254 300 IN TXT "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" ; akamai_raw_rdata="\"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\"" +321 foo255 300 IN TXT "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" ; akamai_raw_rdata="\"BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB\"" +322 foo256 300 IN TXT "CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC" "C" ; akamai_raw_rdata="\"CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC\" \"C\"" +323 foo509 300 IN TXT "DDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDD" "DDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDD" ; akamai_raw_rdata="\"DDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDD\" \"DDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDD\"" +324 foo510 300 IN TXT "EEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE" "EEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE" ; akamai_raw_rdata="\"EEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE\" \"EEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE\"" +325 foo511 300 IN TXT "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF" "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF" "F" ; akamai_raw_rdata="\"FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF\" \"FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF\" \"F\"" +326 foo764 300 IN TXT "GGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGG" "GGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGG" "GGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGG" ; akamai_raw_rdata="\"GGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGG\" \"GGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGG\" \"GGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGG\"" +327 foo765 300 IN TXT "HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH" "HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH" "HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH" ; akamai_raw_rdata="\"HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH\" \"HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH\" \"HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH\"" +328 foo766 300 IN TXT "JJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJ" "JJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJ" "JJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJ" "J" ; akamai_raw_rdata="\"JJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJ\" \"JJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJ\" \"JJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJ\" \"J\"" +329 foobt 300 IN TXT "blah`blah" ; akamai_raw_rdata="\"blah`blah\"" +330 foosc1 300 IN TXT "semi;colon" ; akamai_raw_rdata="\"semi;colon\"" +331 foosc2 300 IN TXT "wssemi ; colon" ; akamai_raw_rdata="\"wssemi ; colon\"" +332 foosp 300 IN TXT "with spaces" ; akamai_raw_rdata="\"with spaces\"" +333 foosq 300 IN TXT "quo'te" ; akamai_raw_rdata="\"quo'te\"" +334 foows1 300 IN TXT "trailingws " ; akamai_raw_rdata="\"trailingws \"" +335 mail 300 IN CNAME ghs.googlehosted.com. ; akamai_raw_rdata="ghs.googlehosted.com." +336 mail.bat 300 IN CNAME ghs.googlehosted.com. ; akamai_raw_rdata="ghs.googlehosted.com." +337 nmx 300 IN A 1.2.3.3 ; akamai_raw_rdata="1.2.3.3" +338 nmx 300 IN MX 0 . ; akamai_raw_rdata="0 ." +339 nmx 300 IN MX 3 nmx.akamaigoldentest.com. ; akamai_raw_rdata="3 nmx.akamaigoldentest.com." +339 nmx 300 IN MX 9 www.akamaigoldentest.com. ; akamai_raw_rdata="9 www.akamaigoldentest.com." +340 pager101-rec0000 300 IN A 1.2.3.4 ; akamai_raw_rdata="1.2.3.4" +341 pager101-rec0001 300 IN A 1.2.3.4 ; akamai_raw_rdata="1.2.3.4" +342 pager101-rec0002 300 IN A 1.2.3.4 ; akamai_raw_rdata="1.2.3.4" +343 pager101-rec0003 300 IN A 1.2.3.4 ; akamai_raw_rdata="1.2.3.4" +344 pager101-rec0004 300 IN A 1.2.3.4 ; akamai_raw_rdata="1.2.3.4" +345 pager101-rec0005 300 IN A 1.2.3.4 ; akamai_raw_rdata="1.2.3.4" +346 pager101-rec0006 300 IN A 1.2.3.4 ; akamai_raw_rdata="1.2.3.4" +347 pager101-rec0007 300 IN A 1.2.3.4 ; akamai_raw_rdata="1.2.3.4" +348 pager101-rec0008 300 IN A 1.2.3.4 ; akamai_raw_rdata="1.2.3.4" +349 pager101-rec0009 300 IN A 1.2.3.4 ; akamai_raw_rdata="1.2.3.4" +350 pager101-rec0010 300 IN A 1.2.3.4 ; akamai_raw_rdata="1.2.3.4" +351 pager101-rec0011 300 IN A 1.2.3.4 ; akamai_raw_rdata="1.2.3.4" +352 pager101-rec0012 300 IN A 1.2.3.4 ; akamai_raw_rdata="1.2.3.4" +353 pager101-rec0013 300 IN A 1.2.3.4 ; akamai_raw_rdata="1.2.3.4" +354 pager101-rec0014 300 IN A 1.2.3.4 ; akamai_raw_rdata="1.2.3.4" +355 pager101-rec0015 300 IN A 1.2.3.4 ; akamai_raw_rdata="1.2.3.4" +356 pager101-rec0016 300 IN A 1.2.3.4 ; akamai_raw_rdata="1.2.3.4" +357 pager101-rec0017 300 IN A 1.2.3.4 ; akamai_raw_rdata="1.2.3.4" +358 pager101-rec0018 300 IN A 1.2.3.4 ; akamai_raw_rdata="1.2.3.4" +359 pager101-rec0019 300 IN A 1.2.3.4 ; akamai_raw_rdata="1.2.3.4" +360 pager101-rec0020 300 IN A 1.2.3.4 ; akamai_raw_rdata="1.2.3.4" +361 pager101-rec0021 300 IN A 1.2.3.4 ; akamai_raw_rdata="1.2.3.4" +362 pager101-rec0022 300 IN A 1.2.3.4 ; akamai_raw_rdata="1.2.3.4" +363 pager101-rec0023 300 IN A 1.2.3.4 ; akamai_raw_rdata="1.2.3.4" +364 pager101-rec0024 300 IN A 1.2.3.4 ; akamai_raw_rdata="1.2.3.4" +365 pager101-rec0025 300 IN A 1.2.3.4 ; akamai_raw_rdata="1.2.3.4" +366 pager101-rec0026 300 IN A 1.2.3.4 ; akamai_raw_rdata="1.2.3.4" +367 pager101-rec0027 300 IN A 1.2.3.4 ; akamai_raw_rdata="1.2.3.4" +368 pager101-rec0028 300 IN A 1.2.3.4 ; akamai_raw_rdata="1.2.3.4" +369 pager101-rec0029 300 IN A 1.2.3.4 ; akamai_raw_rdata="1.2.3.4" +370 pager101-rec0030 300 IN A 1.2.3.4 ; akamai_raw_rdata="1.2.3.4" +371 pager101-rec0031 300 IN A 1.2.3.4 ; akamai_raw_rdata="1.2.3.4" +372 pager101-rec0032 300 IN A 1.2.3.4 ; akamai_raw_rdata="1.2.3.4" +373 pager101-rec0033 300 IN A 1.2.3.4 ; akamai_raw_rdata="1.2.3.4" +374 pager101-rec0034 300 IN A 1.2.3.4 ; akamai_raw_rdata="1.2.3.4" +375 pager101-rec0035 300 IN A 1.2.3.4 ; akamai_raw_rdata="1.2.3.4" +376 pager101-rec0036 300 IN A 1.2.3.4 ; akamai_raw_rdata="1.2.3.4" +377 pager101-rec0037 300 IN A 1.2.3.4 ; akamai_raw_rdata="1.2.3.4" +378 pager101-rec0038 300 IN A 1.2.3.4 ; akamai_raw_rdata="1.2.3.4" +379 pager101-rec0039 300 IN A 1.2.3.4 ; akamai_raw_rdata="1.2.3.4" +380 pager101-rec0040 300 IN A 1.2.3.4 ; akamai_raw_rdata="1.2.3.4" +381 pager101-rec0041 300 IN A 1.2.3.4 ; akamai_raw_rdata="1.2.3.4" +382 pager101-rec0042 300 IN A 1.2.3.4 ; akamai_raw_rdata="1.2.3.4" +383 pager101-rec0043 300 IN A 1.2.3.4 ; akamai_raw_rdata="1.2.3.4" +384 pager101-rec0044 300 IN A 1.2.3.4 ; akamai_raw_rdata="1.2.3.4" +385 pager101-rec0045 300 IN A 1.2.3.4 ; akamai_raw_rdata="1.2.3.4" +386 pager101-rec0046 300 IN A 1.2.3.4 ; akamai_raw_rdata="1.2.3.4" +387 pager101-rec0047 300 IN A 1.2.3.4 ; akamai_raw_rdata="1.2.3.4" +388 pager101-rec0048 300 IN A 1.2.3.4 ; akamai_raw_rdata="1.2.3.4" +389 pager101-rec0049 300 IN A 1.2.3.4 ; akamai_raw_rdata="1.2.3.4" +390 pager101-rec0050 300 IN A 1.2.3.4 ; akamai_raw_rdata="1.2.3.4" +391 pager101-rec0051 300 IN A 1.2.3.4 ; akamai_raw_rdata="1.2.3.4" +392 pager101-rec0052 300 IN A 1.2.3.4 ; akamai_raw_rdata="1.2.3.4" +393 pager101-rec0053 300 IN A 1.2.3.4 ; akamai_raw_rdata="1.2.3.4" +394 pager101-rec0054 300 IN A 1.2.3.4 ; akamai_raw_rdata="1.2.3.4" +395 pager101-rec0055 300 IN A 1.2.3.4 ; akamai_raw_rdata="1.2.3.4" +396 pager101-rec0056 300 IN A 1.2.3.4 ; akamai_raw_rdata="1.2.3.4" +397 pager101-rec0057 300 IN A 1.2.3.4 ; akamai_raw_rdata="1.2.3.4" +398 pager101-rec0058 300 IN A 1.2.3.4 ; akamai_raw_rdata="1.2.3.4" +399 pager101-rec0059 300 IN A 1.2.3.4 ; akamai_raw_rdata="1.2.3.4" +400 pager101-rec0060 300 IN A 1.2.3.4 ; akamai_raw_rdata="1.2.3.4" +401 pager101-rec0061 300 IN A 1.2.3.4 ; akamai_raw_rdata="1.2.3.4" +402 pager101-rec0062 300 IN A 1.2.3.4 ; akamai_raw_rdata="1.2.3.4" +403 pager101-rec0063 300 IN A 1.2.3.4 ; akamai_raw_rdata="1.2.3.4" +404 pager101-rec0064 300 IN A 1.2.3.4 ; akamai_raw_rdata="1.2.3.4" +405 pager101-rec0065 300 IN A 1.2.3.4 ; akamai_raw_rdata="1.2.3.4" +406 pager101-rec0066 300 IN A 1.2.3.4 ; akamai_raw_rdata="1.2.3.4" +407 pager101-rec0067 300 IN A 1.2.3.4 ; akamai_raw_rdata="1.2.3.4" +408 pager101-rec0068 300 IN A 1.2.3.4 ; akamai_raw_rdata="1.2.3.4" +409 pager101-rec0069 300 IN A 1.2.3.4 ; akamai_raw_rdata="1.2.3.4" +410 pager101-rec0070 300 IN A 1.2.3.4 ; akamai_raw_rdata="1.2.3.4" +411 pager101-rec0071 300 IN A 1.2.3.4 ; akamai_raw_rdata="1.2.3.4" +412 pager101-rec0072 300 IN A 1.2.3.4 ; akamai_raw_rdata="1.2.3.4" +413 pager101-rec0073 300 IN A 1.2.3.4 ; akamai_raw_rdata="1.2.3.4" +414 pager101-rec0074 300 IN A 1.2.3.4 ; akamai_raw_rdata="1.2.3.4" +415 pager101-rec0075 300 IN A 1.2.3.4 ; akamai_raw_rdata="1.2.3.4" +416 pager101-rec0076 300 IN A 1.2.3.4 ; akamai_raw_rdata="1.2.3.4" +417 pager101-rec0077 300 IN A 1.2.3.4 ; akamai_raw_rdata="1.2.3.4" +418 pager101-rec0078 300 IN A 1.2.3.4 ; akamai_raw_rdata="1.2.3.4" +419 pager101-rec0079 300 IN A 1.2.3.4 ; akamai_raw_rdata="1.2.3.4" +420 pager101-rec0080 300 IN A 1.2.3.4 ; akamai_raw_rdata="1.2.3.4" +421 pager101-rec0081 300 IN A 1.2.3.4 ; akamai_raw_rdata="1.2.3.4" +422 pager101-rec0082 300 IN A 1.2.3.4 ; akamai_raw_rdata="1.2.3.4" +423 pager101-rec0083 300 IN A 1.2.3.4 ; akamai_raw_rdata="1.2.3.4" +424 pager101-rec0084 300 IN A 1.2.3.4 ; akamai_raw_rdata="1.2.3.4" +425 pager101-rec0085 300 IN A 1.2.3.4 ; akamai_raw_rdata="1.2.3.4" +426 pager101-rec0086 300 IN A 1.2.3.4 ; akamai_raw_rdata="1.2.3.4" +427 pager101-rec0087 300 IN A 1.2.3.4 ; akamai_raw_rdata="1.2.3.4" +428 pager101-rec0088 300 IN A 1.2.3.4 ; akamai_raw_rdata="1.2.3.4" +429 pager101-rec0089 300 IN A 1.2.3.4 ; akamai_raw_rdata="1.2.3.4" +430 pager101-rec0090 300 IN A 1.2.3.4 ; akamai_raw_rdata="1.2.3.4" +431 pager101-rec0091 300 IN A 1.2.3.4 ; akamai_raw_rdata="1.2.3.4" +432 pager101-rec0092 300 IN A 1.2.3.4 ; akamai_raw_rdata="1.2.3.4" +433 pager101-rec0093 300 IN A 1.2.3.4 ; akamai_raw_rdata="1.2.3.4" +434 pager101-rec0094 300 IN A 1.2.3.4 ; akamai_raw_rdata="1.2.3.4" +435 pager101-rec0095 300 IN A 1.2.3.4 ; akamai_raw_rdata="1.2.3.4" +436 pager101-rec0096 300 IN A 1.2.3.4 ; akamai_raw_rdata="1.2.3.4" +437 pager101-rec0097 300 IN A 1.2.3.4 ; akamai_raw_rdata="1.2.3.4" +438 pager101-rec0098 300 IN A 1.2.3.4 ; akamai_raw_rdata="1.2.3.4" +439 pager101-rec0099 300 IN A 1.2.3.4 ; akamai_raw_rdata="1.2.3.4" +440 pager101-rec0100 300 IN A 1.2.3.4 ; akamai_raw_rdata="1.2.3.4" +441 test 300 IN CNAME foo.com. ; akamai_raw_rdata="foo.com." +442 test 300 IN CNAME foo2.com. ; akamai_raw_rdata="foo2.com." +443 test 300 IN NAPTR 100 10 "U" "E2U+sip" "!^.*$!sip:customer-service@example.com!" . ; akamai_raw_rdata="100 10 \"U\" \"E2U+sip\" \"!^.*$!sip:customer-service@example.com!\" ." +443 test 300 IN NAPTR 102 10 "U" "E2U+email" "!^.*$!mailto:information@example.com!" . ; akamai_raw_rdata="102 10 \"U\" \"E2U+email\" \"!^.*$!mailto:information@example.com!\" ." +444 test 300 IN NAPTR 100 10 "U" "E2U+sip" "!^.*$!sip:customer-service@example.com!" . ; akamai_raw_rdata="100 10 \"U\" \"E2U+sip\" \"!^.*$!sip:customer-service@example.com!\" ." +445 test 300 IN NAPTR 103 10 "U" "E2U+email" "!^.*$!mailto:information@example.com!" . ; akamai_raw_rdata="103 10 \"U\" \"E2U+email\" \"!^.*$!mailto:information@example.com!\" ." +446 test 300 IN NAPTR 103 20 "A" "E2U+email" "!^.*$!mailto:information@example.com!" . ; akamai_raw_rdata="103 20 \"A\" \"E2U+email\" \"!^.*$!mailto:information@example.com!\" ." +447 test 300 IN NAPTR 103 20 "A" "E2U+sip" "!^.*$!mailto:information@example.com!" . ; akamai_raw_rdata="103 20 \"A\" \"E2U+sip\" \"!^.*$!mailto:information@example.com!\" ." +448 test 300 IN NAPTR 103 20 "A" "E2U+sip" "!^.*$!sip:customer-service@example.com!" . ; akamai_raw_rdata="103 20 \"A\" \"E2U+sip\" \"!^.*$!sip:customer-service@example.com!\" ." +449 test 300 IN NAPTR 103 20 "A" "E2U+sip" "" example.foo.com. ; akamai_raw_rdata="103 20 \"A\" \"E2U+sip\" \"\" example.foo.com." +450 test 300 IN NAPTR 103 20 "A" "E2U+sip" "" example2.foo.com. ; akamai_raw_rdata="103 20 \"A\" \"E2U+sip\" \"\" example2.foo.com." +451 test 300 IN NAPTR 103 20 "U" "E2U+email" "!^.*$!mailto:information@example.com!" . ; akamai_raw_rdata="103 20 \"U\" \"E2U+email\" \"!^.*$!mailto:information@example.com!\" ." +452 testa 300 IN A 1.1.1.1 ; akamai_raw_rdata="1.1.1.1" +453 testa 300 IN A 3.3.3.3 ; akamai_raw_rdata="3.3.3.3" +454 testa 333 IN A 1.1.1.1 ; akamai_raw_rdata="1.1.1.1" +455 testa 999 IN A 1.1.1.1 ; akamai_raw_rdata="1.1.1.1" +456 testaaaa 300 IN AAAA 2607:f8b0:4006:820::2006 ; akamai_raw_rdata="2607:f8b0:4006:820:0:0:0:2006" +457 testaaaa 300 IN AAAA 2607:f8b0:4006:820::2013 ; akamai_raw_rdata="2607:f8b0:4006:820:0:0:0:2013" +458 testcname 300 IN CNAME foo.akamaigoldentest.com. ; akamai_raw_rdata="foo.akamaigoldentest.com." +459 testcname 300 IN CNAME www.google.com. ; akamai_raw_rdata="www.google.com." +460 testcname 300 IN CNAME www.yahoo.com. ; akamai_raw_rdata="www.yahoo.com." +461 testdefined 300 IN A 2.2.2.2 ; akamai_raw_rdata="2.2.2.2" +462 testdefined 300 IN A 9.9.9.9 ; akamai_raw_rdata="9.9.9.9" +463 testignore 300 IN A 8.8.8.8 ; akamai_raw_rdata="8.8.8.8" +464 testmx 300 IN MX 100 foo.com. ; akamai_raw_rdata="100 foo.com." +465 testmx 300 IN MX 5 bar.com. ; akamai_raw_rdata="5 bar.com." +466 testmx 300 IN MX 5 foo.com. ; akamai_raw_rdata="5 foo.com." +466 testmx 300 IN MX 100 bar.com. ; akamai_raw_rdata="100 bar.com." +467 testmx 300 IN MX 5 foo.com. ; akamai_raw_rdata="5 foo.com." +468 testtxt 300 IN TXT "changed" ; akamai_raw_rdata="\"changed\"" +469 testtxt 300 IN TXT "simple" ; akamai_raw_rdata="\"simple\"" +470 www 300 IN A 1.1.1.1 ; akamai_raw_rdata="1.1.1.1" +470 www 300 IN A 2.2.2.2 ; akamai_raw_rdata="2.2.2.2" +470 www 300 IN A 3.3.3.3 ; akamai_raw_rdata="3.3.3.3" +471 www 300 IN A 1.1.1.1 ; akamai_raw_rdata="1.1.1.1" +471 www 300 IN A 2.2.2.2 ; akamai_raw_rdata="2.2.2.2" +472 www 300 IN A 1.1.1.1 ; akamai_raw_rdata="1.1.1.1" +473 www 300 IN A 1.2.3.4 ; akamai_raw_rdata="1.2.3.4" +473 www 300 IN A 5.6.7.8 ; akamai_raw_rdata="5.6.7.8" +474 www 300 IN A 1.2.3.8 ; akamai_raw_rdata="1.2.3.8" +475 www 300 IN A 1.2.3.9 ; akamai_raw_rdata="1.2.3.9" +476 www 300 IN A 2.2.2.2 ; akamai_raw_rdata="2.2.2.2" +476 www 300 IN A 5.6.7.8 ; akamai_raw_rdata="5.6.7.8" +477 www 300 IN A 5.5.5.5 ; akamai_raw_rdata="5.5.5.5" +478 www 400 IN A 2.2.2.2 ; akamai_raw_rdata="2.2.2.2" +478 www 400 IN A 5.6.7.8 ; akamai_raw_rdata="5.6.7.8" +479 www 400 IN A 5.6.7.8 ; akamai_raw_rdata="5.6.7.8" +480 www 700 IN A 1.2.3.4 ; akamai_raw_rdata="1.2.3.4" +480 www 700 IN A 5.6.7.8 ; akamai_raw_rdata="5.6.7.8" +481 xn--fiq228c 300 IN A 1.2.3.4 ; akamai_raw_rdata="1.2.3.4" +482 xn--ndaaa 300 IN A 1.2.3.4 ; akamai_raw_rdata="1.2.3.4" +483 xn--ndaaa 300 IN A 2.2.2.2 ; akamai_raw_rdata="2.2.2.2" +484 xn--o-0gab 300 IN CNAME xn--ndaaa.xn--vhquv. ; akamai_raw_rdata="xn--ndaaa.xn--vhquv." +485 xyz 300 IN NS ns1.foo.com. ; akamai_raw_rdata="ns1.foo.com." +485 xyz 300 IN NS ns2.foo.com. ; akamai_raw_rdata="ns2.foo.com." +486 xyz 300 IN NS ns2.foo.com. ; akamai_raw_rdata="ns2.foo.com." +487 zzz 300 IN A 3.3.3.3 ; akamai_raw_rdata="3.3.3.3" +487 zzz 300 IN A 4.4.4.4 ; akamai_raw_rdata="4.4.4.4" +488 zzz 300 IN AAAA 2003:dd:d7ff::fe71:cccc ; akamai_raw_rdata="2003:dd:d7ff:0:0:0:fe71:cccc" diff --git a/providers/akamaiedgedns/test_data/meta.json b/providers/akamaiedgedns/test_data/meta.json new file mode 100644 index 0000000000..2552f390a9 --- /dev/null +++ b/providers/akamaiedgedns/test_data/meta.json @@ -0,0 +1,14 @@ +{ + "version": 1, + "recordings": [ + { + "domain": "akamaigoldentest.com", + "to_rc": [ + "nativeToRecords" + ], + "to_native": [ + "rcToRs" + ] + } + ] +} diff --git a/providers/akamaiedgedns/test_data/recorded_tonative_input_rcToRs_akamaigoldentest.com.records b/providers/akamaiedgedns/test_data/recorded_tonative_input_rcToRs_akamaigoldentest.com.records new file mode 100644 index 0000000000..0c438d3ca8 --- /dev/null +++ b/providers/akamaiedgedns/test_data/recorded_tonative_input_rcToRs_akamaigoldentest.com.records @@ -0,0 +1,553 @@ +1 * 300 IN A 3.3.3.3 +2 * 300 IN A 3.3.3.3 ; akamai_raw_rdata="3.3.3.3" +3 4 300 IN PTR bar.com. +4 4 300 IN PTR bar.com. ; akamai_raw_rdata="bar.com." +5 4 300 IN PTR foo.com. +6 @ 1000 IN A 8.8.8.8 +7 @ 300 IN A 1.2.3.2 +8 @ 300 IN A 1.2.3.2 ; akamai_raw_rdata="1.2.3.2" +9 @ 300 IN A 1.2.3.4 +10 @ 300 IN A 1.2.3.4 +10 @ 300 IN A 2.3.4.5 +11 @ 300 IN A 1.2.3.4 ; akamai_raw_rdata="1.2.3.4" +12 @ 300 IN A 1.2.3.4 ; akamai_raw_rdata="1.2.3.4" +12 @ 300 IN A 2.3.4.5 ; akamai_raw_rdata="2.3.4.5" +13 @ 300 IN A 2.2.2.2 +14 @ 300 IN A 2.2.2.2 ; akamai_raw_rdata="2.2.2.2" +15 @ 300 IN A 4.4.4.4 +16 @ 300 IN A 4.4.4.4 ; akamai_raw_rdata="4.4.4.4" +17 @ 300 IN AKAMAITLC DUAL foo.akamaigoldentest.com. +18 @ 300 IN AKAMAITLC DUAL foo.akamaigoldentest.com. ; akamai_raw_rdata="DUAL foo.akamaigoldentest.com." +19 @ 300 IN AKAMAITLC DUAL foo.com. +20 @ 300 IN AKAMAITLC DUAL foo2.com. +21 @ 300 IN AKAMAITLC DUAL foo2.com. ; akamai_raw_rdata="DUAL foo2.com." +22 @ 300 IN CAA 0 issue "letsencrypt.org" +23 @ 300 IN CAA 0 issue "letsencrypt.org; validationmethods=dns-01; accounturi=https://acme-v02.api.letsencrypt.org/acme/acct/1234" +24 @ 300 IN CAA 0 issue "letsencrypt.org; validationmethods=dns-01; accounturi=https://acme-v02.api.letsencrypt.org/acme/acct/1234" ; akamai_raw_rdata="0 issue \"letsencrypt.org; validationmethods=dns-01; accounturi=https://acme-v02.api.letsencrypt.org/acme/acct/1234\"" +25 @ 300 IN CAA 0 issuewild ";" +26 @ 300 IN CAA 0 issuewild "example.com" +27 @ 300 IN CAA 0 issuewild "letsencrypt.org" +28 @ 300 IN CAA 128 issue "letsencrypt.org" +29 @ 300 IN CAA 128 issue "letsencrypt.org" ; akamai_raw_rdata="128 issue \"letsencrypt.org\"" +30 @ 300 IN LOC 42 21 54.000 N 71 06 18.000 W -24.05m 30m 0.00m 0.00m +31 @ 300 IN LOC 42 21 54.000 N 71 06 18.000 W -24.06m 30m 10m 0.00m +32 @ 300 IN LOC 42 21 54.000 N 71 06 18.000 W -24m 30m 0.00m 0.00m +33 @ 300 IN LOC 42 21 54.000 N 71 06 18.000 W -24m 30m 0.00m 0.00m ; akamai_raw_rdata="42 21 54 N 71 6 18 W -24m 30m 0m 0m" +34 @ 300 IN MX 0 . +35 @ 300 IN MX 0 . ; akamai_raw_rdata="0 ." +36 @ 300 IN MX 2 akamaigoldentest.com. +36 @ 300 IN MX 8 www.akamaigoldentest.com. +37 @ 300 IN MX 5 bar.com. +38 @ 300 IN MX 5 bar.com. ; akamai_raw_rdata="5 bar.com." +39 @ 300 IN MX 5 foo.com. +40 @ 300 IN NS a1-98.akam.net. +40 @ 300 IN NS a12-65.akam.net. +40 @ 300 IN NS a13-65.akam.net. +40 @ 300 IN NS a2-64.akam.net. +40 @ 300 IN NS a3-64.akam.net. +40 @ 300 IN NS a4-65.akam.net. +41 @ 300 IN NS a1-98.akam.net. +41 @ 300 IN NS a12-65.akam.net. +41 @ 300 IN NS a13-65.akam.net. +41 @ 300 IN NS a2-64.akam.net. +41 @ 300 IN NS a3-64.akam.net. +41 @ 300 IN NS a4-65.akam.net. +41 @ 300 IN NS ns1.foo.com. +42 @ 300 IN NS a1-98.akam.net. +42 @ 300 IN NS a12-65.akam.net. +42 @ 300 IN NS a13-65.akam.net. +42 @ 300 IN NS a2-64.akam.net. +42 @ 300 IN NS a3-64.akam.net. +42 @ 300 IN NS a4-65.akam.net. +42 @ 300 IN NS ns1.foo.com. +42 @ 300 IN NS ns2.foo.com. +43 @ 300 IN SSHFP 1 1 66C7D5540B7D75A1FB4C84FEBFA178AD99BDD67C +44 @ 300 IN SSHFP 2 1 66C7D5540B7D75A1FB4C84FEBFA178AD99BDD67C +45 @ 300 IN SSHFP 2 2 745A635BC46A397A5C4F21D437483005BCC40D7511FF15FBFAFE913A081559BC +46 @ 300 IN SSHFP 2 2 745A635BC46A397A5C4F21D437483005BCC40D7511FF15FBFAFE913A081559BC ; akamai_raw_rdata="2 2 745A635BC46A397A5C4F21D437483005BCC40D7511FF15FBFAFE913A081559BC" +47 @ 300 IN TXT "asimple" +48 @ 300 IN TXT "asimple" ; akamai_raw_rdata="\"asimple\"" +49 @ 300 IN TXT "simple" +50 @ 300 IN TXT "simple" ; akamai_raw_rdata="\"simple\"" +51 @ 500 IN A 8.8.8.8 +52 @ 500 IN A 8.8.8.8 ; akamai_raw_rdata="8.8.8.8" +53 @ 666 IN A 8.8.8.8 +54 _443._tcp 300 IN TLSA 2 0 1 0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF +55 _443._tcp 300 IN TLSA 2 0 2 0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF +56 _443._tcp 300 IN TLSA 2 0 2 FEDCBA9876543210FEDCBA9876543210FEDCBA9876543210FEDCBA9876543210FEDCBA9876543210FEDCBA9876543210FEDCBA9876543210FEDCBA9876543210 +57 _443._tcp 300 IN TLSA 2 0 2 FEDCBA9876543210FEDCBA9876543210FEDCBA9876543210FEDCBA9876543210FEDCBA9876543210FEDCBA9876543210FEDCBA9876543210FEDCBA9876543210 ; akamai_raw_rdata="2 0 2 FEDCBA9876543210FEDCBA9876543210FEDCBA9876543210FEDCBA9876543210FEDCBA9876543210FEDCBA9876543210FEDCBA9876543210FEDCBA9876543210" +58 _443._tcp 300 IN TLSA 2 1 1 0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF +59 _443._tcp 300 IN TLSA 3 1 1 0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF +60 _sip._tcp 300 IN SRV 15 65 75 . +61 _sip._tcp 300 IN SRV 15 65 75 . ; akamai_raw_rdata="15 65 75 ." +62 _sip._tcp 300 IN SRV 15 65 75 foo4.com. +62 _sip._tcp 300 IN SRV 52 6 7 foo.com. +63 _sip._tcp 300 IN SRV 15 65 75 foo4.com. +63 _sip._tcp 300 IN SRV 52 62 7 foo.com. +64 _sip._tcp 300 IN SRV 15 65 75 foo4.com. +64 _sip._tcp 300 IN SRV 52 62 72 foo.com. +65 _sip._tcp 300 IN SRV 15 65 75 foo4.com. ; akamai_raw_rdata="15 65 75 foo4.com." +65 _sip._tcp 300 IN SRV 52 62 72 foo.com. ; akamai_raw_rdata="52 62 72 foo.com." +66 _sip._tcp 300 IN SRV 5 6 7 foo.com. +67 _sip._tcp 300 IN SRV 5 6 7 foo.com. +67 _sip._tcp 300 IN SRV 15 65 75 foo3.com. +68 _sip._tcp 300 IN SRV 5 6 7 foo.com. +68 _sip._tcp 300 IN SRV 15 65 75 foo4.com. +69 _sip._tcp 300 IN SRV 5 6 7 foo.com. +69 _sip._tcp 300 IN SRV 5 60 70 foo2.com. +70 _sip._tcp 300 IN SRV 5 6 7 foo.com. +70 _sip._tcp 300 IN SRV 5 60 70 foo2.com. +70 _sip._tcp 300 IN SRV 15 65 75 foo3.com. +71 _sip._tcp 333 IN SRV 5 6 7 foo.com. +72 _sip._tcp 4400 IN SRV 5 6 7 foo.com. +73 _sip._tcp 4400 IN SRV 5 6 7 foo.com. ; akamai_raw_rdata="5 6 7 foo.com." +74 a 300 IN CNAME xn--ndaaa.com. +75 a 300 IN CNAME xn--ndaaa.com. ; akamai_raw_rdata="xn--ndaaa.com." +76 a 300 IN LOC 42 21 43.950 N 71 05 6.340 W -24.33m 1m 200m 10m +77 a 300 IN LOC 42 21 43.950 N 71 05 6.340 W -24.33m 1m 200m 10m ; akamai_raw_rdata="42 21 43.950 N 71 5 6.340 W -24.-33m 1m 200m 10m" +78 another-child 300 IN DS 44 13 2 4B9B6B073EDD97FEB5BC12DC4E1B32D2C6AF7AE23A293936CEB87BB10494EC44 +79 another-child 300 IN DS 44 13 2 4B9B6B073EDD97FEB5BC12DC4E1B32D2C6AF7AE23A293936CEB87BB10494EC44 +79 another-child 300 IN DS 1501 14 4 109BB6B5B6D5547C1CE03C7A8BD7D8F80C1CB0957F50C4F7FDA04692079917E4F9CAD52B878F3D8234E1A170B154B72D +79 another-child 300 IN DS 1502 8 2 2FA14F53E6B15CAC9AC77846C7BE87862C2A7E9EC0C6CEA319DB939317F126ED +79 another-child 300 IN DS 65535 13 2 2FA14F53E6B15CAC9AC77846C7BE87862C2A7E9EC0C6CEA319DB939317F126ED +80 another-child 300 IN DS 44 13 2 4B9B6B073EDD97FEB5BC12DC4E1B32D2C6AF7AE23A293936CEB87BB10494EC44 ; akamai_raw_rdata="44 13 2 4B9B6B073EDD97FEB5BC12DC4E1B32D2C6AF7AE23A293936CEB87BB10494EC44" +80 another-child 300 IN DS 1501 14 4 109BB6B5B6D5547C1CE03C7A8BD7D8F80C1CB0957F50C4F7FDA04692079917E4F9CAD52B878F3D8234E1A170B154B72D ; akamai_raw_rdata="1501 14 4 109BB6B5B6D5547C1CE03C7A8BD7D8F80C1CB0957F50C4F7FDA04692079917E4F9CAD52B878F3D8234E1A170B154B72D" +80 another-child 300 IN DS 1502 8 2 2FA14F53E6B15CAC9AC77846C7BE87862C2A7E9EC0C6CEA319DB939317F126ED ; akamai_raw_rdata="1502 8 2 2FA14F53E6B15CAC9AC77846C7BE87862C2A7E9EC0C6CEA319DB939317F126ED" +80 another-child 300 IN DS 65535 13 2 2FA14F53E6B15CAC9AC77846C7BE87862C2A7E9EC0C6CEA319DB939317F126ED ; akamai_raw_rdata="65535 13 2 2FA14F53E6B15CAC9AC77846C7BE87862C2A7E9EC0C6CEA319DB939317F126ED" +81 b 300 IN LOC 52 14 5.000 N 00 08 50.000 E 10.22m 0.00m 0.00m 0.00m +82 b 300 IN LOC 52 14 5.000 N 00 08 50.000 E 10.22m 0.00m 0.00m 0.00m ; akamai_raw_rdata="52 14 5 N 0 8 50 E 10.22m 0m 0m 0m" +83 bar 300 IN A 1.2.3.4 +84 bar 300 IN A 1.2.3.4 ; akamai_raw_rdata="1.2.3.4" +85 bar 300 IN A 5.5.5.5 +86 bar 300 IN A 5.5.5.5 ; akamai_raw_rdata="5.5.5.5" +87 bar 300 IN CNAME redact2.acm-validations.aws. +88 bar 300 IN CNAME redact2.acm-validations.aws. ; akamai_raw_rdata="redact2.acm-validations.aws." +89 bar 300 IN MX 5 bar.com. +90 bar 300 IN MX 5 bar.com. ; akamai_raw_rdata="5 bar.com." +91 bar.bat 300 IN A 5.5.5.5 +92 bar.bat 300 IN A 5.5.5.5 ; akamai_raw_rdata="5.5.5.5" +93 c 300 IN LOC 32 07 19.000 S 116 02 25.000 E 10m 0.00m 0.00m 0.00m +94 c 300 IN LOC 32 07 19.000 S 116 02 25.000 E 10m 0.00m 0.00m 0.00m ; akamai_raw_rdata="32 7 19 S 116 2 25 E 10m 0m 0m 0m" +95 child 300 IN DS 1 14 4 417212FD1C8BC5896FEFD8DB58AF824545E85B0D0546409366A30AEF7269FAE258173BD185FB262C86F3BB86FBA04368 +96 child 300 IN DS 3 13 2 4B9B6B073EDD97FEB5BC12DC4E1B32D2C6AF7AE23A293936CEB87BB10494EC44 +97 child 300 IN DS 3 14 4 3115238F89E0BF5252D9718113B1B9FFF854608D84BE94EEFB9210DC1CC0B4F3557342A27465CFACC42EF137AE9A5489 +98 child 300 IN DS 3 14 4 3115238F89E0BF5252D9718113B1B9FFF854608D84BE94EEFB9210DC1CC0B4F3557342A27465CFACC42EF137AE9A5489 ; akamai_raw_rdata="3 14 4 3115238F89E0BF5252D9718113B1B9FFF854608D84BE94EEFB9210DC1CC0B4F3557342A27465CFACC42EF137AE9A5489" +99 child 300 IN DS 3 8 2 4B9B6B073EDD97FEB5BC12DC4E1B32D2C6AF7AE23A293936CEB87BB10494EC44 +100 child 300 IN DS 8857 8 2 4B9B6B073EDD97FEB5BC12DC4E1B32D2C6AF7AE23A293936CEB87BB10494EC44 +101 d 300 IN LOC 42 21 28.760 N 71 00 51.620 W -44m 2000m 0.00m 0.00m +102 d 300 IN LOC 42 21 28.760 N 71 00 51.620 W -44m 2000m 0.00m 0.00m ; akamai_raw_rdata="42 21 28.760 N 71 0 51.620 W -44m 2000m 0m 0m" +103 decoy 300 IN A 1.1.1.1 +104 decoy 300 IN A 2.2.2.2 +105 decoy 300 IN A 3.3.3.3 +106 decoy 300 IN A 3.3.3.3 ; akamai_raw_rdata="3.3.3.3" +107 dyndns-city1 300 IN A 91.42.1.1 +108 dyndns-city1 300 IN A 91.42.1.1 ; akamai_raw_rdata="91.42.1.1" +109 dyndns-city1 300 IN AAAA 2003:dd:d7ff::fe71:ce77 +110 dyndns-city1 300 IN AAAA 2003:dd:d7ff::fe71:ce77 ; akamai_raw_rdata="2003:dd:d7ff:0:0:0:fe71:ce77" +111 dyndns-city2 300 IN A 91.42.1.2 +112 dyndns-city2 300 IN A 91.42.1.2 ; akamai_raw_rdata="91.42.1.2" +113 dyndns-city2 300 IN AAAA 2003:dd:d7ff::fe71:ce78 +114 dyndns-city2 300 IN AAAA 2003:dd:d7ff::fe71:ce78 ; akamai_raw_rdata="2003:dd:d7ff:0:0:0:fe71:ce78" +115 final 300 IN TXT "TestDNSProviders was successful!" +116 final 300 IN TXT "TestDNSProviders was successful!" ; akamai_raw_rdata="\"TestDNSProviders was successful!\"" +117 foo 300 IN A 1.1.1.1 +117 foo 300 IN A 11.11.11.11 +118 foo 300 IN A 1.1.1.1 +118 foo 300 IN A 12.12.12.12 +119 foo 300 IN A 1.1.1.1 +119 foo 300 IN A 13.13.13.13 +120 foo 300 IN A 1.1.1.1 +120 foo 300 IN A 9.9.9.9 +121 foo 300 IN A 1.1.1.1 ; akamai_raw_rdata="1.1.1.1" +121 foo 300 IN A 14.14.14.14 +122 foo 300 IN A 1.1.1.1 ; akamai_raw_rdata="1.1.1.1" +122 foo 300 IN A 14.14.14.14 ; akamai_raw_rdata="14.14.14.14" +123 foo 300 IN A 1.2.3.4 +124 foo 300 IN A 1.2.3.4 +124 foo 300 IN A 2.3.4.5 +125 foo 300 IN A 1.2.3.4 +125 foo 300 IN A 3.4.5.6 +126 foo 300 IN A 1.2.3.4 ; akamai_raw_rdata="1.2.3.4" +127 foo 300 IN A 1.2.3.4 ; akamai_raw_rdata="1.2.3.4" +127 foo 300 IN A 2.3.4.5 ; akamai_raw_rdata="2.3.4.5" +128 foo 300 IN A 1.2.3.4 ; akamai_raw_rdata="1.2.3.4" +128 foo 300 IN A 3.4.5.6 ; akamai_raw_rdata="3.4.5.6" +129 foo 300 IN A 2.3.4.5 +130 foo 300 IN A 2.3.4.5 +130 foo 300 IN A 3.4.5.6 +131 foo 300 IN A 2.3.4.5 +131 foo 300 IN A 8.8.8.8 +132 foo 300 IN A 2.3.4.5 ; akamai_raw_rdata="2.3.4.5" +132 foo 300 IN A 8.8.8.8 ; akamai_raw_rdata="8.8.8.8" +133 foo 300 IN A 4.5.6.7 +134 foo 300 IN A 4.5.6.7 ; akamai_raw_rdata="4.5.6.7" +135 foo 300 IN AAAA 2003:dd:d7ff::fe71:aaaa +136 foo 300 IN AAAA 2003:dd:d7ff::fe71:aaaa ; akamai_raw_rdata="2003:dd:d7ff:0:0:0:fe71:aaaa" +137 foo 300 IN CNAME akamaigoldentest.com. +138 foo 300 IN CNAME akamaigoldentest.com. ; akamai_raw_rdata="akamaigoldentest.com." +139 foo 300 IN CNAME google.com. +140 foo 300 IN CNAME google.com. ; akamai_raw_rdata="google.com." +141 foo 300 IN CNAME google2.com. +142 foo 300 IN CNAME google2.com. ; akamai_raw_rdata="google2.com." +143 foo 300 IN CNAME redact1.acm-validations.aws. +144 foo 300 IN CNAME redact1.acm-validations.aws. ; akamai_raw_rdata="redact1.acm-validations.aws." +145 foo 300 IN MX 10 aspmx.l.google.com. +145 foo 300 IN MX 20 alt1.aspmx.l.google.com. +146 foo 300 IN MX 10 aspmx.l.google.com. ; akamai_raw_rdata="10 aspmx.l.google.com." +146 foo 300 IN MX 20 alt1.aspmx.l.google.com. ; akamai_raw_rdata="20 alt1.aspmx.l.google.com." +147 foo 300 IN MX 10 foo.akamaigoldentest.com. +147 foo 300 IN MX 20 bar.akamaigoldentest.com. +148 foo 300 IN MX 10 foo.akamaigoldentest.com. ; akamai_raw_rdata="10 foo.akamaigoldentest.com." +148 foo 300 IN MX 20 bar.akamaigoldentest.com. ; akamai_raw_rdata="20 bar.akamaigoldentest.com." +149 foo 300 IN MX 5 mx.google.com. +150 foo 300 IN MX 5 mx.google.com. ; akamai_raw_rdata="5 mx.google.com." +151 foo 300 IN MX 8 akamaigoldentest.com. +152 foo 300 IN MX 8 akamaigoldentest.com. ; akamai_raw_rdata="8 akamaigoldentest.com." +153 foo 300 IN NS akamaigoldentest.com. +154 foo 300 IN NS akamaigoldentest.com. ; akamai_raw_rdata="akamaigoldentest.com." +155 foo 300 IN TXT "simple" +156 foo 300 IN TXT "simple" ; akamai_raw_rdata="\"simple\"" +157 foo 300 IN TXT "v=spf1 ip4:99.99.99.99 -all" +158 foo 300 IN TXT "v=spf1 ip4:99.99.99.99 -all" ; akamai_raw_rdata="\"v=spf1 ip4:99.99.99.99 -all\"" +159 foo.bat 300 IN A 1.2.3.4 +159 foo.bat 300 IN A 2.3.4.5 +160 foo.bat 300 IN A 1.2.3.4 ; akamai_raw_rdata="1.2.3.4" +160 foo.bat 300 IN A 2.3.4.5 ; akamai_raw_rdata="2.3.4.5" +161 foo.bat 300 IN TXT "simple" +162 foo.bat 300 IN TXT "simple" ; akamai_raw_rdata="\"simple\"" +163 foo0 300 IN TXT "" +164 foo0 300 IN TXT "" ; akamai_raw_rdata="\"\"" +165 foo254 300 IN TXT "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" +166 foo254 300 IN TXT "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" ; akamai_raw_rdata="\"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\"" +167 foo255 300 IN TXT "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" +168 foo255 300 IN TXT "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" ; akamai_raw_rdata="\"BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB\"" +169 foo256 300 IN TXT "CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC" "C" +170 foo256 300 IN TXT "CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC" "C" ; akamai_raw_rdata="\"CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC\" \"C\"" +171 foo509 300 IN TXT "DDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDD" "DDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDD" +172 foo509 300 IN TXT "DDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDD" "DDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDD" ; akamai_raw_rdata="\"DDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDD\" \"DDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDD\"" +173 foo510 300 IN TXT "EEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE" "EEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE" +174 foo510 300 IN TXT "EEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE" "EEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE" ; akamai_raw_rdata="\"EEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE\" \"EEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE\"" +175 foo511 300 IN TXT "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF" "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF" "F" +176 foo511 300 IN TXT "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF" "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF" "F" ; akamai_raw_rdata="\"FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF\" \"FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF\" \"F\"" +177 foo764 300 IN TXT "GGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGG" "GGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGG" "GGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGG" +178 foo764 300 IN TXT "GGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGG" "GGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGG" "GGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGG" ; akamai_raw_rdata="\"GGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGG\" \"GGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGG\" \"GGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGG\"" +179 foo765 300 IN TXT "HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH" "HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH" "HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH" +180 foo765 300 IN TXT "HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH" "HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH" "HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH" ; akamai_raw_rdata="\"HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH\" \"HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH\" \"HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH\"" +181 foo766 300 IN TXT "JJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJ" "JJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJ" "JJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJ" "J" +182 foo766 300 IN TXT "JJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJ" "JJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJ" "JJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJ" "J" ; akamai_raw_rdata="\"JJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJ\" \"JJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJ\" \"JJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJ\" \"J\"" +183 foobt 300 IN TXT "blah`blah" +184 foobt 300 IN TXT "blah`blah" ; akamai_raw_rdata="\"blah`blah\"" +185 foosc1 300 IN TXT "semi;colon" +186 foosc1 300 IN TXT "semi;colon" ; akamai_raw_rdata="\"semi;colon\"" +187 foosc2 300 IN TXT "wssemi ; colon" +188 foosc2 300 IN TXT "wssemi ; colon" ; akamai_raw_rdata="\"wssemi ; colon\"" +189 foosp 300 IN TXT "with spaces" +190 foosp 300 IN TXT "with spaces" ; akamai_raw_rdata="\"with spaces\"" +191 foosq 300 IN TXT "quo'te" +192 foosq 300 IN TXT "quo'te" ; akamai_raw_rdata="\"quo'te\"" +193 foows1 300 IN TXT "trailingws " +194 foows1 300 IN TXT "trailingws " ; akamai_raw_rdata="\"trailingws \"" +195 mail 300 IN CNAME ghs.googlehosted.com. +196 mail 300 IN CNAME ghs.googlehosted.com. ; akamai_raw_rdata="ghs.googlehosted.com." +197 mail.bat 300 IN CNAME ghs.googlehosted.com. +198 mail.bat 300 IN CNAME ghs.googlehosted.com. ; akamai_raw_rdata="ghs.googlehosted.com." +199 nmx 300 IN A 1.2.3.3 +200 nmx 300 IN A 1.2.3.3 ; akamai_raw_rdata="1.2.3.3" +201 nmx 300 IN MX 0 . +202 nmx 300 IN MX 0 . ; akamai_raw_rdata="0 ." +203 nmx 300 IN MX 3 nmx.akamaigoldentest.com. +203 nmx 300 IN MX 9 www.akamaigoldentest.com. +204 pager101-rec0000 300 IN A 1.2.3.4 +205 pager101-rec0000 300 IN A 1.2.3.4 ; akamai_raw_rdata="1.2.3.4" +206 pager101-rec0001 300 IN A 1.2.3.4 +207 pager101-rec0001 300 IN A 1.2.3.4 ; akamai_raw_rdata="1.2.3.4" +208 pager101-rec0002 300 IN A 1.2.3.4 +209 pager101-rec0002 300 IN A 1.2.3.4 ; akamai_raw_rdata="1.2.3.4" +210 pager101-rec0003 300 IN A 1.2.3.4 +211 pager101-rec0003 300 IN A 1.2.3.4 ; akamai_raw_rdata="1.2.3.4" +212 pager101-rec0004 300 IN A 1.2.3.4 +213 pager101-rec0004 300 IN A 1.2.3.4 ; akamai_raw_rdata="1.2.3.4" +214 pager101-rec0005 300 IN A 1.2.3.4 +215 pager101-rec0005 300 IN A 1.2.3.4 ; akamai_raw_rdata="1.2.3.4" +216 pager101-rec0006 300 IN A 1.2.3.4 +217 pager101-rec0006 300 IN A 1.2.3.4 ; akamai_raw_rdata="1.2.3.4" +218 pager101-rec0007 300 IN A 1.2.3.4 +219 pager101-rec0007 300 IN A 1.2.3.4 ; akamai_raw_rdata="1.2.3.4" +220 pager101-rec0008 300 IN A 1.2.3.4 +221 pager101-rec0008 300 IN A 1.2.3.4 ; akamai_raw_rdata="1.2.3.4" +222 pager101-rec0009 300 IN A 1.2.3.4 +223 pager101-rec0009 300 IN A 1.2.3.4 ; akamai_raw_rdata="1.2.3.4" +224 pager101-rec0010 300 IN A 1.2.3.4 +225 pager101-rec0010 300 IN A 1.2.3.4 ; akamai_raw_rdata="1.2.3.4" +226 pager101-rec0011 300 IN A 1.2.3.4 +227 pager101-rec0011 300 IN A 1.2.3.4 ; akamai_raw_rdata="1.2.3.4" +228 pager101-rec0012 300 IN A 1.2.3.4 +229 pager101-rec0012 300 IN A 1.2.3.4 ; akamai_raw_rdata="1.2.3.4" +230 pager101-rec0013 300 IN A 1.2.3.4 +231 pager101-rec0013 300 IN A 1.2.3.4 ; akamai_raw_rdata="1.2.3.4" +232 pager101-rec0014 300 IN A 1.2.3.4 +233 pager101-rec0014 300 IN A 1.2.3.4 ; akamai_raw_rdata="1.2.3.4" +234 pager101-rec0015 300 IN A 1.2.3.4 +235 pager101-rec0015 300 IN A 1.2.3.4 ; akamai_raw_rdata="1.2.3.4" +236 pager101-rec0016 300 IN A 1.2.3.4 +237 pager101-rec0016 300 IN A 1.2.3.4 ; akamai_raw_rdata="1.2.3.4" +238 pager101-rec0017 300 IN A 1.2.3.4 +239 pager101-rec0017 300 IN A 1.2.3.4 ; akamai_raw_rdata="1.2.3.4" +240 pager101-rec0018 300 IN A 1.2.3.4 +241 pager101-rec0018 300 IN A 1.2.3.4 ; akamai_raw_rdata="1.2.3.4" +242 pager101-rec0019 300 IN A 1.2.3.4 +243 pager101-rec0019 300 IN A 1.2.3.4 ; akamai_raw_rdata="1.2.3.4" +244 pager101-rec0020 300 IN A 1.2.3.4 +245 pager101-rec0020 300 IN A 1.2.3.4 ; akamai_raw_rdata="1.2.3.4" +246 pager101-rec0021 300 IN A 1.2.3.4 +247 pager101-rec0021 300 IN A 1.2.3.4 ; akamai_raw_rdata="1.2.3.4" +248 pager101-rec0022 300 IN A 1.2.3.4 +249 pager101-rec0022 300 IN A 1.2.3.4 ; akamai_raw_rdata="1.2.3.4" +250 pager101-rec0023 300 IN A 1.2.3.4 +251 pager101-rec0023 300 IN A 1.2.3.4 ; akamai_raw_rdata="1.2.3.4" +252 pager101-rec0024 300 IN A 1.2.3.4 +253 pager101-rec0024 300 IN A 1.2.3.4 ; akamai_raw_rdata="1.2.3.4" +254 pager101-rec0025 300 IN A 1.2.3.4 +255 pager101-rec0025 300 IN A 1.2.3.4 ; akamai_raw_rdata="1.2.3.4" +256 pager101-rec0026 300 IN A 1.2.3.4 +257 pager101-rec0026 300 IN A 1.2.3.4 ; akamai_raw_rdata="1.2.3.4" +258 pager101-rec0027 300 IN A 1.2.3.4 +259 pager101-rec0027 300 IN A 1.2.3.4 ; akamai_raw_rdata="1.2.3.4" +260 pager101-rec0028 300 IN A 1.2.3.4 +261 pager101-rec0028 300 IN A 1.2.3.4 ; akamai_raw_rdata="1.2.3.4" +262 pager101-rec0029 300 IN A 1.2.3.4 +263 pager101-rec0029 300 IN A 1.2.3.4 ; akamai_raw_rdata="1.2.3.4" +264 pager101-rec0030 300 IN A 1.2.3.4 +265 pager101-rec0030 300 IN A 1.2.3.4 ; akamai_raw_rdata="1.2.3.4" +266 pager101-rec0031 300 IN A 1.2.3.4 +267 pager101-rec0031 300 IN A 1.2.3.4 ; akamai_raw_rdata="1.2.3.4" +268 pager101-rec0032 300 IN A 1.2.3.4 +269 pager101-rec0032 300 IN A 1.2.3.4 ; akamai_raw_rdata="1.2.3.4" +270 pager101-rec0033 300 IN A 1.2.3.4 +271 pager101-rec0033 300 IN A 1.2.3.4 ; akamai_raw_rdata="1.2.3.4" +272 pager101-rec0034 300 IN A 1.2.3.4 +273 pager101-rec0034 300 IN A 1.2.3.4 ; akamai_raw_rdata="1.2.3.4" +274 pager101-rec0035 300 IN A 1.2.3.4 +275 pager101-rec0035 300 IN A 1.2.3.4 ; akamai_raw_rdata="1.2.3.4" +276 pager101-rec0036 300 IN A 1.2.3.4 +277 pager101-rec0036 300 IN A 1.2.3.4 ; akamai_raw_rdata="1.2.3.4" +278 pager101-rec0037 300 IN A 1.2.3.4 +279 pager101-rec0037 300 IN A 1.2.3.4 ; akamai_raw_rdata="1.2.3.4" +280 pager101-rec0038 300 IN A 1.2.3.4 +281 pager101-rec0038 300 IN A 1.2.3.4 ; akamai_raw_rdata="1.2.3.4" +282 pager101-rec0039 300 IN A 1.2.3.4 +283 pager101-rec0039 300 IN A 1.2.3.4 ; akamai_raw_rdata="1.2.3.4" +284 pager101-rec0040 300 IN A 1.2.3.4 +285 pager101-rec0040 300 IN A 1.2.3.4 ; akamai_raw_rdata="1.2.3.4" +286 pager101-rec0041 300 IN A 1.2.3.4 +287 pager101-rec0041 300 IN A 1.2.3.4 ; akamai_raw_rdata="1.2.3.4" +288 pager101-rec0042 300 IN A 1.2.3.4 +289 pager101-rec0042 300 IN A 1.2.3.4 ; akamai_raw_rdata="1.2.3.4" +290 pager101-rec0043 300 IN A 1.2.3.4 +291 pager101-rec0043 300 IN A 1.2.3.4 ; akamai_raw_rdata="1.2.3.4" +292 pager101-rec0044 300 IN A 1.2.3.4 +293 pager101-rec0044 300 IN A 1.2.3.4 ; akamai_raw_rdata="1.2.3.4" +294 pager101-rec0045 300 IN A 1.2.3.4 +295 pager101-rec0045 300 IN A 1.2.3.4 ; akamai_raw_rdata="1.2.3.4" +296 pager101-rec0046 300 IN A 1.2.3.4 +297 pager101-rec0046 300 IN A 1.2.3.4 ; akamai_raw_rdata="1.2.3.4" +298 pager101-rec0047 300 IN A 1.2.3.4 +299 pager101-rec0047 300 IN A 1.2.3.4 ; akamai_raw_rdata="1.2.3.4" +300 pager101-rec0048 300 IN A 1.2.3.4 +301 pager101-rec0048 300 IN A 1.2.3.4 ; akamai_raw_rdata="1.2.3.4" +302 pager101-rec0049 300 IN A 1.2.3.4 +303 pager101-rec0049 300 IN A 1.2.3.4 ; akamai_raw_rdata="1.2.3.4" +304 pager101-rec0050 300 IN A 1.2.3.4 +305 pager101-rec0050 300 IN A 1.2.3.4 ; akamai_raw_rdata="1.2.3.4" +306 pager101-rec0051 300 IN A 1.2.3.4 +307 pager101-rec0051 300 IN A 1.2.3.4 ; akamai_raw_rdata="1.2.3.4" +308 pager101-rec0052 300 IN A 1.2.3.4 +309 pager101-rec0052 300 IN A 1.2.3.4 ; akamai_raw_rdata="1.2.3.4" +310 pager101-rec0053 300 IN A 1.2.3.4 +311 pager101-rec0053 300 IN A 1.2.3.4 ; akamai_raw_rdata="1.2.3.4" +312 pager101-rec0054 300 IN A 1.2.3.4 +313 pager101-rec0054 300 IN A 1.2.3.4 ; akamai_raw_rdata="1.2.3.4" +314 pager101-rec0055 300 IN A 1.2.3.4 +315 pager101-rec0055 300 IN A 1.2.3.4 ; akamai_raw_rdata="1.2.3.4" +316 pager101-rec0056 300 IN A 1.2.3.4 +317 pager101-rec0056 300 IN A 1.2.3.4 ; akamai_raw_rdata="1.2.3.4" +318 pager101-rec0057 300 IN A 1.2.3.4 +319 pager101-rec0057 300 IN A 1.2.3.4 ; akamai_raw_rdata="1.2.3.4" +320 pager101-rec0058 300 IN A 1.2.3.4 +321 pager101-rec0058 300 IN A 1.2.3.4 ; akamai_raw_rdata="1.2.3.4" +322 pager101-rec0059 300 IN A 1.2.3.4 +323 pager101-rec0059 300 IN A 1.2.3.4 ; akamai_raw_rdata="1.2.3.4" +324 pager101-rec0060 300 IN A 1.2.3.4 +325 pager101-rec0060 300 IN A 1.2.3.4 ; akamai_raw_rdata="1.2.3.4" +326 pager101-rec0061 300 IN A 1.2.3.4 +327 pager101-rec0061 300 IN A 1.2.3.4 ; akamai_raw_rdata="1.2.3.4" +328 pager101-rec0062 300 IN A 1.2.3.4 +329 pager101-rec0062 300 IN A 1.2.3.4 ; akamai_raw_rdata="1.2.3.4" +330 pager101-rec0063 300 IN A 1.2.3.4 +331 pager101-rec0063 300 IN A 1.2.3.4 ; akamai_raw_rdata="1.2.3.4" +332 pager101-rec0064 300 IN A 1.2.3.4 +333 pager101-rec0064 300 IN A 1.2.3.4 ; akamai_raw_rdata="1.2.3.4" +334 pager101-rec0065 300 IN A 1.2.3.4 +335 pager101-rec0065 300 IN A 1.2.3.4 ; akamai_raw_rdata="1.2.3.4" +336 pager101-rec0066 300 IN A 1.2.3.4 +337 pager101-rec0066 300 IN A 1.2.3.4 ; akamai_raw_rdata="1.2.3.4" +338 pager101-rec0067 300 IN A 1.2.3.4 +339 pager101-rec0067 300 IN A 1.2.3.4 ; akamai_raw_rdata="1.2.3.4" +340 pager101-rec0068 300 IN A 1.2.3.4 +341 pager101-rec0068 300 IN A 1.2.3.4 ; akamai_raw_rdata="1.2.3.4" +342 pager101-rec0069 300 IN A 1.2.3.4 +343 pager101-rec0069 300 IN A 1.2.3.4 ; akamai_raw_rdata="1.2.3.4" +344 pager101-rec0070 300 IN A 1.2.3.4 +345 pager101-rec0070 300 IN A 1.2.3.4 ; akamai_raw_rdata="1.2.3.4" +346 pager101-rec0071 300 IN A 1.2.3.4 +347 pager101-rec0071 300 IN A 1.2.3.4 ; akamai_raw_rdata="1.2.3.4" +348 pager101-rec0072 300 IN A 1.2.3.4 +349 pager101-rec0072 300 IN A 1.2.3.4 ; akamai_raw_rdata="1.2.3.4" +350 pager101-rec0073 300 IN A 1.2.3.4 +351 pager101-rec0073 300 IN A 1.2.3.4 ; akamai_raw_rdata="1.2.3.4" +352 pager101-rec0074 300 IN A 1.2.3.4 +353 pager101-rec0074 300 IN A 1.2.3.4 ; akamai_raw_rdata="1.2.3.4" +354 pager101-rec0075 300 IN A 1.2.3.4 +355 pager101-rec0075 300 IN A 1.2.3.4 ; akamai_raw_rdata="1.2.3.4" +356 pager101-rec0076 300 IN A 1.2.3.4 +357 pager101-rec0076 300 IN A 1.2.3.4 ; akamai_raw_rdata="1.2.3.4" +358 pager101-rec0077 300 IN A 1.2.3.4 +359 pager101-rec0077 300 IN A 1.2.3.4 ; akamai_raw_rdata="1.2.3.4" +360 pager101-rec0078 300 IN A 1.2.3.4 +361 pager101-rec0078 300 IN A 1.2.3.4 ; akamai_raw_rdata="1.2.3.4" +362 pager101-rec0079 300 IN A 1.2.3.4 +363 pager101-rec0079 300 IN A 1.2.3.4 ; akamai_raw_rdata="1.2.3.4" +364 pager101-rec0080 300 IN A 1.2.3.4 +365 pager101-rec0080 300 IN A 1.2.3.4 ; akamai_raw_rdata="1.2.3.4" +366 pager101-rec0081 300 IN A 1.2.3.4 +367 pager101-rec0081 300 IN A 1.2.3.4 ; akamai_raw_rdata="1.2.3.4" +368 pager101-rec0082 300 IN A 1.2.3.4 +369 pager101-rec0082 300 IN A 1.2.3.4 ; akamai_raw_rdata="1.2.3.4" +370 pager101-rec0083 300 IN A 1.2.3.4 +371 pager101-rec0083 300 IN A 1.2.3.4 ; akamai_raw_rdata="1.2.3.4" +372 pager101-rec0084 300 IN A 1.2.3.4 +373 pager101-rec0084 300 IN A 1.2.3.4 ; akamai_raw_rdata="1.2.3.4" +374 pager101-rec0085 300 IN A 1.2.3.4 +375 pager101-rec0085 300 IN A 1.2.3.4 ; akamai_raw_rdata="1.2.3.4" +376 pager101-rec0086 300 IN A 1.2.3.4 +377 pager101-rec0086 300 IN A 1.2.3.4 ; akamai_raw_rdata="1.2.3.4" +378 pager101-rec0087 300 IN A 1.2.3.4 +379 pager101-rec0087 300 IN A 1.2.3.4 ; akamai_raw_rdata="1.2.3.4" +380 pager101-rec0088 300 IN A 1.2.3.4 +381 pager101-rec0088 300 IN A 1.2.3.4 ; akamai_raw_rdata="1.2.3.4" +382 pager101-rec0089 300 IN A 1.2.3.4 +383 pager101-rec0089 300 IN A 1.2.3.4 ; akamai_raw_rdata="1.2.3.4" +384 pager101-rec0090 300 IN A 1.2.3.4 +385 pager101-rec0090 300 IN A 1.2.3.4 ; akamai_raw_rdata="1.2.3.4" +386 pager101-rec0091 300 IN A 1.2.3.4 +387 pager101-rec0091 300 IN A 1.2.3.4 ; akamai_raw_rdata="1.2.3.4" +388 pager101-rec0092 300 IN A 1.2.3.4 +389 pager101-rec0092 300 IN A 1.2.3.4 ; akamai_raw_rdata="1.2.3.4" +390 pager101-rec0093 300 IN A 1.2.3.4 +391 pager101-rec0093 300 IN A 1.2.3.4 ; akamai_raw_rdata="1.2.3.4" +392 pager101-rec0094 300 IN A 1.2.3.4 +393 pager101-rec0094 300 IN A 1.2.3.4 ; akamai_raw_rdata="1.2.3.4" +394 pager101-rec0095 300 IN A 1.2.3.4 +395 pager101-rec0095 300 IN A 1.2.3.4 ; akamai_raw_rdata="1.2.3.4" +396 pager101-rec0096 300 IN A 1.2.3.4 +397 pager101-rec0096 300 IN A 1.2.3.4 ; akamai_raw_rdata="1.2.3.4" +398 pager101-rec0097 300 IN A 1.2.3.4 +399 pager101-rec0097 300 IN A 1.2.3.4 ; akamai_raw_rdata="1.2.3.4" +400 pager101-rec0098 300 IN A 1.2.3.4 +401 pager101-rec0098 300 IN A 1.2.3.4 ; akamai_raw_rdata="1.2.3.4" +402 pager101-rec0099 300 IN A 1.2.3.4 +403 pager101-rec0099 300 IN A 1.2.3.4 ; akamai_raw_rdata="1.2.3.4" +404 pager101-rec0100 300 IN A 1.2.3.4 +405 pager101-rec0100 300 IN A 1.2.3.4 ; akamai_raw_rdata="1.2.3.4" +406 test 300 IN CNAME foo.com. +407 test 300 IN CNAME foo2.com. +408 test 300 IN CNAME foo2.com. ; akamai_raw_rdata="foo2.com." +409 test 300 IN NAPTR 100 10 "U" "E2U+sip" "!^.*$!sip:customer-service@example.com!" . +410 test 300 IN NAPTR 100 10 "U" "E2U+sip" "!^.*$!sip:customer-service@example.com!" . +410 test 300 IN NAPTR 102 10 "U" "E2U+email" "!^.*$!mailto:information@example.com!" . +411 test 300 IN NAPTR 103 10 "U" "E2U+email" "!^.*$!mailto:information@example.com!" . +412 test 300 IN NAPTR 103 20 "A" "E2U+email" "!^.*$!mailto:information@example.com!" . +413 test 300 IN NAPTR 103 20 "A" "E2U+sip" "!^.*$!mailto:information@example.com!" . +414 test 300 IN NAPTR 103 20 "A" "E2U+sip" "!^.*$!sip:customer-service@example.com!" . +415 test 300 IN NAPTR 103 20 "A" "E2U+sip" "" example.foo.com. +416 test 300 IN NAPTR 103 20 "A" "E2U+sip" "" example2.foo.com. +417 test 300 IN NAPTR 103 20 "A" "E2U+sip" "" example2.foo.com. ; akamai_raw_rdata="103 20 \"A\" \"E2U+sip\" \"\" example2.foo.com." +418 test 300 IN NAPTR 103 20 "U" "E2U+email" "!^.*$!mailto:information@example.com!" . +419 testa 300 IN A 1.1.1.1 +420 testa 300 IN A 3.3.3.3 +421 testa 300 IN A 3.3.3.3 ; akamai_raw_rdata="3.3.3.3" +422 testa 333 IN A 1.1.1.1 +423 testa 999 IN A 1.1.1.1 +424 testa 999 IN A 1.1.1.1 ; akamai_raw_rdata="1.1.1.1" +425 testaaaa 300 IN AAAA 2607:f8b0:4006:820::2006 +426 testaaaa 300 IN AAAA 2607:f8b0:4006:820::2013 +427 testaaaa 300 IN AAAA 2607:f8b0:4006:820::2013 ; akamai_raw_rdata="2607:f8b0:4006:820:0:0:0:2013" +428 testcname 300 IN CNAME foo.akamaigoldentest.com. +429 testcname 300 IN CNAME foo.akamaigoldentest.com. ; akamai_raw_rdata="foo.akamaigoldentest.com." +430 testcname 300 IN CNAME www.google.com. +431 testcname 300 IN CNAME www.yahoo.com. +432 testcname 300 IN CNAME www.yahoo.com. ; akamai_raw_rdata="www.yahoo.com." +433 testdefined 300 IN A 2.2.2.2 +434 testdefined 300 IN A 2.2.2.2 ; akamai_raw_rdata="2.2.2.2" +435 testdefined 300 IN A 9.9.9.9 +436 testignore 300 IN A 8.8.8.8 +437 testignore 300 IN A 8.8.8.8 ; akamai_raw_rdata="8.8.8.8" +438 testmx 300 IN MX 100 foo.com. +439 testmx 300 IN MX 100 foo.com. ; akamai_raw_rdata="100 foo.com." +440 testmx 300 IN MX 5 bar.com. +441 testmx 300 IN MX 5 bar.com. ; akamai_raw_rdata="5 bar.com." +442 testmx 300 IN MX 5 foo.com. +443 testmx 300 IN MX 5 foo.com. +443 testmx 300 IN MX 100 bar.com. +444 testmx 300 IN MX 5 foo.com. ; akamai_raw_rdata="5 foo.com." +444 testmx 300 IN MX 100 bar.com. ; akamai_raw_rdata="100 bar.com." +445 testtxt 300 IN TXT "changed" +446 testtxt 300 IN TXT "changed" ; akamai_raw_rdata="\"changed\"" +447 testtxt 300 IN TXT "simple" +448 www 300 IN A 1.1.1.1 +449 www 300 IN A 1.1.1.1 +449 www 300 IN A 2.2.2.2 +450 www 300 IN A 1.1.1.1 +450 www 300 IN A 2.2.2.2 +450 www 300 IN A 3.3.3.3 +451 www 300 IN A 1.1.1.1 ; akamai_raw_rdata="1.1.1.1" +452 www 300 IN A 1.1.1.1 ; akamai_raw_rdata="1.1.1.1" +452 www 300 IN A 2.2.2.2 ; akamai_raw_rdata="2.2.2.2" +452 www 300 IN A 3.3.3.3 ; akamai_raw_rdata="3.3.3.3" +453 www 300 IN A 1.2.3.4 +453 www 300 IN A 5.6.7.8 +454 www 300 IN A 1.2.3.8 +455 www 300 IN A 1.2.3.8 ; akamai_raw_rdata="1.2.3.8" +456 www 300 IN A 1.2.3.9 +457 www 300 IN A 1.2.3.9 ; akamai_raw_rdata="1.2.3.9" +458 www 300 IN A 2.2.2.2 +458 www 300 IN A 5.6.7.8 +459 www 300 IN A 5.5.5.5 +460 www 300 IN A 5.5.5.5 ; akamai_raw_rdata="5.5.5.5" +461 www 400 IN A 2.2.2.2 +461 www 400 IN A 5.6.7.8 +462 www 400 IN A 2.2.2.2 ; akamai_raw_rdata="2.2.2.2" +462 www 400 IN A 5.6.7.8 ; akamai_raw_rdata="5.6.7.8" +463 www 400 IN A 5.6.7.8 +464 www 700 IN A 1.2.3.4 +464 www 700 IN A 5.6.7.8 +465 www 700 IN A 1.2.3.4 ; akamai_raw_rdata="1.2.3.4" +465 www 700 IN A 5.6.7.8 ; akamai_raw_rdata="5.6.7.8" +466 xn--fiq228c 300 IN A 1.2.3.4 +467 xn--fiq228c 300 IN A 1.2.3.4 ; akamai_raw_rdata="1.2.3.4" +468 xn--ndaaa 300 IN A 1.2.3.4 +469 xn--ndaaa 300 IN A 2.2.2.2 +470 xn--ndaaa 300 IN A 2.2.2.2 ; akamai_raw_rdata="2.2.2.2" +471 xn--o-0gab 300 IN CNAME xn--ndaaa.xn--vhquv. +472 xn--o-0gab 300 IN CNAME xn--ndaaa.xn--vhquv. ; akamai_raw_rdata="xn--ndaaa.xn--vhquv." +473 xyz 300 IN NS ns1.foo.com. +473 xyz 300 IN NS ns2.foo.com. +474 xyz 300 IN NS ns1.foo.com. ; akamai_raw_rdata="ns1.foo.com." +474 xyz 300 IN NS ns2.foo.com. ; akamai_raw_rdata="ns2.foo.com." +475 xyz 300 IN NS ns2.foo.com. +476 zzz 300 IN A 3.3.3.3 +476 zzz 300 IN A 4.4.4.4 +477 zzz 300 IN A 3.3.3.3 ; akamai_raw_rdata="3.3.3.3" +477 zzz 300 IN A 4.4.4.4 ; akamai_raw_rdata="4.4.4.4" +478 zzz 300 IN AAAA 2003:dd:d7ff::fe71:cccc +479 zzz 300 IN AAAA 2003:dd:d7ff::fe71:cccc ; akamai_raw_rdata="2003:dd:d7ff:0:0:0:fe71:cccc" diff --git a/providers/akamaiedgedns/test_data/recorded_torc_input_nativeToRecords_akamaigoldentest.com.json b/providers/akamaiedgedns/test_data/recorded_torc_input_nativeToRecords_akamaigoldentest.com.json new file mode 100644 index 0000000000..b1a350c324 --- /dev/null +++ b/providers/akamaiedgedns/test_data/recorded_torc_input_nativeToRecords_akamaigoldentest.com.json @@ -0,0 +1,5430 @@ +[ + { + "index": 1, + "value": { + "name": "*.akamaigoldentest.com", + "type": "A", + "ttl": 300, + "rdata": [ + "3.3.3.3" + ] + } + }, + { + "index": 2, + "value": { + "name": "4.akamaigoldentest.com", + "type": "PTR", + "ttl": 300, + "rdata": [ + "bar.com." + ] + } + }, + { + "index": 3, + "value": { + "name": "4.akamaigoldentest.com", + "type": "PTR", + "ttl": 300, + "rdata": [ + "foo.com." + ] + } + }, + { + "index": 4, + "value": { + "name": "_443._tcp.akamaigoldentest.com", + "type": "TLSA", + "ttl": 300, + "rdata": [ + "2 0 1 0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF" + ] + } + }, + { + "index": 5, + "value": { + "name": "_443._tcp.akamaigoldentest.com", + "type": "TLSA", + "ttl": 300, + "rdata": [ + "2 0 2 0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF" + ] + } + }, + { + "index": 6, + "value": { + "name": "_443._tcp.akamaigoldentest.com", + "type": "TLSA", + "ttl": 300, + "rdata": [ + "2 0 2 FEDCBA9876543210FEDCBA9876543210FEDCBA9876543210FEDCBA9876543210FEDCBA9876543210FEDCBA9876543210FEDCBA9876543210FEDCBA9876543210" + ] + } + }, + { + "index": 7, + "value": { + "name": "_443._tcp.akamaigoldentest.com", + "type": "TLSA", + "ttl": 300, + "rdata": [ + "2 1 1 0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF" + ] + } + }, + { + "index": 8, + "value": { + "name": "_443._tcp.akamaigoldentest.com", + "type": "TLSA", + "ttl": 300, + "rdata": [ + "3 1 1 0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF" + ] + } + }, + { + "index": 9, + "value": { + "name": "_sip._tcp.akamaigoldentest.com", + "type": "SRV", + "ttl": 300, + "rdata": [ + "15 65 75 ." + ] + } + }, + { + "index": 10, + "value": { + "name": "_sip._tcp.akamaigoldentest.com", + "type": "SRV", + "ttl": 300, + "rdata": [ + "15 65 75 foo4.com.", + "52 6 7 foo.com." + ] + } + }, + { + "index": 11, + "value": { + "name": "_sip._tcp.akamaigoldentest.com", + "type": "SRV", + "ttl": 300, + "rdata": [ + "15 65 75 foo4.com.", + "52 62 7 foo.com." + ] + } + }, + { + "index": 12, + "value": { + "name": "_sip._tcp.akamaigoldentest.com", + "type": "SRV", + "ttl": 300, + "rdata": [ + "15 65 75 foo4.com.", + "52 62 72 foo.com." + ] + } + }, + { + "index": 13, + "value": { + "name": "_sip._tcp.akamaigoldentest.com", + "type": "SRV", + "ttl": 300, + "rdata": [ + "5 6 7 foo.com.", + "15 65 75 foo3.com." + ] + } + }, + { + "index": 14, + "value": { + "name": "_sip._tcp.akamaigoldentest.com", + "type": "SRV", + "ttl": 300, + "rdata": [ + "5 6 7 foo.com.", + "15 65 75 foo4.com." + ] + } + }, + { + "index": 15, + "value": { + "name": "_sip._tcp.akamaigoldentest.com", + "type": "SRV", + "ttl": 300, + "rdata": [ + "5 6 7 foo.com.", + "5 60 70 foo2.com.", + "15 65 75 foo3.com." + ] + } + }, + { + "index": 16, + "value": { + "name": "_sip._tcp.akamaigoldentest.com", + "type": "SRV", + "ttl": 300, + "rdata": [ + "5 6 7 foo.com.", + "5 60 70 foo2.com." + ] + } + }, + { + "index": 17, + "value": { + "name": "_sip._tcp.akamaigoldentest.com", + "type": "SRV", + "ttl": 300, + "rdata": [ + "5 6 7 foo.com." + ] + } + }, + { + "index": 18, + "value": { + "name": "_sip._tcp.akamaigoldentest.com", + "type": "SRV", + "ttl": 333, + "rdata": [ + "5 6 7 foo.com." + ] + } + }, + { + "index": 19, + "value": { + "name": "_sip._tcp.akamaigoldentest.com", + "type": "SRV", + "ttl": 4400, + "rdata": [ + "5 6 7 foo.com." + ] + } + }, + { + "index": 20, + "value": { + "name": "a.akamaigoldentest.com", + "type": "CNAME", + "ttl": 300, + "rdata": [ + "xn--ndaaa.com." + ] + } + }, + { + "index": 21, + "value": { + "name": "a.akamaigoldentest.com", + "type": "LOC", + "ttl": 300, + "rdata": [ + "42 21 43.950 N 71 5 6.340 W -24.-33m 1m 200m 10m" + ] + } + }, + { + "index": 22, + "value": { + "name": "akamaigoldentest.com", + "type": "A", + "ttl": 1000, + "rdata": [ + "8.8.8.8" + ] + } + }, + { + "index": 23, + "value": { + "name": "akamaigoldentest.com", + "type": "A", + "ttl": 300, + "rdata": [ + "1.2.3.2" + ] + } + }, + { + "index": 24, + "value": { + "name": "akamaigoldentest.com", + "type": "A", + "ttl": 300, + "rdata": [ + "1.2.3.4", + "2.3.4.5" + ] + } + }, + { + "index": 25, + "value": { + "name": "akamaigoldentest.com", + "type": "A", + "ttl": 300, + "rdata": [ + "1.2.3.4" + ] + } + }, + { + "index": 26, + "value": { + "name": "akamaigoldentest.com", + "type": "A", + "ttl": 300, + "rdata": [ + "2.2.2.2" + ] + } + }, + { + "index": 27, + "value": { + "name": "akamaigoldentest.com", + "type": "A", + "ttl": 300, + "rdata": [ + "4.4.4.4" + ] + } + }, + { + "index": 28, + "value": { + "name": "akamaigoldentest.com", + "type": "A", + "ttl": 500, + "rdata": [ + "8.8.8.8" + ] + } + }, + { + "index": 29, + "value": { + "name": "akamaigoldentest.com", + "type": "A", + "ttl": 666, + "rdata": [ + "8.8.8.8" + ] + } + }, + { + "index": 30, + "value": { + "name": "akamaigoldentest.com", + "type": "AKAMAITLC", + "ttl": 300, + "rdata": [ + "DUAL foo.akamaigoldentest.com." + ] + } + }, + { + "index": 31, + "value": { + "name": "akamaigoldentest.com", + "type": "AKAMAITLC", + "ttl": 300, + "rdata": [ + "DUAL foo.com." + ] + } + }, + { + "index": 32, + "value": { + "name": "akamaigoldentest.com", + "type": "AKAMAITLC", + "ttl": 300, + "rdata": [ + "DUAL foo2.com." + ] + } + }, + { + "index": 33, + "value": { + "name": "akamaigoldentest.com", + "type": "CAA", + "ttl": 300, + "rdata": [ + "0 issue \"letsencrypt.org; validationmethods=dns-01; accounturi=https://acme-v02.api.letsencrypt.org/acme/acct/1234\"" + ] + } + }, + { + "index": 34, + "value": { + "name": "akamaigoldentest.com", + "type": "CAA", + "ttl": 300, + "rdata": [ + "0 issue \"letsencrypt.org\"" + ] + } + }, + { + "index": 35, + "value": { + "name": "akamaigoldentest.com", + "type": "CAA", + "ttl": 300, + "rdata": [ + "0 issuewild \";\"" + ] + } + }, + { + "index": 36, + "value": { + "name": "akamaigoldentest.com", + "type": "CAA", + "ttl": 300, + "rdata": [ + "0 issuewild \"example.com\"" + ] + } + }, + { + "index": 37, + "value": { + "name": "akamaigoldentest.com", + "type": "CAA", + "ttl": 300, + "rdata": [ + "0 issuewild \"letsencrypt.org\"" + ] + } + }, + { + "index": 38, + "value": { + "name": "akamaigoldentest.com", + "type": "CAA", + "ttl": 300, + "rdata": [ + "128 issue \"letsencrypt.org\"" + ] + } + }, + { + "index": 39, + "value": { + "name": "akamaigoldentest.com", + "type": "LOC", + "ttl": 300, + "rdata": [ + "42 21 54 N 71 6 18 W -24.-05m 30m 0m 0m" + ] + } + }, + { + "index": 40, + "value": { + "name": "akamaigoldentest.com", + "type": "LOC", + "ttl": 300, + "rdata": [ + "42 21 54 N 71 6 18 W -24.-06m 30m 10m 0m" + ] + } + }, + { + "index": 41, + "value": { + "name": "akamaigoldentest.com", + "type": "LOC", + "ttl": 300, + "rdata": [ + "42 21 54 N 71 6 18 W -24m 30m 0m 0m" + ] + } + }, + { + "index": 42, + "value": { + "name": "akamaigoldentest.com", + "type": "MX", + "ttl": 300, + "rdata": [ + "0 ." + ] + } + }, + { + "index": 43, + "value": { + "name": "akamaigoldentest.com", + "type": "MX", + "ttl": 300, + "rdata": [ + "2 akamaigoldentest.com.", + "8 www.akamaigoldentest.com." + ] + } + }, + { + "index": 44, + "value": { + "name": "akamaigoldentest.com", + "type": "MX", + "ttl": 300, + "rdata": [ + "5 bar.com." + ] + } + }, + { + "index": 45, + "value": { + "name": "akamaigoldentest.com", + "type": "MX", + "ttl": 300, + "rdata": [ + "5 foo.com." + ] + } + }, + { + "index": 46, + "value": { + "name": "akamaigoldentest.com", + "type": "NS", + "ttl": 300, + "rdata": [ + "a1-98.akam.net.", + "a12-65.akam.net.", + "a13-65.akam.net.", + "a2-64.akam.net.", + "a3-64.akam.net.", + "a4-65.akam.net.", + "ns1.foo.com.", + "ns2.foo.com." + ] + } + }, + { + "index": 47, + "value": { + "name": "akamaigoldentest.com", + "type": "NS", + "ttl": 300, + "rdata": [ + "a1-98.akam.net.", + "a12-65.akam.net.", + "a13-65.akam.net.", + "a2-64.akam.net.", + "a3-64.akam.net.", + "a4-65.akam.net.", + "ns1.foo.com." + ] + } + }, + { + "index": 48, + "value": { + "name": "akamaigoldentest.com", + "type": "NS", + "ttl": 300, + "rdata": [ + "a1-98.akam.net.", + "a12-65.akam.net.", + "a13-65.akam.net.", + "a2-64.akam.net.", + "a3-64.akam.net.", + "a4-65.akam.net." + ] + } + }, + { + "index": 49, + "value": { + "name": "akamaigoldentest.com", + "type": "NS", + "ttl": 86400, + "rdata": [ + "a1-98.akam.net.", + "a12-65.akam.net.", + "a13-65.akam.net.", + "a2-64.akam.net.", + "a3-64.akam.net.", + "a4-65.akam.net." + ] + } + }, + { + "index": 50, + "value": { + "name": "akamaigoldentest.com", + "type": "SOA", + "ttl": 86400, + "rdata": [ + "a1-98.akam.net. hostmaster.akamaigoldentest.com. 2026081000 3600 600 604800 300" + ] + } + }, + { + "index": 51, + "value": { + "name": "akamaigoldentest.com", + "type": "SOA", + "ttl": 86400, + "rdata": [ + "a1-98.akam.net. hostmaster.akamaigoldentest.com. 2026081001 3600 600 604800 300" + ] + } + }, + { + "index": 52, + "value": { + "name": "akamaigoldentest.com", + "type": "SOA", + "ttl": 86400, + "rdata": [ + "a1-98.akam.net. hostmaster.akamaigoldentest.com. 2026081002 3600 600 604800 300" + ] + } + }, + { + "index": 53, + "value": { + "name": "akamaigoldentest.com", + "type": "SOA", + "ttl": 86400, + "rdata": [ + "a1-98.akam.net. hostmaster.akamaigoldentest.com. 2026081003 3600 600 604800 300" + ] + } + }, + { + "index": 54, + "value": { + "name": "akamaigoldentest.com", + "type": "SOA", + "ttl": 86400, + "rdata": [ + "a1-98.akam.net. hostmaster.akamaigoldentest.com. 2026081004 3600 600 604800 300" + ] + } + }, + { + "index": 55, + "value": { + "name": "akamaigoldentest.com", + "type": "SOA", + "ttl": 86400, + "rdata": [ + "a1-98.akam.net. hostmaster.akamaigoldentest.com. 2026081005 3600 600 604800 300" + ] + } + }, + { + "index": 56, + "value": { + "name": "akamaigoldentest.com", + "type": "SOA", + "ttl": 86400, + "rdata": [ + "a1-98.akam.net. hostmaster.akamaigoldentest.com. 2026081006 3600 600 604800 300" + ] + } + }, + { + "index": 57, + "value": { + "name": "akamaigoldentest.com", + "type": "SOA", + "ttl": 86400, + "rdata": [ + "a1-98.akam.net. hostmaster.akamaigoldentest.com. 2026081007 3600 600 604800 300" + ] + } + }, + { + "index": 58, + "value": { + "name": "akamaigoldentest.com", + "type": "SOA", + "ttl": 86400, + "rdata": [ + "a1-98.akam.net. hostmaster.akamaigoldentest.com. 2026081009 3600 600 604800 300" + ] + } + }, + { + "index": 59, + "value": { + "name": "akamaigoldentest.com", + "type": "SOA", + "ttl": 86400, + "rdata": [ + "a1-98.akam.net. hostmaster.akamaigoldentest.com. 2026081010 3600 600 604800 300" + ] + } + }, + { + "index": 60, + "value": { + "name": "akamaigoldentest.com", + "type": "SOA", + "ttl": 86400, + "rdata": [ + "a1-98.akam.net. hostmaster.akamaigoldentest.com. 2026081011 3600 600 604800 300" + ] + } + }, + { + "index": 61, + "value": { + "name": "akamaigoldentest.com", + "type": "SOA", + "ttl": 86400, + "rdata": [ + "a1-98.akam.net. hostmaster.akamaigoldentest.com. 2026081012 3600 600 604800 300" + ] + } + }, + { + "index": 62, + "value": { + "name": "akamaigoldentest.com", + "type": "SOA", + "ttl": 86400, + "rdata": [ + "a1-98.akam.net. hostmaster.akamaigoldentest.com. 2026081013 3600 600 604800 300" + ] + } + }, + { + "index": 63, + "value": { + "name": "akamaigoldentest.com", + "type": "SOA", + "ttl": 86400, + "rdata": [ + "a1-98.akam.net. hostmaster.akamaigoldentest.com. 2026081014 3600 600 604800 300" + ] + } + }, + { + "index": 64, + "value": { + "name": "akamaigoldentest.com", + "type": "SOA", + "ttl": 86400, + "rdata": [ + "a1-98.akam.net. hostmaster.akamaigoldentest.com. 2026081015 3600 600 604800 300" + ] + } + }, + { + "index": 65, + "value": { + "name": "akamaigoldentest.com", + "type": "SOA", + "ttl": 86400, + "rdata": [ + "a1-98.akam.net. hostmaster.akamaigoldentest.com. 2026081016 3600 600 604800 300" + ] + } + }, + { + "index": 66, + "value": { + "name": "akamaigoldentest.com", + "type": "SOA", + "ttl": 86400, + "rdata": [ + "a1-98.akam.net. hostmaster.akamaigoldentest.com. 2026081017 3600 600 604800 300" + ] + } + }, + { + "index": 67, + "value": { + "name": "akamaigoldentest.com", + "type": "SOA", + "ttl": 86400, + "rdata": [ + "a1-98.akam.net. hostmaster.akamaigoldentest.com. 2026081019 3600 600 604800 300" + ] + } + }, + { + "index": 68, + "value": { + "name": "akamaigoldentest.com", + "type": "SOA", + "ttl": 86400, + "rdata": [ + "a1-98.akam.net. hostmaster.akamaigoldentest.com. 2026081021 3600 600 604800 300" + ] + } + }, + { + "index": 69, + "value": { + "name": "akamaigoldentest.com", + "type": "SOA", + "ttl": 86400, + "rdata": [ + "a1-98.akam.net. hostmaster.akamaigoldentest.com. 2026081022 3600 600 604800 300" + ] + } + }, + { + "index": 70, + "value": { + "name": "akamaigoldentest.com", + "type": "SOA", + "ttl": 86400, + "rdata": [ + "a1-98.akam.net. hostmaster.akamaigoldentest.com. 2026081023 3600 600 604800 300" + ] + } + }, + { + "index": 71, + "value": { + "name": "akamaigoldentest.com", + "type": "SOA", + "ttl": 86400, + "rdata": [ + "a1-98.akam.net. hostmaster.akamaigoldentest.com. 2026081025 3600 600 604800 300" + ] + } + }, + { + "index": 72, + "value": { + "name": "akamaigoldentest.com", + "type": "SOA", + "ttl": 86400, + "rdata": [ + "a1-98.akam.net. hostmaster.akamaigoldentest.com. 2026081026 3600 600 604800 300" + ] + } + }, + { + "index": 73, + "value": { + "name": "akamaigoldentest.com", + "type": "SOA", + "ttl": 86400, + "rdata": [ + "a1-98.akam.net. hostmaster.akamaigoldentest.com. 2026081027 3600 600 604800 300" + ] + } + }, + { + "index": 74, + "value": { + "name": "akamaigoldentest.com", + "type": "SOA", + "ttl": 86400, + "rdata": [ + "a1-98.akam.net. hostmaster.akamaigoldentest.com. 2026081028 3600 600 604800 300" + ] + } + }, + { + "index": 75, + "value": { + "name": "akamaigoldentest.com", + "type": "SOA", + "ttl": 86400, + "rdata": [ + "a1-98.akam.net. hostmaster.akamaigoldentest.com. 2026081029 3600 600 604800 300" + ] + } + }, + { + "index": 76, + "value": { + "name": "akamaigoldentest.com", + "type": "SOA", + "ttl": 86400, + "rdata": [ + "a1-98.akam.net. hostmaster.akamaigoldentest.com. 2026081030 3600 600 604800 300" + ] + } + }, + { + "index": 77, + "value": { + "name": "akamaigoldentest.com", + "type": "SOA", + "ttl": 86400, + "rdata": [ + "a1-98.akam.net. hostmaster.akamaigoldentest.com. 2026081031 3600 600 604800 300" + ] + } + }, + { + "index": 78, + "value": { + "name": "akamaigoldentest.com", + "type": "SOA", + "ttl": 86400, + "rdata": [ + "a1-98.akam.net. hostmaster.akamaigoldentest.com. 2026081032 3600 600 604800 300" + ] + } + }, + { + "index": 79, + "value": { + "name": "akamaigoldentest.com", + "type": "SOA", + "ttl": 86400, + "rdata": [ + "a1-98.akam.net. hostmaster.akamaigoldentest.com. 2026081033 3600 600 604800 300" + ] + } + }, + { + "index": 80, + "value": { + "name": "akamaigoldentest.com", + "type": "SOA", + "ttl": 86400, + "rdata": [ + "a1-98.akam.net. hostmaster.akamaigoldentest.com. 2026081034 3600 600 604800 300" + ] + } + }, + { + "index": 81, + "value": { + "name": "akamaigoldentest.com", + "type": "SOA", + "ttl": 86400, + "rdata": [ + "a1-98.akam.net. hostmaster.akamaigoldentest.com. 2026081035 3600 600 604800 300" + ] + } + }, + { + "index": 82, + "value": { + "name": "akamaigoldentest.com", + "type": "SOA", + "ttl": 86400, + "rdata": [ + "a1-98.akam.net. hostmaster.akamaigoldentest.com. 2026081036 3600 600 604800 300" + ] + } + }, + { + "index": 83, + "value": { + "name": "akamaigoldentest.com", + "type": "SOA", + "ttl": 86400, + "rdata": [ + "a1-98.akam.net. hostmaster.akamaigoldentest.com. 2026081037 3600 600 604800 300" + ] + } + }, + { + "index": 84, + "value": { + "name": "akamaigoldentest.com", + "type": "SOA", + "ttl": 86400, + "rdata": [ + "a1-98.akam.net. hostmaster.akamaigoldentest.com. 2026081038 3600 600 604800 300" + ] + } + }, + { + "index": 85, + "value": { + "name": "akamaigoldentest.com", + "type": "SOA", + "ttl": 86400, + "rdata": [ + "a1-98.akam.net. hostmaster.akamaigoldentest.com. 2026081039 3600 600 604800 300" + ] + } + }, + { + "index": 86, + "value": { + "name": "akamaigoldentest.com", + "type": "SOA", + "ttl": 86400, + "rdata": [ + "a1-98.akam.net. hostmaster.akamaigoldentest.com. 2026081041 3600 600 604800 300" + ] + } + }, + { + "index": 87, + "value": { + "name": "akamaigoldentest.com", + "type": "SOA", + "ttl": 86400, + "rdata": [ + "a1-98.akam.net. hostmaster.akamaigoldentest.com. 2026081043 3600 600 604800 300" + ] + } + }, + { + "index": 88, + "value": { + "name": "akamaigoldentest.com", + "type": "SOA", + "ttl": 86400, + "rdata": [ + "a1-98.akam.net. hostmaster.akamaigoldentest.com. 2026081044 3600 600 604800 300" + ] + } + }, + { + "index": 89, + "value": { + "name": "akamaigoldentest.com", + "type": "SOA", + "ttl": 86400, + "rdata": [ + "a1-98.akam.net. hostmaster.akamaigoldentest.com. 2026081045 3600 600 604800 300" + ] + } + }, + { + "index": 90, + "value": { + "name": "akamaigoldentest.com", + "type": "SOA", + "ttl": 86400, + "rdata": [ + "a1-98.akam.net. hostmaster.akamaigoldentest.com. 2026081046 3600 600 604800 300" + ] + } + }, + { + "index": 91, + "value": { + "name": "akamaigoldentest.com", + "type": "SOA", + "ttl": 86400, + "rdata": [ + "a1-98.akam.net. hostmaster.akamaigoldentest.com. 2026081048 3600 600 604800 300" + ] + } + }, + { + "index": 92, + "value": { + "name": "akamaigoldentest.com", + "type": "SOA", + "ttl": 86400, + "rdata": [ + "a1-98.akam.net. hostmaster.akamaigoldentest.com. 2026081049 3600 600 604800 300" + ] + } + }, + { + "index": 93, + "value": { + "name": "akamaigoldentest.com", + "type": "SOA", + "ttl": 86400, + "rdata": [ + "a1-98.akam.net. hostmaster.akamaigoldentest.com. 2026081050 3600 600 604800 300" + ] + } + }, + { + "index": 94, + "value": { + "name": "akamaigoldentest.com", + "type": "SOA", + "ttl": 86400, + "rdata": [ + "a1-98.akam.net. hostmaster.akamaigoldentest.com. 2026081051 3600 600 604800 300" + ] + } + }, + { + "index": 95, + "value": { + "name": "akamaigoldentest.com", + "type": "SOA", + "ttl": 86400, + "rdata": [ + "a1-98.akam.net. hostmaster.akamaigoldentest.com. 2026081053 3600 600 604800 300" + ] + } + }, + { + "index": 96, + "value": { + "name": "akamaigoldentest.com", + "type": "SOA", + "ttl": 86400, + "rdata": [ + "a1-98.akam.net. hostmaster.akamaigoldentest.com. 2026081054 3600 600 604800 300" + ] + } + }, + { + "index": 97, + "value": { + "name": "akamaigoldentest.com", + "type": "SOA", + "ttl": 86400, + "rdata": [ + "a1-98.akam.net. hostmaster.akamaigoldentest.com. 2026081055 3600 600 604800 300" + ] + } + }, + { + "index": 98, + "value": { + "name": "akamaigoldentest.com", + "type": "SOA", + "ttl": 86400, + "rdata": [ + "a1-98.akam.net. hostmaster.akamaigoldentest.com. 2026081057 3600 600 604800 300" + ] + } + }, + { + "index": 99, + "value": { + "name": "akamaigoldentest.com", + "type": "SOA", + "ttl": 86400, + "rdata": [ + "a1-98.akam.net. hostmaster.akamaigoldentest.com. 2026081059 3600 600 604800 300" + ] + } + }, + { + "index": 100, + "value": { + "name": "akamaigoldentest.com", + "type": "SOA", + "ttl": 86400, + "rdata": [ + "a1-98.akam.net. hostmaster.akamaigoldentest.com. 2026081060 3600 600 604800 300" + ] + } + }, + { + "index": 101, + "value": { + "name": "akamaigoldentest.com", + "type": "SOA", + "ttl": 86400, + "rdata": [ + "a1-98.akam.net. hostmaster.akamaigoldentest.com. 2026081061 3600 600 604800 300" + ] + } + }, + { + "index": 102, + "value": { + "name": "akamaigoldentest.com", + "type": "SOA", + "ttl": 86400, + "rdata": [ + "a1-98.akam.net. hostmaster.akamaigoldentest.com. 2026081062 3600 600 604800 300" + ] + } + }, + { + "index": 103, + "value": { + "name": "akamaigoldentest.com", + "type": "SOA", + "ttl": 86400, + "rdata": [ + "a1-98.akam.net. hostmaster.akamaigoldentest.com. 2026081063 3600 600 604800 300" + ] + } + }, + { + "index": 104, + "value": { + "name": "akamaigoldentest.com", + "type": "SOA", + "ttl": 86400, + "rdata": [ + "a1-98.akam.net. hostmaster.akamaigoldentest.com. 2026081065 3600 600 604800 300" + ] + } + }, + { + "index": 105, + "value": { + "name": "akamaigoldentest.com", + "type": "SOA", + "ttl": 86400, + "rdata": [ + "a1-98.akam.net. hostmaster.akamaigoldentest.com. 2026081067 3600 600 604800 300" + ] + } + }, + { + "index": 106, + "value": { + "name": "akamaigoldentest.com", + "type": "SOA", + "ttl": 86400, + "rdata": [ + "a1-98.akam.net. hostmaster.akamaigoldentest.com. 2026081068 3600 600 604800 300" + ] + } + }, + { + "index": 107, + "value": { + "name": "akamaigoldentest.com", + "type": "SOA", + "ttl": 86400, + "rdata": [ + "a1-98.akam.net. hostmaster.akamaigoldentest.com. 2026081069 3600 600 604800 300" + ] + } + }, + { + "index": 108, + "value": { + "name": "akamaigoldentest.com", + "type": "SOA", + "ttl": 86400, + "rdata": [ + "a1-98.akam.net. hostmaster.akamaigoldentest.com. 2026081071 3600 600 604800 300" + ] + } + }, + { + "index": 109, + "value": { + "name": "akamaigoldentest.com", + "type": "SOA", + "ttl": 86400, + "rdata": [ + "a1-98.akam.net. hostmaster.akamaigoldentest.com. 2026081073 3600 600 604800 300" + ] + } + }, + { + "index": 110, + "value": { + "name": "akamaigoldentest.com", + "type": "SOA", + "ttl": 86400, + "rdata": [ + "a1-98.akam.net. hostmaster.akamaigoldentest.com. 2026081074 3600 600 604800 300" + ] + } + }, + { + "index": 111, + "value": { + "name": "akamaigoldentest.com", + "type": "SOA", + "ttl": 86400, + "rdata": [ + "a1-98.akam.net. hostmaster.akamaigoldentest.com. 2026081076 3600 600 604800 300" + ] + } + }, + { + "index": 112, + "value": { + "name": "akamaigoldentest.com", + "type": "SOA", + "ttl": 86400, + "rdata": [ + "a1-98.akam.net. hostmaster.akamaigoldentest.com. 2026081078 3600 600 604800 300" + ] + } + }, + { + "index": 113, + "value": { + "name": "akamaigoldentest.com", + "type": "SOA", + "ttl": 86400, + "rdata": [ + "a1-98.akam.net. hostmaster.akamaigoldentest.com. 2026081080 3600 600 604800 300" + ] + } + }, + { + "index": 114, + "value": { + "name": "akamaigoldentest.com", + "type": "SOA", + "ttl": 86400, + "rdata": [ + "a1-98.akam.net. hostmaster.akamaigoldentest.com. 2026081082 3600 600 604800 300" + ] + } + }, + { + "index": 115, + "value": { + "name": "akamaigoldentest.com", + "type": "SOA", + "ttl": 86400, + "rdata": [ + "a1-98.akam.net. hostmaster.akamaigoldentest.com. 2026081085 3600 600 604800 300" + ] + } + }, + { + "index": 116, + "value": { + "name": "akamaigoldentest.com", + "type": "SOA", + "ttl": 86400, + "rdata": [ + "a1-98.akam.net. hostmaster.akamaigoldentest.com. 2026081086 3600 600 604800 300" + ] + } + }, + { + "index": 117, + "value": { + "name": "akamaigoldentest.com", + "type": "SOA", + "ttl": 86400, + "rdata": [ + "a1-98.akam.net. hostmaster.akamaigoldentest.com. 2026081087 3600 600 604800 300" + ] + } + }, + { + "index": 118, + "value": { + "name": "akamaigoldentest.com", + "type": "SOA", + "ttl": 86400, + "rdata": [ + "a1-98.akam.net. hostmaster.akamaigoldentest.com. 2026081090 3600 600 604800 300" + ] + } + }, + { + "index": 119, + "value": { + "name": "akamaigoldentest.com", + "type": "SOA", + "ttl": 86400, + "rdata": [ + "a1-98.akam.net. hostmaster.akamaigoldentest.com. 2026081093 3600 600 604800 300" + ] + } + }, + { + "index": 120, + "value": { + "name": "akamaigoldentest.com", + "type": "SOA", + "ttl": 86400, + "rdata": [ + "a1-98.akam.net. hostmaster.akamaigoldentest.com. 2026081094 3600 600 604800 300" + ] + } + }, + { + "index": 121, + "value": { + "name": "akamaigoldentest.com", + "type": "SOA", + "ttl": 86400, + "rdata": [ + "a1-98.akam.net. hostmaster.akamaigoldentest.com. 2026081095 3600 600 604800 300" + ] + } + }, + { + "index": 122, + "value": { + "name": "akamaigoldentest.com", + "type": "SOA", + "ttl": 86400, + "rdata": [ + "a1-98.akam.net. hostmaster.akamaigoldentest.com. 2026081098 3600 600 604800 300" + ] + } + }, + { + "index": 123, + "value": { + "name": "akamaigoldentest.com", + "type": "SOA", + "ttl": 86400, + "rdata": [ + "a1-98.akam.net. hostmaster.akamaigoldentest.com. 2026081099 3600 600 604800 300" + ] + } + }, + { + "index": 124, + "value": { + "name": "akamaigoldentest.com", + "type": "SOA", + "ttl": 86400, + "rdata": [ + "a1-98.akam.net. hostmaster.akamaigoldentest.com. 2026081100 3600 600 604800 300" + ] + } + }, + { + "index": 125, + "value": { + "name": "akamaigoldentest.com", + "type": "SOA", + "ttl": 86400, + "rdata": [ + "a1-98.akam.net. hostmaster.akamaigoldentest.com. 2026081103 3600 600 604800 300" + ] + } + }, + { + "index": 126, + "value": { + "name": "akamaigoldentest.com", + "type": "SOA", + "ttl": 86400, + "rdata": [ + "a1-98.akam.net. hostmaster.akamaigoldentest.com. 2026081105 3600 600 604800 300" + ] + } + }, + { + "index": 127, + "value": { + "name": "akamaigoldentest.com", + "type": "SOA", + "ttl": 86400, + "rdata": [ + "a1-98.akam.net. hostmaster.akamaigoldentest.com. 2026081106 3600 600 604800 300" + ] + } + }, + { + "index": 128, + "value": { + "name": "akamaigoldentest.com", + "type": "SOA", + "ttl": 86400, + "rdata": [ + "a1-98.akam.net. hostmaster.akamaigoldentest.com. 2026081107 3600 600 604800 300" + ] + } + }, + { + "index": 129, + "value": { + "name": "akamaigoldentest.com", + "type": "SOA", + "ttl": 86400, + "rdata": [ + "a1-98.akam.net. hostmaster.akamaigoldentest.com. 2026081108 3600 600 604800 300" + ] + } + }, + { + "index": 130, + "value": { + "name": "akamaigoldentest.com", + "type": "SOA", + "ttl": 86400, + "rdata": [ + "a1-98.akam.net. hostmaster.akamaigoldentest.com. 2026081109 3600 600 604800 300" + ] + } + }, + { + "index": 131, + "value": { + "name": "akamaigoldentest.com", + "type": "SOA", + "ttl": 86400, + "rdata": [ + "a1-98.akam.net. hostmaster.akamaigoldentest.com. 2026081111 3600 600 604800 300" + ] + } + }, + { + "index": 132, + "value": { + "name": "akamaigoldentest.com", + "type": "SOA", + "ttl": 86400, + "rdata": [ + "a1-98.akam.net. hostmaster.akamaigoldentest.com. 2026081113 3600 600 604800 300" + ] + } + }, + { + "index": 133, + "value": { + "name": "akamaigoldentest.com", + "type": "SOA", + "ttl": 86400, + "rdata": [ + "a1-98.akam.net. hostmaster.akamaigoldentest.com. 2026081115 3600 600 604800 300" + ] + } + }, + { + "index": 134, + "value": { + "name": "akamaigoldentest.com", + "type": "SOA", + "ttl": 86400, + "rdata": [ + "a1-98.akam.net. hostmaster.akamaigoldentest.com. 2026081117 3600 600 604800 300" + ] + } + }, + { + "index": 135, + "value": { + "name": "akamaigoldentest.com", + "type": "SOA", + "ttl": 86400, + "rdata": [ + "a1-98.akam.net. hostmaster.akamaigoldentest.com. 2026081119 3600 600 604800 300" + ] + } + }, + { + "index": 136, + "value": { + "name": "akamaigoldentest.com", + "type": "SOA", + "ttl": 86400, + "rdata": [ + "a1-98.akam.net. hostmaster.akamaigoldentest.com. 2026081121 3600 600 604800 300" + ] + } + }, + { + "index": 137, + "value": { + "name": "akamaigoldentest.com", + "type": "SOA", + "ttl": 86400, + "rdata": [ + "a1-98.akam.net. hostmaster.akamaigoldentest.com. 2026081123 3600 600 604800 300" + ] + } + }, + { + "index": 138, + "value": { + "name": "akamaigoldentest.com", + "type": "SOA", + "ttl": 86400, + "rdata": [ + "a1-98.akam.net. hostmaster.akamaigoldentest.com. 2026081125 3600 600 604800 300" + ] + } + }, + { + "index": 139, + "value": { + "name": "akamaigoldentest.com", + "type": "SOA", + "ttl": 86400, + "rdata": [ + "a1-98.akam.net. hostmaster.akamaigoldentest.com. 2026081127 3600 600 604800 300" + ] + } + }, + { + "index": 140, + "value": { + "name": "akamaigoldentest.com", + "type": "SOA", + "ttl": 86400, + "rdata": [ + "a1-98.akam.net. hostmaster.akamaigoldentest.com. 2026081129 3600 600 604800 300" + ] + } + }, + { + "index": 141, + "value": { + "name": "akamaigoldentest.com", + "type": "SOA", + "ttl": 86400, + "rdata": [ + "a1-98.akam.net. hostmaster.akamaigoldentest.com. 2026081131 3600 600 604800 300" + ] + } + }, + { + "index": 142, + "value": { + "name": "akamaigoldentest.com", + "type": "SOA", + "ttl": 86400, + "rdata": [ + "a1-98.akam.net. hostmaster.akamaigoldentest.com. 2026081133 3600 600 604800 300" + ] + } + }, + { + "index": 143, + "value": { + "name": "akamaigoldentest.com", + "type": "SOA", + "ttl": 86400, + "rdata": [ + "a1-98.akam.net. hostmaster.akamaigoldentest.com. 2026081135 3600 600 604800 300" + ] + } + }, + { + "index": 144, + "value": { + "name": "akamaigoldentest.com", + "type": "SOA", + "ttl": 86400, + "rdata": [ + "a1-98.akam.net. hostmaster.akamaigoldentest.com. 2026081137 3600 600 604800 300" + ] + } + }, + { + "index": 145, + "value": { + "name": "akamaigoldentest.com", + "type": "SOA", + "ttl": 86400, + "rdata": [ + "a1-98.akam.net. hostmaster.akamaigoldentest.com. 2026081139 3600 600 604800 300" + ] + } + }, + { + "index": 146, + "value": { + "name": "akamaigoldentest.com", + "type": "SOA", + "ttl": 86400, + "rdata": [ + "a1-98.akam.net. hostmaster.akamaigoldentest.com. 2026081141 3600 600 604800 300" + ] + } + }, + { + "index": 147, + "value": { + "name": "akamaigoldentest.com", + "type": "SOA", + "ttl": 86400, + "rdata": [ + "a1-98.akam.net. hostmaster.akamaigoldentest.com. 2026081142 3600 600 604800 300" + ] + } + }, + { + "index": 148, + "value": { + "name": "akamaigoldentest.com", + "type": "SOA", + "ttl": 86400, + "rdata": [ + "a1-98.akam.net. hostmaster.akamaigoldentest.com. 2026081143 3600 600 604800 300" + ] + } + }, + { + "index": 149, + "value": { + "name": "akamaigoldentest.com", + "type": "SOA", + "ttl": 86400, + "rdata": [ + "a1-98.akam.net. hostmaster.akamaigoldentest.com. 2026081144 3600 600 604800 300" + ] + } + }, + { + "index": 150, + "value": { + "name": "akamaigoldentest.com", + "type": "SOA", + "ttl": 86400, + "rdata": [ + "a1-98.akam.net. hostmaster.akamaigoldentest.com. 2026081145 3600 600 604800 300" + ] + } + }, + { + "index": 151, + "value": { + "name": "akamaigoldentest.com", + "type": "SOA", + "ttl": 86400, + "rdata": [ + "a1-98.akam.net. hostmaster.akamaigoldentest.com. 2026081146 3600 600 604800 300" + ] + } + }, + { + "index": 152, + "value": { + "name": "akamaigoldentest.com", + "type": "SOA", + "ttl": 86400, + "rdata": [ + "a1-98.akam.net. hostmaster.akamaigoldentest.com. 2026081148 3600 600 604800 300" + ] + } + }, + { + "index": 153, + "value": { + "name": "akamaigoldentest.com", + "type": "SOA", + "ttl": 86400, + "rdata": [ + "a1-98.akam.net. hostmaster.akamaigoldentest.com. 2026081149 3600 600 604800 300" + ] + } + }, + { + "index": 154, + "value": { + "name": "akamaigoldentest.com", + "type": "SOA", + "ttl": 86400, + "rdata": [ + "a1-98.akam.net. hostmaster.akamaigoldentest.com. 2026081150 3600 600 604800 300" + ] + } + }, + { + "index": 155, + "value": { + "name": "akamaigoldentest.com", + "type": "SOA", + "ttl": 86400, + "rdata": [ + "a1-98.akam.net. hostmaster.akamaigoldentest.com. 2026081151 3600 600 604800 300" + ] + } + }, + { + "index": 156, + "value": { + "name": "akamaigoldentest.com", + "type": "SOA", + "ttl": 86400, + "rdata": [ + "a1-98.akam.net. hostmaster.akamaigoldentest.com. 2026081152 3600 600 604800 300" + ] + } + }, + { + "index": 157, + "value": { + "name": "akamaigoldentest.com", + "type": "SOA", + "ttl": 86400, + "rdata": [ + "a1-98.akam.net. hostmaster.akamaigoldentest.com. 2026081153 3600 600 604800 300" + ] + } + }, + { + "index": 158, + "value": { + "name": "akamaigoldentest.com", + "type": "SOA", + "ttl": 86400, + "rdata": [ + "a1-98.akam.net. hostmaster.akamaigoldentest.com. 2026081156 3600 600 604800 300" + ] + } + }, + { + "index": 159, + "value": { + "name": "akamaigoldentest.com", + "type": "SOA", + "ttl": 86400, + "rdata": [ + "a1-98.akam.net. hostmaster.akamaigoldentest.com. 2026081157 3600 600 604800 300" + ] + } + }, + { + "index": 160, + "value": { + "name": "akamaigoldentest.com", + "type": "SOA", + "ttl": 86400, + "rdata": [ + "a1-98.akam.net. hostmaster.akamaigoldentest.com. 2026081158 3600 600 604800 300" + ] + } + }, + { + "index": 161, + "value": { + "name": "akamaigoldentest.com", + "type": "SOA", + "ttl": 86400, + "rdata": [ + "a1-98.akam.net. hostmaster.akamaigoldentest.com. 2026081159 3600 600 604800 300" + ] + } + }, + { + "index": 162, + "value": { + "name": "akamaigoldentest.com", + "type": "SOA", + "ttl": 86400, + "rdata": [ + "a1-98.akam.net. hostmaster.akamaigoldentest.com. 2026081162 3600 600 604800 300" + ] + } + }, + { + "index": 163, + "value": { + "name": "akamaigoldentest.com", + "type": "SOA", + "ttl": 86400, + "rdata": [ + "a1-98.akam.net. hostmaster.akamaigoldentest.com. 2026081163 3600 600 604800 300" + ] + } + }, + { + "index": 164, + "value": { + "name": "akamaigoldentest.com", + "type": "SOA", + "ttl": 86400, + "rdata": [ + "a1-98.akam.net. hostmaster.akamaigoldentest.com. 2026081164 3600 600 604800 300" + ] + } + }, + { + "index": 165, + "value": { + "name": "akamaigoldentest.com", + "type": "SOA", + "ttl": 86400, + "rdata": [ + "a1-98.akam.net. hostmaster.akamaigoldentest.com. 2026081166 3600 600 604800 300" + ] + } + }, + { + "index": 166, + "value": { + "name": "akamaigoldentest.com", + "type": "SOA", + "ttl": 86400, + "rdata": [ + "a1-98.akam.net. hostmaster.akamaigoldentest.com. 2026081168 3600 600 604800 300" + ] + } + }, + { + "index": 167, + "value": { + "name": "akamaigoldentest.com", + "type": "SOA", + "ttl": 86400, + "rdata": [ + "a1-98.akam.net. hostmaster.akamaigoldentest.com. 2026081169 3600 600 604800 300" + ] + } + }, + { + "index": 168, + "value": { + "name": "akamaigoldentest.com", + "type": "SOA", + "ttl": 86400, + "rdata": [ + "a1-98.akam.net. hostmaster.akamaigoldentest.com. 2026081170 3600 600 604800 300" + ] + } + }, + { + "index": 169, + "value": { + "name": "akamaigoldentest.com", + "type": "SOA", + "ttl": 86400, + "rdata": [ + "a1-98.akam.net. hostmaster.akamaigoldentest.com. 2026081171 3600 600 604800 300" + ] + } + }, + { + "index": 170, + "value": { + "name": "akamaigoldentest.com", + "type": "SOA", + "ttl": 86400, + "rdata": [ + "a1-98.akam.net. hostmaster.akamaigoldentest.com. 2026081270 3600 600 604800 300" + ] + } + }, + { + "index": 171, + "value": { + "name": "akamaigoldentest.com", + "type": "SOA", + "ttl": 86400, + "rdata": [ + "a1-98.akam.net. hostmaster.akamaigoldentest.com. 2026081271 3600 600 604800 300" + ] + } + }, + { + "index": 172, + "value": { + "name": "akamaigoldentest.com", + "type": "SOA", + "ttl": 86400, + "rdata": [ + "a1-98.akam.net. hostmaster.akamaigoldentest.com. 2026081272 3600 600 604800 300" + ] + } + }, + { + "index": 173, + "value": { + "name": "akamaigoldentest.com", + "type": "SOA", + "ttl": 86400, + "rdata": [ + "a1-98.akam.net. hostmaster.akamaigoldentest.com. 2026081373 3600 600 604800 300" + ] + } + }, + { + "index": 174, + "value": { + "name": "akamaigoldentest.com", + "type": "SOA", + "ttl": 86400, + "rdata": [ + "a1-98.akam.net. hostmaster.akamaigoldentest.com. 2026081374 3600 600 604800 300" + ] + } + }, + { + "index": 175, + "value": { + "name": "akamaigoldentest.com", + "type": "SOA", + "ttl": 86400, + "rdata": [ + "a1-98.akam.net. hostmaster.akamaigoldentest.com. 2026081375 3600 600 604800 300" + ] + } + }, + { + "index": 176, + "value": { + "name": "akamaigoldentest.com", + "type": "SOA", + "ttl": 86400, + "rdata": [ + "a1-98.akam.net. hostmaster.akamaigoldentest.com. 2026081376 3600 600 604800 300" + ] + } + }, + { + "index": 177, + "value": { + "name": "akamaigoldentest.com", + "type": "SOA", + "ttl": 86400, + "rdata": [ + "a1-98.akam.net. hostmaster.akamaigoldentest.com. 2026081377 3600 600 604800 300" + ] + } + }, + { + "index": 178, + "value": { + "name": "akamaigoldentest.com", + "type": "SOA", + "ttl": 86400, + "rdata": [ + "a1-98.akam.net. hostmaster.akamaigoldentest.com. 2026081378 3600 600 604800 300" + ] + } + }, + { + "index": 179, + "value": { + "name": "akamaigoldentest.com", + "type": "SOA", + "ttl": 86400, + "rdata": [ + "a1-98.akam.net. hostmaster.akamaigoldentest.com. 2026081379 3600 600 604800 300" + ] + } + }, + { + "index": 180, + "value": { + "name": "akamaigoldentest.com", + "type": "SOA", + "ttl": 86400, + "rdata": [ + "a1-98.akam.net. hostmaster.akamaigoldentest.com. 2026081380 3600 600 604800 300" + ] + } + }, + { + "index": 181, + "value": { + "name": "akamaigoldentest.com", + "type": "SOA", + "ttl": 86400, + "rdata": [ + "a1-98.akam.net. hostmaster.akamaigoldentest.com. 2026081381 3600 600 604800 300" + ] + } + }, + { + "index": 182, + "value": { + "name": "akamaigoldentest.com", + "type": "SOA", + "ttl": 86400, + "rdata": [ + "a1-98.akam.net. hostmaster.akamaigoldentest.com. 2026081382 3600 600 604800 300" + ] + } + }, + { + "index": 183, + "value": { + "name": "akamaigoldentest.com", + "type": "SOA", + "ttl": 86400, + "rdata": [ + "a1-98.akam.net. hostmaster.akamaigoldentest.com. 2026081383 3600 600 604800 300" + ] + } + }, + { + "index": 184, + "value": { + "name": "akamaigoldentest.com", + "type": "SOA", + "ttl": 86400, + "rdata": [ + "a1-98.akam.net. hostmaster.akamaigoldentest.com. 2026081384 3600 600 604800 300" + ] + } + }, + { + "index": 185, + "value": { + "name": "akamaigoldentest.com", + "type": "SOA", + "ttl": 86400, + "rdata": [ + "a1-98.akam.net. hostmaster.akamaigoldentest.com. 2026081389 3600 600 604800 300" + ] + } + }, + { + "index": 186, + "value": { + "name": "akamaigoldentest.com", + "type": "SOA", + "ttl": 86400, + "rdata": [ + "a1-98.akam.net. hostmaster.akamaigoldentest.com. 2026081394 3600 600 604800 300" + ] + } + }, + { + "index": 187, + "value": { + "name": "akamaigoldentest.com", + "type": "SOA", + "ttl": 86400, + "rdata": [ + "a1-98.akam.net. hostmaster.akamaigoldentest.com. 2026081395 3600 600 604800 300" + ] + } + }, + { + "index": 188, + "value": { + "name": "akamaigoldentest.com", + "type": "SOA", + "ttl": 86400, + "rdata": [ + "a1-98.akam.net. hostmaster.akamaigoldentest.com. 2026081396 3600 600 604800 300" + ] + } + }, + { + "index": 189, + "value": { + "name": "akamaigoldentest.com", + "type": "SOA", + "ttl": 86400, + "rdata": [ + "a1-98.akam.net. hostmaster.akamaigoldentest.com. 2026081397 3600 600 604800 300" + ] + } + }, + { + "index": 190, + "value": { + "name": "akamaigoldentest.com", + "type": "SOA", + "ttl": 86400, + "rdata": [ + "a1-98.akam.net. hostmaster.akamaigoldentest.com. 2026081398 3600 600 604800 300" + ] + } + }, + { + "index": 191, + "value": { + "name": "akamaigoldentest.com", + "type": "SOA", + "ttl": 86400, + "rdata": [ + "a1-98.akam.net. hostmaster.akamaigoldentest.com. 2026081399 3600 600 604800 300" + ] + } + }, + { + "index": 192, + "value": { + "name": "akamaigoldentest.com", + "type": "SOA", + "ttl": 86400, + "rdata": [ + "a1-98.akam.net. hostmaster.akamaigoldentest.com. 2026081400 3600 600 604800 300" + ] + } + }, + { + "index": 193, + "value": { + "name": "akamaigoldentest.com", + "type": "SOA", + "ttl": 86400, + "rdata": [ + "a1-98.akam.net. hostmaster.akamaigoldentest.com. 2026081401 3600 600 604800 300" + ] + } + }, + { + "index": 194, + "value": { + "name": "akamaigoldentest.com", + "type": "SOA", + "ttl": 86400, + "rdata": [ + "a1-98.akam.net. hostmaster.akamaigoldentest.com. 2026081402 3600 600 604800 300" + ] + } + }, + { + "index": 195, + "value": { + "name": "akamaigoldentest.com", + "type": "SOA", + "ttl": 86400, + "rdata": [ + "a1-98.akam.net. hostmaster.akamaigoldentest.com. 2026081403 3600 600 604800 300" + ] + } + }, + { + "index": 196, + "value": { + "name": "akamaigoldentest.com", + "type": "SOA", + "ttl": 86400, + "rdata": [ + "a1-98.akam.net. hostmaster.akamaigoldentest.com. 2026081404 3600 600 604800 300" + ] + } + }, + { + "index": 197, + "value": { + "name": "akamaigoldentest.com", + "type": "SOA", + "ttl": 86400, + "rdata": [ + "a1-98.akam.net. hostmaster.akamaigoldentest.com. 2026081405 3600 600 604800 300" + ] + } + }, + { + "index": 198, + "value": { + "name": "akamaigoldentest.com", + "type": "SOA", + "ttl": 86400, + "rdata": [ + "a1-98.akam.net. hostmaster.akamaigoldentest.com. 2026081406 3600 600 604800 300" + ] + } + }, + { + "index": 199, + "value": { + "name": "akamaigoldentest.com", + "type": "SOA", + "ttl": 86400, + "rdata": [ + "a1-98.akam.net. hostmaster.akamaigoldentest.com. 2026081407 3600 600 604800 300" + ] + } + }, + { + "index": 200, + "value": { + "name": "akamaigoldentest.com", + "type": "SOA", + "ttl": 86400, + "rdata": [ + "a1-98.akam.net. hostmaster.akamaigoldentest.com. 2026081408 3600 600 604800 300" + ] + } + }, + { + "index": 201, + "value": { + "name": "akamaigoldentest.com", + "type": "SOA", + "ttl": 86400, + "rdata": [ + "a1-98.akam.net. hostmaster.akamaigoldentest.com. 2026081409 3600 600 604800 300" + ] + } + }, + { + "index": 202, + "value": { + "name": "akamaigoldentest.com", + "type": "SOA", + "ttl": 86400, + "rdata": [ + "a1-98.akam.net. hostmaster.akamaigoldentest.com. 2026081410 3600 600 604800 300" + ] + } + }, + { + "index": 203, + "value": { + "name": "akamaigoldentest.com", + "type": "SOA", + "ttl": 86400, + "rdata": [ + "a1-98.akam.net. hostmaster.akamaigoldentest.com. 2026081411 3600 600 604800 300" + ] + } + }, + { + "index": 204, + "value": { + "name": "akamaigoldentest.com", + "type": "SOA", + "ttl": 86400, + "rdata": [ + "a1-98.akam.net. hostmaster.akamaigoldentest.com. 2026081412 3600 600 604800 300" + ] + } + }, + { + "index": 205, + "value": { + "name": "akamaigoldentest.com", + "type": "SOA", + "ttl": 86400, + "rdata": [ + "a1-98.akam.net. hostmaster.akamaigoldentest.com. 2026081413 3600 600 604800 300" + ] + } + }, + { + "index": 206, + "value": { + "name": "akamaigoldentest.com", + "type": "SOA", + "ttl": 86400, + "rdata": [ + "a1-98.akam.net. hostmaster.akamaigoldentest.com. 2026081414 3600 600 604800 300" + ] + } + }, + { + "index": 207, + "value": { + "name": "akamaigoldentest.com", + "type": "SOA", + "ttl": 86400, + "rdata": [ + "a1-98.akam.net. hostmaster.akamaigoldentest.com. 2026081415 3600 600 604800 300" + ] + } + }, + { + "index": 208, + "value": { + "name": "akamaigoldentest.com", + "type": "SOA", + "ttl": 86400, + "rdata": [ + "a1-98.akam.net. hostmaster.akamaigoldentest.com. 2026081416 3600 600 604800 300" + ] + } + }, + { + "index": 209, + "value": { + "name": "akamaigoldentest.com", + "type": "SOA", + "ttl": 86400, + "rdata": [ + "a1-98.akam.net. hostmaster.akamaigoldentest.com. 2026081417 3600 600 604800 300" + ] + } + }, + { + "index": 210, + "value": { + "name": "akamaigoldentest.com", + "type": "SOA", + "ttl": 86400, + "rdata": [ + "a1-98.akam.net. hostmaster.akamaigoldentest.com. 2026081418 3600 600 604800 300" + ] + } + }, + { + "index": 211, + "value": { + "name": "akamaigoldentest.com", + "type": "SOA", + "ttl": 86400, + "rdata": [ + "a1-98.akam.net. hostmaster.akamaigoldentest.com. 2026081419 3600 600 604800 300" + ] + } + }, + { + "index": 212, + "value": { + "name": "akamaigoldentest.com", + "type": "SOA", + "ttl": 86400, + "rdata": [ + "a1-98.akam.net. hostmaster.akamaigoldentest.com. 2026081420 3600 600 604800 300" + ] + } + }, + { + "index": 213, + "value": { + "name": "akamaigoldentest.com", + "type": "SOA", + "ttl": 86400, + "rdata": [ + "a1-98.akam.net. hostmaster.akamaigoldentest.com. 2026081421 3600 600 604800 300" + ] + } + }, + { + "index": 214, + "value": { + "name": "akamaigoldentest.com", + "type": "SOA", + "ttl": 86400, + "rdata": [ + "a1-98.akam.net. hostmaster.akamaigoldentest.com. 2026081422 3600 600 604800 300" + ] + } + }, + { + "index": 215, + "value": { + "name": "akamaigoldentest.com", + "type": "SOA", + "ttl": 86400, + "rdata": [ + "a1-98.akam.net. hostmaster.akamaigoldentest.com. 2026081423 3600 600 604800 300" + ] + } + }, + { + "index": 216, + "value": { + "name": "akamaigoldentest.com", + "type": "SOA", + "ttl": 86400, + "rdata": [ + "a1-98.akam.net. hostmaster.akamaigoldentest.com. 2026081424 3600 600 604800 300" + ] + } + }, + { + "index": 217, + "value": { + "name": "akamaigoldentest.com", + "type": "SOA", + "ttl": 86400, + "rdata": [ + "a1-98.akam.net. hostmaster.akamaigoldentest.com. 2026081425 3600 600 604800 300" + ] + } + }, + { + "index": 218, + "value": { + "name": "akamaigoldentest.com", + "type": "SOA", + "ttl": 86400, + "rdata": [ + "a1-98.akam.net. hostmaster.akamaigoldentest.com. 2026081426 3600 600 604800 300" + ] + } + }, + { + "index": 219, + "value": { + "name": "akamaigoldentest.com", + "type": "SOA", + "ttl": 86400, + "rdata": [ + "a1-98.akam.net. hostmaster.akamaigoldentest.com. 2026081427 3600 600 604800 300" + ] + } + }, + { + "index": 220, + "value": { + "name": "akamaigoldentest.com", + "type": "SOA", + "ttl": 86400, + "rdata": [ + "a1-98.akam.net. hostmaster.akamaigoldentest.com. 2026081428 3600 600 604800 300" + ] + } + }, + { + "index": 221, + "value": { + "name": "akamaigoldentest.com", + "type": "SOA", + "ttl": 86400, + "rdata": [ + "a1-98.akam.net. hostmaster.akamaigoldentest.com. 2026081429 3600 600 604800 300" + ] + } + }, + { + "index": 222, + "value": { + "name": "akamaigoldentest.com", + "type": "SOA", + "ttl": 86400, + "rdata": [ + "a1-98.akam.net. hostmaster.akamaigoldentest.com. 2026081430 3600 600 604800 300" + ] + } + }, + { + "index": 223, + "value": { + "name": "akamaigoldentest.com", + "type": "SOA", + "ttl": 86400, + "rdata": [ + "a1-98.akam.net. hostmaster.akamaigoldentest.com. 2026081431 3600 600 604800 300" + ] + } + }, + { + "index": 224, + "value": { + "name": "akamaigoldentest.com", + "type": "SOA", + "ttl": 86400, + "rdata": [ + "a1-98.akam.net. hostmaster.akamaigoldentest.com. 2026081432 3600 600 604800 300" + ] + } + }, + { + "index": 225, + "value": { + "name": "akamaigoldentest.com", + "type": "SOA", + "ttl": 86400, + "rdata": [ + "a1-98.akam.net. hostmaster.akamaigoldentest.com. 2026081433 3600 600 604800 300" + ] + } + }, + { + "index": 226, + "value": { + "name": "akamaigoldentest.com", + "type": "SOA", + "ttl": 86400, + "rdata": [ + "a1-98.akam.net. hostmaster.akamaigoldentest.com. 2026081434 3600 600 604800 300" + ] + } + }, + { + "index": 227, + "value": { + "name": "akamaigoldentest.com", + "type": "SOA", + "ttl": 86400, + "rdata": [ + "a1-98.akam.net. hostmaster.akamaigoldentest.com. 2026081435 3600 600 604800 300" + ] + } + }, + { + "index": 228, + "value": { + "name": "akamaigoldentest.com", + "type": "SOA", + "ttl": 86400, + "rdata": [ + "a1-98.akam.net. hostmaster.akamaigoldentest.com. 2026081436 3600 600 604800 300" + ] + } + }, + { + "index": 229, + "value": { + "name": "akamaigoldentest.com", + "type": "SOA", + "ttl": 86400, + "rdata": [ + "a1-98.akam.net. hostmaster.akamaigoldentest.com. 2026081437 3600 600 604800 300" + ] + } + }, + { + "index": 230, + "value": { + "name": "akamaigoldentest.com", + "type": "SOA", + "ttl": 86400, + "rdata": [ + "a1-98.akam.net. hostmaster.akamaigoldentest.com. 2026081439 3600 600 604800 300" + ] + } + }, + { + "index": 231, + "value": { + "name": "akamaigoldentest.com", + "type": "SOA", + "ttl": 86400, + "rdata": [ + "a1-98.akam.net. hostmaster.akamaigoldentest.com. 2026081440 3600 600 604800 300" + ] + } + }, + { + "index": 232, + "value": { + "name": "akamaigoldentest.com", + "type": "SOA", + "ttl": 86400, + "rdata": [ + "a1-98.akam.net. hostmaster.akamaigoldentest.com. 2026081441 3600 600 604800 300" + ] + } + }, + { + "index": 233, + "value": { + "name": "akamaigoldentest.com", + "type": "SOA", + "ttl": 86400, + "rdata": [ + "a1-98.akam.net. hostmaster.akamaigoldentest.com. 2026081442 3600 600 604800 300" + ] + } + }, + { + "index": 234, + "value": { + "name": "akamaigoldentest.com", + "type": "SOA", + "ttl": 86400, + "rdata": [ + "a1-98.akam.net. hostmaster.akamaigoldentest.com. 2026081443 3600 600 604800 300" + ] + } + }, + { + "index": 235, + "value": { + "name": "akamaigoldentest.com", + "type": "SOA", + "ttl": 86400, + "rdata": [ + "a1-98.akam.net. hostmaster.akamaigoldentest.com. 2026081444 3600 600 604800 300" + ] + } + }, + { + "index": 236, + "value": { + "name": "akamaigoldentest.com", + "type": "SOA", + "ttl": 86400, + "rdata": [ + "a1-98.akam.net. hostmaster.akamaigoldentest.com. 2026081446 3600 600 604800 300" + ] + } + }, + { + "index": 237, + "value": { + "name": "akamaigoldentest.com", + "type": "SOA", + "ttl": 86400, + "rdata": [ + "a1-98.akam.net. hostmaster.akamaigoldentest.com. 2026081448 3600 600 604800 300" + ] + } + }, + { + "index": 238, + "value": { + "name": "akamaigoldentest.com", + "type": "SOA", + "ttl": 86400, + "rdata": [ + "a1-98.akam.net. hostmaster.akamaigoldentest.com. 2026081449 3600 600 604800 300" + ] + } + }, + { + "index": 239, + "value": { + "name": "akamaigoldentest.com", + "type": "SOA", + "ttl": 86400, + "rdata": [ + "a1-98.akam.net. hostmaster.akamaigoldentest.com. 2026081450 3600 600 604800 300" + ] + } + }, + { + "index": 240, + "value": { + "name": "akamaigoldentest.com", + "type": "SOA", + "ttl": 86400, + "rdata": [ + "a1-98.akam.net. hostmaster.akamaigoldentest.com. 2026081451 3600 600 604800 300" + ] + } + }, + { + "index": 241, + "value": { + "name": "akamaigoldentest.com", + "type": "SOA", + "ttl": 86400, + "rdata": [ + "a1-98.akam.net. hostmaster.akamaigoldentest.com. 2026081455 3600 600 604800 300" + ] + } + }, + { + "index": 242, + "value": { + "name": "akamaigoldentest.com", + "type": "SOA", + "ttl": 86400, + "rdata": [ + "a1-98.akam.net. hostmaster.akamaigoldentest.com. 2026081459 3600 600 604800 300" + ] + } + }, + { + "index": 243, + "value": { + "name": "akamaigoldentest.com", + "type": "SOA", + "ttl": 86400, + "rdata": [ + "a1-98.akam.net. hostmaster.akamaigoldentest.com. 2026081463 3600 600 604800 300" + ] + } + }, + { + "index": 244, + "value": { + "name": "akamaigoldentest.com", + "type": "SOA", + "ttl": 86400, + "rdata": [ + "a1-98.akam.net. hostmaster.akamaigoldentest.com. 2026081467 3600 600 604800 300" + ] + } + }, + { + "index": 245, + "value": { + "name": "akamaigoldentest.com", + "type": "SOA", + "ttl": 86400, + "rdata": [ + "a1-98.akam.net. hostmaster.akamaigoldentest.com. 2026081471 3600 600 604800 300" + ] + } + }, + { + "index": 246, + "value": { + "name": "akamaigoldentest.com", + "type": "SOA", + "ttl": 86400, + "rdata": [ + "a1-98.akam.net. hostmaster.akamaigoldentest.com. 2026081475 3600 600 604800 300" + ] + } + }, + { + "index": 247, + "value": { + "name": "akamaigoldentest.com", + "type": "SOA", + "ttl": 86400, + "rdata": [ + "a1-98.akam.net. hostmaster.akamaigoldentest.com. 2026081479 3600 600 604800 300" + ] + } + }, + { + "index": 248, + "value": { + "name": "akamaigoldentest.com", + "type": "SOA", + "ttl": 86400, + "rdata": [ + "a1-98.akam.net. hostmaster.akamaigoldentest.com. 2026081483 3600 600 604800 300" + ] + } + }, + { + "index": 249, + "value": { + "name": "akamaigoldentest.com", + "type": "SOA", + "ttl": 86400, + "rdata": [ + "a1-98.akam.net. hostmaster.akamaigoldentest.com. 2026081488 3600 600 604800 300" + ] + } + }, + { + "index": 250, + "value": { + "name": "akamaigoldentest.com", + "type": "SOA", + "ttl": 86400, + "rdata": [ + "a1-98.akam.net. hostmaster.akamaigoldentest.com. 2026081489 3600 600 604800 300" + ] + } + }, + { + "index": 251, + "value": { + "name": "akamaigoldentest.com", + "type": "SOA", + "ttl": 86400, + "rdata": [ + "a1-98.akam.net. hostmaster.akamaigoldentest.com. 2026081490 3600 600 604800 300" + ] + } + }, + { + "index": 252, + "value": { + "name": "akamaigoldentest.com", + "type": "SOA", + "ttl": 86400, + "rdata": [ + "a1-98.akam.net. hostmaster.akamaigoldentest.com. 2026081491 3600 600 604800 300" + ] + } + }, + { + "index": 253, + "value": { + "name": "akamaigoldentest.com", + "type": "SOA", + "ttl": 86400, + "rdata": [ + "a1-98.akam.net. hostmaster.akamaigoldentest.com. 2026081492 3600 600 604800 300" + ] + } + }, + { + "index": 254, + "value": { + "name": "akamaigoldentest.com", + "type": "SOA", + "ttl": 86400, + "rdata": [ + "a1-98.akam.net. hostmaster.akamaigoldentest.com. 2026081497 3600 600 604800 300" + ] + } + }, + { + "index": 255, + "value": { + "name": "akamaigoldentest.com", + "type": "SOA", + "ttl": 86400, + "rdata": [ + "a1-98.akam.net. hostmaster.akamaigoldentest.com. 2026081499 3600 600 604800 300" + ] + } + }, + { + "index": 256, + "value": { + "name": "akamaigoldentest.com", + "type": "SOA", + "ttl": 86400, + "rdata": [ + "a1-98.akam.net. hostmaster.akamaigoldentest.com. 2026081501 3600 600 604800 300" + ] + } + }, + { + "index": 257, + "value": { + "name": "akamaigoldentest.com", + "type": "SOA", + "ttl": 86400, + "rdata": [ + "a1-98.akam.net. hostmaster.akamaigoldentest.com. 2026081505 3600 600 604800 300" + ] + } + }, + { + "index": 258, + "value": { + "name": "akamaigoldentest.com", + "type": "SOA", + "ttl": 86400, + "rdata": [ + "a1-98.akam.net. hostmaster.akamaigoldentest.com. 2026081509 3600 600 604800 300" + ] + } + }, + { + "index": 259, + "value": { + "name": "akamaigoldentest.com", + "type": "SOA", + "ttl": 86400, + "rdata": [ + "a1-98.akam.net. hostmaster.akamaigoldentest.com. 2026081511 3600 600 604800 300" + ] + } + }, + { + "index": 260, + "value": { + "name": "akamaigoldentest.com", + "type": "SOA", + "ttl": 86400, + "rdata": [ + "a1-98.akam.net. hostmaster.akamaigoldentest.com. 2026081512 3600 600 604800 300" + ] + } + }, + { + "index": 261, + "value": { + "name": "akamaigoldentest.com", + "type": "SOA", + "ttl": 86400, + "rdata": [ + "a1-98.akam.net. hostmaster.akamaigoldentest.com. 2026081514 3600 600 604800 300" + ] + } + }, + { + "index": 262, + "value": { + "name": "akamaigoldentest.com", + "type": "SOA", + "ttl": 86400, + "rdata": [ + "a1-98.akam.net. hostmaster.akamaigoldentest.com. 2026081515 3600 600 604800 300" + ] + } + }, + { + "index": 263, + "value": { + "name": "akamaigoldentest.com", + "type": "SOA", + "ttl": 86400, + "rdata": [ + "a1-98.akam.net. hostmaster.akamaigoldentest.com. 2026081516 3600 600 604800 300" + ] + } + }, + { + "index": 264, + "value": { + "name": "akamaigoldentest.com", + "type": "SOA", + "ttl": 86400, + "rdata": [ + "a1-98.akam.net. hostmaster.akamaigoldentest.com. 2026081517 3600 600 604800 300" + ] + } + }, + { + "index": 265, + "value": { + "name": "akamaigoldentest.com", + "type": "SSHFP", + "ttl": 300, + "rdata": [ + "1 1 66C7D5540B7D75A1FB4C84FEBFA178AD99BDD67C" + ] + } + }, + { + "index": 266, + "value": { + "name": "akamaigoldentest.com", + "type": "SSHFP", + "ttl": 300, + "rdata": [ + "2 1 66C7D5540B7D75A1FB4C84FEBFA178AD99BDD67C" + ] + } + }, + { + "index": 267, + "value": { + "name": "akamaigoldentest.com", + "type": "SSHFP", + "ttl": 300, + "rdata": [ + "2 2 745A635BC46A397A5C4F21D437483005BCC40D7511FF15FBFAFE913A081559BC" + ] + } + }, + { + "index": 268, + "value": { + "name": "akamaigoldentest.com", + "type": "TXT", + "ttl": 300, + "rdata": [ + "\"asimple\"" + ] + } + }, + { + "index": 269, + "value": { + "name": "akamaigoldentest.com", + "type": "TXT", + "ttl": 300, + "rdata": [ + "\"simple\"" + ] + } + }, + { + "index": 270, + "value": { + "name": "another-child.akamaigoldentest.com", + "type": "DS", + "ttl": 300, + "rdata": [ + "44 13 2 4B9B6B073EDD97FEB5BC12DC4E1B32D2C6AF7AE23A293936CEB87BB10494EC44", + "1501 14 4 109BB6B5B6D5547C1CE03C7A8BD7D8F80C1CB0957F50C4F7FDA04692079917E4F9CAD52B878F3D8234E1A170B154B72D", + "1502 8 2 2FA14F53E6B15CAC9AC77846C7BE87862C2A7E9EC0C6CEA319DB939317F126ED", + "65535 13 2 2FA14F53E6B15CAC9AC77846C7BE87862C2A7E9EC0C6CEA319DB939317F126ED" + ] + } + }, + { + "index": 271, + "value": { + "name": "another-child.akamaigoldentest.com", + "type": "DS", + "ttl": 300, + "rdata": [ + "44 13 2 4B9B6B073EDD97FEB5BC12DC4E1B32D2C6AF7AE23A293936CEB87BB10494EC44" + ] + } + }, + { + "index": 272, + "value": { + "name": "b.akamaigoldentest.com", + "type": "LOC", + "ttl": 300, + "rdata": [ + "52 14 5 N 0 8 50 E 10.22m 0m 0m 0m" + ] + } + }, + { + "index": 273, + "value": { + "name": "bar.akamaigoldentest.com", + "type": "A", + "ttl": 300, + "rdata": [ + "1.2.3.4" + ] + } + }, + { + "index": 274, + "value": { + "name": "bar.akamaigoldentest.com", + "type": "A", + "ttl": 300, + "rdata": [ + "5.5.5.5" + ] + } + }, + { + "index": 275, + "value": { + "name": "bar.akamaigoldentest.com", + "type": "CNAME", + "ttl": 300, + "rdata": [ + "redact2.acm-validations.aws." + ] + } + }, + { + "index": 276, + "value": { + "name": "bar.akamaigoldentest.com", + "type": "MX", + "ttl": 300, + "rdata": [ + "5 bar.com." + ] + } + }, + { + "index": 277, + "value": { + "name": "bar.bat.akamaigoldentest.com", + "type": "A", + "ttl": 300, + "rdata": [ + "5.5.5.5" + ] + } + }, + { + "index": 278, + "value": { + "name": "c.akamaigoldentest.com", + "type": "LOC", + "ttl": 300, + "rdata": [ + "32 7 19 S 116 2 25 E 10m 0m 0m 0m" + ] + } + }, + { + "index": 279, + "value": { + "name": "child.akamaigoldentest.com", + "type": "DS", + "ttl": 300, + "rdata": [ + "1 14 4 417212FD1C8BC5896FEFD8DB58AF824545E85B0D0546409366A30AEF7269FAE258173BD185FB262C86F3BB86FBA04368" + ] + } + }, + { + "index": 280, + "value": { + "name": "child.akamaigoldentest.com", + "type": "DS", + "ttl": 300, + "rdata": [ + "3 13 2 4B9B6B073EDD97FEB5BC12DC4E1B32D2C6AF7AE23A293936CEB87BB10494EC44" + ] + } + }, + { + "index": 281, + "value": { + "name": "child.akamaigoldentest.com", + "type": "DS", + "ttl": 300, + "rdata": [ + "3 14 4 3115238F89E0BF5252D9718113B1B9FFF854608D84BE94EEFB9210DC1CC0B4F3557342A27465CFACC42EF137AE9A5489" + ] + } + }, + { + "index": 282, + "value": { + "name": "child.akamaigoldentest.com", + "type": "DS", + "ttl": 300, + "rdata": [ + "3 8 2 4B9B6B073EDD97FEB5BC12DC4E1B32D2C6AF7AE23A293936CEB87BB10494EC44" + ] + } + }, + { + "index": 283, + "value": { + "name": "child.akamaigoldentest.com", + "type": "DS", + "ttl": 300, + "rdata": [ + "8857 8 2 4B9B6B073EDD97FEB5BC12DC4E1B32D2C6AF7AE23A293936CEB87BB10494EC44" + ] + } + }, + { + "index": 284, + "value": { + "name": "d.akamaigoldentest.com", + "type": "LOC", + "ttl": 300, + "rdata": [ + "42 21 28.760 N 71 0 51.620 W -44m 2000m 0m 0m" + ] + } + }, + { + "index": 285, + "value": { + "name": "decoy.akamaigoldentest.com", + "type": "A", + "ttl": 300, + "rdata": [ + "1.1.1.1" + ] + } + }, + { + "index": 286, + "value": { + "name": "decoy.akamaigoldentest.com", + "type": "A", + "ttl": 300, + "rdata": [ + "2.2.2.2" + ] + } + }, + { + "index": 287, + "value": { + "name": "decoy.akamaigoldentest.com", + "type": "A", + "ttl": 300, + "rdata": [ + "3.3.3.3" + ] + } + }, + { + "index": 288, + "value": { + "name": "dyndns-city1.akamaigoldentest.com", + "type": "A", + "ttl": 300, + "rdata": [ + "91.42.1.1" + ] + } + }, + { + "index": 289, + "value": { + "name": "dyndns-city1.akamaigoldentest.com", + "type": "AAAA", + "ttl": 300, + "rdata": [ + "2003:dd:d7ff:0:0:0:fe71:ce77" + ] + } + }, + { + "index": 290, + "value": { + "name": "dyndns-city2.akamaigoldentest.com", + "type": "A", + "ttl": 300, + "rdata": [ + "91.42.1.2" + ] + } + }, + { + "index": 291, + "value": { + "name": "dyndns-city2.akamaigoldentest.com", + "type": "AAAA", + "ttl": 300, + "rdata": [ + "2003:dd:d7ff:0:0:0:fe71:ce78" + ] + } + }, + { + "index": 292, + "value": { + "name": "final.akamaigoldentest.com", + "type": "TXT", + "ttl": 300, + "rdata": [ + "\"TestDNSProviders was successful!\"" + ] + } + }, + { + "index": 293, + "value": { + "name": "foo.akamaigoldentest.com", + "type": "A", + "ttl": 300, + "rdata": [ + "1.1.1.1", + "11.11.11.11" + ] + } + }, + { + "index": 294, + "value": { + "name": "foo.akamaigoldentest.com", + "type": "A", + "ttl": 300, + "rdata": [ + "1.1.1.1", + "12.12.12.12" + ] + } + }, + { + "index": 295, + "value": { + "name": "foo.akamaigoldentest.com", + "type": "A", + "ttl": 300, + "rdata": [ + "1.1.1.1", + "13.13.13.13" + ] + } + }, + { + "index": 296, + "value": { + "name": "foo.akamaigoldentest.com", + "type": "A", + "ttl": 300, + "rdata": [ + "1.1.1.1", + "14.14.14.14" + ] + } + }, + { + "index": 297, + "value": { + "name": "foo.akamaigoldentest.com", + "type": "A", + "ttl": 300, + "rdata": [ + "1.1.1.1", + "9.9.9.9" + ] + } + }, + { + "index": 298, + "value": { + "name": "foo.akamaigoldentest.com", + "type": "A", + "ttl": 300, + "rdata": [ + "1.2.3.4", + "2.3.4.5" + ] + } + }, + { + "index": 299, + "value": { + "name": "foo.akamaigoldentest.com", + "type": "A", + "ttl": 300, + "rdata": [ + "1.2.3.4", + "3.4.5.6" + ] + } + }, + { + "index": 300, + "value": { + "name": "foo.akamaigoldentest.com", + "type": "A", + "ttl": 300, + "rdata": [ + "1.2.3.4" + ] + } + }, + { + "index": 301, + "value": { + "name": "foo.akamaigoldentest.com", + "type": "A", + "ttl": 300, + "rdata": [ + "2.3.4.5", + "3.4.5.6" + ] + } + }, + { + "index": 302, + "value": { + "name": "foo.akamaigoldentest.com", + "type": "A", + "ttl": 300, + "rdata": [ + "2.3.4.5", + "8.8.8.8" + ] + } + }, + { + "index": 303, + "value": { + "name": "foo.akamaigoldentest.com", + "type": "A", + "ttl": 300, + "rdata": [ + "2.3.4.5" + ] + } + }, + { + "index": 304, + "value": { + "name": "foo.akamaigoldentest.com", + "type": "A", + "ttl": 300, + "rdata": [ + "4.5.6.7" + ] + } + }, + { + "index": 305, + "value": { + "name": "foo.akamaigoldentest.com", + "type": "AAAA", + "ttl": 300, + "rdata": [ + "2003:dd:d7ff:0:0:0:fe71:aaaa" + ] + } + }, + { + "index": 306, + "value": { + "name": "foo.akamaigoldentest.com", + "type": "CNAME", + "ttl": 300, + "rdata": [ + "akamaigoldentest.com." + ] + } + }, + { + "index": 307, + "value": { + "name": "foo.akamaigoldentest.com", + "type": "CNAME", + "ttl": 300, + "rdata": [ + "google.com." + ] + } + }, + { + "index": 308, + "value": { + "name": "foo.akamaigoldentest.com", + "type": "CNAME", + "ttl": 300, + "rdata": [ + "google2.com." + ] + } + }, + { + "index": 309, + "value": { + "name": "foo.akamaigoldentest.com", + "type": "CNAME", + "ttl": 300, + "rdata": [ + "redact1.acm-validations.aws." + ] + } + }, + { + "index": 310, + "value": { + "name": "foo.akamaigoldentest.com", + "type": "MX", + "ttl": 300, + "rdata": [ + "10 aspmx.l.google.com.", + "20 alt1.aspmx.l.google.com." + ] + } + }, + { + "index": 311, + "value": { + "name": "foo.akamaigoldentest.com", + "type": "MX", + "ttl": 300, + "rdata": [ + "10 foo.akamaigoldentest.com.", + "20 bar.akamaigoldentest.com." + ] + } + }, + { + "index": 312, + "value": { + "name": "foo.akamaigoldentest.com", + "type": "MX", + "ttl": 300, + "rdata": [ + "5 mx.google.com." + ] + } + }, + { + "index": 313, + "value": { + "name": "foo.akamaigoldentest.com", + "type": "MX", + "ttl": 300, + "rdata": [ + "8 akamaigoldentest.com." + ] + } + }, + { + "index": 314, + "value": { + "name": "foo.akamaigoldentest.com", + "type": "NS", + "ttl": 300, + "rdata": [ + "akamaigoldentest.com." + ] + } + }, + { + "index": 315, + "value": { + "name": "foo.akamaigoldentest.com", + "type": "TXT", + "ttl": 300, + "rdata": [ + "\"simple\"" + ] + } + }, + { + "index": 316, + "value": { + "name": "foo.akamaigoldentest.com", + "type": "TXT", + "ttl": 300, + "rdata": [ + "\"v=spf1 ip4:99.99.99.99 -all\"" + ] + } + }, + { + "index": 317, + "value": { + "name": "foo.bat.akamaigoldentest.com", + "type": "A", + "ttl": 300, + "rdata": [ + "1.2.3.4", + "2.3.4.5" + ] + } + }, + { + "index": 318, + "value": { + "name": "foo.bat.akamaigoldentest.com", + "type": "TXT", + "ttl": 300, + "rdata": [ + "\"simple\"" + ] + } + }, + { + "index": 319, + "value": { + "name": "foo0.akamaigoldentest.com", + "type": "TXT", + "ttl": 300, + "rdata": [ + "\"\"" + ] + } + }, + { + "index": 320, + "value": { + "name": "foo254.akamaigoldentest.com", + "type": "TXT", + "ttl": 300, + "rdata": [ + "\"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\"" + ] + } + }, + { + "index": 321, + "value": { + "name": "foo255.akamaigoldentest.com", + "type": "TXT", + "ttl": 300, + "rdata": [ + "\"BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB\"" + ] + } + }, + { + "index": 322, + "value": { + "name": "foo256.akamaigoldentest.com", + "type": "TXT", + "ttl": 300, + "rdata": [ + "\"CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC\" \"C\"" + ] + } + }, + { + "index": 323, + "value": { + "name": "foo509.akamaigoldentest.com", + "type": "TXT", + "ttl": 300, + "rdata": [ + "\"DDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDD\" \"DDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDD\"" + ] + } + }, + { + "index": 324, + "value": { + "name": "foo510.akamaigoldentest.com", + "type": "TXT", + "ttl": 300, + "rdata": [ + "\"EEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE\" \"EEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE\"" + ] + } + }, + { + "index": 325, + "value": { + "name": "foo511.akamaigoldentest.com", + "type": "TXT", + "ttl": 300, + "rdata": [ + "\"FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF\" \"FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF\" \"F\"" + ] + } + }, + { + "index": 326, + "value": { + "name": "foo764.akamaigoldentest.com", + "type": "TXT", + "ttl": 300, + "rdata": [ + "\"GGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGG\" \"GGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGG\" \"GGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGG\"" + ] + } + }, + { + "index": 327, + "value": { + "name": "foo765.akamaigoldentest.com", + "type": "TXT", + "ttl": 300, + "rdata": [ + "\"HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH\" \"HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH\" \"HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH\"" + ] + } + }, + { + "index": 328, + "value": { + "name": "foo766.akamaigoldentest.com", + "type": "TXT", + "ttl": 300, + "rdata": [ + "\"JJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJ\" \"JJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJ\" \"JJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJ\" \"J\"" + ] + } + }, + { + "index": 329, + "value": { + "name": "foobt.akamaigoldentest.com", + "type": "TXT", + "ttl": 300, + "rdata": [ + "\"blah`blah\"" + ] + } + }, + { + "index": 330, + "value": { + "name": "foosc1.akamaigoldentest.com", + "type": "TXT", + "ttl": 300, + "rdata": [ + "\"semi;colon\"" + ] + } + }, + { + "index": 331, + "value": { + "name": "foosc2.akamaigoldentest.com", + "type": "TXT", + "ttl": 300, + "rdata": [ + "\"wssemi ; colon\"" + ] + } + }, + { + "index": 332, + "value": { + "name": "foosp.akamaigoldentest.com", + "type": "TXT", + "ttl": 300, + "rdata": [ + "\"with spaces\"" + ] + } + }, + { + "index": 333, + "value": { + "name": "foosq.akamaigoldentest.com", + "type": "TXT", + "ttl": 300, + "rdata": [ + "\"quo'te\"" + ] + } + }, + { + "index": 334, + "value": { + "name": "foows1.akamaigoldentest.com", + "type": "TXT", + "ttl": 300, + "rdata": [ + "\"trailingws \"" + ] + } + }, + { + "index": 335, + "value": { + "name": "mail.akamaigoldentest.com", + "type": "CNAME", + "ttl": 300, + "rdata": [ + "ghs.googlehosted.com." + ] + } + }, + { + "index": 336, + "value": { + "name": "mail.bat.akamaigoldentest.com", + "type": "CNAME", + "ttl": 300, + "rdata": [ + "ghs.googlehosted.com." + ] + } + }, + { + "index": 337, + "value": { + "name": "nmx.akamaigoldentest.com", + "type": "A", + "ttl": 300, + "rdata": [ + "1.2.3.3" + ] + } + }, + { + "index": 338, + "value": { + "name": "nmx.akamaigoldentest.com", + "type": "MX", + "ttl": 300, + "rdata": [ + "0 ." + ] + } + }, + { + "index": 339, + "value": { + "name": "nmx.akamaigoldentest.com", + "type": "MX", + "ttl": 300, + "rdata": [ + "3 nmx.akamaigoldentest.com.", + "9 www.akamaigoldentest.com." + ] + } + }, + { + "index": 340, + "value": { + "name": "pager101-rec0000.akamaigoldentest.com", + "type": "A", + "ttl": 300, + "rdata": [ + "1.2.3.4" + ] + } + }, + { + "index": 341, + "value": { + "name": "pager101-rec0001.akamaigoldentest.com", + "type": "A", + "ttl": 300, + "rdata": [ + "1.2.3.4" + ] + } + }, + { + "index": 342, + "value": { + "name": "pager101-rec0002.akamaigoldentest.com", + "type": "A", + "ttl": 300, + "rdata": [ + "1.2.3.4" + ] + } + }, + { + "index": 343, + "value": { + "name": "pager101-rec0003.akamaigoldentest.com", + "type": "A", + "ttl": 300, + "rdata": [ + "1.2.3.4" + ] + } + }, + { + "index": 344, + "value": { + "name": "pager101-rec0004.akamaigoldentest.com", + "type": "A", + "ttl": 300, + "rdata": [ + "1.2.3.4" + ] + } + }, + { + "index": 345, + "value": { + "name": "pager101-rec0005.akamaigoldentest.com", + "type": "A", + "ttl": 300, + "rdata": [ + "1.2.3.4" + ] + } + }, + { + "index": 346, + "value": { + "name": "pager101-rec0006.akamaigoldentest.com", + "type": "A", + "ttl": 300, + "rdata": [ + "1.2.3.4" + ] + } + }, + { + "index": 347, + "value": { + "name": "pager101-rec0007.akamaigoldentest.com", + "type": "A", + "ttl": 300, + "rdata": [ + "1.2.3.4" + ] + } + }, + { + "index": 348, + "value": { + "name": "pager101-rec0008.akamaigoldentest.com", + "type": "A", + "ttl": 300, + "rdata": [ + "1.2.3.4" + ] + } + }, + { + "index": 349, + "value": { + "name": "pager101-rec0009.akamaigoldentest.com", + "type": "A", + "ttl": 300, + "rdata": [ + "1.2.3.4" + ] + } + }, + { + "index": 350, + "value": { + "name": "pager101-rec0010.akamaigoldentest.com", + "type": "A", + "ttl": 300, + "rdata": [ + "1.2.3.4" + ] + } + }, + { + "index": 351, + "value": { + "name": "pager101-rec0011.akamaigoldentest.com", + "type": "A", + "ttl": 300, + "rdata": [ + "1.2.3.4" + ] + } + }, + { + "index": 352, + "value": { + "name": "pager101-rec0012.akamaigoldentest.com", + "type": "A", + "ttl": 300, + "rdata": [ + "1.2.3.4" + ] + } + }, + { + "index": 353, + "value": { + "name": "pager101-rec0013.akamaigoldentest.com", + "type": "A", + "ttl": 300, + "rdata": [ + "1.2.3.4" + ] + } + }, + { + "index": 354, + "value": { + "name": "pager101-rec0014.akamaigoldentest.com", + "type": "A", + "ttl": 300, + "rdata": [ + "1.2.3.4" + ] + } + }, + { + "index": 355, + "value": { + "name": "pager101-rec0015.akamaigoldentest.com", + "type": "A", + "ttl": 300, + "rdata": [ + "1.2.3.4" + ] + } + }, + { + "index": 356, + "value": { + "name": "pager101-rec0016.akamaigoldentest.com", + "type": "A", + "ttl": 300, + "rdata": [ + "1.2.3.4" + ] + } + }, + { + "index": 357, + "value": { + "name": "pager101-rec0017.akamaigoldentest.com", + "type": "A", + "ttl": 300, + "rdata": [ + "1.2.3.4" + ] + } + }, + { + "index": 358, + "value": { + "name": "pager101-rec0018.akamaigoldentest.com", + "type": "A", + "ttl": 300, + "rdata": [ + "1.2.3.4" + ] + } + }, + { + "index": 359, + "value": { + "name": "pager101-rec0019.akamaigoldentest.com", + "type": "A", + "ttl": 300, + "rdata": [ + "1.2.3.4" + ] + } + }, + { + "index": 360, + "value": { + "name": "pager101-rec0020.akamaigoldentest.com", + "type": "A", + "ttl": 300, + "rdata": [ + "1.2.3.4" + ] + } + }, + { + "index": 361, + "value": { + "name": "pager101-rec0021.akamaigoldentest.com", + "type": "A", + "ttl": 300, + "rdata": [ + "1.2.3.4" + ] + } + }, + { + "index": 362, + "value": { + "name": "pager101-rec0022.akamaigoldentest.com", + "type": "A", + "ttl": 300, + "rdata": [ + "1.2.3.4" + ] + } + }, + { + "index": 363, + "value": { + "name": "pager101-rec0023.akamaigoldentest.com", + "type": "A", + "ttl": 300, + "rdata": [ + "1.2.3.4" + ] + } + }, + { + "index": 364, + "value": { + "name": "pager101-rec0024.akamaigoldentest.com", + "type": "A", + "ttl": 300, + "rdata": [ + "1.2.3.4" + ] + } + }, + { + "index": 365, + "value": { + "name": "pager101-rec0025.akamaigoldentest.com", + "type": "A", + "ttl": 300, + "rdata": [ + "1.2.3.4" + ] + } + }, + { + "index": 366, + "value": { + "name": "pager101-rec0026.akamaigoldentest.com", + "type": "A", + "ttl": 300, + "rdata": [ + "1.2.3.4" + ] + } + }, + { + "index": 367, + "value": { + "name": "pager101-rec0027.akamaigoldentest.com", + "type": "A", + "ttl": 300, + "rdata": [ + "1.2.3.4" + ] + } + }, + { + "index": 368, + "value": { + "name": "pager101-rec0028.akamaigoldentest.com", + "type": "A", + "ttl": 300, + "rdata": [ + "1.2.3.4" + ] + } + }, + { + "index": 369, + "value": { + "name": "pager101-rec0029.akamaigoldentest.com", + "type": "A", + "ttl": 300, + "rdata": [ + "1.2.3.4" + ] + } + }, + { + "index": 370, + "value": { + "name": "pager101-rec0030.akamaigoldentest.com", + "type": "A", + "ttl": 300, + "rdata": [ + "1.2.3.4" + ] + } + }, + { + "index": 371, + "value": { + "name": "pager101-rec0031.akamaigoldentest.com", + "type": "A", + "ttl": 300, + "rdata": [ + "1.2.3.4" + ] + } + }, + { + "index": 372, + "value": { + "name": "pager101-rec0032.akamaigoldentest.com", + "type": "A", + "ttl": 300, + "rdata": [ + "1.2.3.4" + ] + } + }, + { + "index": 373, + "value": { + "name": "pager101-rec0033.akamaigoldentest.com", + "type": "A", + "ttl": 300, + "rdata": [ + "1.2.3.4" + ] + } + }, + { + "index": 374, + "value": { + "name": "pager101-rec0034.akamaigoldentest.com", + "type": "A", + "ttl": 300, + "rdata": [ + "1.2.3.4" + ] + } + }, + { + "index": 375, + "value": { + "name": "pager101-rec0035.akamaigoldentest.com", + "type": "A", + "ttl": 300, + "rdata": [ + "1.2.3.4" + ] + } + }, + { + "index": 376, + "value": { + "name": "pager101-rec0036.akamaigoldentest.com", + "type": "A", + "ttl": 300, + "rdata": [ + "1.2.3.4" + ] + } + }, + { + "index": 377, + "value": { + "name": "pager101-rec0037.akamaigoldentest.com", + "type": "A", + "ttl": 300, + "rdata": [ + "1.2.3.4" + ] + } + }, + { + "index": 378, + "value": { + "name": "pager101-rec0038.akamaigoldentest.com", + "type": "A", + "ttl": 300, + "rdata": [ + "1.2.3.4" + ] + } + }, + { + "index": 379, + "value": { + "name": "pager101-rec0039.akamaigoldentest.com", + "type": "A", + "ttl": 300, + "rdata": [ + "1.2.3.4" + ] + } + }, + { + "index": 380, + "value": { + "name": "pager101-rec0040.akamaigoldentest.com", + "type": "A", + "ttl": 300, + "rdata": [ + "1.2.3.4" + ] + } + }, + { + "index": 381, + "value": { + "name": "pager101-rec0041.akamaigoldentest.com", + "type": "A", + "ttl": 300, + "rdata": [ + "1.2.3.4" + ] + } + }, + { + "index": 382, + "value": { + "name": "pager101-rec0042.akamaigoldentest.com", + "type": "A", + "ttl": 300, + "rdata": [ + "1.2.3.4" + ] + } + }, + { + "index": 383, + "value": { + "name": "pager101-rec0043.akamaigoldentest.com", + "type": "A", + "ttl": 300, + "rdata": [ + "1.2.3.4" + ] + } + }, + { + "index": 384, + "value": { + "name": "pager101-rec0044.akamaigoldentest.com", + "type": "A", + "ttl": 300, + "rdata": [ + "1.2.3.4" + ] + } + }, + { + "index": 385, + "value": { + "name": "pager101-rec0045.akamaigoldentest.com", + "type": "A", + "ttl": 300, + "rdata": [ + "1.2.3.4" + ] + } + }, + { + "index": 386, + "value": { + "name": "pager101-rec0046.akamaigoldentest.com", + "type": "A", + "ttl": 300, + "rdata": [ + "1.2.3.4" + ] + } + }, + { + "index": 387, + "value": { + "name": "pager101-rec0047.akamaigoldentest.com", + "type": "A", + "ttl": 300, + "rdata": [ + "1.2.3.4" + ] + } + }, + { + "index": 388, + "value": { + "name": "pager101-rec0048.akamaigoldentest.com", + "type": "A", + "ttl": 300, + "rdata": [ + "1.2.3.4" + ] + } + }, + { + "index": 389, + "value": { + "name": "pager101-rec0049.akamaigoldentest.com", + "type": "A", + "ttl": 300, + "rdata": [ + "1.2.3.4" + ] + } + }, + { + "index": 390, + "value": { + "name": "pager101-rec0050.akamaigoldentest.com", + "type": "A", + "ttl": 300, + "rdata": [ + "1.2.3.4" + ] + } + }, + { + "index": 391, + "value": { + "name": "pager101-rec0051.akamaigoldentest.com", + "type": "A", + "ttl": 300, + "rdata": [ + "1.2.3.4" + ] + } + }, + { + "index": 392, + "value": { + "name": "pager101-rec0052.akamaigoldentest.com", + "type": "A", + "ttl": 300, + "rdata": [ + "1.2.3.4" + ] + } + }, + { + "index": 393, + "value": { + "name": "pager101-rec0053.akamaigoldentest.com", + "type": "A", + "ttl": 300, + "rdata": [ + "1.2.3.4" + ] + } + }, + { + "index": 394, + "value": { + "name": "pager101-rec0054.akamaigoldentest.com", + "type": "A", + "ttl": 300, + "rdata": [ + "1.2.3.4" + ] + } + }, + { + "index": 395, + "value": { + "name": "pager101-rec0055.akamaigoldentest.com", + "type": "A", + "ttl": 300, + "rdata": [ + "1.2.3.4" + ] + } + }, + { + "index": 396, + "value": { + "name": "pager101-rec0056.akamaigoldentest.com", + "type": "A", + "ttl": 300, + "rdata": [ + "1.2.3.4" + ] + } + }, + { + "index": 397, + "value": { + "name": "pager101-rec0057.akamaigoldentest.com", + "type": "A", + "ttl": 300, + "rdata": [ + "1.2.3.4" + ] + } + }, + { + "index": 398, + "value": { + "name": "pager101-rec0058.akamaigoldentest.com", + "type": "A", + "ttl": 300, + "rdata": [ + "1.2.3.4" + ] + } + }, + { + "index": 399, + "value": { + "name": "pager101-rec0059.akamaigoldentest.com", + "type": "A", + "ttl": 300, + "rdata": [ + "1.2.3.4" + ] + } + }, + { + "index": 400, + "value": { + "name": "pager101-rec0060.akamaigoldentest.com", + "type": "A", + "ttl": 300, + "rdata": [ + "1.2.3.4" + ] + } + }, + { + "index": 401, + "value": { + "name": "pager101-rec0061.akamaigoldentest.com", + "type": "A", + "ttl": 300, + "rdata": [ + "1.2.3.4" + ] + } + }, + { + "index": 402, + "value": { + "name": "pager101-rec0062.akamaigoldentest.com", + "type": "A", + "ttl": 300, + "rdata": [ + "1.2.3.4" + ] + } + }, + { + "index": 403, + "value": { + "name": "pager101-rec0063.akamaigoldentest.com", + "type": "A", + "ttl": 300, + "rdata": [ + "1.2.3.4" + ] + } + }, + { + "index": 404, + "value": { + "name": "pager101-rec0064.akamaigoldentest.com", + "type": "A", + "ttl": 300, + "rdata": [ + "1.2.3.4" + ] + } + }, + { + "index": 405, + "value": { + "name": "pager101-rec0065.akamaigoldentest.com", + "type": "A", + "ttl": 300, + "rdata": [ + "1.2.3.4" + ] + } + }, + { + "index": 406, + "value": { + "name": "pager101-rec0066.akamaigoldentest.com", + "type": "A", + "ttl": 300, + "rdata": [ + "1.2.3.4" + ] + } + }, + { + "index": 407, + "value": { + "name": "pager101-rec0067.akamaigoldentest.com", + "type": "A", + "ttl": 300, + "rdata": [ + "1.2.3.4" + ] + } + }, + { + "index": 408, + "value": { + "name": "pager101-rec0068.akamaigoldentest.com", + "type": "A", + "ttl": 300, + "rdata": [ + "1.2.3.4" + ] + } + }, + { + "index": 409, + "value": { + "name": "pager101-rec0069.akamaigoldentest.com", + "type": "A", + "ttl": 300, + "rdata": [ + "1.2.3.4" + ] + } + }, + { + "index": 410, + "value": { + "name": "pager101-rec0070.akamaigoldentest.com", + "type": "A", + "ttl": 300, + "rdata": [ + "1.2.3.4" + ] + } + }, + { + "index": 411, + "value": { + "name": "pager101-rec0071.akamaigoldentest.com", + "type": "A", + "ttl": 300, + "rdata": [ + "1.2.3.4" + ] + } + }, + { + "index": 412, + "value": { + "name": "pager101-rec0072.akamaigoldentest.com", + "type": "A", + "ttl": 300, + "rdata": [ + "1.2.3.4" + ] + } + }, + { + "index": 413, + "value": { + "name": "pager101-rec0073.akamaigoldentest.com", + "type": "A", + "ttl": 300, + "rdata": [ + "1.2.3.4" + ] + } + }, + { + "index": 414, + "value": { + "name": "pager101-rec0074.akamaigoldentest.com", + "type": "A", + "ttl": 300, + "rdata": [ + "1.2.3.4" + ] + } + }, + { + "index": 415, + "value": { + "name": "pager101-rec0075.akamaigoldentest.com", + "type": "A", + "ttl": 300, + "rdata": [ + "1.2.3.4" + ] + } + }, + { + "index": 416, + "value": { + "name": "pager101-rec0076.akamaigoldentest.com", + "type": "A", + "ttl": 300, + "rdata": [ + "1.2.3.4" + ] + } + }, + { + "index": 417, + "value": { + "name": "pager101-rec0077.akamaigoldentest.com", + "type": "A", + "ttl": 300, + "rdata": [ + "1.2.3.4" + ] + } + }, + { + "index": 418, + "value": { + "name": "pager101-rec0078.akamaigoldentest.com", + "type": "A", + "ttl": 300, + "rdata": [ + "1.2.3.4" + ] + } + }, + { + "index": 419, + "value": { + "name": "pager101-rec0079.akamaigoldentest.com", + "type": "A", + "ttl": 300, + "rdata": [ + "1.2.3.4" + ] + } + }, + { + "index": 420, + "value": { + "name": "pager101-rec0080.akamaigoldentest.com", + "type": "A", + "ttl": 300, + "rdata": [ + "1.2.3.4" + ] + } + }, + { + "index": 421, + "value": { + "name": "pager101-rec0081.akamaigoldentest.com", + "type": "A", + "ttl": 300, + "rdata": [ + "1.2.3.4" + ] + } + }, + { + "index": 422, + "value": { + "name": "pager101-rec0082.akamaigoldentest.com", + "type": "A", + "ttl": 300, + "rdata": [ + "1.2.3.4" + ] + } + }, + { + "index": 423, + "value": { + "name": "pager101-rec0083.akamaigoldentest.com", + "type": "A", + "ttl": 300, + "rdata": [ + "1.2.3.4" + ] + } + }, + { + "index": 424, + "value": { + "name": "pager101-rec0084.akamaigoldentest.com", + "type": "A", + "ttl": 300, + "rdata": [ + "1.2.3.4" + ] + } + }, + { + "index": 425, + "value": { + "name": "pager101-rec0085.akamaigoldentest.com", + "type": "A", + "ttl": 300, + "rdata": [ + "1.2.3.4" + ] + } + }, + { + "index": 426, + "value": { + "name": "pager101-rec0086.akamaigoldentest.com", + "type": "A", + "ttl": 300, + "rdata": [ + "1.2.3.4" + ] + } + }, + { + "index": 427, + "value": { + "name": "pager101-rec0087.akamaigoldentest.com", + "type": "A", + "ttl": 300, + "rdata": [ + "1.2.3.4" + ] + } + }, + { + "index": 428, + "value": { + "name": "pager101-rec0088.akamaigoldentest.com", + "type": "A", + "ttl": 300, + "rdata": [ + "1.2.3.4" + ] + } + }, + { + "index": 429, + "value": { + "name": "pager101-rec0089.akamaigoldentest.com", + "type": "A", + "ttl": 300, + "rdata": [ + "1.2.3.4" + ] + } + }, + { + "index": 430, + "value": { + "name": "pager101-rec0090.akamaigoldentest.com", + "type": "A", + "ttl": 300, + "rdata": [ + "1.2.3.4" + ] + } + }, + { + "index": 431, + "value": { + "name": "pager101-rec0091.akamaigoldentest.com", + "type": "A", + "ttl": 300, + "rdata": [ + "1.2.3.4" + ] + } + }, + { + "index": 432, + "value": { + "name": "pager101-rec0092.akamaigoldentest.com", + "type": "A", + "ttl": 300, + "rdata": [ + "1.2.3.4" + ] + } + }, + { + "index": 433, + "value": { + "name": "pager101-rec0093.akamaigoldentest.com", + "type": "A", + "ttl": 300, + "rdata": [ + "1.2.3.4" + ] + } + }, + { + "index": 434, + "value": { + "name": "pager101-rec0094.akamaigoldentest.com", + "type": "A", + "ttl": 300, + "rdata": [ + "1.2.3.4" + ] + } + }, + { + "index": 435, + "value": { + "name": "pager101-rec0095.akamaigoldentest.com", + "type": "A", + "ttl": 300, + "rdata": [ + "1.2.3.4" + ] + } + }, + { + "index": 436, + "value": { + "name": "pager101-rec0096.akamaigoldentest.com", + "type": "A", + "ttl": 300, + "rdata": [ + "1.2.3.4" + ] + } + }, + { + "index": 437, + "value": { + "name": "pager101-rec0097.akamaigoldentest.com", + "type": "A", + "ttl": 300, + "rdata": [ + "1.2.3.4" + ] + } + }, + { + "index": 438, + "value": { + "name": "pager101-rec0098.akamaigoldentest.com", + "type": "A", + "ttl": 300, + "rdata": [ + "1.2.3.4" + ] + } + }, + { + "index": 439, + "value": { + "name": "pager101-rec0099.akamaigoldentest.com", + "type": "A", + "ttl": 300, + "rdata": [ + "1.2.3.4" + ] + } + }, + { + "index": 440, + "value": { + "name": "pager101-rec0100.akamaigoldentest.com", + "type": "A", + "ttl": 300, + "rdata": [ + "1.2.3.4" + ] + } + }, + { + "index": 441, + "value": { + "name": "test.akamaigoldentest.com", + "type": "CNAME", + "ttl": 300, + "rdata": [ + "foo.com." + ] + } + }, + { + "index": 442, + "value": { + "name": "test.akamaigoldentest.com", + "type": "CNAME", + "ttl": 300, + "rdata": [ + "foo2.com." + ] + } + }, + { + "index": 443, + "value": { + "name": "test.akamaigoldentest.com", + "type": "NAPTR", + "ttl": 300, + "rdata": [ + "100 10 \"U\" \"E2U+sip\" \"!^.*$!sip:customer-service@example.com!\" .", + "102 10 \"U\" \"E2U+email\" \"!^.*$!mailto:information@example.com!\" ." + ] + } + }, + { + "index": 444, + "value": { + "name": "test.akamaigoldentest.com", + "type": "NAPTR", + "ttl": 300, + "rdata": [ + "100 10 \"U\" \"E2U+sip\" \"!^.*$!sip:customer-service@example.com!\" ." + ] + } + }, + { + "index": 445, + "value": { + "name": "test.akamaigoldentest.com", + "type": "NAPTR", + "ttl": 300, + "rdata": [ + "103 10 \"U\" \"E2U+email\" \"!^.*$!mailto:information@example.com!\" ." + ] + } + }, + { + "index": 446, + "value": { + "name": "test.akamaigoldentest.com", + "type": "NAPTR", + "ttl": 300, + "rdata": [ + "103 20 \"A\" \"E2U+email\" \"!^.*$!mailto:information@example.com!\" ." + ] + } + }, + { + "index": 447, + "value": { + "name": "test.akamaigoldentest.com", + "type": "NAPTR", + "ttl": 300, + "rdata": [ + "103 20 \"A\" \"E2U+sip\" \"!^.*$!mailto:information@example.com!\" ." + ] + } + }, + { + "index": 448, + "value": { + "name": "test.akamaigoldentest.com", + "type": "NAPTR", + "ttl": 300, + "rdata": [ + "103 20 \"A\" \"E2U+sip\" \"!^.*$!sip:customer-service@example.com!\" ." + ] + } + }, + { + "index": 449, + "value": { + "name": "test.akamaigoldentest.com", + "type": "NAPTR", + "ttl": 300, + "rdata": [ + "103 20 \"A\" \"E2U+sip\" \"\" example.foo.com." + ] + } + }, + { + "index": 450, + "value": { + "name": "test.akamaigoldentest.com", + "type": "NAPTR", + "ttl": 300, + "rdata": [ + "103 20 \"A\" \"E2U+sip\" \"\" example2.foo.com." + ] + } + }, + { + "index": 451, + "value": { + "name": "test.akamaigoldentest.com", + "type": "NAPTR", + "ttl": 300, + "rdata": [ + "103 20 \"U\" \"E2U+email\" \"!^.*$!mailto:information@example.com!\" ." + ] + } + }, + { + "index": 452, + "value": { + "name": "testa.akamaigoldentest.com", + "type": "A", + "ttl": 300, + "rdata": [ + "1.1.1.1" + ] + } + }, + { + "index": 453, + "value": { + "name": "testa.akamaigoldentest.com", + "type": "A", + "ttl": 300, + "rdata": [ + "3.3.3.3" + ] + } + }, + { + "index": 454, + "value": { + "name": "testa.akamaigoldentest.com", + "type": "A", + "ttl": 333, + "rdata": [ + "1.1.1.1" + ] + } + }, + { + "index": 455, + "value": { + "name": "testa.akamaigoldentest.com", + "type": "A", + "ttl": 999, + "rdata": [ + "1.1.1.1" + ] + } + }, + { + "index": 456, + "value": { + "name": "testaaaa.akamaigoldentest.com", + "type": "AAAA", + "ttl": 300, + "rdata": [ + "2607:f8b0:4006:820:0:0:0:2006" + ] + } + }, + { + "index": 457, + "value": { + "name": "testaaaa.akamaigoldentest.com", + "type": "AAAA", + "ttl": 300, + "rdata": [ + "2607:f8b0:4006:820:0:0:0:2013" + ] + } + }, + { + "index": 458, + "value": { + "name": "testcname.akamaigoldentest.com", + "type": "CNAME", + "ttl": 300, + "rdata": [ + "foo.akamaigoldentest.com." + ] + } + }, + { + "index": 459, + "value": { + "name": "testcname.akamaigoldentest.com", + "type": "CNAME", + "ttl": 300, + "rdata": [ + "www.google.com." + ] + } + }, + { + "index": 460, + "value": { + "name": "testcname.akamaigoldentest.com", + "type": "CNAME", + "ttl": 300, + "rdata": [ + "www.yahoo.com." + ] + } + }, + { + "index": 461, + "value": { + "name": "testdefined.akamaigoldentest.com", + "type": "A", + "ttl": 300, + "rdata": [ + "2.2.2.2" + ] + } + }, + { + "index": 462, + "value": { + "name": "testdefined.akamaigoldentest.com", + "type": "A", + "ttl": 300, + "rdata": [ + "9.9.9.9" + ] + } + }, + { + "index": 463, + "value": { + "name": "testignore.akamaigoldentest.com", + "type": "A", + "ttl": 300, + "rdata": [ + "8.8.8.8" + ] + } + }, + { + "index": 464, + "value": { + "name": "testmx.akamaigoldentest.com", + "type": "MX", + "ttl": 300, + "rdata": [ + "100 foo.com." + ] + } + }, + { + "index": 465, + "value": { + "name": "testmx.akamaigoldentest.com", + "type": "MX", + "ttl": 300, + "rdata": [ + "5 bar.com." + ] + } + }, + { + "index": 466, + "value": { + "name": "testmx.akamaigoldentest.com", + "type": "MX", + "ttl": 300, + "rdata": [ + "5 foo.com.", + "100 bar.com." + ] + } + }, + { + "index": 467, + "value": { + "name": "testmx.akamaigoldentest.com", + "type": "MX", + "ttl": 300, + "rdata": [ + "5 foo.com." + ] + } + }, + { + "index": 468, + "value": { + "name": "testtxt.akamaigoldentest.com", + "type": "TXT", + "ttl": 300, + "rdata": [ + "\"changed\"" + ] + } + }, + { + "index": 469, + "value": { + "name": "testtxt.akamaigoldentest.com", + "type": "TXT", + "ttl": 300, + "rdata": [ + "\"simple\"" + ] + } + }, + { + "index": 470, + "value": { + "name": "www.akamaigoldentest.com", + "type": "A", + "ttl": 300, + "rdata": [ + "1.1.1.1", + "2.2.2.2", + "3.3.3.3" + ] + } + }, + { + "index": 471, + "value": { + "name": "www.akamaigoldentest.com", + "type": "A", + "ttl": 300, + "rdata": [ + "1.1.1.1", + "2.2.2.2" + ] + } + }, + { + "index": 472, + "value": { + "name": "www.akamaigoldentest.com", + "type": "A", + "ttl": 300, + "rdata": [ + "1.1.1.1" + ] + } + }, + { + "index": 473, + "value": { + "name": "www.akamaigoldentest.com", + "type": "A", + "ttl": 300, + "rdata": [ + "1.2.3.4", + "5.6.7.8" + ] + } + }, + { + "index": 474, + "value": { + "name": "www.akamaigoldentest.com", + "type": "A", + "ttl": 300, + "rdata": [ + "1.2.3.8" + ] + } + }, + { + "index": 475, + "value": { + "name": "www.akamaigoldentest.com", + "type": "A", + "ttl": 300, + "rdata": [ + "1.2.3.9" + ] + } + }, + { + "index": 476, + "value": { + "name": "www.akamaigoldentest.com", + "type": "A", + "ttl": 300, + "rdata": [ + "2.2.2.2", + "5.6.7.8" + ] + } + }, + { + "index": 477, + "value": { + "name": "www.akamaigoldentest.com", + "type": "A", + "ttl": 300, + "rdata": [ + "5.5.5.5" + ] + } + }, + { + "index": 478, + "value": { + "name": "www.akamaigoldentest.com", + "type": "A", + "ttl": 400, + "rdata": [ + "2.2.2.2", + "5.6.7.8" + ] + } + }, + { + "index": 479, + "value": { + "name": "www.akamaigoldentest.com", + "type": "A", + "ttl": 400, + "rdata": [ + "5.6.7.8" + ] + } + }, + { + "index": 480, + "value": { + "name": "www.akamaigoldentest.com", + "type": "A", + "ttl": 700, + "rdata": [ + "1.2.3.4", + "5.6.7.8" + ] + } + }, + { + "index": 481, + "value": { + "name": "xn--fiq228c.akamaigoldentest.com", + "type": "A", + "ttl": 300, + "rdata": [ + "1.2.3.4" + ] + } + }, + { + "index": 482, + "value": { + "name": "xn--ndaaa.akamaigoldentest.com", + "type": "A", + "ttl": 300, + "rdata": [ + "1.2.3.4" + ] + } + }, + { + "index": 483, + "value": { + "name": "xn--ndaaa.akamaigoldentest.com", + "type": "A", + "ttl": 300, + "rdata": [ + "2.2.2.2" + ] + } + }, + { + "index": 484, + "value": { + "name": "xn--o-0gab.akamaigoldentest.com", + "type": "CNAME", + "ttl": 300, + "rdata": [ + "xn--ndaaa.xn--vhquv." + ] + } + }, + { + "index": 485, + "value": { + "name": "xyz.akamaigoldentest.com", + "type": "NS", + "ttl": 300, + "rdata": [ + "ns1.foo.com.", + "ns2.foo.com." + ] + } + }, + { + "index": 486, + "value": { + "name": "xyz.akamaigoldentest.com", + "type": "NS", + "ttl": 300, + "rdata": [ + "ns2.foo.com." + ] + } + }, + { + "index": 487, + "value": { + "name": "zzz.akamaigoldentest.com", + "type": "A", + "ttl": 300, + "rdata": [ + "3.3.3.3", + "4.4.4.4" + ] + } + }, + { + "index": 488, + "value": { + "name": "zzz.akamaigoldentest.com", + "type": "AAAA", + "ttl": 300, + "rdata": [ + "2003:dd:d7ff:0:0:0:fe71:cccc" + ] + } + } +] diff --git a/providers/alidns/aliDnsProvider.go b/providers/alidns/aliDnsProvider.go index 177c3487c5..c83be2732e 100644 --- a/providers/alidns/aliDnsProvider.go +++ b/providers/alidns/aliDnsProvider.go @@ -2,14 +2,15 @@ package alidns import ( "encoding/json" + "errors" "fmt" "strings" "sync" - "github.com/DNSControl/dnscontrol/v4/models" - "github.com/DNSControl/dnscontrol/v4/pkg/diff2" - "github.com/DNSControl/dnscontrol/v4/pkg/printer" - "github.com/DNSControl/dnscontrol/v4/pkg/providers" + "github.com/DNSControl/dnscontrol/v5/models" + "github.com/DNSControl/dnscontrol/v5/pkg/diff2" + "github.com/DNSControl/dnscontrol/v5/pkg/printer" + "github.com/DNSControl/dnscontrol/v5/pkg/providers" "github.com/aliyun/alibaba-cloud-sdk-go/services/alidns" ) @@ -81,12 +82,12 @@ type domainVersionInfo struct { func newAliDNSDsp(config map[string]string, metadata json.RawMessage) (providers.DNSServiceProvider, error) { accessKeyID := config["access_key_id"] if accessKeyID == "" { - return nil, fmt.Errorf("creds.json: access_key_id must not be empty") + return nil, errors.New("creds.json: access_key_id must not be empty") } accessKeySecret := config["access_key_secret"] if accessKeySecret == "" { - return nil, fmt.Errorf("creds.json: access_key_secret must not be empty") + return nil, errors.New("creds.json: access_key_secret must not be empty") } // Region ID defaults to "cn-hangzhou". The region value does not affect @@ -136,7 +137,7 @@ func (a *aliDNSDsp) GetZoneRecords(dc *models.DomainConfig) (models.Records, err continue } - rc, err := nativeToRecord(r, domain) + rc, err := nativeToRecord(r, dc) if err != nil { return nil, err } @@ -152,7 +153,10 @@ func (a *aliDNSDsp) GetZoneRecords(dc *models.DomainConfig) (models.Records, err } for _, ns := range nameservers { - rc := nativeToRecordNS(ns, domain) + rc, err := nativeToRecordNS(ns, dc) + if err != nil { + return nil, err + } out = append(out, rc) } @@ -171,8 +175,8 @@ func deduplicateNameServerTargets(newRecs models.Records) models.Records { dedupedMap := make(map[string]bool) var deduped models.Records for _, rec := range newRecs { - if !dedupedMap[rec.GetTargetField()] { - dedupedMap[rec.GetTargetField()] = true + if !dedupedMap[rec.AsNS().Ns] { + dedupedMap[rec.AsNS().Ns] = true deduped = append(deduped, rec) } } @@ -186,7 +190,7 @@ func (a *aliDNSDsp) PrepDesiredRecords(dc *models.DomainConfig) { return } - recordsToKeep := make([]*models.RecordConfig, 0, len(dc.Records)) + recordsToKeep := make(models.Records, 0, len(dc.Records)) for _, rec := range dc.Records { // If TTL is 0 (not set), use the minimum TTL as default @@ -260,7 +264,7 @@ func (a *aliDNSDsp) GetZoneRecordsCorrections(dc *models.DomainConfig, existingR corrections = append(corrections, &models.Correction{ Msg: msgs, F: func() error { - return a.deleteRecordset(change.Old, dcn) + return a.deleteRecordset(change.Old) }, }) default: diff --git a/providers/alidns/api.go b/providers/alidns/api.go index 8328293e1e..fd9f9098c4 100644 --- a/providers/alidns/api.go +++ b/providers/alidns/api.go @@ -1,9 +1,10 @@ package alidns import ( + "errors" "fmt" - "github.com/DNSControl/dnscontrol/v4/models" + "github.com/DNSControl/dnscontrol/v5/models" "github.com/aliyun/alibaba-cloud-sdk-go/sdk/requests" "github.com/aliyun/alibaba-cloud-sdk-go/services/alidns" ) @@ -75,12 +76,12 @@ func (a *aliDNSDsp) getNameservers(domain string) ([]string, error) { return nameservers, nil } -func (a *aliDNSDsp) deleteRecordset(records []*models.RecordConfig, domainName string) error { +func (a *aliDNSDsp) deleteRecordset(records models.Records) error { for _, r := range records { req := alidns.CreateDeleteDomainRecordRequest() original, ok := r.Original.(*alidns.Record) if !ok { - return fmt.Errorf("deleteRecordset: record original is not of type *alidns.Record") + return errors.New("deleteRecordset: record original is not of type *alidns.Record") } req.RecordId = original.RecordId @@ -92,7 +93,7 @@ func (a *aliDNSDsp) deleteRecordset(records []*models.RecordConfig, domainName s return nil } -func (a *aliDNSDsp) createRecordset(records []*models.RecordConfig, domainName string) error { +func (a *aliDNSDsp) createRecordset(records models.Records, domainName string) error { for _, r := range records { req := alidns.CreateAddDomainRecordRequest() req.DomainName = domainName @@ -114,7 +115,7 @@ func (a *aliDNSDsp) createRecordset(records []*models.RecordConfig, domainName s return nil } -func (a *aliDNSDsp) updateRecordset(existing, desired []*models.RecordConfig, domainName string) error { +func (a *aliDNSDsp) updateRecordset(existing, desired models.Records, domainName string) error { // Strategy: Delete all existing records, then create all desired records. // This is the simplest and most reliable approach because: // 1. The number of records in a recordset may change @@ -122,7 +123,7 @@ func (a *aliDNSDsp) updateRecordset(existing, desired []*models.RecordConfig, do // 3. Alibaba Cloud API requires RecordId for updates, which desired records don't have // Delete all existing records first - if err := a.deleteRecordset(existing, domainName); err != nil { + if err := a.deleteRecordset(existing); err != nil { return err } diff --git a/providers/alidns/auditrecords.go b/providers/alidns/auditrecords.go index e47b0c401f..130b51ea40 100644 --- a/providers/alidns/auditrecords.go +++ b/providers/alidns/auditrecords.go @@ -4,8 +4,9 @@ import ( "errors" "unicode" - "github.com/DNSControl/dnscontrol/v4/models" - "github.com/DNSControl/dnscontrol/v4/pkg/rejectif" + dnsv2 "codeberg.org/miekg/dns" + "github.com/DNSControl/dnscontrol/v5/models" + "github.com/DNSControl/dnscontrol/v5/pkg/rejectif" "golang.org/x/net/idna" ) @@ -26,8 +27,15 @@ func isValidAliDNSString(s string) bool { } // labelConstraint detects labels that contain non-ASCII characters except Chinese characters. +// Punycode-encoded labels (xn--...) are decoded to Unicode before checking so that +// non-Chinese IDN labels such as xn--ndaaa (ööö) are correctly rejected. func labelConstraint(rc *models.RecordConfig) error { - if !isValidAliDNSString(rc.GetLabel()) { + label := rc.GetLabel() + decoded, err := idna.ToUnicode(label) + if err == nil { + label = decoded + } + if !isValidAliDNSString(label) { return errors.New("label contains non-ASCII characters (only Chinese is allowed)") } return nil @@ -36,9 +44,21 @@ func labelConstraint(rc *models.RecordConfig) error { // targetConstraint detects target values that contain non-ASCII characters except Chinese characters. // This applies to CNAME, MX, NS, SRV targets. func targetConstraint(rc *models.RecordConfig) error { - target, err := idna.ToUnicode(rc.GetTargetField()) - if err != nil { - target = rc.GetTargetField() + var target string + switch rc.TypeNum { + case dnsv2.TypeCNAME: + target = rc.AsCNAME().Target + case dnsv2.TypeMX: + target = rc.AsMX().Mx + case dnsv2.TypeNS: + target = rc.AsNS().Ns + case dnsv2.TypeSRV: + target = rc.AsSRV().Target + default: + target = rc.GetRDATA().String() + } + if t, err := idna.ToUnicode(target); err == nil { + target = t } if !isValidAliDNSString(target) { return errors.New("target contains non-ASCII characters (only Chinese is allowed)") @@ -49,7 +69,7 @@ func targetConstraint(rc *models.RecordConfig) error { // AuditRecords returns a list of errors corresponding to the records // that aren't supported by this provider. If all records are // supported, an empty list is returned. -func AuditRecords(records []*models.RecordConfig) []error { +func AuditRecords(records models.Records) []error { // Note: We can't get domain version info here because AuditRecords // is called without provider context. TTL validation will be done // at the provider level in GetZoneRecordsCorrections. diff --git a/providers/alidns/auditrecords_test.go b/providers/alidns/auditrecords_test.go index a65363b780..545c95caec 100644 --- a/providers/alidns/auditrecords_test.go +++ b/providers/alidns/auditrecords_test.go @@ -3,9 +3,54 @@ package alidns import ( "testing" - "github.com/DNSControl/dnscontrol/v4/models" + dnsv2 "codeberg.org/miekg/dns" + "github.com/DNSControl/dnscontrol/v5/models" ) +func TestLabelConstraint(t *testing.T) { + tests := []struct { + name string + label string + wantErr bool + }{ + { + name: "ascii label", + label: "www", + }, + { + name: "chinese idn label (punycode)", + label: "xn--55qx5d", // 公司 + }, + { + name: "non-chinese idn label (punycode)", + label: "xn--ndaaa", // ööö + wantErr: true, + }, + } + + dc := models.MustNewDomainConfig("example.com") + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + rc := dc.MustNewRecordConfig(tt.label, 0, dnsv2.TypeA, "1.2.3.4") + + err := labelConstraint(rc) + if (err != nil) != tt.wantErr { + t.Fatalf("labelConstraint() error = %v, wantErr %v", err, tt.wantErr) + } + }) + } +} + +func TestAuditRecordsRejectsNonChineseIDNLabel(t *testing.T) { + dc := models.MustNewDomainConfig("example.com") + rc := dc.MustNewRecordConfig("xn--ndaaa", 0, dnsv2.TypeA, "1.2.3.4") + + errs := AuditRecords(models.Records{rc}) + if len(errs) != 1 { + t.Fatalf("AuditRecords() returned %d errors, want 1", len(errs)) + } +} + func TestTargetConstraint(t *testing.T) { tests := []struct { name string @@ -29,9 +74,8 @@ func TestTargetConstraint(t *testing.T) { for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { - rc := &models.RecordConfig{Type: "CNAME"} - rc.SetLabel("a", "example.com") - rc.MustSetTarget(tt.target) + dc := models.MustNewDomainConfig("example.com") + rc := dc.MustNewRecordConfig("a", 0, dnsv2.TypeCNAME, tt.target) err := targetConstraint(rc) if (err != nil) != tt.wantErr { @@ -42,11 +86,10 @@ func TestTargetConstraint(t *testing.T) { } func TestAuditRecordsRejectsNonChineseIDNCNAMETarget(t *testing.T) { - rc := &models.RecordConfig{Type: "CNAME"} - rc.SetLabel("a", "example.com") - rc.MustSetTarget("xn--ndaaa.com.") + dc := models.MustNewDomainConfig("example.com") + rc := dc.MustNewRecordConfig("a", 0, dnsv2.TypeCNAME, "xn--ndaaa.com.") - errs := AuditRecords([]*models.RecordConfig{rc}) + errs := AuditRecords(models.Records{rc}) if len(errs) != 1 { t.Fatalf("AuditRecords() returned %d errors, want 1", len(errs)) } diff --git a/providers/alidns/convert.go b/providers/alidns/convert.go index 6728aa1028..49759a2d3e 100644 --- a/providers/alidns/convert.go +++ b/providers/alidns/convert.go @@ -4,23 +4,19 @@ import ( "fmt" "strings" - "github.com/DNSControl/dnscontrol/v4/models" + dnsv2 "codeberg.org/miekg/dns" + "github.com/DNSControl/dnscontrol/v5/models" "github.com/aliyun/alibaba-cloud-sdk-go/services/alidns" "golang.org/x/net/idna" ) // nativeToRecord converts an Alibaba Cloud DNS record to a RecordConfig. -func nativeToRecord(r *alidns.Record, domain string) (*models.RecordConfig, error) { - rc := &models.RecordConfig{ - TTL: uint32(r.TTL), - Original: r, - } - +func nativeToRecord(r *alidns.Record, dc *models.DomainConfig) (*models.RecordConfig, error) { label, err := idna.ToASCII(r.RR) if err != nil { return nil, fmt.Errorf("failed to convert label to ASCII: %w", err) } - rc.SetLabel(label, domain) + label = dc.LabelFromShort(label) // Normalize CNAME, MX, NS records with trailing dot to be consistent with FQDN format. value := r.Value @@ -30,11 +26,11 @@ func nativeToRecord(r *alidns.Record, domain string) (*models.RecordConfig, erro } } + ttl := uint32(r.TTL) + var rc *models.RecordConfig switch r.Type { case "MX": - if err := rc.SetTargetMX(uint16(r.Priority), value); err != nil { - return nil, fmt.Errorf("unparsable MX record received from ALIDNS: %w", err) - } + rc, err = dc.NewRecordConfig(label, ttl, dnsv2.TypeMX, r.Priority, value) case "SRV": // SRV records in Alibaba Cloud: Value contains "priority weight port target" // e.g., "1 1 5060 www.cloud-example.com." @@ -48,63 +44,52 @@ func nativeToRecord(r *alidns.Record, domain string) (*models.RecordConfig, erro if target != "" && target != "." && !strings.HasSuffix(target, ".") { target = target + "." } - // Reconstruct with normalized target and let PopulateFromString handle it + // Reconstruct with normalized target and let NewRecordConfigParse handle it. srvValue := fmt.Sprintf("%s %s %s %s", parts[0], parts[1], parts[2], target) - if err := rc.PopulateFromString(r.Type, srvValue, domain); err != nil { - return nil, fmt.Errorf("unparsable SRV record received from ALIDNS: %w", err) - } + rc, err = dc.NewRecordConfigParse(label, ttl, dnsv2.TypeSRV, srvValue) case "CAA": // Alibaba Cloud CAA format: "0 issue \"letsencrypt.org\"" - if err := rc.SetTargetCAAString(r.Value); err != nil { - return nil, fmt.Errorf("unparsable CAA record received from ALIDNS: %w", err) - } + rc, err = dc.NewRecordConfigParse(label, ttl, dnsv2.TypeCAA, r.Value) case "TXT": - if err := rc.SetTargetTXT(r.Value); err != nil { - return nil, fmt.Errorf("unparsable TXT record received from ALIDNS: %w", err) - } + rc, err = dc.NewRecordConfig(label, ttl, dnsv2.TypeTXT, r.Value) default: - rc.Type = r.Type - if err := rc.SetTarget(value); err != nil { - return nil, fmt.Errorf("unparsable record received from ALIDNS: %w", err) - } + rc, err = dc.NewRecordConfigParse(label, ttl, r.Type, value) + } + if err != nil { + return nil, fmt.Errorf("unparsable %s record received from ALIDNS: %w", r.Type, err) } + rc.Original = r return rc, nil } // recordToNativeContent converts a RecordConfig to the Value format expected by Alibaba Cloud DNS API. -func recordToNativeContent(r *models.RecordConfig) string { - switch r.Type { - case "SRV": - return fmt.Sprintf("%d %d %d %s", r.SrvPriority, r.SrvWeight, r.SrvPort, r.GetTargetField()) - case "CAA": - return fmt.Sprintf("%d %s \"%s\"", r.CaaFlag, r.CaaTag, r.GetTargetField()) - case "TXT": - return r.GetTargetTXTJoined() - default: - return r.GetTargetField() +func recordToNativeContent(rc *models.RecordConfig) string { + switch rc.TypeNum { + case dnsv2.TypeMX: + return rc.AsMX().Mx + case dnsv2.TypeSRV: + return rc.AsSRV().String() + case dnsv2.TypeCAA: + return rc.AsCAA().String() + case dnsv2.TypeTXT: + return rc.GetTargetTXTJoined() } + return rc.GetRDATA().String() } // recordToNativePriority returns the priority value for MX and SRV records. -func recordToNativePriority(r *models.RecordConfig) int64 { - switch r.Type { - case "MX": - return int64(r.MxPreference) - case "SRV": - return int64(r.SrvPriority) - default: - return 0 +func recordToNativePriority(rc *models.RecordConfig) int64 { + switch rc.TypeNum { + case dnsv2.TypeMX: + return int64(rc.AsMX().Preference) + case dnsv2.TypeSRV: + return int64(rc.AsSRV().Priority) } + return 0 } // nativeToRecordNS takes a NS record from DNS and returns a native RecordConfig struct. -func nativeToRecordNS(ns string, origin string) *models.RecordConfig { - rc := &models.RecordConfig{ - Type: "NS", - TTL: 600, - } - rc.SetLabel("@", origin) - rc.MustSetTarget(ns) - return rc +func nativeToRecordNS(ns string, dc *models.DomainConfig) (*models.RecordConfig, error) { + return dc.NewRecordConfig("@", 600, dnsv2.TypeNS, ns) } diff --git a/providers/alidns/convert_test.go b/providers/alidns/convert_test.go new file mode 100644 index 0000000000..04e2fc9061 --- /dev/null +++ b/providers/alidns/convert_test.go @@ -0,0 +1,45 @@ +package alidns + +import ( + "testing" + + "github.com/DNSControl/dnscontrol/v5/models" + alinative "github.com/aliyun/alibaba-cloud-sdk-go/services/alidns" +) + +func TestNativeToRecord(t *testing.T) { + t.Parallel() + + dc := models.MustNewDomainConfig("example.com") + tests := []struct { + name string + native *alinative.Record + wantType string + wantContent string + wantPriority int64 + }{ + {"A", &alinative.Record{RR: "www", Type: "A", Value: "192.0.2.1", TTL: 300}, "A", "192.0.2.1", 0}, + {"MX", &alinative.Record{RR: "www", Type: "MX", Value: "mail.example.net", TTL: 300, Priority: 10}, "MX", "mail.example.net.", 10}, + {"SRV", &alinative.Record{RR: "_sip._tcp", Type: "SRV", Value: "1 2 443 service.example.net", TTL: 300}, "SRV", "1 2 443 service.example.net.", 1}, + {"CAA", &alinative.Record{RR: "www", Type: "CAA", Value: `0 issue "letsencrypt.org"`, TTL: 300}, "CAA", `0 issue "letsencrypt.org"`, 0}, + {"TXT", &alinative.Record{RR: "www", Type: "TXT", Value: "hello world", TTL: 300}, "TXT", "hello world", 0}, + } + + for _, tc := range tests { + t.Run(tc.name, func(t *testing.T) { + rc, err := nativeToRecord(tc.native, dc) + if err != nil { + t.Fatalf("nativeToRecord() error = %v", err) + } + if rc.Type != tc.wantType { + t.Errorf("nativeToRecord() type = %q, want %q", rc.Type, tc.wantType) + } + if got := recordToNativeContent(rc); got != tc.wantContent { + t.Errorf("recordToNativeContent() = %q, want %q", got, tc.wantContent) + } + if got := recordToNativePriority(rc); got != tc.wantPriority { + t.Errorf("recordToNativePriority() = %d, want %d", got, tc.wantPriority) + } + }) + } +} diff --git a/providers/autodns/api.go b/providers/autodns/api.go index 246005ff7a..b813d84367 100644 --- a/providers/autodns/api.go +++ b/providers/autodns/api.go @@ -12,7 +12,7 @@ import ( "sort" "time" - "github.com/DNSControl/dnscontrol/v4/models" + "github.com/DNSControl/dnscontrol/v5/models" ) // ZoneListFilter describes a JSON list filter. @@ -120,7 +120,7 @@ func (api *autoDNSProvider) request(method string, requestPath string, data any) time.Sleep(sleepDuration) } - return nil, errors.New("Failed to fetch" + requestURL.Path + " after 4 retries") + return nil, fmt.Errorf("failed to fetch %s after 4 retries", requestURL.Path) } func (api *autoDNSProvider) findZoneSystemNameServer(domain string) (*models.Nameserver, error) { diff --git a/providers/autodns/auditrecords.go b/providers/autodns/auditrecords.go index 308ecf99df..39ee4758cd 100644 --- a/providers/autodns/auditrecords.go +++ b/providers/autodns/auditrecords.go @@ -1,14 +1,14 @@ package autodns import ( - "github.com/DNSControl/dnscontrol/v4/models" - "github.com/DNSControl/dnscontrol/v4/pkg/rejectif" + "github.com/DNSControl/dnscontrol/v5/models" + "github.com/DNSControl/dnscontrol/v5/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 { +func AuditRecords(records models.Records) []error { a := rejectif.Auditor{} a.Add("MX", rejectif.MxNull) // Last verified 2022-03-25 diff --git a/providers/autodns/autoDnsProvider.go b/providers/autodns/autoDnsProvider.go index 073a152d93..543e093d90 100644 --- a/providers/autodns/autoDnsProvider.go +++ b/providers/autodns/autoDnsProvider.go @@ -7,18 +7,17 @@ import ( "net/http" "net/url" "os" - "regexp" "sort" - "strconv" "strings" "time" "github.com/pquerna/otp/totp" - "github.com/DNSControl/dnscontrol/v4/models" - "github.com/DNSControl/dnscontrol/v4/pkg/diff2" - "github.com/DNSControl/dnscontrol/v4/pkg/providers" - "github.com/DNSControl/dnscontrol/v4/providers/bind" + dnsv2 "codeberg.org/miekg/dns" + "github.com/DNSControl/dnscontrol/v5/models" + "github.com/DNSControl/dnscontrol/v5/pkg/diff2" + "github.com/DNSControl/dnscontrol/v5/pkg/providers" + "github.com/DNSControl/dnscontrol/v5/providers/bind" ) var features = providers.DocumentationNotes{ @@ -203,45 +202,43 @@ func recordsToNative(recs models.Records) ([]*models.Nameserver, uint32, []*Reso var zoneTTL uint32 var resourceRecords []*ResourceRecord - for _, record := range recs { - if record.Type == "NS" && record.Name == "@" { + for _, rc := range recs { + if rc.Type == "NS" && rc.Name == "@" { // NS records for the APEX should be handled differently nameServers = append(nameServers, &models.Nameserver{ - Name: strings.TrimSuffix(record.GetTargetField(), "."), + Name: strings.TrimSuffix(rc.AsNS().Ns, "."), }) - zoneTTL = record.TTL + zoneTTL = rc.TTL } else { - resourceRecord := &ResourceRecord{ - Name: record.Name, - TTL: int64(record.TTL), - Type: record.Type, - Value: record.GetTargetField(), + name := rc.Name + if name == "@" { + name = "" } - if resourceRecord.Name == "@" { - resourceRecord.Name = "" + resourceRecord := &ResourceRecord{ + Name: name, + TTL: int64(rc.TTL), + Type: rc.Type, } - if record.Type == "MX" { - resourceRecord.Pref = int32(record.MxPreference) - } + switch rc.TypeNum { + case dnsv2.TypeMX: + f := rc.AsMX() + resourceRecord.Pref = int32(f.Preference) + resourceRecord.Value = rc.GetRDATA().String() + // If that doesn't work, try: + //resourceRecord.Pref = int32(f.Preference) + //resourceRecord.Value = f.Mx - if record.Type == "SRV" { - resourceRecord.Value = fmt.Sprintf("%d %d %d %s", - record.SrvPriority, - record.SrvWeight, - record.SrvPort, - record.GetTargetField(), - ) - } + // case dnsv2.TypeSRV: + // resourceRecord.Value = rc.GetRDATA().String() - if record.Type == "CAA" { - resourceRecord.Value = fmt.Sprintf("%d %s \"%s\"", - record.CaaFlag, - record.CaaTag, - record.GetTargetField(), - ) + // case dnsv2.TypeCAA: + // resourceRecord.Value = rc.GetRDATA().String() + + default: + resourceRecord.Value = rc.GetRDATA().String() } resourceRecords = append(resourceRecords, resourceRecord) @@ -269,10 +266,10 @@ func (api *autoDNSProvider) GetZoneRecords(dc *models.DomainConfig) (models.Reco return nil, err } - existingRecords := make([]*models.RecordConfig, len(zone.ResourceRecords)) + existingRecords := make(models.Records, len(zone.ResourceRecords)) for i, resourceRecord := range zone.ResourceRecords { var err error - existingRecords[i], err = toRecordConfig(domain, resourceRecord) + existingRecords[i], err = toRecordConfig(dc, resourceRecord) if err != nil { return nil, err } @@ -284,48 +281,34 @@ func (api *autoDNSProvider) GetZoneRecords(dc *models.DomainConfig) (models.Reco // AutoDNS doesn't respond with APEX nameserver records as regular RR but rather as a zone property for _, nameServer := range zone.NameServers { - nameServerRecord := &models.RecordConfig{ - TTL: zone.Soa.TTL, - } - - nameServerRecord.SetLabel("", domain) - // make sure the value for this NS record is suffixed with a dot at the end - _ = nameServerRecord.PopulateFromString("NS", strings.TrimSuffix(nameServer.Name, ".")+".", domain) + nameServerRecord, err := dc.NewRecordConfig("@", zone.Soa.TTL, dnsv2.TypeNS, strings.TrimSuffix(nameServer.Name, ".")+".") + if err != nil { + return nil, err + } existingRecords = append(existingRecords, nameServerRecord) } if zone.MainRecord != nil && zone.MainRecord.Value != "" { - addressRecord := &models.RecordConfig{ - TTL: uint32(zone.MainRecord.TTL), - } - + ttl := uint32(zone.MainRecord.TTL) // If TTL is not set for an individual RR AutoDNS defaults to the zone TTL defined in SOA - if addressRecord.TTL == 0 { - addressRecord.TTL = zone.Soa.TTL + if ttl == 0 { + ttl = zone.Soa.TTL + } + addressRecord, err := dc.NewRecordConfig("@", ttl, dnsv2.TypeA, zone.MainRecord.Value) + if err != nil { + return nil, err } - - addressRecord.SetLabel("", domain) - - _ = addressRecord.PopulateFromString("A", zone.MainRecord.Value, domain) existingRecords = append(existingRecords, addressRecord) if zone.IncludeWwwForMain { - prefixedAddressRecord := &models.RecordConfig{ - TTL: uint32(zone.MainRecord.TTL), - } - - // If TTL is not set for an individual RR AutoDNS defaults to the zone TTL defined in SOA - if prefixedAddressRecord.TTL == 0 { - prefixedAddressRecord.TTL = zone.Soa.TTL + prefixedAddressRecord, err := dc.NewRecordConfig(dc.LabelFromShort("www"), ttl, dnsv2.TypeA, zone.MainRecord.Value) + if err != nil { + return nil, err } - prefixedAddressRecord.SetLabel("www", domain) - - _ = prefixedAddressRecord.PopulateFromString("A", zone.MainRecord.Value, domain) - existingRecords = append(existingRecords, prefixedAddressRecord) } } @@ -403,65 +386,24 @@ func (api *autoDNSProvider) GetRegistrarCorrections(dc *models.DomainConfig) ([] return nil, nil } -func toRecordConfig(domain string, record *ResourceRecord) (*models.RecordConfig, error) { - rc := &models.RecordConfig{ - Type: record.Type, - TTL: uint32(record.TTL), - Original: record, - } - rc.SetLabel(record.Name, domain) - - // special record types are handled below, skip the `rc.PopulateFromString` method - if record.Type != "MX" && record.Type != "SRV" { - if err := rc.PopulateFromString(record.Type, record.Value, domain); err != nil { - return nil, err - } +func toRecordConfig(dc *models.DomainConfig, record *ResourceRecord) (*models.RecordConfig, error) { + label := dc.LabelFromShort(record.Name) + var rc *models.RecordConfig + var err error + + ttl := uint32(record.TTL) + switch record.Type { + case "MX": + rc, err = dc.NewRecordConfig(label, ttl, dnsv2.TypeMX, uint16(record.Pref), record.Value) + case "SRV": + rc, err = dc.NewRecordConfigParse(label, ttl, dnsv2.TypeSRV, fmt.Sprintf("%d %s", record.Pref, record.Value)) + default: + rc, err = dc.NewRecordConfigParse(label, ttl, record.Type, record.Value) } - - if record.Type == "MX" { - rc.MxPreference = uint16(record.Pref) - if err := rc.SetTarget(record.Value); err != nil { - return nil, err - } - } - - if record.Type == "SRV" { - rc.SrvPriority = uint16(record.Pref) - - re := regexp.MustCompile(`(\d+) (\d+) (.+)$`) - found := re.FindStringSubmatch(record.Value) - if len(found) != 4 { - return nil, fmt.Errorf("invalid SRV record value: %s", record.Value) - } - - weight, err := strconv.Atoi(found[1]) - if err != nil { - return nil, err - } - if weight < 0 { - rc.SrvWeight = 0 - } else if weight > 65535 { - rc.SrvWeight = 65535 - } else { - rc.SrvWeight = uint16(weight) - } - - port, err := strconv.Atoi(found[2]) - if err != nil { - return nil, err - } - if port < 0 { - rc.SrvPort = 0 - } else if port > 65535 { - rc.SrvPort = 65535 - } else { - rc.SrvPort = uint16(port) - } - - if err := rc.SetTarget(found[3]); err != nil { - return nil, err - } + if err != nil { + return nil, err } + rc.Original = record return rc, nil } diff --git a/providers/autodns/autoDnsProvider_test.go b/providers/autodns/autoDnsProvider_test.go new file mode 100644 index 0000000000..72f7badfa9 --- /dev/null +++ b/providers/autodns/autoDnsProvider_test.go @@ -0,0 +1,38 @@ +package autodns + +import ( + "testing" + + "github.com/DNSControl/dnscontrol/v5/models" +) + +func TestToRecordConfig(t *testing.T) { + t.Parallel() + + dc := models.MustNewDomainConfig("example.com") + tests := []struct { + name string + native *ResourceRecord + wantType string + wantData string + }{ + {"A", &ResourceRecord{Name: "www", Type: "A", Value: "192.0.2.1", TTL: 300}, "A", "192.0.2.1"}, + {"MX", &ResourceRecord{Name: "www", Type: "MX", Value: "mail.example.net.", Pref: 10, TTL: 300}, "MX", "10 mail.example.net."}, + {"SRV", &ResourceRecord{Name: "_sip._tcp", Type: "SRV", Value: "2 443 service.example.net.", Pref: 1, TTL: 300}, "SRV", "1 2 443 service.example.net."}, + } + + for _, tc := range tests { + t.Run(tc.name, func(t *testing.T) { + rc, err := toRecordConfig(dc, tc.native) + if err != nil { + t.Fatalf("toRecordConfig() error = %v", err) + } + if rc.Type != tc.wantType { + t.Errorf("toRecordConfig() type = %q, want %q", rc.Type, tc.wantType) + } + if got := rc.GetRDATA().String(); got != tc.wantData { + t.Errorf("toRecordConfig() data = %q, want %q", got, tc.wantData) + } + }) + } +} diff --git a/providers/autodns/types.go b/providers/autodns/types.go index d6814ce846..10c7d7cb90 100644 --- a/providers/autodns/types.go +++ b/providers/autodns/types.go @@ -1,8 +1,8 @@ package autodns import ( - "github.com/DNSControl/dnscontrol/v4/models" - "github.com/DNSControl/dnscontrol/v4/providers/bind" + "github.com/DNSControl/dnscontrol/v5/models" + "github.com/DNSControl/dnscontrol/v5/providers/bind" ) // ResourceRecord represents DNS records in API calls. diff --git a/providers/axfrddns/auditrecords.go b/providers/axfrddns/auditrecords.go index a98fc355ed..56c0c0bbe9 100644 --- a/providers/axfrddns/auditrecords.go +++ b/providers/axfrddns/auditrecords.go @@ -1,14 +1,14 @@ package axfrddns import ( - "github.com/DNSControl/dnscontrol/v4/models" - "github.com/DNSControl/dnscontrol/v4/pkg/rejectif" + "github.com/DNSControl/dnscontrol/v5/models" + "github.com/DNSControl/dnscontrol/v5/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 { +func AuditRecords(records models.Records) []error { a := rejectif.Auditor{} a.Add("TXT", rejectif.TxtIsEmpty) // Last verified 2025-01-01 diff --git a/providers/axfrddns/axfrddnsProvider.go b/providers/axfrddns/axfrddnsProvider.go index d6b86ae067..502e38976d 100644 --- a/providers/axfrddns/axfrddnsProvider.go +++ b/providers/axfrddns/axfrddnsProvider.go @@ -12,6 +12,7 @@ axfrddns - */ import ( + "context" "crypto/tls" "encoding/base64" "encoding/json" @@ -22,13 +23,13 @@ import ( "sync" "time" + dnsv2 "codeberg.org/miekg/dns" "codeberg.org/miekg/dns/dnsutil" - "github.com/DNSControl/dnscontrol/v4/models" - "github.com/DNSControl/dnscontrol/v4/pkg/diff2" - "github.com/DNSControl/dnscontrol/v4/pkg/dnsrr" - "github.com/DNSControl/dnscontrol/v4/pkg/printer" - "github.com/DNSControl/dnscontrol/v4/pkg/providers" - dnsv1 "github.com/miekg/dns" + "github.com/DNSControl/dnscontrol/v5/models" + "github.com/DNSControl/dnscontrol/v5/pkg/diff2" + "github.com/DNSControl/dnscontrol/v5/pkg/dnsrr" + "github.com/DNSControl/dnscontrol/v5/pkg/printer" + "github.com/DNSControl/dnscontrol/v5/pkg/providers" ) const ( @@ -203,7 +204,7 @@ type Param struct { type Key struct { algo string id string - secret string + secret []byte } func readKey(raw string, kind string) (*Key, error) { @@ -217,26 +218,39 @@ func readKey(raw string, kind string) (*Key, error) { var algo string switch arr[0] { case "hmac-md5", "md5": - algo = dnsv1.HmacMD5 + algo = dnsv2.HmacMD5 case "hmac-sha1", "sha1": - algo = dnsv1.HmacSHA1 + algo = dnsv2.HmacSHA1 case "hmac-sha224", "sha224": - algo = dnsv1.HmacSHA224 + algo = dnsv2.HmacSHA224 case "hmac-sha256", "sha256": - algo = dnsv1.HmacSHA256 + algo = dnsv2.HmacSHA256 case "hmac-sha384", "sha384": - algo = dnsv1.HmacSHA384 + algo = dnsv2.HmacSHA384 case "hmac-sha512", "sha512": - algo = dnsv1.HmacSHA512 + algo = dnsv2.HmacSHA512 default: return nil, fmt.Errorf("unknown algorithm (%s) in AXFRDDNS.TSIG", kind) } - _, err := base64.StdEncoding.DecodeString(arr[2]) + secret, err := base64.StdEncoding.DecodeString(arr[2]) if err != nil { return nil, fmt.Errorf("cannot decode Base64 secret (%s) in AXFRDDNS.TSIG", kind) } id := dnsutil.Canonical(arr[1]) - return &Key{algo: algo, id: id, secret: arr[2]}, nil + return &Key{algo: algo, id: id, secret: secret}, nil +} + +// signer returns the TSIG signer for the key. +func (k *Key) signer() dnsv2.TSIGSigner { + if k.algo == dnsv2.HmacMD5 { + return md5Provider(k.secret) + } + return dnsv2.HmacTSIG{Secret: k.secret} +} + +// stub returns the unsigned TSIG record to attach to a message signed with the key. +func (k *Key) stub() dnsv2.RR { + return dnsv2.NewTSIG(k.id, k.algo, 300) } // GetNameservers returns the nameservers for a domain. @@ -244,62 +258,62 @@ func (c *axfrddnsProvider) GetNameservers(domain string) ([]*models.Nameserver, return c.nameservers, nil } -func (c *axfrddnsProvider) getAxfrConnection() (*dnsv1.Transfer, error) { - var con net.Conn - var err error +func (c *axfrddnsProvider) getAxfrConnection() (net.Conn, error) { switch c.transferMode { case "tcp-tls": // RFC 9103 "DNS Zone Transfer over TLS" section 7.1 requires "dot" - con, err = tls.Dial("tcp", c.transferServer, &tls.Config{NextProtos: []string{"dot"}}) + return tls.Dial("tcp", c.transferServer, &tls.Config{NextProtos: []string{"dot"}}) case "unix": - con, err = net.Dial("unix", c.transferServer) + return net.Dial("unix", c.transferServer) default: - con, err = net.Dial("tcp", c.transferServer) - } - if err != nil { - return nil, err + return net.Dial("tcp", c.transferServer) } - dnscon := &dnsv1.Conn{Conn: con} - transfer := &dnsv1.Transfer{Conn: dnscon} - return transfer, nil } // FetchZoneRecords gets the records of a zone and returns them in dns.RR format. -func (c *axfrddnsProvider) FetchZoneRecords(domain string) ([]dnsv1.RR, error) { - transfer, err := c.getAxfrConnection() +func (c *axfrddnsProvider) FetchZoneRecords(domain string) ([]dnsv2.RR, error) { + con, err := c.getAxfrConnection() if err != nil { return nil, err } - transfer.DialTimeout = dnsTimeout - transfer.ReadTimeout = dnsTimeout - request := new(dnsv1.Msg) - request.SetAxfr(domain + ".") + client := dnsv2.NewClient() + client.ReadTimeout = dnsTimeout + + request := dnsv2.NewMsg(domain+".", dnsv2.TypeAXFR) + request.RecursionDesired = false if c.transferKey != nil { - transfer.TsigSecret = map[string]string{c.transferKey.id: c.transferKey.secret} - request.SetTsig(c.transferKey.id, c.transferKey.algo, 300, time.Now().Unix()) - if c.transferKey.algo == dnsv1.HmacMD5 { - transfer.TsigProvider = md5Provider(c.transferKey.secret) - } + request.Pseudo = []dnsv2.RR{c.transferKey.stub()} + client.Transfer = &dnsv2.Transfer{TSIGSigner: c.transferKey.signer()} } - envelope, err := transfer.In(request, c.transferServer) + envelope, err := client.TransferInWithConn(context.Background(), request, con) if err != nil { return nil, err } - var rawRecords []dnsv1.RR + // RFC 5936 section 2.2: a complete AXFR answer ends with the SOA it began + // with. The connection is closed on that SOA and the remaining envelopes + // are drained. + var rawRecords []dnsv2.RR + var complete bool for msg := range envelope { + if complete { + continue + } if msg.Error != nil { - // Fragile but more "user-friendly" error-handling - err := msg.Error.Error() - if err == "dns: bad xfr rcode: 9" { - err = "NOT AUTH (9)" - } - return nil, fmt.Errorf("[Error] AXFRDDNS: nameserver refused to transfer the zone %s: %s", domain, err) + return nil, fmt.Errorf("[Error] AXFRDDNS: nameserver refused to transfer the zone %s: %s", domain, msg.Error) } - rawRecords = append(rawRecords, msg.RR...) + rawRecords = append(rawRecords, msg.Answer...) + if len(rawRecords) >= 2 && dnsv2.RRToType(rawRecords[len(rawRecords)-1]) == dnsv2.TypeSOA { + complete = true + con.Close() + } + } + + if !complete { + return nil, fmt.Errorf("[Error] AXFRDDNS: incomplete transfer of the zone %s: the answer does not end with the SOA record", domain) } return rawRecords, nil } @@ -316,15 +330,15 @@ func (c *axfrddnsProvider) GetZoneRecords(dc *models.DomainConfig) (models.Recor var foundDNSSecRecords *models.RecordConfig foundRecords := models.Records{} for _, rr := range rawRecords { - switch rr.Header().Rrtype { - case dnsv1.TypeRRSIG, - dnsv1.TypeDNSKEY, - dnsv1.TypeCDNSKEY, - dnsv1.TypeCDS, - dnsv1.TypeNSEC, - dnsv1.TypeNSEC3, - dnsv1.TypeNSEC3PARAM, - dnsv1.TypeZONEMD, + switch dnsv2.RRToType(rr) { + case dnsv2.TypeRRSIG, + dnsv2.TypeDNSKEY, + dnsv2.TypeCDNSKEY, + dnsv2.TypeCDS, + dnsv2.TypeNSEC, + dnsv2.TypeNSEC3, + dnsv2.TypeNSEC3PARAM, + dnsv2.TypeZONEMD, 65281, 65534: // Ignoring DNSSec RRs, but replacing it with a single @@ -333,21 +347,18 @@ func (c *axfrddnsProvider) GetZoneRecords(dc *models.DomainConfig) (models.Recor // Also ignoring spurious TYPE65534, see: // https://bind9-users.isc.narkive.com/zX29ay0j/rndc-signing-list-not-working#post2 if foundDNSSecRecords == nil { - foundDNSSecRecords = new(models.RecordConfig) - foundDNSSecRecords.Type = "TXT" - foundDNSSecRecords.SetLabel(dnssecDummyLabel, domain) - err = foundDNSSecRecords.SetTargetTXT(dnssecDummyTxt) + foundDNSSecRecords, err = dc.NewRecordConfig(dc.LabelFromShort(dnssecDummyLabel), 0, dnsv2.TypeTXT, dnssecDummyTxt) if err != nil { return nil, err } } continue default: - rec, err := dnsrr.RRtoRC(rr, domain) + rec, err := dnsrr.RRv2toRC(dc, rr) if err != nil { return nil, err } - foundRecords = append(foundRecords, &rec) + foundRecords = append(foundRecords, rec) } } @@ -378,7 +389,7 @@ func (c *axfrddnsProvider) GetZoneRecords(dc *models.DomainConfig) (models.Recor } // BuildCorrection return a Correction for a given set of DDNS update and the corresponding message. -func (c *axfrddnsProvider) BuildCorrection(dc *models.DomainConfig, msgs []string, updates []*dnsv1.Msg) *models.Correction { +func (c *axfrddnsProvider) BuildCorrection(dc *models.DomainConfig, msgs []string, updates []*dnsv2.Msg) *models.Correction { if updates == nil { return &models.Correction{ Msg: fmt.Sprintf("DDNS UPDATES to '%s' (primary master: '%s'). Changes:\n%s", dc.Name, c.master, strings.Join(msgs, "\n")), @@ -387,26 +398,44 @@ func (c *axfrddnsProvider) BuildCorrection(dc *models.DomainConfig, msgs []strin return &models.Correction{ Msg: fmt.Sprintf("DDNS UPDATES to '%s' (primary master: '%s'). Changes:\n%s", dc.Name, c.master, strings.Join(msgs, "\n")), F: func() error { + client := dnsv2.NewClient() + client.Dialer = &net.Dialer{Timeout: dnsTimeout} + client.ReadTimeout = dnsTimeout + network := c.updateMode + switch network { + case "": + network = "udp" + case "tcp-tls": + network = "tcp" + client.TLSConfig = &tls.Config{} + } + + var signer dnsv2.TSIGSigner + if c.updateKey != nil { + signer = c.updateKey.signer() + } + for _, update := range updates { - update.Compress = true - client := new(dnsv1.Client) - client.Net = c.updateMode - client.Timeout = dnsTimeout - if c.updateKey != nil { - client.TsigSecret = map[string]string{c.updateKey.id: c.updateKey.secret} - update.SetTsig(c.updateKey.id, c.updateKey.algo, 300, time.Now().Unix()) - if c.updateKey.algo == dnsv1.HmacMD5 { - client.TsigProvider = md5Provider(c.updateKey.secret) + option := dnsv2.TSIGOption{} + if signer != nil { + update.Pseudo = []dnsv2.RR{c.updateKey.stub()} + if err := dnsv2.TSIGSign(update, signer, &option); err != nil { + return err } } - msg, _, err := client.Exchange(update, c.master) + msg, _, err := client.Exchange(context.Background(), update, network, c.master) if err != nil { return err } + if signer != nil && isSigned(msg) { + if err := dnsv2.TSIGVerify(msg, signer, &option); err != nil { + return err + } + } if msg.Rcode != 0 { return fmt.Errorf("[Error] AXFRDDNS: nameserver refused to update the zone: %s (%d)", - dnsv1.RcodeToString[msg.Rcode], + dnsv2.RcodeToString[msg.Rcode], msg.Rcode) } } @@ -416,7 +445,46 @@ func (c *axfrddnsProvider) BuildCorrection(dc *models.DomainConfig, msgs []strin } } -// hasNSDeletion returns true if there exist a correction that deletes or changes an NS record. +// isSigned reports whether msg carries a TSIG record. +func isSigned(msg *dnsv2.Msg) bool { + for _, rr := range msg.Pseudo { + if _, ok := rr.(*dnsv2.TSIG); ok { + return true + } + } + return false +} + +// newUpdate returns an empty DDNS update whose zone section is zone, see RFC 2136 section 2.3. +func newUpdate(zone string) *dnsv2.Msg { + update := dnsv2.NewMsg(zone, dnsv2.TypeSOA) + update.Opcode = dnsv2.OpcodeUpdate + update.RecursionDesired = false + return update +} + +// insert adds rr to the update section as an addition, see RFC 2136 section 2.5.1. +func insert(update *dnsv2.Msg, rr dnsv2.RR) { + rr.Header().Class = dnsv2.ClassINET + update.Ns = append(update.Ns, rr) +} + +// remove adds rr to the update section as the deletion of that single RR, see +// RFC 2136 section 2.5.4. +func remove(update *dnsv2.Msg, rr dnsv2.RR) { + hdr := rr.Header() + hdr.Class = dnsv2.ClassNONE + hdr.TTL = 0 + update.Ns = append(update.Ns, rr) +} + +// removeName adds rr to the update section as the deletion of every RRset owned +// by its name, see RFC 2136 section 2.5.3. +func removeName(update *dnsv2.Msg, rr dnsv2.RR) { + update.Ns = append(update.Ns, &dnsv2.ANY{Hdr: dnsv2.Header{Name: rr.Header().Name, Class: dnsv2.ClassANY}}) +} + +// hasNSDeletion returns true if there exist a correction that deletes or changes an apex NS record. func hasNSDeletion(changes diff2.ChangeList) bool { for _, change := range changes { switch change.Type { @@ -467,13 +535,13 @@ func (c *axfrddnsProvider) GetZoneRecordsCorrections(dc *models.DomainConfig, fo var msgs []string var reports []string - updates := []*dnsv1.Msg{} + updates := []*dnsv2.Msg{} - dummyNs1, err := dnsv1.NewRR(dc.Name + ". IN NS dnscontrol.invalid.") + dummyNs1, err := dnsv2.New(dc.Name + ". IN NS dnscontrol.invalid.") if err != nil { return nil, 0, err } - dummyNs2, err := dnsv1.NewRR(dc.Name + ". IN NS dnscontrol.invalid.") + dummyNs2, err := dnsv2.New(dc.Name + ". IN NS dnscontrol.invalid.") if err != nil { return nil, 0, err } @@ -486,8 +554,7 @@ func (c *axfrddnsProvider) GetZoneRecordsCorrections(dc *models.DomainConfig, fo return nil, 0, nil } - update := new(dnsv1.Msg) - update.SetUpdate(dc.Name + ".") + update := newUpdate(dc.Name + ".") // A DNS server should silently ignore a DDNS update that removes // the last NS record of a zone. Since modifying a record is @@ -504,7 +571,7 @@ func (c *axfrddnsProvider) GetZoneRecordsCorrections(dc *models.DomainConfig, fo hasNSDeletion := hasNSDeletion(changes) if hasNSDeletion { - update.Insert([]dnsv1.RR{dummyNs1}) + insert(update, dummyNs1) } i := 1 @@ -517,28 +584,28 @@ func (c *axfrddnsProvider) GetZoneRecordsCorrections(dc *models.DomainConfig, fo // It's semantically invalid for any RRs to exist alongside a // CNAME RR if change.Old[0].Type == "CNAME" { - update.RemoveName([]dnsv1.RR{change.Old[0].ToRR()}) + removeName(update, change.Old[0].ToRRv2()) } else { - update.Remove([]dnsv1.RR{change.Old[0].ToRR()}) + remove(update, change.Old[0].ToRRv2()) } case diff2.CREATE: msgs = append(msgs, change.Msgs[0]) // It's semantically invalid for any RRs to exist alongside a // CNAME RR if change.New[0].Type == "CNAME" { - update.RemoveName([]dnsv1.RR{change.New[0].ToRR()}) + removeName(update, change.New[0].ToRRv2()) } - update.Insert([]dnsv1.RR{change.New[0].ToRR()}) + insert(update, change.New[0].ToRRv2()) case diff2.CHANGE: msgs = append(msgs, change.Msgs[0]) // It's semantically invalid for any RRs to exist alongside a // CNAME RR if (change.New[0].Type == "CNAME") || (change.Old[0].Type == "CNAME") { - update.RemoveName([]dnsv1.RR{change.Old[0].ToRR()}) + removeName(update, change.Old[0].ToRRv2()) } else { - update.Remove([]dnsv1.RR{change.Old[0].ToRR()}) + remove(update, change.Old[0].ToRRv2()) } - update.Insert([]dnsv1.RR{change.New[0].ToRR()}) + insert(update, change.New[0].ToRRv2()) case diff2.REPORT: reports = append(reports, change.Msgs...) } @@ -548,8 +615,7 @@ func (c *axfrddnsProvider) GetZoneRecordsCorrections(dc *models.DomainConfig, fo // This is a compromise, succeeding whenever RRs are not bigger than about 64 KiB - 16 KiB = 48 KiB. if update.Len() >= 2<<13 { updates = append(updates, update) - update = new(dnsv1.Msg) - update.SetUpdate(dc.Name + ".") + update = newUpdate(dc.Name + ".") appendFinalUpdate = false i = 1 } else { @@ -559,7 +625,7 @@ func (c *axfrddnsProvider) GetZoneRecordsCorrections(dc *models.DomainConfig, fo } if hasNSDeletion { - update.Remove([]dnsv1.RR{dummyNs2}) + remove(update, dummyNs2) appendFinalUpdate = true } diff --git a/providers/axfrddns/axfrddnsProvider_test.go b/providers/axfrddns/axfrddnsProvider_test.go new file mode 100644 index 0000000000..e1ecd94bde --- /dev/null +++ b/providers/axfrddns/axfrddnsProvider_test.go @@ -0,0 +1,694 @@ +package axfrddns + +import ( + "context" + "fmt" + "io" + "strings" + "sync" + "testing" + "time" + + dnsv2 "codeberg.org/miekg/dns" + "codeberg.org/miekg/dns/dnstest" + "codeberg.org/miekg/dns/dnsutil" + "github.com/DNSControl/dnscontrol/v5/models" +) + +const ( + testZone = "example.com." + testSecret = "c2VjcmV0Cg==" + otherKey = "b3RoZXJzZWNyZXQK" +) + +var testZoneContents = []string{ + "example.com. 3600 IN SOA ns1.example.com. hostmaster.example.com. 1 7200 3600 1209600 3600", + "example.com. 3600 IN NS ns1.example.com.", + "www.example.com. 300 IN A 192.0.2.1", + "www.example.com. 300 IN AAAA 2001:db8::1", + "example.com. 3600 IN MX 10 mail.example.com.", + "txt.example.com. 60 IN TXT \"hello world\"", + "example.com. 3600 IN SOA ns1.example.com. hostmaster.example.com. 1 7200 3600 1209600 3600", +} + +func mustRR(t *testing.T, s string) dnsv2.RR { + t.Helper() + rr, err := dnsv2.New(s) + if err != nil { + t.Fatalf("dnsv2.New(%q): %v", s, err) + } + return rr +} + +func mustKey(t *testing.T, raw string) *Key { + t.Helper() + key, err := readKey(raw, "transfer-key") + if err != nil { + t.Fatalf("readKey(%q): %v", raw, err) + } + return key +} + +// serveAXFR starts a nameserver on localhost that answers an AXFR for testZone +// with contents in a single message, signing it with signer when it is not nil, +// and closes the connection afterwards. It returns the "host:port" the server +// listens on. +func serveAXFR(t *testing.T, contents []string, signer dnsv2.TSIGSigner) string { + t.Helper() + return newAXFRServer(t, [][]string{contents}, signer, true) +} + +// newAXFRServer starts a nameserver on localhost that answers an AXFR for +// testZone with one message per element of messages, signing each with signer +// when it is not nil and closing the connection afterwards when closeConn is +// set. It returns the "host:port" the server listens on. +func newAXFRServer(t *testing.T, messages [][]string, signer dnsv2.TSIGSigner, closeConn bool) string { + t.Helper() + + answers := make([][]dnsv2.RR, 0, len(messages)) + for _, contents := range messages { + answer := make([]dnsv2.RR, 0, len(contents)) + for _, s := range contents { + answer = append(answer, mustRR(t, s)) + } + answers = append(answers, answer) + } + + mux := dnsv2.NewServeMux() + mux.HandleFunc(testZone, func(_ context.Context, w dnsv2.ResponseWriter, r *dnsv2.Msg) { + if err := r.Unpack(); err != nil { + t.Errorf("server: unpack request: %v", err) + return + } + w.Hijack() + if signer != nil && !isSigned(r) { + t.Error("server: AXFR request arrived without a TSIG") + w.Close() + return + } + + client := dnsv2.NewClient() + if signer != nil { + client.Transfer = &dnsv2.Transfer{TSIGSigner: signer} + } + + env := make(chan *dnsv2.Envelope) + var wg sync.WaitGroup + wg.Go(func() { + if err := client.TransferOut(w, r, env); err != nil { + t.Errorf("server: TransferOut: %v", err) + } + if closeConn { + w.Close() + } + }) + for _, answer := range answers { + env <- &dnsv2.Envelope{Answer: answer} + } + close(env) + wg.Wait() + }) + + cancel, addr, err := dnstest.TCPServer("127.0.0.1:0", func(s *dnsv2.Server) { s.Handler = mux }) + if err != nil { + t.Fatalf("starting AXFR server: %v", err) + } + t.Cleanup(cancel) + return addr +} + +// serveUpdate starts a nameserver on localhost that answers every DDNS update +// for testZone with rcode. The request is verified with requestKey when it is +// not nil, and the reply is signed with replyKey when it is not nil. Received +// updates are sent to the returned channel. +func serveUpdate(t *testing.T, rcode uint16, requestKey, replyKey dnsv2.TSIGSigner) (string, <-chan *dnsv2.Msg) { + t.Helper() + + received := make(chan *dnsv2.Msg, 8) + + mux := dnsv2.NewServeMux() + mux.HandleFunc(testZone, func(_ context.Context, w dnsv2.ResponseWriter, r *dnsv2.Msg) { + if err := r.Unpack(); err != nil { + t.Errorf("server: unpack update: %v", err) + return + } + + option := dnsv2.TSIGOption{} + var stub dnsv2.RR + if requestKey != nil { + if len(r.Pseudo) == 0 { + t.Error("server: update arrived without a TSIG") + return + } + stub = r.Pseudo[len(r.Pseudo)-1] + if err := dnsv2.TSIGVerify(r, requestKey, &option); err != nil { + t.Errorf("server: TSIGVerify: %v", err) + return + } + } + received <- r + + reply := new(dnsv2.Msg) + dnsutil.SetReply(reply, r) + reply.Rcode = rcode + if replyKey != nil { + reply.Pseudo = []dnsv2.RR{stub} + if err := reply.Pack(); err != nil { + t.Errorf("server: pack reply: %v", err) + return + } + if err := dnsv2.TSIGSign(reply, replyKey, &option); err != nil { + t.Errorf("server: TSIGSign: %v", err) + return + } + } + if _, err := io.Copy(w, reply); err != nil { + t.Errorf("server: write reply: %v", err) + } + }) + + cancel, addr, err := dnstest.TCPServer("127.0.0.1:0", func(s *dnsv2.Server) { s.Handler = mux }) + if err != nil { + t.Fatalf("starting update server: %v", err) + } + t.Cleanup(cancel) + return addr, received +} + +func TestReadKey(t *testing.T) { + tests := []struct { + name string + raw string + wantAlgo string + wantID string + wantErr string + }{ + {"hmac-md5", "hmac-md5:key:" + testSecret, dnsv2.HmacMD5, "key.", ""}, + {"md5", "md5:key:" + testSecret, dnsv2.HmacMD5, "key.", ""}, + {"hmac-sha1", "hmac-sha1:key:" + testSecret, dnsv2.HmacSHA1, "key.", ""}, + {"sha1", "sha1:key:" + testSecret, dnsv2.HmacSHA1, "key.", ""}, + {"hmac-sha224", "hmac-sha224:key:" + testSecret, dnsv2.HmacSHA224, "key.", ""}, + {"sha224", "sha224:key:" + testSecret, dnsv2.HmacSHA224, "key.", ""}, + {"hmac-sha256", "hmac-sha256:KEY.example.com:" + testSecret, dnsv2.HmacSHA256, "key.example.com.", ""}, + {"sha256", "sha256:key:" + testSecret, dnsv2.HmacSHA256, "key.", ""}, + {"hmac-sha384", "hmac-sha384:key:" + testSecret, dnsv2.HmacSHA384, "key.", ""}, + {"sha384", "sha384:key:" + testSecret, dnsv2.HmacSHA384, "key.", ""}, + {"hmac-sha512", "hmac-sha512:key:" + testSecret, dnsv2.HmacSHA512, "key.", ""}, + {"sha512", "sha512:key:" + testSecret, dnsv2.HmacSHA512, "key.", ""}, + {"empty", "", "", "", ""}, + {"too few fields", "hmac-sha256:key", "", "", "invalid key format"}, + {"unknown algorithm", "hmac-sha3:key:" + testSecret, "", "", "unknown algorithm"}, + {"bad base64", "hmac-sha256:key:!!!", "", "", "cannot decode Base64 secret"}, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + key, err := readKey(tt.raw, "transfer-key") + if tt.wantErr != "" { + if err == nil || !strings.Contains(err.Error(), tt.wantErr) { + t.Fatalf("readKey() error = %v, want it to contain %q", err, tt.wantErr) + } + return + } + if err != nil { + t.Fatalf("readKey() error = %v", err) + } + if tt.raw == "" { + if key != nil { + t.Fatalf("readKey(\"\") = %v, want nil", key) + } + return + } + if key.algo != tt.wantAlgo { + t.Errorf("algo = %q, want %q", key.algo, tt.wantAlgo) + } + if key.id != tt.wantID { + t.Errorf("id = %q, want %q", key.id, tt.wantID) + } + if string(key.secret) != "secret\n" { + t.Errorf("secret = %q, want the decoded secret", key.secret) + } + }) + } +} + +func TestKeySigner(t *testing.T) { + if _, ok := mustKey(t, "hmac-md5:key:"+testSecret).signer().(md5Provider); !ok { + t.Error("hmac-md5 key is not signed by md5Provider") + } + if _, ok := mustKey(t, "hmac-sha256:key:"+testSecret).signer().(dnsv2.HmacTSIG); !ok { + t.Error("hmac-sha256 key is not signed by dnsv2.HmacTSIG") + } +} + +func TestFetchZoneRecords(t *testing.T) { + tests := []struct { + name string + serverKey string + clientKey string + wantErrSub string + }{ + {name: "unauthenticated"}, + {name: "hmac-sha256", serverKey: "hmac-sha256:key:" + testSecret, clientKey: "hmac-sha256:key:" + testSecret}, + {name: "hmac-sha512", serverKey: "hmac-sha512:key:" + testSecret, clientKey: "hmac-sha512:key:" + testSecret}, + {name: "hmac-md5", serverKey: "hmac-md5:key:" + testSecret, clientKey: "hmac-md5:key:" + testSecret}, + { + name: "wrong secret is rejected", + serverKey: "hmac-sha256:key:" + testSecret, + clientKey: "hmac-sha256:key:" + otherKey, + wantErrSub: "bad signature", + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + var serverSigner dnsv2.TSIGSigner + if tt.serverKey != "" { + serverSigner = mustKey(t, tt.serverKey).signer() + } + addr := serveAXFR(t, testZoneContents, serverSigner) + + api := &axfrddnsProvider{transferServer: addr, transferMode: "tcp"} + if tt.clientKey != "" { + api.transferKey = mustKey(t, tt.clientKey) + } + + got, err := api.FetchZoneRecords("example.com") + if tt.wantErrSub != "" { + if err == nil || !strings.Contains(err.Error(), tt.wantErrSub) { + t.Fatalf("FetchZoneRecords() error = %v, want it to contain %q", err, tt.wantErrSub) + } + return + } + if err != nil { + t.Fatalf("FetchZoneRecords() error = %v", err) + } + if len(got) != len(testZoneContents) { + t.Fatalf("FetchZoneRecords() returned %d records, want %d", len(got), len(testZoneContents)) + } + for i, rr := range got { + if want := mustRR(t, testZoneContents[i]).String(); rr.String() != want { + t.Errorf("record %d = %q, want %q", i, rr.String(), want) + } + } + }) + } +} + +func TestFetchZoneRecordsDoesNotStopOnTheOpeningSOA(t *testing.T) { + addr := newAXFRServer(t, [][]string{testZoneContents[:1], testZoneContents[1:]}, nil, true) + api := &axfrddnsProvider{transferServer: addr, transferMode: "tcp"} + + got, err := api.FetchZoneRecords("example.com") + if err != nil { + t.Fatalf("FetchZoneRecords() error = %v", err) + } + if len(got) != len(testZoneContents) { + t.Fatalf("FetchZoneRecords() returned %d records, want %d", len(got), len(testZoneContents)) + } + for i, rr := range got { + if want := mustRR(t, testZoneContents[i]).String(); rr.String() != want { + t.Errorf("record %d = %q, want %q", i, rr.String(), want) + } + } +} + +func TestFetchZoneRecordsReturnsOnTheClosingSOA(t *testing.T) { + addr := newAXFRServer(t, [][]string{testZoneContents}, nil, false) + api := &axfrddnsProvider{transferServer: addr, transferMode: "tcp"} + + type result struct { + records []dnsv2.RR + err error + } + done := make(chan result, 1) + go func() { + records, err := api.FetchZoneRecords("example.com") + done <- result{records: records, err: err} + }() + + select { + case got := <-done: + if got.err != nil { + t.Fatalf("FetchZoneRecords() error = %v", got.err) + } + if len(got.records) != len(testZoneContents) { + t.Fatalf("FetchZoneRecords() returned %d records, want %d", len(got.records), len(testZoneContents)) + } + case <-time.After(5 * time.Second): + t.Fatal("FetchZoneRecords() did not return while the nameserver held the connection open") + } +} + +func TestFetchZoneRecordsReportsRefusedTransfer(t *testing.T) { + mux := dnsv2.NewServeMux() + mux.HandleFunc(testZone, func(_ context.Context, w dnsv2.ResponseWriter, r *dnsv2.Msg) { + if err := r.Unpack(); err != nil { + t.Errorf("server: unpack request: %v", err) + return + } + reply := new(dnsv2.Msg) + dnsutil.SetReply(reply, r) + reply.Rcode = dnsv2.RcodeNotAuth + if _, err := io.Copy(w, reply); err != nil { + t.Errorf("server: write reply: %v", err) + } + }) + cancel, addr, err := dnstest.TCPServer("127.0.0.1:0", func(s *dnsv2.Server) { s.Handler = mux }) + if err != nil { + t.Fatalf("starting AXFR server: %v", err) + } + t.Cleanup(cancel) + + api := &axfrddnsProvider{transferServer: addr, transferMode: "tcp"} + _, err = api.FetchZoneRecords("example.com") + + want := "[Error] AXFRDDNS: nameserver refused to transfer the zone example.com: dns: bad rcode: NOTAUTH" + if err == nil || err.Error() != want { + t.Fatalf("FetchZoneRecords() error = %v, want %q", err, want) + } +} + +func TestFetchZoneRecordsRejectsTruncatedTransfer(t *testing.T) { + addr := serveAXFR(t, testZoneContents[:len(testZoneContents)-1], nil) + api := &axfrddnsProvider{transferServer: addr, transferMode: "tcp"} + + _, err := api.FetchZoneRecords("example.com") + if err == nil || !strings.Contains(err.Error(), "does not end with the SOA record") { + t.Fatalf("FetchZoneRecords() error = %v, want it to report an incomplete transfer", err) + } +} + +func TestGetZoneRecordsDropsTrailingSOA(t *testing.T) { + addr := serveAXFR(t, testZoneContents, nil) + api := &axfrddnsProvider{ + transferServer: addr, + transferMode: "tcp", + hasDnssecRecords: map[string]bool{}, + } + + got, err := api.GetZoneRecords(models.MustNewDomainConfig("example.com")) + if err != nil { + t.Fatalf("GetZoneRecords() error = %v", err) + } + + want := []string{ + "@ 3600 IN SOA ns1.example.com. hostmaster.example.com. 1 7200 3600 1209600 3600", + "@ 3600 IN NS ns1.example.com.", + "www 300 IN A 192.0.2.1", + "www 300 IN AAAA 2001:db8::1", + "@ 3600 IN MX 10 mail.example.com.", + "txt 60 IN TXT \"hello world\"", + } + if len(got) != len(want) { + t.Fatalf("GetZoneRecords() returned %d records, want %d", len(got), len(want)) + } + for i, rc := range got { + if rc.LineString() != want[i] { + t.Errorf("record %d = %q, want %q", i, rc.LineString(), want[i]) + } + } +} + +func TestGetZoneRecordsReplacesDNSSECRecordsWithPlaceholder(t *testing.T) { + contents := []string{ + "example.com. 3600 IN SOA ns1.example.com. hostmaster.example.com. 1 7200 3600 1209600 3600", + "example.com. 3600 IN NS ns1.example.com.", + "example.com. 3600 IN NSEC3PARAM 1 0 0 -", + "example.com. 3600 IN SOA ns1.example.com. hostmaster.example.com. 1 7200 3600 1209600 3600", + } + addr := serveAXFR(t, contents, nil) + api := &axfrddnsProvider{ + transferServer: addr, + transferMode: "tcp", + hasDnssecRecords: map[string]bool{}, + } + + got, err := api.GetZoneRecords(models.MustNewDomainConfig("example.com")) + if err != nil { + t.Fatalf("GetZoneRecords() error = %v", err) + } + if len(got) != 2 { + t.Fatalf("GetZoneRecords() returned %d records, want 2", len(got)) + } + if !api.hasDnssecRecords["example.com"] { + t.Error("GetZoneRecords() did not record that the zone is signed") + } +} + +func TestNewUpdateMessage(t *testing.T) { + update := newUpdate(testZone) + + if update.Opcode != dnsv2.OpcodeUpdate { + t.Errorf("Opcode = %d, want %d", update.Opcode, dnsv2.OpcodeUpdate) + } + if update.Response { + t.Error("Response is set") + } + if update.RecursionDesired { + t.Error("RecursionDesired is set") + } + if len(update.Question) != 1 { + t.Fatalf("zone section holds %d entries, want 1", len(update.Question)) + } + zone := update.Question[0] + if zone.Header().Name != testZone { + t.Errorf("zone name = %q, want %q", zone.Header().Name, testZone) + } + if got := dnsv2.RRToType(zone); got != dnsv2.TypeSOA { + t.Errorf("zone type = %d, want %d", got, dnsv2.TypeSOA) + } + if zone.Header().Class != dnsv2.ClassINET { + t.Errorf("zone class = %d, want %d", zone.Header().Class, dnsv2.ClassINET) + } +} + +func TestUpdateSectionEncoding(t *testing.T) { + rr := "www.example.com. 300 IN A 192.0.2.1" + + tests := []struct { + name string + build func(*dnsv2.Msg, dnsv2.RR) + wantClass uint16 + wantTTL uint32 + wantType uint16 + }{ + {"insert", insert, dnsv2.ClassINET, 300, dnsv2.TypeA}, + {"remove", remove, dnsv2.ClassNONE, 0, dnsv2.TypeA}, + {"removeName", removeName, dnsv2.ClassANY, 0, dnsv2.TypeANY}, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + update := newUpdate(testZone) + tt.build(update, mustRR(t, rr)) + + if len(update.Ns) != 1 { + t.Fatalf("update section holds %d entries, want 1", len(update.Ns)) + } + got := update.Ns[0] + if got.Header().Name != "www.example.com." { + t.Errorf("name = %q, want %q", got.Header().Name, "www.example.com.") + } + if got.Header().Class != tt.wantClass { + t.Errorf("class = %d, want %d", got.Header().Class, tt.wantClass) + } + if got.Header().TTL != tt.wantTTL { + t.Errorf("ttl = %d, want %d", got.Header().TTL, tt.wantTTL) + } + if n := dnsv2.RRToType(got); n != tt.wantType { + t.Errorf("type = %d, want %d", n, tt.wantType) + } + if err := update.Pack(); err != nil { + t.Fatalf("Pack() error = %v", err) + } + }) + } +} + +func TestGetZoneRecordsCorrections(t *testing.T) { + addr, received := serveUpdate(t, dnsv2.RcodeSuccess, nil, nil) + + dc := models.MustNewDomainConfig("example.com") + dc.Records = models.Records{ + dc.MustNewRecordConfig("www", 300, dnsv2.TypeA, "192.0.2.9"), + dc.MustNewRecordConfig("alias", 300, dnsv2.TypeCNAME, "www.example.com."), + } + foundRecords := models.Records{ + dc.MustNewRecordConfig("old", 300, dnsv2.TypeA, "192.0.2.8"), + } + + api := &axfrddnsProvider{master: addr, updateMode: "tcp", hasDnssecRecords: map[string]bool{}} + corrections, changeCount, err := api.GetZoneRecordsCorrections(dc, foundRecords) + if err != nil { + t.Fatalf("GetZoneRecordsCorrections() error = %v", err) + } + if changeCount != 3 { + t.Errorf("changeCount = %d, want 3", changeCount) + } + if len(corrections) != 1 { + t.Fatalf("GetZoneRecordsCorrections() returned %d corrections, want 1", len(corrections)) + } + if err := corrections[0].F(); err != nil { + t.Fatalf("correction error = %v", err) + } + + got := <-received + want := []struct { + name string + ttl uint32 + class uint16 + rrtype uint16 + rrstring string + }{ + {"old.example.com.", 0, dnsv2.ClassNONE, dnsv2.TypeA, "old.example.com.\t0\tNONE\tA\t192.0.2.8"}, + {"www.example.com.", 300, dnsv2.ClassINET, dnsv2.TypeA, "www.example.com.\t300\tIN\tA\t192.0.2.9"}, + {"alias.example.com.", 0, dnsv2.ClassANY, dnsv2.TypeANY, "alias.example.com.\t0\tANY"}, + {"alias.example.com.", 300, dnsv2.ClassINET, dnsv2.TypeCNAME, "alias.example.com.\t300\tIN\tCNAME\twww.example.com."}, + } + if len(got.Ns) != len(want) { + t.Fatalf("update section holds %d entries, want %d", len(got.Ns), len(want)) + } + for i, rr := range got.Ns { + hdr := rr.Header() + if hdr.Name != want[i].name || hdr.TTL != want[i].ttl || hdr.Class != want[i].class { + t.Errorf("update section entry %d header = %s %d class %d, want %s %d class %d", + i, hdr.Name, hdr.TTL, hdr.Class, want[i].name, want[i].ttl, want[i].class) + } + if n := dnsv2.RRToType(rr); n != want[i].rrtype { + t.Errorf("update section entry %d type = %d, want %d", i, n, want[i].rrtype) + } + if rr.String() != want[i].rrstring { + t.Errorf("update section entry %d = %q, want %q", i, rr.String(), want[i].rrstring) + } + } +} + +func TestGetZoneRecordsCorrectionsChunksLargeUpdates(t *testing.T) { + addr, received := serveUpdate(t, dnsv2.RcodeSuccess, nil, nil) + + const recordCount = 200 + dc := models.MustNewDomainConfig("example.com") + for i := range recordCount { + dc.Records = append(dc.Records, + dc.MustNewRecordConfig(fmt.Sprintf("txt%d", i), 300, dnsv2.TypeTXT, strings.Repeat("x", 255))) + } + + api := &axfrddnsProvider{master: addr, updateMode: "tcp", hasDnssecRecords: map[string]bool{}} + corrections, _, err := api.GetZoneRecordsCorrections(dc, models.Records{}) + if err != nil { + t.Fatalf("GetZoneRecordsCorrections() error = %v", err) + } + if len(corrections) != 1 { + t.Fatalf("GetZoneRecordsCorrections() returned %d corrections, want 1", len(corrections)) + } + if err := corrections[0].F(); err != nil { + t.Fatalf("correction error = %v", err) + } + + messages, inserted := 0, 0 + for inserted < recordCount { + select { + case update := <-received: + messages++ + inserted += len(update.Ns) + case <-time.After(5 * time.Second): + t.Fatalf("received %d of %d records in %d update message(s)", inserted, recordCount, messages) + } + } + if messages < 2 { + t.Errorf("the update was sent as %d message(s), want it split over several", messages) + } +} + +func TestBuildCorrection(t *testing.T) { + sha256Key := "hmac-sha256:key:" + testSecret + + tests := []struct { + name string + key string + replyKey string + unsigned bool + rcode uint16 + wantErrSub string + }{ + {name: "unauthenticated"}, + {name: "hmac-sha256", key: sha256Key}, + {name: "hmac-md5", key: "hmac-md5:key:" + testSecret}, + { + name: "refused update is reported", + rcode: dnsv2.RcodeNotAuth, + wantErrSub: "nameserver refused to update the zone: NOTAUTH (9)", + }, + { + name: "reply signed with the wrong key is rejected", + key: sha256Key, + replyKey: "hmac-sha256:key:" + otherKey, + wantErrSub: "bad signature", + }, + { + name: "unsigned reply is accepted", + key: sha256Key, + unsigned: true, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + var requestKey, replyKey dnsv2.TSIGSigner + if tt.key != "" { + requestKey = mustKey(t, tt.key).signer() + replyKey = requestKey + } + if tt.replyKey != "" { + replyKey = mustKey(t, tt.replyKey).signer() + } + if tt.unsigned { + replyKey = nil + } + addr, received := serveUpdate(t, tt.rcode, requestKey, replyKey) + + api := &axfrddnsProvider{master: addr, updateMode: "tcp"} + if tt.key != "" { + api.updateKey = mustKey(t, tt.key) + } + + update := newUpdate(testZone) + insert(update, mustRR(t, "www.example.com. 300 IN A 192.0.2.1")) + remove(update, mustRR(t, "old.example.com. 300 IN A 192.0.2.2")) + + dc := models.MustNewDomainConfig("example.com") + err := api.BuildCorrection(dc, []string{"+ A www"}, []*dnsv2.Msg{update}).F() + + if tt.wantErrSub != "" { + if err == nil || !strings.Contains(err.Error(), tt.wantErrSub) { + t.Fatalf("correction error = %v, want it to contain %q", err, tt.wantErrSub) + } + return + } + if err != nil { + t.Fatalf("correction error = %v", err) + } + + got := <-received + if got.Opcode != dnsv2.OpcodeUpdate { + t.Errorf("Opcode = %d, want %d", got.Opcode, dnsv2.OpcodeUpdate) + } + if len(got.Question) != 1 || got.Question[0].Header().Name != testZone { + t.Fatalf("zone section = %v, want a single %q entry", got.Question, testZone) + } + want := []string{ + "www.example.com.\t300\tIN\tA\t192.0.2.1", + "old.example.com.\t0\tNONE\tA\t192.0.2.2", + } + if len(got.Ns) != len(want) { + t.Fatalf("update section holds %d entries, want %d", len(got.Ns), len(want)) + } + for i, rr := range got.Ns { + if rr.String() != want[i] { + t.Errorf("update section entry %d = %q, want %q", i, rr.String(), want[i]) + } + } + }) + } +} diff --git a/providers/axfrddns/md5Provider.go b/providers/axfrddns/md5Provider.go index c90bf1b6d3..0f0cf6cd93 100644 --- a/providers/axfrddns/md5Provider.go +++ b/providers/axfrddns/md5Provider.go @@ -3,35 +3,24 @@ package axfrddns import ( "crypto/hmac" "crypto/md5" //#nosec - "encoding/base64" "encoding/hex" - dnsv1 "github.com/miekg/dns" + dnsv2 "codeberg.org/miekg/dns" ) -type md5Provider string +// md5Provider signs and verifies TSIGs with HMAC-MD5. +type md5Provider []byte -func fromBase64(s []byte) (buf []byte, err error) { - buflen := base64.StdEncoding.DecodedLen(len(s)) - buf = make([]byte, buflen) - n, err := base64.StdEncoding.Decode(buf, s) - buf = buf[:n] - return -} - -func (key md5Provider) Generate(msg []byte, _ *dnsv1.TSIG) ([]byte, error) { - rawsecret, err := fromBase64([]byte(key)) - if err != nil { - return nil, err - } - h := hmac.New(md5.New, rawsecret) +func (key md5Provider) Key() []byte { return key } +func (key md5Provider) Sign(_ *dnsv2.TSIG, msg []byte, _ dnsv2.TSIGOption) ([]byte, error) { + h := hmac.New(md5.New, key) h.Write(msg) return h.Sum(nil), nil } -func (key md5Provider) Verify(msg []byte, t *dnsv1.TSIG) error { - b, err := key.Generate(msg, t) +func (key md5Provider) Verify(t *dnsv2.TSIG, msg []byte, options dnsv2.TSIGOption) error { + b, err := key.Sign(t, msg, options) if err != nil { return err } @@ -40,7 +29,7 @@ func (key md5Provider) Verify(msg []byte, t *dnsv1.TSIG) error { return err } if !hmac.Equal(b, mac) { - return dnsv1.ErrSig + return dnsv2.ErrSig } return nil } diff --git a/providers/axfrddns/test_data/meta.json b/providers/axfrddns/test_data/meta.json new file mode 100644 index 0000000000..201d44d530 --- /dev/null +++ b/providers/axfrddns/test_data/meta.json @@ -0,0 +1,11 @@ +{ + "version": 1, + "recordings": [ + { + "domain": "with-dnssec.dnscontrol.internal" + }, + { + "domain": "without-dnssec.dnscontrol.internal" + } + ] +} diff --git a/providers/azuredns/auditrecords.go b/providers/azuredns/auditrecords.go index 90d63037ca..d723f605aa 100644 --- a/providers/azuredns/auditrecords.go +++ b/providers/azuredns/auditrecords.go @@ -1,19 +1,14 @@ package azuredns import ( - "github.com/DNSControl/dnscontrol/v4/models" - "github.com/DNSControl/dnscontrol/v4/pkg/rejectif" + "github.com/DNSControl/dnscontrol/v5/models" + "github.com/DNSControl/dnscontrol/v5/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 { +func AuditRecords(records models.Records) []error { a := rejectif.Auditor{} - - 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/azuredns/azureDnsProvider.go b/providers/azuredns/azureDnsProvider.go index 89301bbb16..cc7a0a63a4 100644 --- a/providers/azuredns/azureDnsProvider.go +++ b/providers/azuredns/azureDnsProvider.go @@ -10,19 +10,21 @@ import ( "strings" "time" + dnsv2 "codeberg.org/miekg/dns" "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/dns/armdns" - - "github.com/DNSControl/dnscontrol/v4/models" - "github.com/DNSControl/dnscontrol/v4/pkg/diff2" - "github.com/DNSControl/dnscontrol/v4/pkg/printer" - "github.com/DNSControl/dnscontrol/v4/pkg/providers" + "github.com/DNSControl/dnscontrol/v5/models" + "github.com/DNSControl/dnscontrol/v5/pkg/diff2" + "github.com/DNSControl/dnscontrol/v5/pkg/printer" + "github.com/DNSControl/dnscontrol/v5/pkg/privatetypes" + "github.com/DNSControl/dnscontrol/v5/pkg/providers" ) const azurePendingOperationConflictMessage = "Another operation is pending for requested object" type azurednsProvider struct { + observer providers.ConversionObserver zonesClient *adns.ZonesClient recordsClient *adns.RecordSetsClient zones map[string]*adns.Zone @@ -30,6 +32,10 @@ type azurednsProvider struct { subscriptionID *string } +func (a *azurednsProvider) SetConversionObserver(observer providers.ConversionObserver) { + a.observer = observer +} + // Modified `newAzureDNSDsp` to maintain backward compatibility with the new OIDC support. func newAzureDNSDsp(conf map[string]string, metadata json.RawMessage) (providers.DNSServiceProvider, error) { return newAzureDNS(conf, metadata) @@ -261,8 +267,7 @@ func (a *azurednsProvider) getNameNonDefaultNameServers(domain string, nss []str if recordsErr != nil { err := recordsErr - var e *azcore.ResponseError - if errors.As(err, &e) { + if e, ok := errors.AsType[*azcore.ResponseError](err); ok { if e.StatusCode == http.StatusTooManyRequests { waitTime = waitTime * 2 if waitTime > 300 { @@ -291,9 +296,7 @@ func (a *azurednsProvider) getNameNonDefaultNameServers(domain string, nss []str // GetZoneRecords gets the records of a zone and returns them in RecordConfig format. func (a *azurednsProvider) GetZoneRecords(dc *models.DomainConfig) (models.Records, error) { - domain := dc.Name - - existingRecords, _, _, err := a.getExistingRecords(domain) + existingRecords, _, _, err := a.getExistingRecords(dc) if err != nil { return nil, err } @@ -301,7 +304,8 @@ func (a *azurednsProvider) GetZoneRecords(dc *models.DomainConfig) (models.Recor return existingRecords, nil } -func (a *azurednsProvider) getExistingRecords(domain string) (models.Records, []*adns.RecordSet, string, error) { +func (a *azurednsProvider) getExistingRecords(dc *models.DomainConfig) (models.Records, []*adns.RecordSet, string, error) { + domain := dc.Name zone, ok := a.zones[domain] if !ok { return nil, nil, "", errNoExist{domain} @@ -314,7 +318,10 @@ func (a *azurednsProvider) getExistingRecords(domain string) (models.Records, [] var existingRecords models.Records for _, set := range rawRecords { - existingRecords = append(existingRecords, nativeToRecords(set, zoneName)...) + before := providers.BeginToRC(a.observer, "nativeToRecords", set) + records := nativeToRecords(set, dc) + providers.EndToRC(a.observer, "nativeToRecords", before, set, records, nil) + existingRecords = append(existingRecords, records...) } return existingRecords, rawRecords, zoneName, nil @@ -487,139 +494,97 @@ func safeTarget(t *string) string { return *t } -func nativeToRecords(set *adns.RecordSet, origin string) []*models.RecordConfig { - var results []*models.RecordConfig +func nativeToRecords(set *adns.RecordSet, dc *models.DomainConfig) models.Records { + var results models.Records + label := dc.LabelFromFQDNWithDot(*set.Properties.Fqdn) + ttl := uint32(*set.Properties.TTL) switch rtype := *set.Type; rtype { case "Microsoft.Network/dnszones/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) + rc, _ := dc.NewRecordConfig(label, ttl, dnsv2.TypeA, *rec.IPv4Address) + rc.Original = set results = append(results, rc) } } else { // This is an AZURE_ALIAS of an "A" record. - rc := &models.RecordConfig{ - Type: "AZURE_ALIAS", - TTL: uint32(*set.Properties.TTL), - AzureAlias: map[string]string{ - "type": "A", - }, - Original: set, - } - rc.SetLabelFromFQDN(*set.Properties.Fqdn, origin) - _ = rc.SetTarget(safeTarget(set.Properties.TargetResource.ID)) + rc, _ := dc.NewRecordConfig(label, ttl, privatetypes.TypeAZUREALIAS, "A", safeTarget(set.Properties.TargetResource.ID)) + rc.Original = set results = append(results, rc) } case "Microsoft.Network/dnszones/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) + rc, _ := dc.NewRecordConfig(label, ttl, dnsv2.TypeAAAA, *rec.IPv6Address) + rc.Original = set results = append(results, rc) } } else { // This is an AZURE_ALIAS of an "AAAA" record. - rc := &models.RecordConfig{ - Type: "AZURE_ALIAS", - TTL: uint32(*set.Properties.TTL), - AzureAlias: map[string]string{ - "type": "AAAA", - }, - Original: set, - } - rc.SetLabelFromFQDN(*set.Properties.Fqdn, origin) - _ = rc.SetTarget(safeTarget(set.Properties.TargetResource.ID)) + rc, _ := dc.NewRecordConfig(label, ttl, privatetypes.TypeAZUREALIAS, "AAAA", safeTarget(set.Properties.TargetResource.ID)) + rc.Original = set results = append(results, rc) } case "Microsoft.Network/dnszones/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) + rc, _ := dc.NewRecordConfig(label, ttl, dnsv2.TypeCNAME, *set.Properties.CnameRecord.Cname) + rc.Original = set results = append(results, rc) } else { // This is an AZURE_ALIAS of a "CNAME" record. - rc := &models.RecordConfig{ - Type: "AZURE_ALIAS", - TTL: uint32(*set.Properties.TTL), - AzureAlias: map[string]string{ - "type": "CNAME", - }, - Original: set, - } - rc.SetLabelFromFQDN(*set.Properties.Fqdn, origin) - _ = rc.SetTarget(safeTarget(set.Properties.TargetResource.ID)) + rc, _ := dc.NewRecordConfig(label, ttl, privatetypes.TypeAZUREALIAS, "CNAME", safeTarget(set.Properties.TargetResource.ID)) + rc.Original = set results = append(results, rc) } case "Microsoft.Network/dnszones/NS": for _, rec := range set.Properties.NsRecords { - rc := &models.RecordConfig{TTL: uint32(*set.Properties.TTL), Original: set} - rc.SetLabelFromFQDN(*set.Properties.Fqdn, origin) - rc.Type = "NS" - _ = rc.SetTarget(*rec.Nsdname) + rc, _ := dc.NewRecordConfig(label, ttl, dnsv2.TypeNS, *rec.Nsdname) + rc.Original = set results = append(results, rc) } case "Microsoft.Network/dnszones/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) + rc, _ := dc.NewRecordConfig(label, ttl, dnsv2.TypePTR, *rec.Ptrdname) + rc.Original = set results = append(results, rc) } case "Microsoft.Network/dnszones/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("") + rc, _ := dc.NewRecordConfig(label, ttl, dnsv2.TypeTXT, "") + rc.Original = set 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) + rc, _ := dc.NewRecordConfig(label, ttl, dnsv2.TypeTXT, strings.Join(txts, "")) + rc.Original = set results = append(results, rc) } } case "Microsoft.Network/dnszones/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) + rc, _ := dc.NewRecordConfig(label, ttl, dnsv2.TypeMX, uint16(*rec.Preference), *rec.Exchange) + rc.Original = set results = append(results, rc) } case "Microsoft.Network/dnszones/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) + rc, _ := dc.NewRecordConfig(label, ttl, dnsv2.TypeSRV, uint16(*rec.Priority), uint16(*rec.Weight), uint16(*rec.Port), *rec.Target) + rc.Original = set results = append(results, rc) } case "Microsoft.Network/dnszones/CAA": for _, rec := range set.Properties.CaaRecords { - rc := &models.RecordConfig{TTL: uint32(*set.Properties.TTL), Original: set} - rc.SetLabelFromFQDN(*set.Properties.Fqdn, origin) - rc.Type = "CAA" - _ = rc.SetTargetCAA(uint8(*rec.Flags), *rec.Tag, *rec.Value) + rc, _ := dc.NewRecordConfig(label, ttl, dnsv2.TypeCAA, uint8(*rec.Flags), *rec.Tag, *rec.Value) + rc.Original = set results = append(results, rc) } case "Microsoft.Network/dnszones/SOA": @@ -631,7 +596,7 @@ func nativeToRecords(set *adns.RecordSet, origin string) []*models.RecordConfig // NOTE recordToNativeDiff2 is really "convert []RecordConfig to rrset". -func (a *azurednsProvider) recordToNativeDiff2(recordKey models.RecordKey, recordConfig []*models.RecordConfig) (*adns.RecordSet, adns.RecordType, error) { +func (a *azurednsProvider) recordToNativeDiff2(recordKey models.RecordKey, recordConfig models.Records) (*adns.RecordSet, adns.RecordType, error) { recordKeyType := recordKey.Type // if recordKeyType == "AZURE_ALIAS" { // fmt.Fprintf(os.Stderr, "DEBUG: XXXXXXXXXXXXXXXXXXXXXXX %v\n", recordKeyType) @@ -641,15 +606,15 @@ func (a *azurednsProvider) recordToNativeDiff2(recordKey models.RecordKey, recor for _, rec := range recordConfig { switch recordKeyType { case "A": - recordSet.Properties.ARecords = append(recordSet.Properties.ARecords, &adns.ARecord{IPv4Address: new(rec.GetTargetField())}) + recordSet.Properties.ARecords = append(recordSet.Properties.ARecords, &adns.ARecord{IPv4Address: new(rec.AsA().Addr.String())}) case "AAAA": - recordSet.Properties.AaaaRecords = append(recordSet.Properties.AaaaRecords, &adns.AaaaRecord{IPv6Address: new(rec.GetTargetField())}) + recordSet.Properties.AaaaRecords = append(recordSet.Properties.AaaaRecords, &adns.AaaaRecord{IPv6Address: new(rec.AsAAAA().Addr.String())}) case "CNAME": - recordSet.Properties.CnameRecord = &adns.CnameRecord{Cname: new(rec.GetTargetField())} + recordSet.Properties.CnameRecord = &adns.CnameRecord{Cname: new(rec.AsCNAME().Target)} case "NS": - recordSet.Properties.NsRecords = append(recordSet.Properties.NsRecords, &adns.NsRecord{Nsdname: new(rec.GetTargetField())}) + recordSet.Properties.NsRecords = append(recordSet.Properties.NsRecords, &adns.NsRecord{Nsdname: new(rec.AsNS().Ns)}) case "PTR": - recordSet.Properties.PtrRecords = append(recordSet.Properties.PtrRecords, &adns.PtrRecord{Ptrdname: new(rec.GetTargetField())}) + recordSet.Properties.PtrRecords = append(recordSet.Properties.PtrRecords, &adns.PtrRecord{Ptrdname: new(rec.AsPTR().Ptr)}) case "TXT": // When a TXT record is empty, Azure requires that the .Properties.TxtRecords have no value, not "". Therefore we skip this. if rec.GetTargetTXTSegmentCount() != 1 || rec.GetTargetTXTSegmented()[0] != "" { @@ -660,14 +625,18 @@ func (a *azurednsProvider) recordToNativeDiff2(recordKey models.RecordKey, recor recordSet.Properties.TxtRecords = append(recordSet.Properties.TxtRecords, &adns.TxtRecord{Value: txts}) } case "MX": - recordSet.Properties.MxRecords = append(recordSet.Properties.MxRecords, &adns.MxRecord{Exchange: new(rec.GetTargetField()), Preference: new(int32(rec.MxPreference))}) + f := rec.AsMX() + recordSet.Properties.MxRecords = append(recordSet.Properties.MxRecords, &adns.MxRecord{Exchange: new(f.Mx), Preference: new(int32(f.Preference))}) case "SRV": - recordSet.Properties.SrvRecords = append(recordSet.Properties.SrvRecords, &adns.SrvRecord{Target: new(rec.GetTargetField()), Port: new(int32(rec.SrvPort)), Weight: new(int32(rec.SrvWeight)), Priority: new(int32(rec.SrvPriority))}) + f := rec.AsSRV() + recordSet.Properties.SrvRecords = append(recordSet.Properties.SrvRecords, &adns.SrvRecord{Target: new(f.Target), Port: new(int32(f.Port)), Weight: new(int32(f.Weight)), Priority: new(int32(f.Priority))}) case "CAA": - recordSet.Properties.CaaRecords = append(recordSet.Properties.CaaRecords, &adns.CaaRecord{Value: new(rec.GetTargetField()), Tag: new(rec.CaaTag), Flags: new(int32(rec.CaaFlag))}) + f := rec.AsCAA() + recordSet.Properties.CaaRecords = append(recordSet.Properties.CaaRecords, &adns.CaaRecord{Value: new(f.Value), Tag: new(f.Tag), Flags: new(int32(f.Flag))}) case "AZURE_ALIAS_A", "AZURE_ALIAS_AAAA", "AZURE_ALIAS_CNAME": - recordSet.Type = new(rec.AzureAlias["type"]) - recordSet.Properties.TargetResource = new(adns.SubResource{ID: new(rec.GetTargetField())}) + f := rec.AsAZUREALIAS() + recordSet.Type = new(f.AliasType) + recordSet.Properties.TargetResource = new(adns.SubResource{ID: new(f.Target)}) default: return nil, adns.RecordTypeA, fmt.Errorf("recordToNativeDiff2 RTYPE %v UNIMPLEMENTED", recordKeyType) // ands.A is a placeholder @@ -698,8 +667,7 @@ func (a *azurednsProvider) fetchRecordSets(zoneName string) ([]*adns.RecordSet, if recordsErr != nil { err := recordsErr - var e *azcore.ResponseError - if errors.As(err, &e) { + if e, ok := errors.AsType[*azcore.ResponseError](err); ok { if e.StatusCode == http.StatusTooManyRequests { waitTime = waitTime * 2 if waitTime > 300 { @@ -744,8 +712,8 @@ func deduplicateNameServerTargets(newRecs models.Records) models.Records { dedupedMap := make(map[string]bool) var deduped models.Records for _, rec := range newRecs { - if !dedupedMap[rec.GetTargetField()] { - dedupedMap[rec.GetTargetField()] = true + if !dedupedMap[rec.AsNS().Ns] { + dedupedMap[rec.AsNS().Ns] = true deduped = append(deduped, rec) } } diff --git a/providers/azuredns/azureDnsProvider_test.go b/providers/azuredns/azureDnsProvider_test.go index 9dedf8b6c5..fff9d225fc 100644 --- a/providers/azuredns/azureDnsProvider_test.go +++ b/providers/azuredns/azureDnsProvider_test.go @@ -7,9 +7,99 @@ import ( "strings" "testing" + dnsv2 "codeberg.org/miekg/dns" "github.com/Azure/azure-sdk-for-go/sdk/azcore" + adns "github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/dns/armdns" + "github.com/DNSControl/dnscontrol/v5/models" ) +func TestNativeToRecordsUsesV3RecordConfig(t *testing.T) { + dc := models.MustNewDomainConfig("example.com") + tests := []struct { + name string + azureType string + properties func() *adns.RecordSetProperties + want *models.RecordConfig + }{ + { + name: "NS", + azureType: "Microsoft.Network/dnszones/NS", + properties: func() *adns.RecordSetProperties { + return &adns.RecordSetProperties{NsRecords: []*adns.NsRecord{{Nsdname: new("ns1.example.net.")}}} + }, + want: dc.MustNewRecordConfig("www", 300, dnsv2.TypeNS, "ns1.example.net."), + }, + { + name: "PTR", + azureType: "Microsoft.Network/dnszones/PTR", + properties: func() *adns.RecordSetProperties { + return &adns.RecordSetProperties{PtrRecords: []*adns.PtrRecord{{Ptrdname: new("host.example.net.")}}} + }, + want: dc.MustNewRecordConfig("www", 300, dnsv2.TypePTR, "host.example.net."), + }, + { + name: "empty TXT record set", + azureType: "Microsoft.Network/dnszones/TXT", + properties: func() *adns.RecordSetProperties { + return &adns.RecordSetProperties{} + }, + want: dc.MustNewRecordConfig("www", 300, dnsv2.TypeTXT, ""), + }, + { + name: "segmented TXT", + azureType: "Microsoft.Network/dnszones/TXT", + properties: func() *adns.RecordSetProperties { + return &adns.RecordSetProperties{TxtRecords: []*adns.TxtRecord{{Value: []*string{new("first"), new("second")}}}} + }, + want: dc.MustNewRecordConfig("www", 300, dnsv2.TypeTXT, "firstsecond"), + }, + { + name: "MX", + azureType: "Microsoft.Network/dnszones/MX", + properties: func() *adns.RecordSetProperties { + return &adns.RecordSetProperties{MxRecords: []*adns.MxRecord{{Preference: new(int32(10)), Exchange: new("mail.example.net.")}}} + }, + want: dc.MustNewRecordConfig("www", 300, dnsv2.TypeMX, uint16(10), "mail.example.net."), + }, + { + name: "SRV", + azureType: "Microsoft.Network/dnszones/SRV", + properties: func() *adns.RecordSetProperties { + return &adns.RecordSetProperties{SrvRecords: []*adns.SrvRecord{{Priority: new(int32(1)), Weight: new(int32(2)), Port: new(int32(443)), Target: new("service.example.net.")}}} + }, + want: dc.MustNewRecordConfig("www", 300, dnsv2.TypeSRV, uint16(1), uint16(2), uint16(443), "service.example.net."), + }, + { + name: "CAA", + azureType: "Microsoft.Network/dnszones/CAA", + properties: func() *adns.RecordSetProperties { + return &adns.RecordSetProperties{CaaRecords: []*adns.CaaRecord{{Flags: new(int32(0)), Tag: new("issue"), Value: new("letsencrypt.org")}}} + }, + want: dc.MustNewRecordConfig("www", 300, dnsv2.TypeCAA, uint8(0), "issue", "letsencrypt.org"), + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + properties := tt.properties() + properties.Fqdn = new("www.example.com.") + properties.TTL = new(int64(300)) + set := &adns.RecordSet{Type: new(tt.azureType), Properties: properties} + + got := nativeToRecords(set, dc) + if len(got) != 1 { + t.Fatalf("nativeToRecords() returned %d records, want 1", len(got)) + } + if got[0].NameFQDN != tt.want.NameFQDN || got[0].TTL != tt.want.TTL || got[0].TypeNum != tt.want.TypeNum || got[0].GetRDATA().String() != tt.want.GetRDATA().String() { + t.Errorf("nativeToRecords() = %s %d IN %s %s, want %s %d IN %s %s", got[0].NameFQDN, got[0].TTL, got[0].Type, got[0].GetRDATA(), tt.want.NameFQDN, tt.want.TTL, tt.want.Type, tt.want.GetRDATA()) + } + if got[0].Original != set { + t.Error("nativeToRecords() did not preserve the original Azure record set") + } + }) + } +} + func TestRetryableRecordSetMutation(t *testing.T) { tests := []struct { name string diff --git a/providers/azuredns/convert_golden_test.go b/providers/azuredns/convert_golden_test.go new file mode 100644 index 0000000000..f045abd960 --- /dev/null +++ b/providers/azuredns/convert_golden_test.go @@ -0,0 +1,16 @@ +package azuredns + +import ( + "testing" + + adns "github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/dns/armdns" + "github.com/DNSControl/dnscontrol/v5/models" + "github.com/DNSControl/dnscontrol/v5/pkg/providergolden" +) + +func TestNativeToRecordsGolden(t *testing.T) { + providergolden.CheckToRC(t, "nativeToRecords", + func(dc *models.DomainConfig, native adns.RecordSet) (models.Records, error) { + return nativeToRecords(&native, dc), nil + }) +} diff --git a/providers/azuredns/test_data/expected_torc_output_nativeToRecords_dnscontrol-azure.com.records b/providers/azuredns/test_data/expected_torc_output_nativeToRecords_dnscontrol-azure.com.records new file mode 100644 index 0000000000..30aae849ab --- /dev/null +++ b/providers/azuredns/test_data/expected_torc_output_nativeToRecords_dnscontrol-azure.com.records @@ -0,0 +1,246 @@ +1 foo254 300 IN TXT "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" +2 www 400 IN A 2.2.2.2 +2 www 400 IN A 5.6.7.8 +3 testcname 300 IN CNAME www.yahoo.com. +4 @ 300 IN A 2.2.2.2 +5 @ 300 IN A 1.2.3.2 +6 foo 300 IN CNAME google.com. +7 foo764 300 IN TXT "GGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGG" "GGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGG" "GGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGG" +8 foosq 300 IN TXT "quo'te" +9 _sip._tcp 300 IN SRV 5 6 7 foo.com. +10 www 300 IN A 1.1.1.1 +11 foo.bat 300 IN A 1.2.3.4 +11 foo.bat 300 IN A 2.3.4.5 +12 foo 300 IN CNAME google2.com. +13 testdefined 300 IN A 9.9.9.9 +14 xn--ndaaa 300 IN A 1.2.3.4 +15 _sip._tcp 300 IN SRV 5 6 7 foo.com. +15 _sip._tcp 300 IN SRV 5 60 70 foo2.com. +15 _sip._tcp 300 IN SRV 15 65 75 foo3.com. +16 nmx 300 IN MX 0 . +17 @ 300 IN NS ns1-06.azure-dns.com. +17 @ 300 IN NS ns2-06.azure-dns.net. +17 @ 300 IN NS ns3-06.azure-dns.org. +17 @ 300 IN NS ns4-06.azure-dns.info. +18 foo 300 IN A 1.1.1.1 +18 foo 300 IN A 11.11.11.11 +19 @ 300 IN CAA 0 issuewild "letsencrypt.org" +20 @ 300 IN A 4.4.4.4 +21 foo 300 IN MX 8 dnscontrol-azure.com. +22 fooosbs2 300 IN TXT "2back\\\\slash" +23 xn--o-0gab 300 IN CNAME xn--ndaaa.xn--vhquv. +24 foosc2 300 IN TXT "wssemi ; colon" +25 _sip._tcp 300 IN SRV 15 65 75 foo4.com. +25 _sip._tcp 300 IN SRV 52 62 7 foo.com. +26 @ 1000 IN A 8.8.8.8 +27 www 300 IN A 1.1.1.1 +28 www 300 IN A 1.1.1.1 +28 www 300 IN A 2.2.2.2 +29 foo766 300 IN TXT "JJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJ" "JJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJ" "JJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJ" "J" +30 testignore 300 IN A 8.8.8.8 +31 foo 300 IN NS dnscontrol-azure.com. +32 foo 300 IN TXT "simple" +33 foo 300 IN A 1.1.1.1 +33 foo 300 IN A 12.12.12.12 +34 foo 300 IN A 1.2.3.4 +34 foo 300 IN A 2.3.4.5 +35 4 300 IN PTR foo.com. +36 _sip._tcp 333 IN SRV 5 6 7 foo.com. +37 foo.bat 300 IN TXT "simple" +38 quux.a 300 IN A 2.3.4.5 +39 4 300 IN PTR bar.com. +40 foosp 300 IN TXT "with spaces" +41 foo 300 IN TXT "v=spf1 ip4:99.99.99.99 -all" +42 xyz 300 IN NS ns2.foo.com. +43 foo.a 300 IN A 1.2.3.4 +44 foo 300 IN TXT "simple" +45 mail 300 IN CNAME ghs.googlehosted.com. +46 foo 300 IN CNAME dnscontrol-azure.com. +47 @ 300 IN NS ns1-06.azure-dns.com. +47 @ 300 IN NS ns1.foo.com. +47 @ 300 IN NS ns2-06.azure-dns.net. +47 @ 300 IN NS ns2.foo.com. +47 @ 300 IN NS ns3-06.azure-dns.org. +47 @ 300 IN NS ns4-06.azure-dns.info. +48 bar.a 300 IN AZURE_ALIAS A "/subscriptions/02efc9e4-732d-4a8d-8b82-5b37e10eb89d/resourceGroups/dnscontroltest/providers/Microsoft.Network/dnszones/dnscontrol-azure.com/A/quux.a" +49 foodqs 300 IN TXT "right\"" +50 testa 999 IN A 1.1.1.1 +51 testtxt 300 IN TXT "simple" +52 www 400 IN A 5.6.7.8 +53 foo 300 IN A 1.2.3.4 +53 foo 300 IN A 3.4.5.6 +54 www 300 IN A 1.2.3.9 +55 fooosbs3 300 IN TXT "3back\\\\\\slash" +56 foo 300 IN AAAA 2003:dd:d7ff::fe71:aaaa +57 nmx 300 IN MX 3 nmx.dnscontrol-azure.com. +57 nmx 300 IN MX 9 www.dnscontrol-azure.com. +58 testaaaa 300 IN AAAA 2607:f8b0:4006:820::2006 +59 foo 300 IN CNAME redact1.acm-validations.aws. +60 bar 300 IN A 1.2.3.4 +61 www 300 IN A 1.1.1.1 +61 www 300 IN A 2.2.2.2 +61 www 300 IN A 3.3.3.3 +62 @ 300 IN CAA 0 issue "letsencrypt.org" +63 @ 666 IN A 8.8.8.8 +64 testa 300 IN A 1.1.1.1 +65 @ 300 IN NS ns1-06.azure-dns.com. +65 @ 300 IN NS ns2-06.azure-dns.net. +65 @ 300 IN NS ns3-06.azure-dns.org. +65 @ 300 IN NS ns4-06.azure-dns.info. +66 bar.bat 300 IN A 5.5.5.5 +67 dyndns-city1 300 IN A 91.42.1.1 +68 foodqs 300 IN TXT "in\"ter\"ior" +69 @ 300 IN MX 5 bar.com. +70 decoy 300 IN A 3.3.3.3 +71 testcname 300 IN CNAME foo.dnscontrol-azure.com. +72 foo510 300 IN TXT "EEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE" "EEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE" +73 zzz 300 IN AAAA 2003:dd:d7ff::fe71:cccc +74 decoy 300 IN A 2.2.2.2 +75 @ 300 IN A 1.2.3.4 +75 @ 300 IN A 2.3.4.5 +76 fooosbs4 300 IN TXT "4back\\\\\\\\slash" +77 www 300 IN A 1.2.3.4 +77 www 300 IN A 5.6.7.8 +78 foo0 300 IN TXT "" +79 fooosbs1 300 IN TXT "1back\\slash" +80 foo 300 IN A 1.2.3.4 +81 @ 300 IN A 1.2.3.4 +82 @ 300 IN MX 0 . +83 @ 300 IN CAA 128 issue "letsencrypt.org" +84 testmx 300 IN MX 5 foo.com. +84 testmx 300 IN MX 100 bar.com. +85 foo 300 IN A 1.1.1.1 +85 foo 300 IN A 14.14.14.14 +86 foo 300 IN A 1.2.3.4 +86 foo 300 IN A 3.4.5.6 +87 @ 300 IN CAA 0 issue "letsencrypt.org" +88 bar.cname 300 IN AZURE_ALIAS CNAME "/subscriptions/02efc9e4-732d-4a8d-8b82-5b37e10eb89d/resourceGroups/dnscontroltest/providers/Microsoft.Network/dnszones/dnscontrol-azure.com/CNAME/foo.cname" +89 @ 300 IN MX 2 dnscontrol-azure.com. +89 @ 300 IN MX 8 www.dnscontrol-azure.com. +90 bar 300 IN A 5.5.5.5 +91 xn--fiq228c 300 IN A 1.2.3.4 +92 testmx 300 IN MX 100 foo.com. +93 _sip._tcp 300 IN SRV 5 6 7 foo.com. +93 _sip._tcp 300 IN SRV 15 65 75 foo4.com. +94 www 300 IN A 5.5.5.5 +95 quux.cname 300 IN CNAME google2.com. +96 nmx 300 IN A 1.2.3.3 +97 foo 300 IN A 1.1.1.1 +97 foo 300 IN A 13.13.13.13 +98 testmx 300 IN MX 5 foo.com. +98 testmx 300 IN MX 100 bar.com. +99 foo 300 IN A 2.3.4.5 +100 www 300 IN A 2.2.2.2 +100 www 300 IN A 5.6.7.8 +101 final 300 IN TXT "TestDNSProviders was successful!" +102 @ 300 IN NS ns1-06.azure-dns.com. +102 @ 300 IN NS ns1.foo.com. +102 @ 300 IN NS ns2-06.azure-dns.net. +102 @ 300 IN NS ns3-06.azure-dns.org. +102 @ 300 IN NS ns4-06.azure-dns.info. +103 foo 300 IN MX 10 foo.dnscontrol-azure.com. +103 foo 300 IN MX 20 bar.dnscontrol-azure.com. +104 @ 300 IN TXT "asimple" +105 testcname 300 IN CNAME www.google.com. +106 foo 300 IN A 1.2.3.4 +106 foo 300 IN A 2.3.4.5 +107 testmx 300 IN MX 5 foo.com. +108 mail 300 IN CNAME ghs.googlehosted.com. +109 testmx 300 IN MX 5 foo.com. +110 testa 333 IN A 1.1.1.1 +111 foo 300 IN A 2.3.4.5 +111 foo 300 IN A 8.8.8.8 +112 bar.cname 300 IN AZURE_ALIAS CNAME "/subscriptions/02efc9e4-732d-4a8d-8b82-5b37e10eb89d/resourceGroups/dnscontroltest/providers/Microsoft.Network/dnszones/dnscontrol-azure.com/CNAME/foo.cname" +113 @ 300 IN MX 0 . +114 _sip._tcp 300 IN SRV 5 6 7 foo.com. +114 _sip._tcp 300 IN SRV 15 65 75 foo3.com. +115 bar.a 300 IN AZURE_ALIAS A "/subscriptions/02efc9e4-732d-4a8d-8b82-5b37e10eb89d/resourceGroups/dnscontroltest/providers/Microsoft.Network/dnszones/dnscontrol-azure.com/A/foo.a" +116 bar 300 IN CNAME redact2.acm-validations.aws. +118 xn--ndaaa 300 IN A 2.2.2.2 +119 @ 300 IN TXT "simple" +120 @ 300 IN A 1.2.3.4 +121 @ 300 IN NS ns1-06.azure-dns.com. +121 @ 300 IN NS ns1.example.com. +121 @ 300 IN NS ns2-06.azure-dns.net. +121 @ 300 IN NS ns2.example.com. +121 @ 300 IN NS ns3-06.azure-dns.org. +121 @ 300 IN NS ns4-06.azure-dns.info. +122 @ 300 IN NS ns1-06.azure-dns.com. +122 @ 300 IN NS ns2-06.azure-dns.net. +122 @ 300 IN NS ns3-06.azure-dns.org. +122 @ 300 IN NS ns4-06.azure-dns.info. +123 foo 300 IN A 1.2.3.4 +124 @ 300 IN MX 5 foo.com. +125 _sip._tcp 300 IN SRV 15 65 75 foo4.com. +125 _sip._tcp 300 IN SRV 52 62 72 foo.com. +126 foodqs 300 IN TXT "\"left" +127 a 300 IN CNAME xn--ndaaa.com. +128 foo 300 IN A 2.3.4.5 +128 foo 300 IN A 3.4.5.6 +129 foo765 300 IN TXT "HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH" "HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH" "HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH" +130 www 700 IN A 1.2.3.4 +130 www 700 IN A 5.6.7.8 +131 foobt 300 IN TXT "blah`blah" +132 testaaaa 300 IN AAAA 2607:f8b0:4006:820::2013 +133 foo255 300 IN TXT "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" +134 @ 500 IN A 8.8.8.8 +135 foo 300 IN A 1.2.3.4 +136 dyndns-city2 300 IN AAAA 2003:dd:d7ff::fe71:ce78 +137 foosc1 300 IN TXT "semi;colon" +138 foo511 300 IN TXT "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF" "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF" "F" +139 www 300 IN A 1.1.1.1 +140 final 300 IN TXT "TestDNSProviders was successful!" +141 foo 300 IN MX 10 aspmx.l.google.com. +141 foo 300 IN MX 20 alt1.aspmx.l.google.com. +142 xyz 300 IN NS ns1.foo.com. +142 xyz 300 IN NS ns2.foo.com. +143 foo.cname 300 IN CNAME google.com. +144 bar.cname 300 IN AZURE_ALIAS CNAME "/subscriptions/02efc9e4-732d-4a8d-8b82-5b37e10eb89d/resourceGroups/dnscontroltest/providers/Microsoft.Network/dnszones/dnscontrol-azure.com/CNAME/quux.cname" +145 foows1 300 IN TXT "trailingws " +146 @ 300 IN CAA 0 issuewild ";" +147 _sip._tcp 4400 IN SRV 5 6 7 foo.com. +148 www 300 IN A 1.2.3.8 +149 testmx 300 IN MX 5 foo.com. +150 foo256 300 IN TXT "CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC" "C" +151 _sip._tcp 300 IN SRV 15 65 75 foo4.com. +151 _sip._tcp 300 IN SRV 52 6 7 foo.com. +152 _sip._tcp 300 IN SRV 5 6 7 foo.com. +152 _sip._tcp 300 IN SRV 5 60 70 foo2.com. +153 dyndns-city1 300 IN AAAA 2003:dd:d7ff::fe71:ce77 +154 _sip._tcp 300 IN SRV 15 65 75 . +155 @ 300 IN CAA 0 issuewild "example.com" +156 @ 300 IN NS ns1-06.azure-dns.com. +156 @ 300 IN NS ns1.example.com. +156 @ 300 IN NS ns2-06.azure-dns.net. +156 @ 300 IN NS ns3-06.azure-dns.org. +156 @ 300 IN NS ns4-06.azure-dns.info. +157 foodq 300 IN TXT "in\"side" +158 mail.bat 300 IN CNAME ghs.googlehosted.com. +159 www 300 IN A 1.1.1.1 +159 www 300 IN A 2.2.2.2 +159 www 300 IN A 3.3.3.3 +160 testmx 300 IN MX 5 bar.com. +161 foo509 300 IN TXT "DDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDD" "DDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDD" +162 foo 300 IN A 4.5.6.7 +163 @ 300 IN A 2.2.2.2 +164 @ 300 IN CAA 0 issue "letsencrypt.org; validationmethods=dns-01; accounturi=https://acme-v02.api.letsencrypt.org/acme/acct/1234" +165 * 300 IN A 3.3.3.3 +166 zzz 300 IN A 3.3.3.3 +166 zzz 300 IN A 4.4.4.4 +167 bar 300 IN MX 5 bar.com. +168 testdefined 300 IN A 2.2.2.2 +169 bar.a 300 IN AZURE_ALIAS A "/subscriptions/02efc9e4-732d-4a8d-8b82-5b37e10eb89d/resourceGroups/dnscontroltest/providers/Microsoft.Network/dnszones/dnscontrol-azure.com/A/foo.a" +170 testa 300 IN A 3.3.3.3 +171 foo 300 IN MX 5 mx.google.com. +172 foo 300 IN A 1.2.3.4 +173 testtxt 300 IN TXT "changed" +174 @ 300 IN A 1.2.3.4 +175 bar 300 IN A 5.5.5.5 +176 foo 300 IN A 2.3.4.5 +176 foo 300 IN A 8.8.8.8 +177 decoy 300 IN A 1.1.1.1 +178 dyndns-city2 300 IN A 91.42.1.2 +179 foo 300 IN A 1.2.3.4 +180 foo 300 IN A 1.1.1.1 +180 foo 300 IN A 10.10.10.10 +181 nmx 300 IN MX 0 . diff --git a/providers/azuredns/test_data/meta.json b/providers/azuredns/test_data/meta.json new file mode 100644 index 0000000000..783949b8ba --- /dev/null +++ b/providers/azuredns/test_data/meta.json @@ -0,0 +1,11 @@ +{ + "version": 1, + "recordings": [ + { + "domain": "dnscontrol-azure.com", + "to_rc": [ + "nativeToRecords" + ] + } + ] +} diff --git a/providers/azuredns/test_data/recorded_torc_input_nativeToRecords_dnscontrol-azure.com.json b/providers/azuredns/test_data/recorded_torc_input_nativeToRecords_dnscontrol-azure.com.json new file mode 100644 index 0000000000..6184bb1fbb --- /dev/null +++ b/providers/azuredns/test_data/recorded_torc_input_nativeToRecords_dnscontrol-azure.com.json @@ -0,0 +1,3947 @@ +[ + { + "index": 1, + "value": { + "etag": "01df182f-efbc-4a5d-ba8b-8c3e8b0ab1ed", + "id": "/subscriptions/02efc9e4-732d-4a8d-8b82-5b37e10eb89d/resourceGroups/dnscontroltest/providers/Microsoft.Network/dnszones/dnscontrol-azure.com/TXT/foo254", + "name": "foo254", + "properties": { + "TTL": 300, + "TXTRecords": [ + { + "value": [ + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" + ] + } + ], + "fqdn": "foo254.dnscontrol-azure.com.", + "provisioningState": "Succeeded", + "targetResource": {} + }, + "type": "Microsoft.Network/dnszones/TXT" + } + }, + { + "index": 2, + "value": { + "etag": "02a7a96a-279a-4dea-8bf3-d5f217e5e934", + "id": "/subscriptions/02efc9e4-732d-4a8d-8b82-5b37e10eb89d/resourceGroups/dnscontroltest/providers/Microsoft.Network/dnszones/dnscontrol-azure.com/A/www", + "name": "www", + "properties": { + "ARecords": [ + { + "ipv4Address": "2.2.2.2" + }, + { + "ipv4Address": "5.6.7.8" + } + ], + "TTL": 400, + "fqdn": "www.dnscontrol-azure.com.", + "provisioningState": "Succeeded", + "targetResource": {} + }, + "type": "Microsoft.Network/dnszones/A" + } + }, + { + "index": 3, + "value": { + "etag": "03ed9f28-833c-437a-a41d-002f03cc412f", + "id": "/subscriptions/02efc9e4-732d-4a8d-8b82-5b37e10eb89d/resourceGroups/dnscontroltest/providers/Microsoft.Network/dnszones/dnscontrol-azure.com/CNAME/testcname", + "name": "testcname", + "properties": { + "CNAMERecord": { + "cname": "www.yahoo.com." + }, + "TTL": 300, + "fqdn": "testcname.dnscontrol-azure.com.", + "provisioningState": "Succeeded", + "targetResource": {} + }, + "type": "Microsoft.Network/dnszones/CNAME" + } + }, + { + "index": 4, + "value": { + "etag": "071a486d-143b-4227-bae4-9ba516e60607", + "id": "/subscriptions/02efc9e4-732d-4a8d-8b82-5b37e10eb89d/resourceGroups/dnscontroltest/providers/Microsoft.Network/dnszones/dnscontrol-azure.com/A/@", + "name": "@", + "properties": { + "ARecords": [ + { + "ipv4Address": "2.2.2.2" + } + ], + "TTL": 300, + "fqdn": "dnscontrol-azure.com.", + "provisioningState": "Succeeded", + "targetResource": {} + }, + "type": "Microsoft.Network/dnszones/A" + } + }, + { + "index": 5, + "value": { + "etag": "084eab9f-ae04-462c-b6ce-0436b8595d49", + "id": "/subscriptions/02efc9e4-732d-4a8d-8b82-5b37e10eb89d/resourceGroups/dnscontroltest/providers/Microsoft.Network/dnszones/dnscontrol-azure.com/A/@", + "name": "@", + "properties": { + "ARecords": [ + { + "ipv4Address": "1.2.3.2" + } + ], + "TTL": 300, + "fqdn": "dnscontrol-azure.com.", + "provisioningState": "Succeeded", + "targetResource": {} + }, + "type": "Microsoft.Network/dnszones/A" + } + }, + { + "index": 6, + "value": { + "etag": "09b77f76-2c71-4c8a-a24a-866f00600fa4", + "id": "/subscriptions/02efc9e4-732d-4a8d-8b82-5b37e10eb89d/resourceGroups/dnscontroltest/providers/Microsoft.Network/dnszones/dnscontrol-azure.com/CNAME/foo", + "name": "foo", + "properties": { + "CNAMERecord": { + "cname": "google.com." + }, + "TTL": 300, + "fqdn": "foo.dnscontrol-azure.com.", + "provisioningState": "Succeeded", + "targetResource": {} + }, + "type": "Microsoft.Network/dnszones/CNAME" + } + }, + { + "index": 7, + "value": { + "etag": "0adb254e-cb95-4a2c-9b5a-480a632c3a12", + "id": "/subscriptions/02efc9e4-732d-4a8d-8b82-5b37e10eb89d/resourceGroups/dnscontroltest/providers/Microsoft.Network/dnszones/dnscontrol-azure.com/TXT/foo764", + "name": "foo764", + "properties": { + "TTL": 300, + "TXTRecords": [ + { + "value": [ + "GGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGG", + "GGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGG", + "GGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGG" + ] + } + ], + "fqdn": "foo764.dnscontrol-azure.com.", + "provisioningState": "Succeeded", + "targetResource": {} + }, + "type": "Microsoft.Network/dnszones/TXT" + } + }, + { + "index": 8, + "value": { + "etag": "0c199f6a-de7b-4baa-9454-91ee72b347a3", + "id": "/subscriptions/02efc9e4-732d-4a8d-8b82-5b37e10eb89d/resourceGroups/dnscontroltest/providers/Microsoft.Network/dnszones/dnscontrol-azure.com/TXT/foosq", + "name": "foosq", + "properties": { + "TTL": 300, + "TXTRecords": [ + { + "value": [ + "quo'te" + ] + } + ], + "fqdn": "foosq.dnscontrol-azure.com.", + "provisioningState": "Succeeded", + "targetResource": {} + }, + "type": "Microsoft.Network/dnszones/TXT" + } + }, + { + "index": 9, + "value": { + "etag": "0e466815-95a5-4bed-98d3-1a9ae0713d98", + "id": "/subscriptions/02efc9e4-732d-4a8d-8b82-5b37e10eb89d/resourceGroups/dnscontroltest/providers/Microsoft.Network/dnszones/dnscontrol-azure.com/SRV/_sip._tcp", + "name": "_sip._tcp", + "properties": { + "SRVRecords": [ + { + "port": 7, + "priority": 5, + "target": "foo.com.", + "weight": 6 + } + ], + "TTL": 300, + "fqdn": "_sip._tcp.dnscontrol-azure.com.", + "provisioningState": "Succeeded", + "targetResource": {} + }, + "type": "Microsoft.Network/dnszones/SRV" + } + }, + { + "index": 10, + "value": { + "etag": "0e59a2b2-9c3d-437a-b865-f3679d0455ee", + "id": "/subscriptions/02efc9e4-732d-4a8d-8b82-5b37e10eb89d/resourceGroups/dnscontroltest/providers/Microsoft.Network/dnszones/dnscontrol-azure.com/A/www", + "name": "www", + "properties": { + "ARecords": [ + { + "ipv4Address": "1.1.1.1" + } + ], + "TTL": 300, + "fqdn": "www.dnscontrol-azure.com.", + "provisioningState": "Succeeded", + "targetResource": {} + }, + "type": "Microsoft.Network/dnszones/A" + } + }, + { + "index": 11, + "value": { + "etag": "0f9d3519-ab00-47bf-8256-c3902c103fb0", + "id": "/subscriptions/02efc9e4-732d-4a8d-8b82-5b37e10eb89d/resourceGroups/dnscontroltest/providers/Microsoft.Network/dnszones/dnscontrol-azure.com/A/foo.bat", + "name": "foo.bat", + "properties": { + "ARecords": [ + { + "ipv4Address": "1.2.3.4" + }, + { + "ipv4Address": "2.3.4.5" + } + ], + "TTL": 300, + "fqdn": "foo.bat.dnscontrol-azure.com.", + "provisioningState": "Succeeded", + "targetResource": {} + }, + "type": "Microsoft.Network/dnszones/A" + } + }, + { + "index": 12, + "value": { + "etag": "0fe5f579-6849-4b16-a845-efa544b366da", + "id": "/subscriptions/02efc9e4-732d-4a8d-8b82-5b37e10eb89d/resourceGroups/dnscontroltest/providers/Microsoft.Network/dnszones/dnscontrol-azure.com/CNAME/foo", + "name": "foo", + "properties": { + "CNAMERecord": { + "cname": "google2.com." + }, + "TTL": 300, + "fqdn": "foo.dnscontrol-azure.com.", + "provisioningState": "Succeeded", + "targetResource": {} + }, + "type": "Microsoft.Network/dnszones/CNAME" + } + }, + { + "index": 13, + "value": { + "etag": "10862186-f842-4b2c-a4f5-b2f1672d6fbe", + "id": "/subscriptions/02efc9e4-732d-4a8d-8b82-5b37e10eb89d/resourceGroups/dnscontroltest/providers/Microsoft.Network/dnszones/dnscontrol-azure.com/A/testdefined", + "name": "testdefined", + "properties": { + "ARecords": [ + { + "ipv4Address": "9.9.9.9" + } + ], + "TTL": 300, + "fqdn": "testdefined.dnscontrol-azure.com.", + "provisioningState": "Succeeded", + "targetResource": {} + }, + "type": "Microsoft.Network/dnszones/A" + } + }, + { + "index": 14, + "value": { + "etag": "10fe37a1-c193-4d7c-a0e6-3a346886f9d3", + "id": "/subscriptions/02efc9e4-732d-4a8d-8b82-5b37e10eb89d/resourceGroups/dnscontroltest/providers/Microsoft.Network/dnszones/dnscontrol-azure.com/A/xn--ndaaa", + "name": "xn--ndaaa", + "properties": { + "ARecords": [ + { + "ipv4Address": "1.2.3.4" + } + ], + "TTL": 300, + "fqdn": "xn--ndaaa.dnscontrol-azure.com.", + "provisioningState": "Succeeded", + "targetResource": {} + }, + "type": "Microsoft.Network/dnszones/A" + } + }, + { + "index": 15, + "value": { + "etag": "11ae0e42-a68b-4be6-96d2-cbb5500914b0", + "id": "/subscriptions/02efc9e4-732d-4a8d-8b82-5b37e10eb89d/resourceGroups/dnscontroltest/providers/Microsoft.Network/dnszones/dnscontrol-azure.com/SRV/_sip._tcp", + "name": "_sip._tcp", + "properties": { + "SRVRecords": [ + { + "port": 7, + "priority": 5, + "target": "foo.com.", + "weight": 6 + }, + { + "port": 70, + "priority": 5, + "target": "foo2.com.", + "weight": 60 + }, + { + "port": 75, + "priority": 15, + "target": "foo3.com.", + "weight": 65 + } + ], + "TTL": 300, + "fqdn": "_sip._tcp.dnscontrol-azure.com.", + "provisioningState": "Succeeded", + "targetResource": {} + }, + "type": "Microsoft.Network/dnszones/SRV" + } + }, + { + "index": 16, + "value": { + "etag": "12f50734-9107-49f1-aef1-8d7467a12d67", + "id": "/subscriptions/02efc9e4-732d-4a8d-8b82-5b37e10eb89d/resourceGroups/dnscontroltest/providers/Microsoft.Network/dnszones/dnscontrol-azure.com/MX/nmx", + "name": "nmx", + "properties": { + "MXRecords": [ + { + "exchange": ".", + "preference": 0 + } + ], + "TTL": 300, + "fqdn": "nmx.dnscontrol-azure.com.", + "provisioningState": "Succeeded", + "targetResource": {} + }, + "type": "Microsoft.Network/dnszones/MX" + } + }, + { + "index": 17, + "value": { + "etag": "137ddc45-adc4-4df0-a19e-9bd42812331a", + "id": "/subscriptions/02efc9e4-732d-4a8d-8b82-5b37e10eb89d/resourceGroups/dnscontroltest/providers/Microsoft.Network/dnszones/dnscontrol-azure.com/NS/@", + "name": "@", + "properties": { + "NSRecords": [ + { + "nsdname": "ns1-06.azure-dns.com." + }, + { + "nsdname": "ns2-06.azure-dns.net." + }, + { + "nsdname": "ns3-06.azure-dns.org." + }, + { + "nsdname": "ns4-06.azure-dns.info." + } + ], + "TTL": 300, + "fqdn": "dnscontrol-azure.com.", + "provisioningState": "Succeeded", + "targetResource": {} + }, + "type": "Microsoft.Network/dnszones/NS" + } + }, + { + "index": 18, + "value": { + "etag": "14e34382-44ad-4a45-a395-0b934a669b1c", + "id": "/subscriptions/02efc9e4-732d-4a8d-8b82-5b37e10eb89d/resourceGroups/dnscontroltest/providers/Microsoft.Network/dnszones/dnscontrol-azure.com/A/foo", + "name": "foo", + "properties": { + "ARecords": [ + { + "ipv4Address": "1.1.1.1" + }, + { + "ipv4Address": "11.11.11.11" + } + ], + "TTL": 300, + "fqdn": "foo.dnscontrol-azure.com.", + "provisioningState": "Succeeded", + "targetResource": {} + }, + "type": "Microsoft.Network/dnszones/A" + } + }, + { + "index": 19, + "value": { + "etag": "17b4a8eb-142b-4c26-83c8-e358a2ea4d47", + "id": "/subscriptions/02efc9e4-732d-4a8d-8b82-5b37e10eb89d/resourceGroups/dnscontroltest/providers/Microsoft.Network/dnszones/dnscontrol-azure.com/CAA/@", + "name": "@", + "properties": { + "TTL": 300, + "caaRecords": [ + { + "flags": 0, + "tag": "issuewild", + "value": "letsencrypt.org" + } + ], + "fqdn": "dnscontrol-azure.com.", + "provisioningState": "Succeeded", + "targetResource": {} + }, + "type": "Microsoft.Network/dnszones/CAA" + } + }, + { + "index": 20, + "value": { + "etag": "18d38635-74b7-4590-9282-6a3e45ee5dda", + "id": "/subscriptions/02efc9e4-732d-4a8d-8b82-5b37e10eb89d/resourceGroups/dnscontroltest/providers/Microsoft.Network/dnszones/dnscontrol-azure.com/A/@", + "name": "@", + "properties": { + "ARecords": [ + { + "ipv4Address": "4.4.4.4" + } + ], + "TTL": 300, + "fqdn": "dnscontrol-azure.com.", + "provisioningState": "Succeeded", + "targetResource": {} + }, + "type": "Microsoft.Network/dnszones/A" + } + }, + { + "index": 21, + "value": { + "etag": "195ec5a4-b7d5-4c40-956e-3f9c23aacfe9", + "id": "/subscriptions/02efc9e4-732d-4a8d-8b82-5b37e10eb89d/resourceGroups/dnscontroltest/providers/Microsoft.Network/dnszones/dnscontrol-azure.com/MX/foo", + "name": "foo", + "properties": { + "MXRecords": [ + { + "exchange": "dnscontrol-azure.com.", + "preference": 8 + } + ], + "TTL": 300, + "fqdn": "foo.dnscontrol-azure.com.", + "provisioningState": "Succeeded", + "targetResource": {} + }, + "type": "Microsoft.Network/dnszones/MX" + } + }, + { + "index": 22, + "value": { + "etag": "19e7cb68-7840-462b-b4c5-0750135472b1", + "id": "/subscriptions/02efc9e4-732d-4a8d-8b82-5b37e10eb89d/resourceGroups/dnscontroltest/providers/Microsoft.Network/dnszones/dnscontrol-azure.com/TXT/fooosbs2", + "name": "fooosbs2", + "properties": { + "TTL": 300, + "TXTRecords": [ + { + "value": [ + "2back\\\\slash" + ] + } + ], + "fqdn": "fooosbs2.dnscontrol-azure.com.", + "provisioningState": "Succeeded", + "targetResource": {} + }, + "type": "Microsoft.Network/dnszones/TXT" + } + }, + { + "index": 23, + "value": { + "etag": "19ec279e-21af-4c2a-ba41-331f51f172bf", + "id": "/subscriptions/02efc9e4-732d-4a8d-8b82-5b37e10eb89d/resourceGroups/dnscontroltest/providers/Microsoft.Network/dnszones/dnscontrol-azure.com/CNAME/xn--o-0gab", + "name": "xn--o-0gab", + "properties": { + "CNAMERecord": { + "cname": "xn--ndaaa.xn--vhquv." + }, + "TTL": 300, + "fqdn": "xn--o-0gab.dnscontrol-azure.com.", + "provisioningState": "Succeeded", + "targetResource": {} + }, + "type": "Microsoft.Network/dnszones/CNAME" + } + }, + { + "index": 24, + "value": { + "etag": "1c0885fb-2bfb-42ff-8186-97505281496a", + "id": "/subscriptions/02efc9e4-732d-4a8d-8b82-5b37e10eb89d/resourceGroups/dnscontroltest/providers/Microsoft.Network/dnszones/dnscontrol-azure.com/TXT/foosc2", + "name": "foosc2", + "properties": { + "TTL": 300, + "TXTRecords": [ + { + "value": [ + "wssemi ; colon" + ] + } + ], + "fqdn": "foosc2.dnscontrol-azure.com.", + "provisioningState": "Succeeded", + "targetResource": {} + }, + "type": "Microsoft.Network/dnszones/TXT" + } + }, + { + "index": 25, + "value": { + "etag": "1c9af882-df67-4ac2-a37c-aec67c2babf1", + "id": "/subscriptions/02efc9e4-732d-4a8d-8b82-5b37e10eb89d/resourceGroups/dnscontroltest/providers/Microsoft.Network/dnszones/dnscontrol-azure.com/SRV/_sip._tcp", + "name": "_sip._tcp", + "properties": { + "SRVRecords": [ + { + "port": 75, + "priority": 15, + "target": "foo4.com.", + "weight": 65 + }, + { + "port": 7, + "priority": 52, + "target": "foo.com.", + "weight": 62 + } + ], + "TTL": 300, + "fqdn": "_sip._tcp.dnscontrol-azure.com.", + "provisioningState": "Succeeded", + "targetResource": {} + }, + "type": "Microsoft.Network/dnszones/SRV" + } + }, + { + "index": 26, + "value": { + "etag": "1d1f03f5-5b00-482d-bc1f-2e8e05c89772", + "id": "/subscriptions/02efc9e4-732d-4a8d-8b82-5b37e10eb89d/resourceGroups/dnscontroltest/providers/Microsoft.Network/dnszones/dnscontrol-azure.com/A/@", + "name": "@", + "properties": { + "ARecords": [ + { + "ipv4Address": "8.8.8.8" + } + ], + "TTL": 1000, + "fqdn": "dnscontrol-azure.com.", + "provisioningState": "Succeeded", + "targetResource": {} + }, + "type": "Microsoft.Network/dnszones/A" + } + }, + { + "index": 27, + "value": { + "etag": "20424c2e-3415-4c45-94cf-1fc8faa19c17", + "id": "/subscriptions/02efc9e4-732d-4a8d-8b82-5b37e10eb89d/resourceGroups/dnscontroltest/providers/Microsoft.Network/dnszones/dnscontrol-azure.com/A/www", + "name": "www", + "properties": { + "ARecords": [ + { + "ipv4Address": "1.1.1.1" + } + ], + "TTL": 300, + "fqdn": "www.dnscontrol-azure.com.", + "provisioningState": "Succeeded", + "targetResource": {} + }, + "type": "Microsoft.Network/dnszones/A" + } + }, + { + "index": 28, + "value": { + "etag": "20e87159-2653-4ac7-89e5-7cb46739fd0f", + "id": "/subscriptions/02efc9e4-732d-4a8d-8b82-5b37e10eb89d/resourceGroups/dnscontroltest/providers/Microsoft.Network/dnszones/dnscontrol-azure.com/A/www", + "name": "www", + "properties": { + "ARecords": [ + { + "ipv4Address": "1.1.1.1" + }, + { + "ipv4Address": "2.2.2.2" + } + ], + "TTL": 300, + "fqdn": "www.dnscontrol-azure.com.", + "provisioningState": "Succeeded", + "targetResource": {} + }, + "type": "Microsoft.Network/dnszones/A" + } + }, + { + "index": 29, + "value": { + "etag": "25c2af4e-17e2-49c0-ae9a-621e5263cb30", + "id": "/subscriptions/02efc9e4-732d-4a8d-8b82-5b37e10eb89d/resourceGroups/dnscontroltest/providers/Microsoft.Network/dnszones/dnscontrol-azure.com/TXT/foo766", + "name": "foo766", + "properties": { + "TTL": 300, + "TXTRecords": [ + { + "value": [ + "JJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJ", + "JJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJ", + "JJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJ", + "J" + ] + } + ], + "fqdn": "foo766.dnscontrol-azure.com.", + "provisioningState": "Succeeded", + "targetResource": {} + }, + "type": "Microsoft.Network/dnszones/TXT" + } + }, + { + "index": 30, + "value": { + "etag": "2604497f-0cba-491a-b634-8fc397ea6ab5", + "id": "/subscriptions/02efc9e4-732d-4a8d-8b82-5b37e10eb89d/resourceGroups/dnscontroltest/providers/Microsoft.Network/dnszones/dnscontrol-azure.com/A/testignore", + "name": "testignore", + "properties": { + "ARecords": [ + { + "ipv4Address": "8.8.8.8" + } + ], + "TTL": 300, + "fqdn": "testignore.dnscontrol-azure.com.", + "provisioningState": "Succeeded", + "targetResource": {} + }, + "type": "Microsoft.Network/dnszones/A" + } + }, + { + "index": 31, + "value": { + "etag": "2656e780-8e98-4bbe-90dd-6348521c1b4e", + "id": "/subscriptions/02efc9e4-732d-4a8d-8b82-5b37e10eb89d/resourceGroups/dnscontroltest/providers/Microsoft.Network/dnszones/dnscontrol-azure.com/NS/foo", + "name": "foo", + "properties": { + "NSRecords": [ + { + "nsdname": "dnscontrol-azure.com." + } + ], + "TTL": 300, + "fqdn": "foo.dnscontrol-azure.com.", + "provisioningState": "Succeeded", + "targetResource": {} + }, + "type": "Microsoft.Network/dnszones/NS" + } + }, + { + "index": 32, + "value": { + "etag": "26d493dc-be53-4de6-b4a2-08bbcb954ffc", + "id": "/subscriptions/02efc9e4-732d-4a8d-8b82-5b37e10eb89d/resourceGroups/dnscontroltest/providers/Microsoft.Network/dnszones/dnscontrol-azure.com/TXT/foo", + "name": "foo", + "properties": { + "TTL": 300, + "TXTRecords": [ + { + "value": [ + "simple" + ] + } + ], + "fqdn": "foo.dnscontrol-azure.com.", + "provisioningState": "Succeeded", + "targetResource": {} + }, + "type": "Microsoft.Network/dnszones/TXT" + } + }, + { + "index": 33, + "value": { + "etag": "283d2188-23d3-43d1-8162-ef99d3fcaa80", + "id": "/subscriptions/02efc9e4-732d-4a8d-8b82-5b37e10eb89d/resourceGroups/dnscontroltest/providers/Microsoft.Network/dnszones/dnscontrol-azure.com/A/foo", + "name": "foo", + "properties": { + "ARecords": [ + { + "ipv4Address": "1.1.1.1" + }, + { + "ipv4Address": "12.12.12.12" + } + ], + "TTL": 300, + "fqdn": "foo.dnscontrol-azure.com.", + "provisioningState": "Succeeded", + "targetResource": {} + }, + "type": "Microsoft.Network/dnszones/A" + } + }, + { + "index": 34, + "value": { + "etag": "290e9226-a0ed-40db-9bdd-d2c24da94455", + "id": "/subscriptions/02efc9e4-732d-4a8d-8b82-5b37e10eb89d/resourceGroups/dnscontroltest/providers/Microsoft.Network/dnszones/dnscontrol-azure.com/A/foo", + "name": "foo", + "properties": { + "ARecords": [ + { + "ipv4Address": "1.2.3.4" + }, + { + "ipv4Address": "2.3.4.5" + } + ], + "TTL": 300, + "fqdn": "foo.dnscontrol-azure.com.", + "provisioningState": "Succeeded", + "targetResource": {} + }, + "type": "Microsoft.Network/dnszones/A" + } + }, + { + "index": 35, + "value": { + "etag": "29c28471-210a-4480-a8b8-398a44382a80", + "id": "/subscriptions/02efc9e4-732d-4a8d-8b82-5b37e10eb89d/resourceGroups/dnscontroltest/providers/Microsoft.Network/dnszones/dnscontrol-azure.com/PTR/4", + "name": "4", + "properties": { + "PTRRecords": [ + { + "ptrdname": "foo.com." + } + ], + "TTL": 300, + "fqdn": "4.dnscontrol-azure.com.", + "provisioningState": "Succeeded", + "targetResource": {} + }, + "type": "Microsoft.Network/dnszones/PTR" + } + }, + { + "index": 36, + "value": { + "etag": "2b28a1ae-6387-4e15-b634-0abe068ecf89", + "id": "/subscriptions/02efc9e4-732d-4a8d-8b82-5b37e10eb89d/resourceGroups/dnscontroltest/providers/Microsoft.Network/dnszones/dnscontrol-azure.com/SRV/_sip._tcp", + "name": "_sip._tcp", + "properties": { + "SRVRecords": [ + { + "port": 7, + "priority": 5, + "target": "foo.com.", + "weight": 6 + } + ], + "TTL": 333, + "fqdn": "_sip._tcp.dnscontrol-azure.com.", + "provisioningState": "Succeeded", + "targetResource": {} + }, + "type": "Microsoft.Network/dnszones/SRV" + } + }, + { + "index": 37, + "value": { + "etag": "2bc51362-5399-4195-9c5a-537deec8a700", + "id": "/subscriptions/02efc9e4-732d-4a8d-8b82-5b37e10eb89d/resourceGroups/dnscontroltest/providers/Microsoft.Network/dnszones/dnscontrol-azure.com/TXT/foo.bat", + "name": "foo.bat", + "properties": { + "TTL": 300, + "TXTRecords": [ + { + "value": [ + "simple" + ] + } + ], + "fqdn": "foo.bat.dnscontrol-azure.com.", + "provisioningState": "Succeeded", + "targetResource": {} + }, + "type": "Microsoft.Network/dnszones/TXT" + } + }, + { + "index": 38, + "value": { + "etag": "2c36441b-1448-41da-baf8-b49378db0dd4", + "id": "/subscriptions/02efc9e4-732d-4a8d-8b82-5b37e10eb89d/resourceGroups/dnscontroltest/providers/Microsoft.Network/dnszones/dnscontrol-azure.com/A/quux.a", + "name": "quux.a", + "properties": { + "ARecords": [ + { + "ipv4Address": "2.3.4.5" + } + ], + "TTL": 300, + "fqdn": "quux.a.dnscontrol-azure.com.", + "provisioningState": "Succeeded", + "targetResource": {} + }, + "type": "Microsoft.Network/dnszones/A" + } + }, + { + "index": 39, + "value": { + "etag": "2d04e585-3909-4112-82d1-ea67ba84fa6f", + "id": "/subscriptions/02efc9e4-732d-4a8d-8b82-5b37e10eb89d/resourceGroups/dnscontroltest/providers/Microsoft.Network/dnszones/dnscontrol-azure.com/PTR/4", + "name": "4", + "properties": { + "PTRRecords": [ + { + "ptrdname": "bar.com." + } + ], + "TTL": 300, + "fqdn": "4.dnscontrol-azure.com.", + "provisioningState": "Succeeded", + "targetResource": {} + }, + "type": "Microsoft.Network/dnszones/PTR" + } + }, + { + "index": 40, + "value": { + "etag": "2d3e2317-14f1-467e-af1e-d14e9bf5fed8", + "id": "/subscriptions/02efc9e4-732d-4a8d-8b82-5b37e10eb89d/resourceGroups/dnscontroltest/providers/Microsoft.Network/dnszones/dnscontrol-azure.com/TXT/foosp", + "name": "foosp", + "properties": { + "TTL": 300, + "TXTRecords": [ + { + "value": [ + "with spaces" + ] + } + ], + "fqdn": "foosp.dnscontrol-azure.com.", + "provisioningState": "Succeeded", + "targetResource": {} + }, + "type": "Microsoft.Network/dnszones/TXT" + } + }, + { + "index": 41, + "value": { + "etag": "319e8e82-9b52-4431-a978-5361f727a60e", + "id": "/subscriptions/02efc9e4-732d-4a8d-8b82-5b37e10eb89d/resourceGroups/dnscontroltest/providers/Microsoft.Network/dnszones/dnscontrol-azure.com/TXT/foo", + "name": "foo", + "properties": { + "TTL": 300, + "TXTRecords": [ + { + "value": [ + "v=spf1 ip4:99.99.99.99 -all" + ] + } + ], + "fqdn": "foo.dnscontrol-azure.com.", + "provisioningState": "Succeeded", + "targetResource": {} + }, + "type": "Microsoft.Network/dnszones/TXT" + } + }, + { + "index": 42, + "value": { + "etag": "31f01b37-5a0e-4909-b397-9ecb232bada8", + "id": "/subscriptions/02efc9e4-732d-4a8d-8b82-5b37e10eb89d/resourceGroups/dnscontroltest/providers/Microsoft.Network/dnszones/dnscontrol-azure.com/NS/xyz", + "name": "xyz", + "properties": { + "NSRecords": [ + { + "nsdname": "ns2.foo.com." + } + ], + "TTL": 300, + "fqdn": "xyz.dnscontrol-azure.com.", + "provisioningState": "Succeeded", + "targetResource": {} + }, + "type": "Microsoft.Network/dnszones/NS" + } + }, + { + "index": 43, + "value": { + "etag": "3503500f-4fdc-4645-a6f2-f6dc832b1067", + "id": "/subscriptions/02efc9e4-732d-4a8d-8b82-5b37e10eb89d/resourceGroups/dnscontroltest/providers/Microsoft.Network/dnszones/dnscontrol-azure.com/A/foo.a", + "name": "foo.a", + "properties": { + "ARecords": [ + { + "ipv4Address": "1.2.3.4" + } + ], + "TTL": 300, + "fqdn": "foo.a.dnscontrol-azure.com.", + "provisioningState": "Succeeded", + "targetResource": {} + }, + "type": "Microsoft.Network/dnszones/A" + } + }, + { + "index": 44, + "value": { + "etag": "36c5c1b0-fe23-43f0-821d-75897a41a31e", + "id": "/subscriptions/02efc9e4-732d-4a8d-8b82-5b37e10eb89d/resourceGroups/dnscontroltest/providers/Microsoft.Network/dnszones/dnscontrol-azure.com/TXT/foo", + "name": "foo", + "properties": { + "TTL": 300, + "TXTRecords": [ + { + "value": [ + "simple" + ] + } + ], + "fqdn": "foo.dnscontrol-azure.com.", + "provisioningState": "Succeeded", + "targetResource": {} + }, + "type": "Microsoft.Network/dnszones/TXT" + } + }, + { + "index": 45, + "value": { + "etag": "376ee044-1166-435d-8c3b-734551d4a3e5", + "id": "/subscriptions/02efc9e4-732d-4a8d-8b82-5b37e10eb89d/resourceGroups/dnscontroltest/providers/Microsoft.Network/dnszones/dnscontrol-azure.com/CNAME/mail", + "name": "mail", + "properties": { + "CNAMERecord": { + "cname": "ghs.googlehosted.com." + }, + "TTL": 300, + "fqdn": "mail.dnscontrol-azure.com.", + "provisioningState": "Succeeded", + "targetResource": {} + }, + "type": "Microsoft.Network/dnszones/CNAME" + } + }, + { + "index": 46, + "value": { + "etag": "37d76987-0e27-4c52-a1fc-88009c202cb5", + "id": "/subscriptions/02efc9e4-732d-4a8d-8b82-5b37e10eb89d/resourceGroups/dnscontroltest/providers/Microsoft.Network/dnszones/dnscontrol-azure.com/CNAME/foo", + "name": "foo", + "properties": { + "CNAMERecord": { + "cname": "dnscontrol-azure.com." + }, + "TTL": 300, + "fqdn": "foo.dnscontrol-azure.com.", + "provisioningState": "Succeeded", + "targetResource": {} + }, + "type": "Microsoft.Network/dnszones/CNAME" + } + }, + { + "index": 47, + "value": { + "etag": "387accfd-adac-4a89-8bd5-1b35cd3d8a5e", + "id": "/subscriptions/02efc9e4-732d-4a8d-8b82-5b37e10eb89d/resourceGroups/dnscontroltest/providers/Microsoft.Network/dnszones/dnscontrol-azure.com/NS/@", + "name": "@", + "properties": { + "NSRecords": [ + { + "nsdname": "ns1-06.azure-dns.com." + }, + { + "nsdname": "ns1.foo.com." + }, + { + "nsdname": "ns2-06.azure-dns.net." + }, + { + "nsdname": "ns2.foo.com." + }, + { + "nsdname": "ns3-06.azure-dns.org." + }, + { + "nsdname": "ns4-06.azure-dns.info." + } + ], + "TTL": 300, + "fqdn": "dnscontrol-azure.com.", + "provisioningState": "Succeeded", + "targetResource": {} + }, + "type": "Microsoft.Network/dnszones/NS" + } + }, + { + "index": 48, + "value": { + "etag": "3aa7873d-5db8-409b-849b-ce79f3d3e553", + "id": "/subscriptions/02efc9e4-732d-4a8d-8b82-5b37e10eb89d/resourceGroups/dnscontroltest/providers/Microsoft.Network/dnszones/dnscontrol-azure.com/A/bar.a", + "name": "bar.a", + "properties": { + "TTL": 300, + "fqdn": "bar.a.dnscontrol-azure.com.", + "provisioningState": "Succeeded", + "targetResource": { + "id": "/subscriptions/02efc9e4-732d-4a8d-8b82-5b37e10eb89d/resourceGroups/dnscontroltest/providers/Microsoft.Network/dnszones/dnscontrol-azure.com/A/quux.a" + } + }, + "type": "Microsoft.Network/dnszones/A" + } + }, + { + "index": 49, + "value": { + "etag": "3ad5d1e7-890f-4a21-8db4-1297fdd0aac7", + "id": "/subscriptions/02efc9e4-732d-4a8d-8b82-5b37e10eb89d/resourceGroups/dnscontroltest/providers/Microsoft.Network/dnszones/dnscontrol-azure.com/TXT/foodqs", + "name": "foodqs", + "properties": { + "TTL": 300, + "TXTRecords": [ + { + "value": [ + "right\"" + ] + } + ], + "fqdn": "foodqs.dnscontrol-azure.com.", + "provisioningState": "Succeeded", + "targetResource": {} + }, + "type": "Microsoft.Network/dnszones/TXT" + } + }, + { + "index": 50, + "value": { + "etag": "3b1a764c-24e2-4c17-bf21-021e28953172", + "id": "/subscriptions/02efc9e4-732d-4a8d-8b82-5b37e10eb89d/resourceGroups/dnscontroltest/providers/Microsoft.Network/dnszones/dnscontrol-azure.com/A/testa", + "name": "testa", + "properties": { + "ARecords": [ + { + "ipv4Address": "1.1.1.1" + } + ], + "TTL": 999, + "fqdn": "testa.dnscontrol-azure.com.", + "provisioningState": "Succeeded", + "targetResource": {} + }, + "type": "Microsoft.Network/dnszones/A" + } + }, + { + "index": 51, + "value": { + "etag": "3c874e03-2ad9-4e80-b83f-73d71cc13aea", + "id": "/subscriptions/02efc9e4-732d-4a8d-8b82-5b37e10eb89d/resourceGroups/dnscontroltest/providers/Microsoft.Network/dnszones/dnscontrol-azure.com/TXT/testtxt", + "name": "testtxt", + "properties": { + "TTL": 300, + "TXTRecords": [ + { + "value": [ + "simple" + ] + } + ], + "fqdn": "testtxt.dnscontrol-azure.com.", + "provisioningState": "Succeeded", + "targetResource": {} + }, + "type": "Microsoft.Network/dnszones/TXT" + } + }, + { + "index": 52, + "value": { + "etag": "3ccc213f-49eb-4cbb-803f-0531c6946fc8", + "id": "/subscriptions/02efc9e4-732d-4a8d-8b82-5b37e10eb89d/resourceGroups/dnscontroltest/providers/Microsoft.Network/dnszones/dnscontrol-azure.com/A/www", + "name": "www", + "properties": { + "ARecords": [ + { + "ipv4Address": "5.6.7.8" + } + ], + "TTL": 400, + "fqdn": "www.dnscontrol-azure.com.", + "provisioningState": "Succeeded", + "targetResource": {} + }, + "type": "Microsoft.Network/dnszones/A" + } + }, + { + "index": 53, + "value": { + "etag": "3e1e1242-698f-4441-b5de-a20a0fc5f6d7", + "id": "/subscriptions/02efc9e4-732d-4a8d-8b82-5b37e10eb89d/resourceGroups/dnscontroltest/providers/Microsoft.Network/dnszones/dnscontrol-azure.com/A/foo", + "name": "foo", + "properties": { + "ARecords": [ + { + "ipv4Address": "1.2.3.4" + }, + { + "ipv4Address": "3.4.5.6" + } + ], + "TTL": 300, + "fqdn": "foo.dnscontrol-azure.com.", + "provisioningState": "Succeeded", + "targetResource": {} + }, + "type": "Microsoft.Network/dnszones/A" + } + }, + { + "index": 54, + "value": { + "etag": "3e3eea8b-3b7d-4e57-824c-09fc1b47a0cc", + "id": "/subscriptions/02efc9e4-732d-4a8d-8b82-5b37e10eb89d/resourceGroups/dnscontroltest/providers/Microsoft.Network/dnszones/dnscontrol-azure.com/A/www", + "name": "www", + "properties": { + "ARecords": [ + { + "ipv4Address": "1.2.3.9" + } + ], + "TTL": 300, + "fqdn": "www.dnscontrol-azure.com.", + "provisioningState": "Succeeded", + "targetResource": {} + }, + "type": "Microsoft.Network/dnszones/A" + } + }, + { + "index": 55, + "value": { + "etag": "43c09415-a017-455a-9810-017173b40b3c", + "id": "/subscriptions/02efc9e4-732d-4a8d-8b82-5b37e10eb89d/resourceGroups/dnscontroltest/providers/Microsoft.Network/dnszones/dnscontrol-azure.com/TXT/fooosbs3", + "name": "fooosbs3", + "properties": { + "TTL": 300, + "TXTRecords": [ + { + "value": [ + "3back\\\\\\slash" + ] + } + ], + "fqdn": "fooosbs3.dnscontrol-azure.com.", + "provisioningState": "Succeeded", + "targetResource": {} + }, + "type": "Microsoft.Network/dnszones/TXT" + } + }, + { + "index": 56, + "value": { + "etag": "4518540d-4e76-4222-a160-7142c94cfe88", + "id": "/subscriptions/02efc9e4-732d-4a8d-8b82-5b37e10eb89d/resourceGroups/dnscontroltest/providers/Microsoft.Network/dnszones/dnscontrol-azure.com/AAAA/foo", + "name": "foo", + "properties": { + "AAAARecords": [ + { + "ipv6Address": "2003:dd:d7ff::fe71:aaaa" + } + ], + "TTL": 300, + "fqdn": "foo.dnscontrol-azure.com.", + "provisioningState": "Succeeded", + "targetResource": {} + }, + "type": "Microsoft.Network/dnszones/AAAA" + } + }, + { + "index": 57, + "value": { + "etag": "4584b55b-9df8-4eb5-8a45-98023c99bbeb", + "id": "/subscriptions/02efc9e4-732d-4a8d-8b82-5b37e10eb89d/resourceGroups/dnscontroltest/providers/Microsoft.Network/dnszones/dnscontrol-azure.com/MX/nmx", + "name": "nmx", + "properties": { + "MXRecords": [ + { + "exchange": "nmx.dnscontrol-azure.com.", + "preference": 3 + }, + { + "exchange": "www.dnscontrol-azure.com.", + "preference": 9 + } + ], + "TTL": 300, + "fqdn": "nmx.dnscontrol-azure.com.", + "provisioningState": "Succeeded", + "targetResource": {} + }, + "type": "Microsoft.Network/dnszones/MX" + } + }, + { + "index": 58, + "value": { + "etag": "4646fa40-05f8-4c73-9dfb-ea6c8bf04f2d", + "id": "/subscriptions/02efc9e4-732d-4a8d-8b82-5b37e10eb89d/resourceGroups/dnscontroltest/providers/Microsoft.Network/dnszones/dnscontrol-azure.com/AAAA/testaaaa", + "name": "testaaaa", + "properties": { + "AAAARecords": [ + { + "ipv6Address": "2607:f8b0:4006:820::2006" + } + ], + "TTL": 300, + "fqdn": "testaaaa.dnscontrol-azure.com.", + "provisioningState": "Succeeded", + "targetResource": {} + }, + "type": "Microsoft.Network/dnszones/AAAA" + } + }, + { + "index": 59, + "value": { + "etag": "46a414ee-e0db-49a7-9d8e-a40c5d547752", + "id": "/subscriptions/02efc9e4-732d-4a8d-8b82-5b37e10eb89d/resourceGroups/dnscontroltest/providers/Microsoft.Network/dnszones/dnscontrol-azure.com/CNAME/foo", + "name": "foo", + "properties": { + "CNAMERecord": { + "cname": "redact1.acm-validations.aws." + }, + "TTL": 300, + "fqdn": "foo.dnscontrol-azure.com.", + "provisioningState": "Succeeded", + "targetResource": {} + }, + "type": "Microsoft.Network/dnszones/CNAME" + } + }, + { + "index": 60, + "value": { + "etag": "47639a0d-c4eb-41e1-8e4c-4c8465b72a15", + "id": "/subscriptions/02efc9e4-732d-4a8d-8b82-5b37e10eb89d/resourceGroups/dnscontroltest/providers/Microsoft.Network/dnszones/dnscontrol-azure.com/A/bar", + "name": "bar", + "properties": { + "ARecords": [ + { + "ipv4Address": "1.2.3.4" + } + ], + "TTL": 300, + "fqdn": "bar.dnscontrol-azure.com.", + "provisioningState": "Succeeded", + "targetResource": {} + }, + "type": "Microsoft.Network/dnszones/A" + } + }, + { + "index": 61, + "value": { + "etag": "48e613b7-1dcf-4ef8-8dc3-c18d3977511a", + "id": "/subscriptions/02efc9e4-732d-4a8d-8b82-5b37e10eb89d/resourceGroups/dnscontroltest/providers/Microsoft.Network/dnszones/dnscontrol-azure.com/A/www", + "name": "www", + "properties": { + "ARecords": [ + { + "ipv4Address": "1.1.1.1" + }, + { + "ipv4Address": "2.2.2.2" + }, + { + "ipv4Address": "3.3.3.3" + } + ], + "TTL": 300, + "fqdn": "www.dnscontrol-azure.com.", + "provisioningState": "Succeeded", + "targetResource": {} + }, + "type": "Microsoft.Network/dnszones/A" + } + }, + { + "index": 62, + "value": { + "etag": "4af8995d-8f91-4685-a3ce-e1cd8c34d5d2", + "id": "/subscriptions/02efc9e4-732d-4a8d-8b82-5b37e10eb89d/resourceGroups/dnscontroltest/providers/Microsoft.Network/dnszones/dnscontrol-azure.com/CAA/@", + "name": "@", + "properties": { + "TTL": 300, + "caaRecords": [ + { + "flags": 0, + "tag": "issue", + "value": "letsencrypt.org" + } + ], + "fqdn": "dnscontrol-azure.com.", + "provisioningState": "Succeeded", + "targetResource": {} + }, + "type": "Microsoft.Network/dnszones/CAA" + } + }, + { + "index": 63, + "value": { + "etag": "4be0397a-c6e2-4f33-aede-2dd869ad5783", + "id": "/subscriptions/02efc9e4-732d-4a8d-8b82-5b37e10eb89d/resourceGroups/dnscontroltest/providers/Microsoft.Network/dnszones/dnscontrol-azure.com/A/@", + "name": "@", + "properties": { + "ARecords": [ + { + "ipv4Address": "8.8.8.8" + } + ], + "TTL": 666, + "fqdn": "dnscontrol-azure.com.", + "provisioningState": "Succeeded", + "targetResource": {} + }, + "type": "Microsoft.Network/dnszones/A" + } + }, + { + "index": 64, + "value": { + "etag": "4d31d632-590e-4be6-9363-c5805f33fb5b", + "id": "/subscriptions/02efc9e4-732d-4a8d-8b82-5b37e10eb89d/resourceGroups/dnscontroltest/providers/Microsoft.Network/dnszones/dnscontrol-azure.com/A/testa", + "name": "testa", + "properties": { + "ARecords": [ + { + "ipv4Address": "1.1.1.1" + } + ], + "TTL": 300, + "fqdn": "testa.dnscontrol-azure.com.", + "provisioningState": "Succeeded", + "targetResource": {} + }, + "type": "Microsoft.Network/dnszones/A" + } + }, + { + "index": 65, + "value": { + "etag": "4d3e6672-d62c-4fc2-812c-933365851da4", + "id": "/subscriptions/02efc9e4-732d-4a8d-8b82-5b37e10eb89d/resourceGroups/dnscontroltest/providers/Microsoft.Network/dnszones/dnscontrol-azure.com/NS/@", + "name": "@", + "properties": { + "NSRecords": [ + { + "nsdname": "ns1-06.azure-dns.com." + }, + { + "nsdname": "ns2-06.azure-dns.net." + }, + { + "nsdname": "ns3-06.azure-dns.org." + }, + { + "nsdname": "ns4-06.azure-dns.info." + } + ], + "TTL": 300, + "fqdn": "dnscontrol-azure.com.", + "provisioningState": "Succeeded", + "targetResource": {} + }, + "type": "Microsoft.Network/dnszones/NS" + } + }, + { + "index": 66, + "value": { + "etag": "4eb5efda-666d-4433-b944-313fd06a9a9a", + "id": "/subscriptions/02efc9e4-732d-4a8d-8b82-5b37e10eb89d/resourceGroups/dnscontroltest/providers/Microsoft.Network/dnszones/dnscontrol-azure.com/A/bar.bat", + "name": "bar.bat", + "properties": { + "ARecords": [ + { + "ipv4Address": "5.5.5.5" + } + ], + "TTL": 300, + "fqdn": "bar.bat.dnscontrol-azure.com.", + "provisioningState": "Succeeded", + "targetResource": {} + }, + "type": "Microsoft.Network/dnszones/A" + } + }, + { + "index": 67, + "value": { + "etag": "4fb0819c-ee98-477b-8574-a11ec366cc6c", + "id": "/subscriptions/02efc9e4-732d-4a8d-8b82-5b37e10eb89d/resourceGroups/dnscontroltest/providers/Microsoft.Network/dnszones/dnscontrol-azure.com/A/dyndns-city1", + "name": "dyndns-city1", + "properties": { + "ARecords": [ + { + "ipv4Address": "91.42.1.1" + } + ], + "TTL": 300, + "fqdn": "dyndns-city1.dnscontrol-azure.com.", + "provisioningState": "Succeeded", + "targetResource": {} + }, + "type": "Microsoft.Network/dnszones/A" + } + }, + { + "index": 68, + "value": { + "etag": "52e900ac-5c3b-4e6f-98e0-9fe7e1f90e92", + "id": "/subscriptions/02efc9e4-732d-4a8d-8b82-5b37e10eb89d/resourceGroups/dnscontroltest/providers/Microsoft.Network/dnszones/dnscontrol-azure.com/TXT/foodqs", + "name": "foodqs", + "properties": { + "TTL": 300, + "TXTRecords": [ + { + "value": [ + "in\"ter\"ior" + ] + } + ], + "fqdn": "foodqs.dnscontrol-azure.com.", + "provisioningState": "Succeeded", + "targetResource": {} + }, + "type": "Microsoft.Network/dnszones/TXT" + } + }, + { + "index": 69, + "value": { + "etag": "536342f2-38a6-42e8-89df-99b3a4c5b68b", + "id": "/subscriptions/02efc9e4-732d-4a8d-8b82-5b37e10eb89d/resourceGroups/dnscontroltest/providers/Microsoft.Network/dnszones/dnscontrol-azure.com/MX/@", + "name": "@", + "properties": { + "MXRecords": [ + { + "exchange": "bar.com.", + "preference": 5 + } + ], + "TTL": 300, + "fqdn": "dnscontrol-azure.com.", + "provisioningState": "Succeeded", + "targetResource": {} + }, + "type": "Microsoft.Network/dnszones/MX" + } + }, + { + "index": 70, + "value": { + "etag": "569607f1-0888-4a33-b0a1-df71ba1fb498", + "id": "/subscriptions/02efc9e4-732d-4a8d-8b82-5b37e10eb89d/resourceGroups/dnscontroltest/providers/Microsoft.Network/dnszones/dnscontrol-azure.com/A/decoy", + "name": "decoy", + "properties": { + "ARecords": [ + { + "ipv4Address": "3.3.3.3" + } + ], + "TTL": 300, + "fqdn": "decoy.dnscontrol-azure.com.", + "provisioningState": "Succeeded", + "targetResource": {} + }, + "type": "Microsoft.Network/dnszones/A" + } + }, + { + "index": 71, + "value": { + "etag": "576d7f6c-46d8-4b27-a6ad-e6b3a0ec80a8", + "id": "/subscriptions/02efc9e4-732d-4a8d-8b82-5b37e10eb89d/resourceGroups/dnscontroltest/providers/Microsoft.Network/dnszones/dnscontrol-azure.com/CNAME/testcname", + "name": "testcname", + "properties": { + "CNAMERecord": { + "cname": "foo.dnscontrol-azure.com." + }, + "TTL": 300, + "fqdn": "testcname.dnscontrol-azure.com.", + "provisioningState": "Succeeded", + "targetResource": {} + }, + "type": "Microsoft.Network/dnszones/CNAME" + } + }, + { + "index": 72, + "value": { + "etag": "579adf1c-8588-4a23-8072-4619738020bc", + "id": "/subscriptions/02efc9e4-732d-4a8d-8b82-5b37e10eb89d/resourceGroups/dnscontroltest/providers/Microsoft.Network/dnszones/dnscontrol-azure.com/TXT/foo510", + "name": "foo510", + "properties": { + "TTL": 300, + "TXTRecords": [ + { + "value": [ + "EEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE", + "EEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE" + ] + } + ], + "fqdn": "foo510.dnscontrol-azure.com.", + "provisioningState": "Succeeded", + "targetResource": {} + }, + "type": "Microsoft.Network/dnszones/TXT" + } + }, + { + "index": 73, + "value": { + "etag": "5bc20e60-a986-44b3-9474-c10cf584ef3e", + "id": "/subscriptions/02efc9e4-732d-4a8d-8b82-5b37e10eb89d/resourceGroups/dnscontroltest/providers/Microsoft.Network/dnszones/dnscontrol-azure.com/AAAA/zzz", + "name": "zzz", + "properties": { + "AAAARecords": [ + { + "ipv6Address": "2003:dd:d7ff::fe71:cccc" + } + ], + "TTL": 300, + "fqdn": "zzz.dnscontrol-azure.com.", + "provisioningState": "Succeeded", + "targetResource": {} + }, + "type": "Microsoft.Network/dnszones/AAAA" + } + }, + { + "index": 74, + "value": { + "etag": "5ee06359-1cf2-44dc-9591-1eca902a666d", + "id": "/subscriptions/02efc9e4-732d-4a8d-8b82-5b37e10eb89d/resourceGroups/dnscontroltest/providers/Microsoft.Network/dnszones/dnscontrol-azure.com/A/decoy", + "name": "decoy", + "properties": { + "ARecords": [ + { + "ipv4Address": "2.2.2.2" + } + ], + "TTL": 300, + "fqdn": "decoy.dnscontrol-azure.com.", + "provisioningState": "Succeeded", + "targetResource": {} + }, + "type": "Microsoft.Network/dnszones/A" + } + }, + { + "index": 75, + "value": { + "etag": "5f209975-c9c9-4ccf-8d1f-db7906d4664a", + "id": "/subscriptions/02efc9e4-732d-4a8d-8b82-5b37e10eb89d/resourceGroups/dnscontroltest/providers/Microsoft.Network/dnszones/dnscontrol-azure.com/A/@", + "name": "@", + "properties": { + "ARecords": [ + { + "ipv4Address": "1.2.3.4" + }, + { + "ipv4Address": "2.3.4.5" + } + ], + "TTL": 300, + "fqdn": "dnscontrol-azure.com.", + "provisioningState": "Succeeded", + "targetResource": {} + }, + "type": "Microsoft.Network/dnszones/A" + } + }, + { + "index": 76, + "value": { + "etag": "6008956f-17c0-4929-9d90-1a88ced73c33", + "id": "/subscriptions/02efc9e4-732d-4a8d-8b82-5b37e10eb89d/resourceGroups/dnscontroltest/providers/Microsoft.Network/dnszones/dnscontrol-azure.com/TXT/fooosbs4", + "name": "fooosbs4", + "properties": { + "TTL": 300, + "TXTRecords": [ + { + "value": [ + "4back\\\\\\\\slash" + ] + } + ], + "fqdn": "fooosbs4.dnscontrol-azure.com.", + "provisioningState": "Succeeded", + "targetResource": {} + }, + "type": "Microsoft.Network/dnszones/TXT" + } + }, + { + "index": 77, + "value": { + "etag": "60fa8542-bf39-451e-9952-2e416ff2eaeb", + "id": "/subscriptions/02efc9e4-732d-4a8d-8b82-5b37e10eb89d/resourceGroups/dnscontroltest/providers/Microsoft.Network/dnszones/dnscontrol-azure.com/A/www", + "name": "www", + "properties": { + "ARecords": [ + { + "ipv4Address": "1.2.3.4" + }, + { + "ipv4Address": "5.6.7.8" + } + ], + "TTL": 300, + "fqdn": "www.dnscontrol-azure.com.", + "provisioningState": "Succeeded", + "targetResource": {} + }, + "type": "Microsoft.Network/dnszones/A" + } + }, + { + "index": 78, + "value": { + "etag": "662dd79f-62a3-4e4b-8441-25baa64ff642", + "id": "/subscriptions/02efc9e4-732d-4a8d-8b82-5b37e10eb89d/resourceGroups/dnscontroltest/providers/Microsoft.Network/dnszones/dnscontrol-azure.com/TXT/foo0", + "name": "foo0", + "properties": { + "TTL": 300, + "TXTRecords": [], + "fqdn": "foo0.dnscontrol-azure.com.", + "provisioningState": "Succeeded", + "targetResource": {} + }, + "type": "Microsoft.Network/dnszones/TXT" + } + }, + { + "index": 79, + "value": { + "etag": "664df5ac-f45b-4fc4-a71d-3fccc560a14e", + "id": "/subscriptions/02efc9e4-732d-4a8d-8b82-5b37e10eb89d/resourceGroups/dnscontroltest/providers/Microsoft.Network/dnszones/dnscontrol-azure.com/TXT/fooosbs1", + "name": "fooosbs1", + "properties": { + "TTL": 300, + "TXTRecords": [ + { + "value": [ + "1back\\slash" + ] + } + ], + "fqdn": "fooosbs1.dnscontrol-azure.com.", + "provisioningState": "Succeeded", + "targetResource": {} + }, + "type": "Microsoft.Network/dnszones/TXT" + } + }, + { + "index": 80, + "value": { + "etag": "66609724-7875-4eb1-874c-5ad1905d6f3b", + "id": "/subscriptions/02efc9e4-732d-4a8d-8b82-5b37e10eb89d/resourceGroups/dnscontroltest/providers/Microsoft.Network/dnszones/dnscontrol-azure.com/A/foo", + "name": "foo", + "properties": { + "ARecords": [ + { + "ipv4Address": "1.2.3.4" + } + ], + "TTL": 300, + "fqdn": "foo.dnscontrol-azure.com.", + "provisioningState": "Succeeded", + "targetResource": {} + }, + "type": "Microsoft.Network/dnszones/A" + } + }, + { + "index": 81, + "value": { + "etag": "666cb1fa-f6ed-4922-8c0d-6f7940aeac54", + "id": "/subscriptions/02efc9e4-732d-4a8d-8b82-5b37e10eb89d/resourceGroups/dnscontroltest/providers/Microsoft.Network/dnszones/dnscontrol-azure.com/A/@", + "name": "@", + "properties": { + "ARecords": [ + { + "ipv4Address": "1.2.3.4" + } + ], + "TTL": 300, + "fqdn": "dnscontrol-azure.com.", + "provisioningState": "Succeeded", + "targetResource": {} + }, + "type": "Microsoft.Network/dnszones/A" + } + }, + { + "index": 82, + "value": { + "etag": "669a2c3f-c41e-43b5-aab6-1a1bbd5224b2", + "id": "/subscriptions/02efc9e4-732d-4a8d-8b82-5b37e10eb89d/resourceGroups/dnscontroltest/providers/Microsoft.Network/dnszones/dnscontrol-azure.com/MX/@", + "name": "@", + "properties": { + "MXRecords": [ + { + "exchange": ".", + "preference": 0 + } + ], + "TTL": 300, + "fqdn": "dnscontrol-azure.com.", + "provisioningState": "Succeeded", + "targetResource": {} + }, + "type": "Microsoft.Network/dnszones/MX" + } + }, + { + "index": 83, + "value": { + "etag": "6bb655ea-5eac-4738-9655-5853dd89c9f0", + "id": "/subscriptions/02efc9e4-732d-4a8d-8b82-5b37e10eb89d/resourceGroups/dnscontroltest/providers/Microsoft.Network/dnszones/dnscontrol-azure.com/CAA/@", + "name": "@", + "properties": { + "TTL": 300, + "caaRecords": [ + { + "flags": 128, + "tag": "issue", + "value": "letsencrypt.org" + } + ], + "fqdn": "dnscontrol-azure.com.", + "provisioningState": "Succeeded", + "targetResource": {} + }, + "type": "Microsoft.Network/dnszones/CAA" + } + }, + { + "index": 84, + "value": { + "etag": "6c741a92-4d6a-4a10-ab73-f5f742328773", + "id": "/subscriptions/02efc9e4-732d-4a8d-8b82-5b37e10eb89d/resourceGroups/dnscontroltest/providers/Microsoft.Network/dnszones/dnscontrol-azure.com/MX/testmx", + "name": "testmx", + "properties": { + "MXRecords": [ + { + "exchange": "foo.com.", + "preference": 5 + }, + { + "exchange": "bar.com.", + "preference": 100 + } + ], + "TTL": 300, + "fqdn": "testmx.dnscontrol-azure.com.", + "provisioningState": "Succeeded", + "targetResource": {} + }, + "type": "Microsoft.Network/dnszones/MX" + } + }, + { + "index": 85, + "value": { + "etag": "6f621847-fdc1-4866-a5b3-5ab0693f1d06", + "id": "/subscriptions/02efc9e4-732d-4a8d-8b82-5b37e10eb89d/resourceGroups/dnscontroltest/providers/Microsoft.Network/dnszones/dnscontrol-azure.com/A/foo", + "name": "foo", + "properties": { + "ARecords": [ + { + "ipv4Address": "1.1.1.1" + }, + { + "ipv4Address": "14.14.14.14" + } + ], + "TTL": 300, + "fqdn": "foo.dnscontrol-azure.com.", + "provisioningState": "Succeeded", + "targetResource": {} + }, + "type": "Microsoft.Network/dnszones/A" + } + }, + { + "index": 86, + "value": { + "etag": "70d2e789-ed56-4999-a72a-2e7583ecd0e9", + "id": "/subscriptions/02efc9e4-732d-4a8d-8b82-5b37e10eb89d/resourceGroups/dnscontroltest/providers/Microsoft.Network/dnszones/dnscontrol-azure.com/A/foo", + "name": "foo", + "properties": { + "ARecords": [ + { + "ipv4Address": "1.2.3.4" + }, + { + "ipv4Address": "3.4.5.6" + } + ], + "TTL": 300, + "fqdn": "foo.dnscontrol-azure.com.", + "provisioningState": "Succeeded", + "targetResource": {} + }, + "type": "Microsoft.Network/dnszones/A" + } + }, + { + "index": 87, + "value": { + "etag": "7352fddb-f6bf-48d8-b68a-f898ba245d91", + "id": "/subscriptions/02efc9e4-732d-4a8d-8b82-5b37e10eb89d/resourceGroups/dnscontroltest/providers/Microsoft.Network/dnszones/dnscontrol-azure.com/CAA/@", + "name": "@", + "properties": { + "TTL": 300, + "caaRecords": [ + { + "flags": 0, + "tag": "issue", + "value": "letsencrypt.org" + } + ], + "fqdn": "dnscontrol-azure.com.", + "provisioningState": "Succeeded", + "targetResource": {} + }, + "type": "Microsoft.Network/dnszones/CAA" + } + }, + { + "index": 88, + "value": { + "etag": "73e242b5-4eb1-4db5-b1d3-463b27fc90d6", + "id": "/subscriptions/02efc9e4-732d-4a8d-8b82-5b37e10eb89d/resourceGroups/dnscontroltest/providers/Microsoft.Network/dnszones/dnscontrol-azure.com/CNAME/bar.cname", + "name": "bar.cname", + "properties": { + "TTL": 300, + "fqdn": "bar.cname.dnscontrol-azure.com.", + "provisioningState": "Succeeded", + "targetResource": { + "id": "/subscriptions/02efc9e4-732d-4a8d-8b82-5b37e10eb89d/resourceGroups/dnscontroltest/providers/Microsoft.Network/dnszones/dnscontrol-azure.com/CNAME/foo.cname" + } + }, + "type": "Microsoft.Network/dnszones/CNAME" + } + }, + { + "index": 89, + "value": { + "etag": "74577365-ccd7-4c8f-9a3d-2f40df51fd1c", + "id": "/subscriptions/02efc9e4-732d-4a8d-8b82-5b37e10eb89d/resourceGroups/dnscontroltest/providers/Microsoft.Network/dnszones/dnscontrol-azure.com/MX/@", + "name": "@", + "properties": { + "MXRecords": [ + { + "exchange": "dnscontrol-azure.com.", + "preference": 2 + }, + { + "exchange": "www.dnscontrol-azure.com.", + "preference": 8 + } + ], + "TTL": 300, + "fqdn": "dnscontrol-azure.com.", + "provisioningState": "Succeeded", + "targetResource": {} + }, + "type": "Microsoft.Network/dnszones/MX" + } + }, + { + "index": 90, + "value": { + "etag": "74607df4-bbe1-4f9b-be66-52514d253cca", + "id": "/subscriptions/02efc9e4-732d-4a8d-8b82-5b37e10eb89d/resourceGroups/dnscontroltest/providers/Microsoft.Network/dnszones/dnscontrol-azure.com/A/bar", + "name": "bar", + "properties": { + "ARecords": [ + { + "ipv4Address": "5.5.5.5" + } + ], + "TTL": 300, + "fqdn": "bar.dnscontrol-azure.com.", + "provisioningState": "Succeeded", + "targetResource": {} + }, + "type": "Microsoft.Network/dnszones/A" + } + }, + { + "index": 91, + "value": { + "etag": "77e95ad1-438d-4a9e-a2d2-22cfbd53f067", + "id": "/subscriptions/02efc9e4-732d-4a8d-8b82-5b37e10eb89d/resourceGroups/dnscontroltest/providers/Microsoft.Network/dnszones/dnscontrol-azure.com/A/xn--fiq228c", + "name": "xn--fiq228c", + "properties": { + "ARecords": [ + { + "ipv4Address": "1.2.3.4" + } + ], + "TTL": 300, + "fqdn": "xn--fiq228c.dnscontrol-azure.com.", + "provisioningState": "Succeeded", + "targetResource": {} + }, + "type": "Microsoft.Network/dnszones/A" + } + }, + { + "index": 92, + "value": { + "etag": "78d7ffd0-f89a-4c52-b957-843f6fc6afc1", + "id": "/subscriptions/02efc9e4-732d-4a8d-8b82-5b37e10eb89d/resourceGroups/dnscontroltest/providers/Microsoft.Network/dnszones/dnscontrol-azure.com/MX/testmx", + "name": "testmx", + "properties": { + "MXRecords": [ + { + "exchange": "foo.com.", + "preference": 100 + } + ], + "TTL": 300, + "fqdn": "testmx.dnscontrol-azure.com.", + "provisioningState": "Succeeded", + "targetResource": {} + }, + "type": "Microsoft.Network/dnszones/MX" + } + }, + { + "index": 93, + "value": { + "etag": "79428258-735a-487d-b6e2-5a3755efac24", + "id": "/subscriptions/02efc9e4-732d-4a8d-8b82-5b37e10eb89d/resourceGroups/dnscontroltest/providers/Microsoft.Network/dnszones/dnscontrol-azure.com/SRV/_sip._tcp", + "name": "_sip._tcp", + "properties": { + "SRVRecords": [ + { + "port": 7, + "priority": 5, + "target": "foo.com.", + "weight": 6 + }, + { + "port": 75, + "priority": 15, + "target": "foo4.com.", + "weight": 65 + } + ], + "TTL": 300, + "fqdn": "_sip._tcp.dnscontrol-azure.com.", + "provisioningState": "Succeeded", + "targetResource": {} + }, + "type": "Microsoft.Network/dnszones/SRV" + } + }, + { + "index": 94, + "value": { + "etag": "79edc939-3d4c-43fa-8f02-e05632994fba", + "id": "/subscriptions/02efc9e4-732d-4a8d-8b82-5b37e10eb89d/resourceGroups/dnscontroltest/providers/Microsoft.Network/dnszones/dnscontrol-azure.com/A/www", + "name": "www", + "properties": { + "ARecords": [ + { + "ipv4Address": "5.5.5.5" + } + ], + "TTL": 300, + "fqdn": "www.dnscontrol-azure.com.", + "provisioningState": "Succeeded", + "targetResource": {} + }, + "type": "Microsoft.Network/dnszones/A" + } + }, + { + "index": 95, + "value": { + "etag": "7a7588ca-7b44-48ae-bf03-eed12b2be929", + "id": "/subscriptions/02efc9e4-732d-4a8d-8b82-5b37e10eb89d/resourceGroups/dnscontroltest/providers/Microsoft.Network/dnszones/dnscontrol-azure.com/CNAME/quux.cname", + "name": "quux.cname", + "properties": { + "CNAMERecord": { + "cname": "google2.com." + }, + "TTL": 300, + "fqdn": "quux.cname.dnscontrol-azure.com.", + "provisioningState": "Succeeded", + "targetResource": {} + }, + "type": "Microsoft.Network/dnszones/CNAME" + } + }, + { + "index": 96, + "value": { + "etag": "7a7df3a5-0ce8-4e3f-8732-7a9fb667d1ac", + "id": "/subscriptions/02efc9e4-732d-4a8d-8b82-5b37e10eb89d/resourceGroups/dnscontroltest/providers/Microsoft.Network/dnszones/dnscontrol-azure.com/A/nmx", + "name": "nmx", + "properties": { + "ARecords": [ + { + "ipv4Address": "1.2.3.3" + } + ], + "TTL": 300, + "fqdn": "nmx.dnscontrol-azure.com.", + "provisioningState": "Succeeded", + "targetResource": {} + }, + "type": "Microsoft.Network/dnszones/A" + } + }, + { + "index": 97, + "value": { + "etag": "7b181533-ca36-4ff3-8c46-06f252574509", + "id": "/subscriptions/02efc9e4-732d-4a8d-8b82-5b37e10eb89d/resourceGroups/dnscontroltest/providers/Microsoft.Network/dnszones/dnscontrol-azure.com/A/foo", + "name": "foo", + "properties": { + "ARecords": [ + { + "ipv4Address": "1.1.1.1" + }, + { + "ipv4Address": "13.13.13.13" + } + ], + "TTL": 300, + "fqdn": "foo.dnscontrol-azure.com.", + "provisioningState": "Succeeded", + "targetResource": {} + }, + "type": "Microsoft.Network/dnszones/A" + } + }, + { + "index": 98, + "value": { + "etag": "7c10eafe-a91c-444e-9c0c-d60514188c2a", + "id": "/subscriptions/02efc9e4-732d-4a8d-8b82-5b37e10eb89d/resourceGroups/dnscontroltest/providers/Microsoft.Network/dnszones/dnscontrol-azure.com/MX/testmx", + "name": "testmx", + "properties": { + "MXRecords": [ + { + "exchange": "foo.com.", + "preference": 5 + }, + { + "exchange": "bar.com.", + "preference": 100 + } + ], + "TTL": 300, + "fqdn": "testmx.dnscontrol-azure.com.", + "provisioningState": "Succeeded", + "targetResource": {} + }, + "type": "Microsoft.Network/dnszones/MX" + } + }, + { + "index": 99, + "value": { + "etag": "7e7938f7-bbfb-4ee7-8e1e-766aeddd660c", + "id": "/subscriptions/02efc9e4-732d-4a8d-8b82-5b37e10eb89d/resourceGroups/dnscontroltest/providers/Microsoft.Network/dnszones/dnscontrol-azure.com/A/foo", + "name": "foo", + "properties": { + "ARecords": [ + { + "ipv4Address": "2.3.4.5" + } + ], + "TTL": 300, + "fqdn": "foo.dnscontrol-azure.com.", + "provisioningState": "Succeeded", + "targetResource": {} + }, + "type": "Microsoft.Network/dnszones/A" + } + }, + { + "index": 100, + "value": { + "etag": "81d270d3-255d-4f3e-aab5-c091fc46bdbb", + "id": "/subscriptions/02efc9e4-732d-4a8d-8b82-5b37e10eb89d/resourceGroups/dnscontroltest/providers/Microsoft.Network/dnszones/dnscontrol-azure.com/A/www", + "name": "www", + "properties": { + "ARecords": [ + { + "ipv4Address": "2.2.2.2" + }, + { + "ipv4Address": "5.6.7.8" + } + ], + "TTL": 300, + "fqdn": "www.dnscontrol-azure.com.", + "provisioningState": "Succeeded", + "targetResource": {} + }, + "type": "Microsoft.Network/dnszones/A" + } + }, + { + "index": 101, + "value": { + "etag": "8301aed5-fa72-485b-8de8-7299c869877e", + "id": "/subscriptions/02efc9e4-732d-4a8d-8b82-5b37e10eb89d/resourceGroups/dnscontroltest/providers/Microsoft.Network/dnszones/dnscontrol-azure.com/TXT/final", + "name": "final", + "properties": { + "TTL": 300, + "TXTRecords": [ + { + "value": [ + "TestDNSProviders was successful!" + ] + } + ], + "fqdn": "final.dnscontrol-azure.com.", + "provisioningState": "Succeeded", + "targetResource": {} + }, + "type": "Microsoft.Network/dnszones/TXT" + } + }, + { + "index": 102, + "value": { + "etag": "837200eb-f029-4e8d-a6b2-cd7227053d3b", + "id": "/subscriptions/02efc9e4-732d-4a8d-8b82-5b37e10eb89d/resourceGroups/dnscontroltest/providers/Microsoft.Network/dnszones/dnscontrol-azure.com/NS/@", + "name": "@", + "properties": { + "NSRecords": [ + { + "nsdname": "ns1-06.azure-dns.com." + }, + { + "nsdname": "ns1.foo.com." + }, + { + "nsdname": "ns2-06.azure-dns.net." + }, + { + "nsdname": "ns3-06.azure-dns.org." + }, + { + "nsdname": "ns4-06.azure-dns.info." + } + ], + "TTL": 300, + "fqdn": "dnscontrol-azure.com.", + "provisioningState": "Succeeded", + "targetResource": {} + }, + "type": "Microsoft.Network/dnszones/NS" + } + }, + { + "index": 103, + "value": { + "etag": "837e5da5-470d-46c7-9654-42dd611cc276", + "id": "/subscriptions/02efc9e4-732d-4a8d-8b82-5b37e10eb89d/resourceGroups/dnscontroltest/providers/Microsoft.Network/dnszones/dnscontrol-azure.com/MX/foo", + "name": "foo", + "properties": { + "MXRecords": [ + { + "exchange": "foo.dnscontrol-azure.com.", + "preference": 10 + }, + { + "exchange": "bar.dnscontrol-azure.com.", + "preference": 20 + } + ], + "TTL": 300, + "fqdn": "foo.dnscontrol-azure.com.", + "provisioningState": "Succeeded", + "targetResource": {} + }, + "type": "Microsoft.Network/dnszones/MX" + } + }, + { + "index": 104, + "value": { + "etag": "83f4b120-b4d2-4353-8041-b9dcbd421125", + "id": "/subscriptions/02efc9e4-732d-4a8d-8b82-5b37e10eb89d/resourceGroups/dnscontroltest/providers/Microsoft.Network/dnszones/dnscontrol-azure.com/TXT/@", + "name": "@", + "properties": { + "TTL": 300, + "TXTRecords": [ + { + "value": [ + "asimple" + ] + } + ], + "fqdn": "dnscontrol-azure.com.", + "provisioningState": "Succeeded", + "targetResource": {} + }, + "type": "Microsoft.Network/dnszones/TXT" + } + }, + { + "index": 105, + "value": { + "etag": "8a050506-96da-4c5d-9776-d67445549c4a", + "id": "/subscriptions/02efc9e4-732d-4a8d-8b82-5b37e10eb89d/resourceGroups/dnscontroltest/providers/Microsoft.Network/dnszones/dnscontrol-azure.com/CNAME/testcname", + "name": "testcname", + "properties": { + "CNAMERecord": { + "cname": "www.google.com." + }, + "TTL": 300, + "fqdn": "testcname.dnscontrol-azure.com.", + "provisioningState": "Succeeded", + "targetResource": {} + }, + "type": "Microsoft.Network/dnszones/CNAME" + } + }, + { + "index": 106, + "value": { + "etag": "8d07fc54-28c9-4bb9-8d1f-5e328b6cfd25", + "id": "/subscriptions/02efc9e4-732d-4a8d-8b82-5b37e10eb89d/resourceGroups/dnscontroltest/providers/Microsoft.Network/dnszones/dnscontrol-azure.com/A/foo", + "name": "foo", + "properties": { + "ARecords": [ + { + "ipv4Address": "1.2.3.4" + }, + { + "ipv4Address": "2.3.4.5" + } + ], + "TTL": 300, + "fqdn": "foo.dnscontrol-azure.com.", + "provisioningState": "Succeeded", + "targetResource": {} + }, + "type": "Microsoft.Network/dnszones/A" + } + }, + { + "index": 107, + "value": { + "etag": "8e34c5d6-f3b4-4950-bbe3-5283270bbb21", + "id": "/subscriptions/02efc9e4-732d-4a8d-8b82-5b37e10eb89d/resourceGroups/dnscontroltest/providers/Microsoft.Network/dnszones/dnscontrol-azure.com/MX/testmx", + "name": "testmx", + "properties": { + "MXRecords": [ + { + "exchange": "foo.com.", + "preference": 5 + } + ], + "TTL": 300, + "fqdn": "testmx.dnscontrol-azure.com.", + "provisioningState": "Succeeded", + "targetResource": {} + }, + "type": "Microsoft.Network/dnszones/MX" + } + }, + { + "index": 108, + "value": { + "etag": "911851c9-4ad7-4067-abbb-161e37400277", + "id": "/subscriptions/02efc9e4-732d-4a8d-8b82-5b37e10eb89d/resourceGroups/dnscontroltest/providers/Microsoft.Network/dnszones/dnscontrol-azure.com/CNAME/mail", + "name": "mail", + "properties": { + "CNAMERecord": { + "cname": "ghs.googlehosted.com." + }, + "TTL": 300, + "fqdn": "mail.dnscontrol-azure.com.", + "provisioningState": "Succeeded", + "targetResource": {} + }, + "type": "Microsoft.Network/dnszones/CNAME" + } + }, + { + "index": 109, + "value": { + "etag": "919bd0df-485d-4d98-8a0e-9518ee47de82", + "id": "/subscriptions/02efc9e4-732d-4a8d-8b82-5b37e10eb89d/resourceGroups/dnscontroltest/providers/Microsoft.Network/dnszones/dnscontrol-azure.com/MX/testmx", + "name": "testmx", + "properties": { + "MXRecords": [ + { + "exchange": "foo.com.", + "preference": 5 + } + ], + "TTL": 300, + "fqdn": "testmx.dnscontrol-azure.com.", + "provisioningState": "Succeeded", + "targetResource": {} + }, + "type": "Microsoft.Network/dnszones/MX" + } + }, + { + "index": 110, + "value": { + "etag": "9306f82d-b887-4fcc-852a-172913d647d9", + "id": "/subscriptions/02efc9e4-732d-4a8d-8b82-5b37e10eb89d/resourceGroups/dnscontroltest/providers/Microsoft.Network/dnszones/dnscontrol-azure.com/A/testa", + "name": "testa", + "properties": { + "ARecords": [ + { + "ipv4Address": "1.1.1.1" + } + ], + "TTL": 333, + "fqdn": "testa.dnscontrol-azure.com.", + "provisioningState": "Succeeded", + "targetResource": {} + }, + "type": "Microsoft.Network/dnszones/A" + } + }, + { + "index": 111, + "value": { + "etag": "95d40280-d943-4f83-94c4-3c3265febb1a", + "id": "/subscriptions/02efc9e4-732d-4a8d-8b82-5b37e10eb89d/resourceGroups/dnscontroltest/providers/Microsoft.Network/dnszones/dnscontrol-azure.com/A/foo", + "name": "foo", + "properties": { + "ARecords": [ + { + "ipv4Address": "2.3.4.5" + }, + { + "ipv4Address": "8.8.8.8" + } + ], + "TTL": 300, + "fqdn": "foo.dnscontrol-azure.com.", + "provisioningState": "Succeeded", + "targetResource": {} + }, + "type": "Microsoft.Network/dnszones/A" + } + }, + { + "index": 112, + "value": { + "etag": "9c77e1f7-1526-448e-8ba1-7354d5ff6c9d", + "id": "/subscriptions/02efc9e4-732d-4a8d-8b82-5b37e10eb89d/resourceGroups/dnscontroltest/providers/Microsoft.Network/dnszones/dnscontrol-azure.com/CNAME/bar.cname", + "name": "bar.cname", + "properties": { + "TTL": 300, + "fqdn": "bar.cname.dnscontrol-azure.com.", + "provisioningState": "Succeeded", + "targetResource": { + "id": "/subscriptions/02efc9e4-732d-4a8d-8b82-5b37e10eb89d/resourceGroups/dnscontroltest/providers/Microsoft.Network/dnszones/dnscontrol-azure.com/CNAME/foo.cname" + } + }, + "type": "Microsoft.Network/dnszones/CNAME" + } + }, + { + "index": 113, + "value": { + "etag": "9cff5a21-44f0-4866-b1fd-24a6d11ea66d", + "id": "/subscriptions/02efc9e4-732d-4a8d-8b82-5b37e10eb89d/resourceGroups/dnscontroltest/providers/Microsoft.Network/dnszones/dnscontrol-azure.com/MX/@", + "name": "@", + "properties": { + "MXRecords": [ + { + "exchange": ".", + "preference": 0 + } + ], + "TTL": 300, + "fqdn": "dnscontrol-azure.com.", + "provisioningState": "Succeeded", + "targetResource": {} + }, + "type": "Microsoft.Network/dnszones/MX" + } + }, + { + "index": 114, + "value": { + "etag": "9ff3ba3c-4994-4124-b8b5-600ea029d073", + "id": "/subscriptions/02efc9e4-732d-4a8d-8b82-5b37e10eb89d/resourceGroups/dnscontroltest/providers/Microsoft.Network/dnszones/dnscontrol-azure.com/SRV/_sip._tcp", + "name": "_sip._tcp", + "properties": { + "SRVRecords": [ + { + "port": 7, + "priority": 5, + "target": "foo.com.", + "weight": 6 + }, + { + "port": 75, + "priority": 15, + "target": "foo3.com.", + "weight": 65 + } + ], + "TTL": 300, + "fqdn": "_sip._tcp.dnscontrol-azure.com.", + "provisioningState": "Succeeded", + "targetResource": {} + }, + "type": "Microsoft.Network/dnszones/SRV" + } + }, + { + "index": 115, + "value": { + "etag": "a24ccafe-5a65-4c13-ab65-43c6bf350724", + "id": "/subscriptions/02efc9e4-732d-4a8d-8b82-5b37e10eb89d/resourceGroups/dnscontroltest/providers/Microsoft.Network/dnszones/dnscontrol-azure.com/A/bar.a", + "name": "bar.a", + "properties": { + "TTL": 300, + "fqdn": "bar.a.dnscontrol-azure.com.", + "provisioningState": "Succeeded", + "targetResource": { + "id": "/subscriptions/02efc9e4-732d-4a8d-8b82-5b37e10eb89d/resourceGroups/dnscontroltest/providers/Microsoft.Network/dnszones/dnscontrol-azure.com/A/foo.a" + } + }, + "type": "Microsoft.Network/dnszones/A" + } + }, + { + "index": 116, + "value": { + "etag": "a3e70f3f-c857-40f4-b42b-41b8f2e68825", + "id": "/subscriptions/02efc9e4-732d-4a8d-8b82-5b37e10eb89d/resourceGroups/dnscontroltest/providers/Microsoft.Network/dnszones/dnscontrol-azure.com/CNAME/bar", + "name": "bar", + "properties": { + "CNAMERecord": { + "cname": "redact2.acm-validations.aws." + }, + "TTL": 300, + "fqdn": "bar.dnscontrol-azure.com.", + "provisioningState": "Succeeded", + "targetResource": {} + }, + "type": "Microsoft.Network/dnszones/CNAME" + } + }, + { + "index": 117, + "value": { + "etag": "a81df834-8705-4279-91ae-68c441d4c9d0", + "id": "/subscriptions/02efc9e4-732d-4a8d-8b82-5b37e10eb89d/resourceGroups/dnscontroltest/providers/Microsoft.Network/dnszones/dnscontrol-azure.com/SOA/@", + "name": "@", + "properties": { + "SOARecord": { + "email": "azuredns-hostmaster.microsoft.com", + "expireTime": 2419200, + "host": "ns1-06.azure-dns.com.", + "minimumTTL": 300, + "refreshTime": 3600, + "retryTime": 300, + "serialNumber": 1 + }, + "TTL": 3600, + "fqdn": "dnscontrol-azure.com.", + "provisioningState": "Succeeded", + "targetResource": {} + }, + "type": "Microsoft.Network/dnszones/SOA" + } + }, + { + "index": 118, + "value": { + "etag": "a974f7c8-782b-4d41-b40f-a6260d0b7363", + "id": "/subscriptions/02efc9e4-732d-4a8d-8b82-5b37e10eb89d/resourceGroups/dnscontroltest/providers/Microsoft.Network/dnszones/dnscontrol-azure.com/A/xn--ndaaa", + "name": "xn--ndaaa", + "properties": { + "ARecords": [ + { + "ipv4Address": "2.2.2.2" + } + ], + "TTL": 300, + "fqdn": "xn--ndaaa.dnscontrol-azure.com.", + "provisioningState": "Succeeded", + "targetResource": {} + }, + "type": "Microsoft.Network/dnszones/A" + } + }, + { + "index": 119, + "value": { + "etag": "aadd7aed-9a12-402b-af85-858139da8e1d", + "id": "/subscriptions/02efc9e4-732d-4a8d-8b82-5b37e10eb89d/resourceGroups/dnscontroltest/providers/Microsoft.Network/dnszones/dnscontrol-azure.com/TXT/@", + "name": "@", + "properties": { + "TTL": 300, + "TXTRecords": [ + { + "value": [ + "simple" + ] + } + ], + "fqdn": "dnscontrol-azure.com.", + "provisioningState": "Succeeded", + "targetResource": {} + }, + "type": "Microsoft.Network/dnszones/TXT" + } + }, + { + "index": 120, + "value": { + "etag": "aae3eb51-55c5-4bfe-a4e9-a768ffdb5073", + "id": "/subscriptions/02efc9e4-732d-4a8d-8b82-5b37e10eb89d/resourceGroups/dnscontroltest/providers/Microsoft.Network/dnszones/dnscontrol-azure.com/A/@", + "name": "@", + "properties": { + "ARecords": [ + { + "ipv4Address": "1.2.3.4" + } + ], + "TTL": 300, + "fqdn": "dnscontrol-azure.com.", + "provisioningState": "Succeeded", + "targetResource": {} + }, + "type": "Microsoft.Network/dnszones/A" + } + }, + { + "index": 121, + "value": { + "etag": "ad6d0e40-9957-4428-9aae-f892d28ca16c", + "id": "/subscriptions/02efc9e4-732d-4a8d-8b82-5b37e10eb89d/resourceGroups/dnscontroltest/providers/Microsoft.Network/dnszones/dnscontrol-azure.com/NS/@", + "name": "@", + "properties": { + "NSRecords": [ + { + "nsdname": "ns1-06.azure-dns.com." + }, + { + "nsdname": "ns1.example.com." + }, + { + "nsdname": "ns2-06.azure-dns.net." + }, + { + "nsdname": "ns2.example.com." + }, + { + "nsdname": "ns3-06.azure-dns.org." + }, + { + "nsdname": "ns4-06.azure-dns.info." + } + ], + "TTL": 300, + "fqdn": "dnscontrol-azure.com.", + "provisioningState": "Succeeded", + "targetResource": {} + }, + "type": "Microsoft.Network/dnszones/NS" + } + }, + { + "index": 122, + "value": { + "etag": "adb102d2-e008-4605-a863-4002b8109e9c", + "id": "/subscriptions/02efc9e4-732d-4a8d-8b82-5b37e10eb89d/resourceGroups/dnscontroltest/providers/Microsoft.Network/dnszones/dnscontrol-azure.com/NS/@", + "name": "@", + "properties": { + "NSRecords": [ + { + "nsdname": "ns1-06.azure-dns.com." + }, + { + "nsdname": "ns2-06.azure-dns.net." + }, + { + "nsdname": "ns3-06.azure-dns.org." + }, + { + "nsdname": "ns4-06.azure-dns.info." + } + ], + "TTL": 300, + "fqdn": "dnscontrol-azure.com.", + "provisioningState": "Succeeded", + "targetResource": {} + }, + "type": "Microsoft.Network/dnszones/NS" + } + }, + { + "index": 123, + "value": { + "etag": "adbbe017-21bb-4c14-80f1-e3edcdb4c11c", + "id": "/subscriptions/02efc9e4-732d-4a8d-8b82-5b37e10eb89d/resourceGroups/dnscontroltest/providers/Microsoft.Network/dnszones/dnscontrol-azure.com/A/foo", + "name": "foo", + "properties": { + "ARecords": [ + { + "ipv4Address": "1.2.3.4" + } + ], + "TTL": 300, + "fqdn": "foo.dnscontrol-azure.com.", + "provisioningState": "Succeeded", + "targetResource": {} + }, + "type": "Microsoft.Network/dnszones/A" + } + }, + { + "index": 124, + "value": { + "etag": "b08fea00-af9c-45b8-815d-bea128985c61", + "id": "/subscriptions/02efc9e4-732d-4a8d-8b82-5b37e10eb89d/resourceGroups/dnscontroltest/providers/Microsoft.Network/dnszones/dnscontrol-azure.com/MX/@", + "name": "@", + "properties": { + "MXRecords": [ + { + "exchange": "foo.com.", + "preference": 5 + } + ], + "TTL": 300, + "fqdn": "dnscontrol-azure.com.", + "provisioningState": "Succeeded", + "targetResource": {} + }, + "type": "Microsoft.Network/dnszones/MX" + } + }, + { + "index": 125, + "value": { + "etag": "b4367fbf-8c36-48b1-89c0-546bf5faf7c2", + "id": "/subscriptions/02efc9e4-732d-4a8d-8b82-5b37e10eb89d/resourceGroups/dnscontroltest/providers/Microsoft.Network/dnszones/dnscontrol-azure.com/SRV/_sip._tcp", + "name": "_sip._tcp", + "properties": { + "SRVRecords": [ + { + "port": 75, + "priority": 15, + "target": "foo4.com.", + "weight": 65 + }, + { + "port": 72, + "priority": 52, + "target": "foo.com.", + "weight": 62 + } + ], + "TTL": 300, + "fqdn": "_sip._tcp.dnscontrol-azure.com.", + "provisioningState": "Succeeded", + "targetResource": {} + }, + "type": "Microsoft.Network/dnszones/SRV" + } + }, + { + "index": 126, + "value": { + "etag": "b43c9f27-8d51-4921-942a-47b092b9ca93", + "id": "/subscriptions/02efc9e4-732d-4a8d-8b82-5b37e10eb89d/resourceGroups/dnscontroltest/providers/Microsoft.Network/dnszones/dnscontrol-azure.com/TXT/foodqs", + "name": "foodqs", + "properties": { + "TTL": 300, + "TXTRecords": [ + { + "value": [ + "\"left" + ] + } + ], + "fqdn": "foodqs.dnscontrol-azure.com.", + "provisioningState": "Succeeded", + "targetResource": {} + }, + "type": "Microsoft.Network/dnszones/TXT" + } + }, + { + "index": 127, + "value": { + "etag": "b51e06dd-1ed7-4beb-9d17-cac86e9400b9", + "id": "/subscriptions/02efc9e4-732d-4a8d-8b82-5b37e10eb89d/resourceGroups/dnscontroltest/providers/Microsoft.Network/dnszones/dnscontrol-azure.com/CNAME/a", + "name": "a", + "properties": { + "CNAMERecord": { + "cname": "xn--ndaaa.com." + }, + "TTL": 300, + "fqdn": "a.dnscontrol-azure.com.", + "provisioningState": "Succeeded", + "targetResource": {} + }, + "type": "Microsoft.Network/dnszones/CNAME" + } + }, + { + "index": 128, + "value": { + "etag": "b5b14737-68a9-4006-a743-6f9551e4065b", + "id": "/subscriptions/02efc9e4-732d-4a8d-8b82-5b37e10eb89d/resourceGroups/dnscontroltest/providers/Microsoft.Network/dnszones/dnscontrol-azure.com/A/foo", + "name": "foo", + "properties": { + "ARecords": [ + { + "ipv4Address": "2.3.4.5" + }, + { + "ipv4Address": "3.4.5.6" + } + ], + "TTL": 300, + "fqdn": "foo.dnscontrol-azure.com.", + "provisioningState": "Succeeded", + "targetResource": {} + }, + "type": "Microsoft.Network/dnszones/A" + } + }, + { + "index": 129, + "value": { + "etag": "b69d2aaf-ee01-45f5-9b40-1eb9d75e7cf2", + "id": "/subscriptions/02efc9e4-732d-4a8d-8b82-5b37e10eb89d/resourceGroups/dnscontroltest/providers/Microsoft.Network/dnszones/dnscontrol-azure.com/TXT/foo765", + "name": "foo765", + "properties": { + "TTL": 300, + "TXTRecords": [ + { + "value": [ + "HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH", + "HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH", + "HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH" + ] + } + ], + "fqdn": "foo765.dnscontrol-azure.com.", + "provisioningState": "Succeeded", + "targetResource": {} + }, + "type": "Microsoft.Network/dnszones/TXT" + } + }, + { + "index": 130, + "value": { + "etag": "b74b80a3-b116-446e-bba9-f539efbf1fe9", + "id": "/subscriptions/02efc9e4-732d-4a8d-8b82-5b37e10eb89d/resourceGroups/dnscontroltest/providers/Microsoft.Network/dnszones/dnscontrol-azure.com/A/www", + "name": "www", + "properties": { + "ARecords": [ + { + "ipv4Address": "1.2.3.4" + }, + { + "ipv4Address": "5.6.7.8" + } + ], + "TTL": 700, + "fqdn": "www.dnscontrol-azure.com.", + "provisioningState": "Succeeded", + "targetResource": {} + }, + "type": "Microsoft.Network/dnszones/A" + } + }, + { + "index": 131, + "value": { + "etag": "b7a7cea4-372c-4685-9080-cc0ae21dfb07", + "id": "/subscriptions/02efc9e4-732d-4a8d-8b82-5b37e10eb89d/resourceGroups/dnscontroltest/providers/Microsoft.Network/dnszones/dnscontrol-azure.com/TXT/foobt", + "name": "foobt", + "properties": { + "TTL": 300, + "TXTRecords": [ + { + "value": [ + "blah`blah" + ] + } + ], + "fqdn": "foobt.dnscontrol-azure.com.", + "provisioningState": "Succeeded", + "targetResource": {} + }, + "type": "Microsoft.Network/dnszones/TXT" + } + }, + { + "index": 132, + "value": { + "etag": "b8ca19e0-2c8e-47d1-a7c4-73e00760698c", + "id": "/subscriptions/02efc9e4-732d-4a8d-8b82-5b37e10eb89d/resourceGroups/dnscontroltest/providers/Microsoft.Network/dnszones/dnscontrol-azure.com/AAAA/testaaaa", + "name": "testaaaa", + "properties": { + "AAAARecords": [ + { + "ipv6Address": "2607:f8b0:4006:820::2013" + } + ], + "TTL": 300, + "fqdn": "testaaaa.dnscontrol-azure.com.", + "provisioningState": "Succeeded", + "targetResource": {} + }, + "type": "Microsoft.Network/dnszones/AAAA" + } + }, + { + "index": 133, + "value": { + "etag": "b8f776a2-851c-4add-92a5-c528d73b677c", + "id": "/subscriptions/02efc9e4-732d-4a8d-8b82-5b37e10eb89d/resourceGroups/dnscontroltest/providers/Microsoft.Network/dnszones/dnscontrol-azure.com/TXT/foo255", + "name": "foo255", + "properties": { + "TTL": 300, + "TXTRecords": [ + { + "value": [ + "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" + ] + } + ], + "fqdn": "foo255.dnscontrol-azure.com.", + "provisioningState": "Succeeded", + "targetResource": {} + }, + "type": "Microsoft.Network/dnszones/TXT" + } + }, + { + "index": 134, + "value": { + "etag": "b9b57c92-2a71-4c17-b232-1ecda12d138b", + "id": "/subscriptions/02efc9e4-732d-4a8d-8b82-5b37e10eb89d/resourceGroups/dnscontroltest/providers/Microsoft.Network/dnszones/dnscontrol-azure.com/A/@", + "name": "@", + "properties": { + "ARecords": [ + { + "ipv4Address": "8.8.8.8" + } + ], + "TTL": 500, + "fqdn": "dnscontrol-azure.com.", + "provisioningState": "Succeeded", + "targetResource": {} + }, + "type": "Microsoft.Network/dnszones/A" + } + }, + { + "index": 135, + "value": { + "etag": "ba7444ea-12d1-4eb1-8adb-a07b1e4c3880", + "id": "/subscriptions/02efc9e4-732d-4a8d-8b82-5b37e10eb89d/resourceGroups/dnscontroltest/providers/Microsoft.Network/dnszones/dnscontrol-azure.com/A/foo", + "name": "foo", + "properties": { + "ARecords": [ + { + "ipv4Address": "1.2.3.4" + } + ], + "TTL": 300, + "fqdn": "foo.dnscontrol-azure.com.", + "provisioningState": "Succeeded", + "targetResource": {} + }, + "type": "Microsoft.Network/dnszones/A" + } + }, + { + "index": 136, + "value": { + "etag": "bb607512-474f-463e-8276-b7fe41bbf4dd", + "id": "/subscriptions/02efc9e4-732d-4a8d-8b82-5b37e10eb89d/resourceGroups/dnscontroltest/providers/Microsoft.Network/dnszones/dnscontrol-azure.com/AAAA/dyndns-city2", + "name": "dyndns-city2", + "properties": { + "AAAARecords": [ + { + "ipv6Address": "2003:dd:d7ff::fe71:ce78" + } + ], + "TTL": 300, + "fqdn": "dyndns-city2.dnscontrol-azure.com.", + "provisioningState": "Succeeded", + "targetResource": {} + }, + "type": "Microsoft.Network/dnszones/AAAA" + } + }, + { + "index": 137, + "value": { + "etag": "c01b9737-ed7a-4ac9-aa0e-dee341dae145", + "id": "/subscriptions/02efc9e4-732d-4a8d-8b82-5b37e10eb89d/resourceGroups/dnscontroltest/providers/Microsoft.Network/dnszones/dnscontrol-azure.com/TXT/foosc1", + "name": "foosc1", + "properties": { + "TTL": 300, + "TXTRecords": [ + { + "value": [ + "semi;colon" + ] + } + ], + "fqdn": "foosc1.dnscontrol-azure.com.", + "provisioningState": "Succeeded", + "targetResource": {} + }, + "type": "Microsoft.Network/dnszones/TXT" + } + }, + { + "index": 138, + "value": { + "etag": "c3eda3b0-c917-4c24-a72d-f0d0e49d1bce", + "id": "/subscriptions/02efc9e4-732d-4a8d-8b82-5b37e10eb89d/resourceGroups/dnscontroltest/providers/Microsoft.Network/dnszones/dnscontrol-azure.com/TXT/foo511", + "name": "foo511", + "properties": { + "TTL": 300, + "TXTRecords": [ + { + "value": [ + "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF", + "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF", + "F" + ] + } + ], + "fqdn": "foo511.dnscontrol-azure.com.", + "provisioningState": "Succeeded", + "targetResource": {} + }, + "type": "Microsoft.Network/dnszones/TXT" + } + }, + { + "index": 139, + "value": { + "etag": "c50954af-7c89-45b3-aac3-54d1116aa4a0", + "id": "/subscriptions/02efc9e4-732d-4a8d-8b82-5b37e10eb89d/resourceGroups/dnscontroltest/providers/Microsoft.Network/dnszones/dnscontrol-azure.com/A/www", + "name": "www", + "properties": { + "ARecords": [ + { + "ipv4Address": "1.1.1.1" + } + ], + "TTL": 300, + "fqdn": "www.dnscontrol-azure.com.", + "provisioningState": "Succeeded", + "targetResource": {} + }, + "type": "Microsoft.Network/dnszones/A" + } + }, + { + "index": 140, + "value": { + "etag": "c6894976-9f02-4a0a-9bf7-6f722c622f7b", + "id": "/subscriptions/02efc9e4-732d-4a8d-8b82-5b37e10eb89d/resourceGroups/dnscontroltest/providers/Microsoft.Network/dnszones/dnscontrol-azure.com/TXT/final", + "name": "final", + "properties": { + "TTL": 300, + "TXTRecords": [ + { + "value": [ + "TestDNSProviders was successful!" + ] + } + ], + "fqdn": "final.dnscontrol-azure.com.", + "provisioningState": "Succeeded", + "targetResource": {} + }, + "type": "Microsoft.Network/dnszones/TXT" + } + }, + { + "index": 141, + "value": { + "etag": "c71ddff8-9a96-40a1-aebc-837f511eb661", + "id": "/subscriptions/02efc9e4-732d-4a8d-8b82-5b37e10eb89d/resourceGroups/dnscontroltest/providers/Microsoft.Network/dnszones/dnscontrol-azure.com/MX/foo", + "name": "foo", + "properties": { + "MXRecords": [ + { + "exchange": "aspmx.l.google.com.", + "preference": 10 + }, + { + "exchange": "alt1.aspmx.l.google.com.", + "preference": 20 + } + ], + "TTL": 300, + "fqdn": "foo.dnscontrol-azure.com.", + "provisioningState": "Succeeded", + "targetResource": {} + }, + "type": "Microsoft.Network/dnszones/MX" + } + }, + { + "index": 142, + "value": { + "etag": "c8360a03-eea4-44c0-bc60-3f9bd1dae10f", + "id": "/subscriptions/02efc9e4-732d-4a8d-8b82-5b37e10eb89d/resourceGroups/dnscontroltest/providers/Microsoft.Network/dnszones/dnscontrol-azure.com/NS/xyz", + "name": "xyz", + "properties": { + "NSRecords": [ + { + "nsdname": "ns1.foo.com." + }, + { + "nsdname": "ns2.foo.com." + } + ], + "TTL": 300, + "fqdn": "xyz.dnscontrol-azure.com.", + "provisioningState": "Succeeded", + "targetResource": {} + }, + "type": "Microsoft.Network/dnszones/NS" + } + }, + { + "index": 143, + "value": { + "etag": "c9662508-9785-40e1-b2d2-cb4fd22db314", + "id": "/subscriptions/02efc9e4-732d-4a8d-8b82-5b37e10eb89d/resourceGroups/dnscontroltest/providers/Microsoft.Network/dnszones/dnscontrol-azure.com/CNAME/foo.cname", + "name": "foo.cname", + "properties": { + "CNAMERecord": { + "cname": "google.com." + }, + "TTL": 300, + "fqdn": "foo.cname.dnscontrol-azure.com.", + "provisioningState": "Succeeded", + "targetResource": {} + }, + "type": "Microsoft.Network/dnszones/CNAME" + } + }, + { + "index": 144, + "value": { + "etag": "ca35c053-5e9b-4590-8be9-d2bf743c0028", + "id": "/subscriptions/02efc9e4-732d-4a8d-8b82-5b37e10eb89d/resourceGroups/dnscontroltest/providers/Microsoft.Network/dnszones/dnscontrol-azure.com/CNAME/bar.cname", + "name": "bar.cname", + "properties": { + "TTL": 300, + "fqdn": "bar.cname.dnscontrol-azure.com.", + "provisioningState": "Succeeded", + "targetResource": { + "id": "/subscriptions/02efc9e4-732d-4a8d-8b82-5b37e10eb89d/resourceGroups/dnscontroltest/providers/Microsoft.Network/dnszones/dnscontrol-azure.com/CNAME/quux.cname" + } + }, + "type": "Microsoft.Network/dnszones/CNAME" + } + }, + { + "index": 145, + "value": { + "etag": "cad0f683-b980-4e46-945f-b189d0b9b4b6", + "id": "/subscriptions/02efc9e4-732d-4a8d-8b82-5b37e10eb89d/resourceGroups/dnscontroltest/providers/Microsoft.Network/dnszones/dnscontrol-azure.com/TXT/foows1", + "name": "foows1", + "properties": { + "TTL": 300, + "TXTRecords": [ + { + "value": [ + "trailingws " + ] + } + ], + "fqdn": "foows1.dnscontrol-azure.com.", + "provisioningState": "Succeeded", + "targetResource": {} + }, + "type": "Microsoft.Network/dnszones/TXT" + } + }, + { + "index": 146, + "value": { + "etag": "cae02e38-3b81-4014-9520-36fb6c39564d", + "id": "/subscriptions/02efc9e4-732d-4a8d-8b82-5b37e10eb89d/resourceGroups/dnscontroltest/providers/Microsoft.Network/dnszones/dnscontrol-azure.com/CAA/@", + "name": "@", + "properties": { + "TTL": 300, + "caaRecords": [ + { + "flags": 0, + "tag": "issuewild", + "value": ";" + } + ], + "fqdn": "dnscontrol-azure.com.", + "provisioningState": "Succeeded", + "targetResource": {} + }, + "type": "Microsoft.Network/dnszones/CAA" + } + }, + { + "index": 147, + "value": { + "etag": "cb96a2f1-e3b3-4aa4-9578-1cf1a50599a7", + "id": "/subscriptions/02efc9e4-732d-4a8d-8b82-5b37e10eb89d/resourceGroups/dnscontroltest/providers/Microsoft.Network/dnszones/dnscontrol-azure.com/SRV/_sip._tcp", + "name": "_sip._tcp", + "properties": { + "SRVRecords": [ + { + "port": 7, + "priority": 5, + "target": "foo.com.", + "weight": 6 + } + ], + "TTL": 4400, + "fqdn": "_sip._tcp.dnscontrol-azure.com.", + "provisioningState": "Succeeded", + "targetResource": {} + }, + "type": "Microsoft.Network/dnszones/SRV" + } + }, + { + "index": 148, + "value": { + "etag": "cc91bebf-f50c-4c11-8515-0a7fb9f7d56f", + "id": "/subscriptions/02efc9e4-732d-4a8d-8b82-5b37e10eb89d/resourceGroups/dnscontroltest/providers/Microsoft.Network/dnszones/dnscontrol-azure.com/A/www", + "name": "www", + "properties": { + "ARecords": [ + { + "ipv4Address": "1.2.3.8" + } + ], + "TTL": 300, + "fqdn": "www.dnscontrol-azure.com.", + "provisioningState": "Succeeded", + "targetResource": {} + }, + "type": "Microsoft.Network/dnszones/A" + } + }, + { + "index": 149, + "value": { + "etag": "cdc32576-325a-48f9-a0a9-0763046b0d2b", + "id": "/subscriptions/02efc9e4-732d-4a8d-8b82-5b37e10eb89d/resourceGroups/dnscontroltest/providers/Microsoft.Network/dnszones/dnscontrol-azure.com/MX/testmx", + "name": "testmx", + "properties": { + "MXRecords": [ + { + "exchange": "foo.com.", + "preference": 5 + } + ], + "TTL": 300, + "fqdn": "testmx.dnscontrol-azure.com.", + "provisioningState": "Succeeded", + "targetResource": {} + }, + "type": "Microsoft.Network/dnszones/MX" + } + }, + { + "index": 150, + "value": { + "etag": "ceb42243-fe77-4880-b43e-f7ea8f92077f", + "id": "/subscriptions/02efc9e4-732d-4a8d-8b82-5b37e10eb89d/resourceGroups/dnscontroltest/providers/Microsoft.Network/dnszones/dnscontrol-azure.com/TXT/foo256", + "name": "foo256", + "properties": { + "TTL": 300, + "TXTRecords": [ + { + "value": [ + "CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC", + "C" + ] + } + ], + "fqdn": "foo256.dnscontrol-azure.com.", + "provisioningState": "Succeeded", + "targetResource": {} + }, + "type": "Microsoft.Network/dnszones/TXT" + } + }, + { + "index": 151, + "value": { + "etag": "cfb93c10-31d2-4532-a1e7-9453f0a431e2", + "id": "/subscriptions/02efc9e4-732d-4a8d-8b82-5b37e10eb89d/resourceGroups/dnscontroltest/providers/Microsoft.Network/dnszones/dnscontrol-azure.com/SRV/_sip._tcp", + "name": "_sip._tcp", + "properties": { + "SRVRecords": [ + { + "port": 75, + "priority": 15, + "target": "foo4.com.", + "weight": 65 + }, + { + "port": 7, + "priority": 52, + "target": "foo.com.", + "weight": 6 + } + ], + "TTL": 300, + "fqdn": "_sip._tcp.dnscontrol-azure.com.", + "provisioningState": "Succeeded", + "targetResource": {} + }, + "type": "Microsoft.Network/dnszones/SRV" + } + }, + { + "index": 152, + "value": { + "etag": "d06ca21b-d4f7-48a7-a95a-7f6005ea92ce", + "id": "/subscriptions/02efc9e4-732d-4a8d-8b82-5b37e10eb89d/resourceGroups/dnscontroltest/providers/Microsoft.Network/dnszones/dnscontrol-azure.com/SRV/_sip._tcp", + "name": "_sip._tcp", + "properties": { + "SRVRecords": [ + { + "port": 7, + "priority": 5, + "target": "foo.com.", + "weight": 6 + }, + { + "port": 70, + "priority": 5, + "target": "foo2.com.", + "weight": 60 + } + ], + "TTL": 300, + "fqdn": "_sip._tcp.dnscontrol-azure.com.", + "provisioningState": "Succeeded", + "targetResource": {} + }, + "type": "Microsoft.Network/dnszones/SRV" + } + }, + { + "index": 153, + "value": { + "etag": "d0846243-c70d-484c-ad80-8acfed2a4fa5", + "id": "/subscriptions/02efc9e4-732d-4a8d-8b82-5b37e10eb89d/resourceGroups/dnscontroltest/providers/Microsoft.Network/dnszones/dnscontrol-azure.com/AAAA/dyndns-city1", + "name": "dyndns-city1", + "properties": { + "AAAARecords": [ + { + "ipv6Address": "2003:dd:d7ff::fe71:ce77" + } + ], + "TTL": 300, + "fqdn": "dyndns-city1.dnscontrol-azure.com.", + "provisioningState": "Succeeded", + "targetResource": {} + }, + "type": "Microsoft.Network/dnszones/AAAA" + } + }, + { + "index": 154, + "value": { + "etag": "d31ca63c-2c61-472e-98b0-514750db8218", + "id": "/subscriptions/02efc9e4-732d-4a8d-8b82-5b37e10eb89d/resourceGroups/dnscontroltest/providers/Microsoft.Network/dnszones/dnscontrol-azure.com/SRV/_sip._tcp", + "name": "_sip._tcp", + "properties": { + "SRVRecords": [ + { + "port": 75, + "priority": 15, + "target": ".", + "weight": 65 + } + ], + "TTL": 300, + "fqdn": "_sip._tcp.dnscontrol-azure.com.", + "provisioningState": "Succeeded", + "targetResource": {} + }, + "type": "Microsoft.Network/dnszones/SRV" + } + }, + { + "index": 155, + "value": { + "etag": "d33d74a0-eb64-4a49-b652-65bae6e7f2b1", + "id": "/subscriptions/02efc9e4-732d-4a8d-8b82-5b37e10eb89d/resourceGroups/dnscontroltest/providers/Microsoft.Network/dnszones/dnscontrol-azure.com/CAA/@", + "name": "@", + "properties": { + "TTL": 300, + "caaRecords": [ + { + "flags": 0, + "tag": "issuewild", + "value": "example.com" + } + ], + "fqdn": "dnscontrol-azure.com.", + "provisioningState": "Succeeded", + "targetResource": {} + }, + "type": "Microsoft.Network/dnszones/CAA" + } + }, + { + "index": 156, + "value": { + "etag": "d4a42822-c1a1-4b5d-899e-b5eeab14b089", + "id": "/subscriptions/02efc9e4-732d-4a8d-8b82-5b37e10eb89d/resourceGroups/dnscontroltest/providers/Microsoft.Network/dnszones/dnscontrol-azure.com/NS/@", + "name": "@", + "properties": { + "NSRecords": [ + { + "nsdname": "ns1-06.azure-dns.com." + }, + { + "nsdname": "ns1.example.com." + }, + { + "nsdname": "ns2-06.azure-dns.net." + }, + { + "nsdname": "ns3-06.azure-dns.org." + }, + { + "nsdname": "ns4-06.azure-dns.info." + } + ], + "TTL": 300, + "fqdn": "dnscontrol-azure.com.", + "provisioningState": "Succeeded", + "targetResource": {} + }, + "type": "Microsoft.Network/dnszones/NS" + } + }, + { + "index": 157, + "value": { + "etag": "d72932de-edb8-46f1-9897-8794c6a8b570", + "id": "/subscriptions/02efc9e4-732d-4a8d-8b82-5b37e10eb89d/resourceGroups/dnscontroltest/providers/Microsoft.Network/dnszones/dnscontrol-azure.com/TXT/foodq", + "name": "foodq", + "properties": { + "TTL": 300, + "TXTRecords": [ + { + "value": [ + "in\"side" + ] + } + ], + "fqdn": "foodq.dnscontrol-azure.com.", + "provisioningState": "Succeeded", + "targetResource": {} + }, + "type": "Microsoft.Network/dnszones/TXT" + } + }, + { + "index": 158, + "value": { + "etag": "d910365e-da76-4146-8fe7-a3899b993be0", + "id": "/subscriptions/02efc9e4-732d-4a8d-8b82-5b37e10eb89d/resourceGroups/dnscontroltest/providers/Microsoft.Network/dnszones/dnscontrol-azure.com/CNAME/mail.bat", + "name": "mail.bat", + "properties": { + "CNAMERecord": { + "cname": "ghs.googlehosted.com." + }, + "TTL": 300, + "fqdn": "mail.bat.dnscontrol-azure.com.", + "provisioningState": "Succeeded", + "targetResource": {} + }, + "type": "Microsoft.Network/dnszones/CNAME" + } + }, + { + "index": 159, + "value": { + "etag": "dab87f02-d6f7-4297-9c2f-58d59080c2a4", + "id": "/subscriptions/02efc9e4-732d-4a8d-8b82-5b37e10eb89d/resourceGroups/dnscontroltest/providers/Microsoft.Network/dnszones/dnscontrol-azure.com/A/www", + "name": "www", + "properties": { + "ARecords": [ + { + "ipv4Address": "1.1.1.1" + }, + { + "ipv4Address": "2.2.2.2" + }, + { + "ipv4Address": "3.3.3.3" + } + ], + "TTL": 300, + "fqdn": "www.dnscontrol-azure.com.", + "provisioningState": "Succeeded", + "targetResource": {} + }, + "type": "Microsoft.Network/dnszones/A" + } + }, + { + "index": 160, + "value": { + "etag": "db271fad-c5ff-40b1-be83-b41ba55670c6", + "id": "/subscriptions/02efc9e4-732d-4a8d-8b82-5b37e10eb89d/resourceGroups/dnscontroltest/providers/Microsoft.Network/dnszones/dnscontrol-azure.com/MX/testmx", + "name": "testmx", + "properties": { + "MXRecords": [ + { + "exchange": "bar.com.", + "preference": 5 + } + ], + "TTL": 300, + "fqdn": "testmx.dnscontrol-azure.com.", + "provisioningState": "Succeeded", + "targetResource": {} + }, + "type": "Microsoft.Network/dnszones/MX" + } + }, + { + "index": 161, + "value": { + "etag": "dc83618d-0a2f-48d1-ae70-0eb584f40ba4", + "id": "/subscriptions/02efc9e4-732d-4a8d-8b82-5b37e10eb89d/resourceGroups/dnscontroltest/providers/Microsoft.Network/dnszones/dnscontrol-azure.com/TXT/foo509", + "name": "foo509", + "properties": { + "TTL": 300, + "TXTRecords": [ + { + "value": [ + "DDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDD", + "DDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDD" + ] + } + ], + "fqdn": "foo509.dnscontrol-azure.com.", + "provisioningState": "Succeeded", + "targetResource": {} + }, + "type": "Microsoft.Network/dnszones/TXT" + } + }, + { + "index": 162, + "value": { + "etag": "e2cf3d79-3568-4f15-953d-043792da8aa1", + "id": "/subscriptions/02efc9e4-732d-4a8d-8b82-5b37e10eb89d/resourceGroups/dnscontroltest/providers/Microsoft.Network/dnszones/dnscontrol-azure.com/A/foo", + "name": "foo", + "properties": { + "ARecords": [ + { + "ipv4Address": "4.5.6.7" + } + ], + "TTL": 300, + "fqdn": "foo.dnscontrol-azure.com.", + "provisioningState": "Succeeded", + "targetResource": {} + }, + "type": "Microsoft.Network/dnszones/A" + } + }, + { + "index": 163, + "value": { + "etag": "e323e791-7b95-4775-8b44-c37440e114bb", + "id": "/subscriptions/02efc9e4-732d-4a8d-8b82-5b37e10eb89d/resourceGroups/dnscontroltest/providers/Microsoft.Network/dnszones/dnscontrol-azure.com/A/@", + "name": "@", + "properties": { + "ARecords": [ + { + "ipv4Address": "2.2.2.2" + } + ], + "TTL": 300, + "fqdn": "dnscontrol-azure.com.", + "provisioningState": "Succeeded", + "targetResource": {} + }, + "type": "Microsoft.Network/dnszones/A" + } + }, + { + "index": 164, + "value": { + "etag": "e6138827-ea51-47d2-9340-8ab9f9cd9eaa", + "id": "/subscriptions/02efc9e4-732d-4a8d-8b82-5b37e10eb89d/resourceGroups/dnscontroltest/providers/Microsoft.Network/dnszones/dnscontrol-azure.com/CAA/@", + "name": "@", + "properties": { + "TTL": 300, + "caaRecords": [ + { + "flags": 0, + "tag": "issue", + "value": "letsencrypt.org; validationmethods=dns-01; accounturi=https://acme-v02.api.letsencrypt.org/acme/acct/1234" + } + ], + "fqdn": "dnscontrol-azure.com.", + "provisioningState": "Succeeded", + "targetResource": {} + }, + "type": "Microsoft.Network/dnszones/CAA" + } + }, + { + "index": 165, + "value": { + "etag": "e757a270-b89d-47f6-89a0-e3e72081baeb", + "id": "/subscriptions/02efc9e4-732d-4a8d-8b82-5b37e10eb89d/resourceGroups/dnscontroltest/providers/Microsoft.Network/dnszones/dnscontrol-azure.com/A/*", + "name": "*", + "properties": { + "ARecords": [ + { + "ipv4Address": "3.3.3.3" + } + ], + "TTL": 300, + "fqdn": "*.dnscontrol-azure.com.", + "provisioningState": "Succeeded", + "targetResource": {} + }, + "type": "Microsoft.Network/dnszones/A" + } + }, + { + "index": 166, + "value": { + "etag": "e8bda399-cca6-4941-8e44-25f7ea39eeae", + "id": "/subscriptions/02efc9e4-732d-4a8d-8b82-5b37e10eb89d/resourceGroups/dnscontroltest/providers/Microsoft.Network/dnszones/dnscontrol-azure.com/A/zzz", + "name": "zzz", + "properties": { + "ARecords": [ + { + "ipv4Address": "3.3.3.3" + }, + { + "ipv4Address": "4.4.4.4" + } + ], + "TTL": 300, + "fqdn": "zzz.dnscontrol-azure.com.", + "provisioningState": "Succeeded", + "targetResource": {} + }, + "type": "Microsoft.Network/dnszones/A" + } + }, + { + "index": 167, + "value": { + "etag": "e9de2665-0ae3-4d3a-ae8e-00ad4f0095b5", + "id": "/subscriptions/02efc9e4-732d-4a8d-8b82-5b37e10eb89d/resourceGroups/dnscontroltest/providers/Microsoft.Network/dnszones/dnscontrol-azure.com/MX/bar", + "name": "bar", + "properties": { + "MXRecords": [ + { + "exchange": "bar.com.", + "preference": 5 + } + ], + "TTL": 300, + "fqdn": "bar.dnscontrol-azure.com.", + "provisioningState": "Succeeded", + "targetResource": {} + }, + "type": "Microsoft.Network/dnszones/MX" + } + }, + { + "index": 168, + "value": { + "etag": "e9f77b10-271a-43e8-bc60-6de4b6639ff3", + "id": "/subscriptions/02efc9e4-732d-4a8d-8b82-5b37e10eb89d/resourceGroups/dnscontroltest/providers/Microsoft.Network/dnszones/dnscontrol-azure.com/A/testdefined", + "name": "testdefined", + "properties": { + "ARecords": [ + { + "ipv4Address": "2.2.2.2" + } + ], + "TTL": 300, + "fqdn": "testdefined.dnscontrol-azure.com.", + "provisioningState": "Succeeded", + "targetResource": {} + }, + "type": "Microsoft.Network/dnszones/A" + } + }, + { + "index": 169, + "value": { + "etag": "f22782e3-cdac-4a0b-9309-822247fe460b", + "id": "/subscriptions/02efc9e4-732d-4a8d-8b82-5b37e10eb89d/resourceGroups/dnscontroltest/providers/Microsoft.Network/dnszones/dnscontrol-azure.com/A/bar.a", + "name": "bar.a", + "properties": { + "TTL": 300, + "fqdn": "bar.a.dnscontrol-azure.com.", + "provisioningState": "Succeeded", + "targetResource": { + "id": "/subscriptions/02efc9e4-732d-4a8d-8b82-5b37e10eb89d/resourceGroups/dnscontroltest/providers/Microsoft.Network/dnszones/dnscontrol-azure.com/A/foo.a" + } + }, + "type": "Microsoft.Network/dnszones/A" + } + }, + { + "index": 170, + "value": { + "etag": "f29ee712-c006-47cd-907a-ef1d8578c5b8", + "id": "/subscriptions/02efc9e4-732d-4a8d-8b82-5b37e10eb89d/resourceGroups/dnscontroltest/providers/Microsoft.Network/dnszones/dnscontrol-azure.com/A/testa", + "name": "testa", + "properties": { + "ARecords": [ + { + "ipv4Address": "3.3.3.3" + } + ], + "TTL": 300, + "fqdn": "testa.dnscontrol-azure.com.", + "provisioningState": "Succeeded", + "targetResource": {} + }, + "type": "Microsoft.Network/dnszones/A" + } + }, + { + "index": 171, + "value": { + "etag": "f45b7b93-cc92-4dbd-a067-a38cdf12f1d6", + "id": "/subscriptions/02efc9e4-732d-4a8d-8b82-5b37e10eb89d/resourceGroups/dnscontroltest/providers/Microsoft.Network/dnszones/dnscontrol-azure.com/MX/foo", + "name": "foo", + "properties": { + "MXRecords": [ + { + "exchange": "mx.google.com.", + "preference": 5 + } + ], + "TTL": 300, + "fqdn": "foo.dnscontrol-azure.com.", + "provisioningState": "Succeeded", + "targetResource": {} + }, + "type": "Microsoft.Network/dnszones/MX" + } + }, + { + "index": 172, + "value": { + "etag": "f48df3f3-0134-41aa-bce1-a5dc3048d739", + "id": "/subscriptions/02efc9e4-732d-4a8d-8b82-5b37e10eb89d/resourceGroups/dnscontroltest/providers/Microsoft.Network/dnszones/dnscontrol-azure.com/A/foo", + "name": "foo", + "properties": { + "ARecords": [ + { + "ipv4Address": "1.2.3.4" + } + ], + "TTL": 300, + "fqdn": "foo.dnscontrol-azure.com.", + "provisioningState": "Succeeded", + "targetResource": {} + }, + "type": "Microsoft.Network/dnszones/A" + } + }, + { + "index": 173, + "value": { + "etag": "f4f8e9b6-ebab-4464-b594-543ef3c6d38f", + "id": "/subscriptions/02efc9e4-732d-4a8d-8b82-5b37e10eb89d/resourceGroups/dnscontroltest/providers/Microsoft.Network/dnszones/dnscontrol-azure.com/TXT/testtxt", + "name": "testtxt", + "properties": { + "TTL": 300, + "TXTRecords": [ + { + "value": [ + "changed" + ] + } + ], + "fqdn": "testtxt.dnscontrol-azure.com.", + "provisioningState": "Succeeded", + "targetResource": {} + }, + "type": "Microsoft.Network/dnszones/TXT" + } + }, + { + "index": 174, + "value": { + "etag": "f64b78bd-1de2-423c-8332-908ff2e954ba", + "id": "/subscriptions/02efc9e4-732d-4a8d-8b82-5b37e10eb89d/resourceGroups/dnscontroltest/providers/Microsoft.Network/dnszones/dnscontrol-azure.com/A/@", + "name": "@", + "properties": { + "ARecords": [ + { + "ipv4Address": "1.2.3.4" + } + ], + "TTL": 300, + "fqdn": "dnscontrol-azure.com.", + "provisioningState": "Succeeded", + "targetResource": {} + }, + "type": "Microsoft.Network/dnszones/A" + } + }, + { + "index": 175, + "value": { + "etag": "fa98d6dc-8605-4481-a73e-2aef0ef80877", + "id": "/subscriptions/02efc9e4-732d-4a8d-8b82-5b37e10eb89d/resourceGroups/dnscontroltest/providers/Microsoft.Network/dnszones/dnscontrol-azure.com/A/bar", + "name": "bar", + "properties": { + "ARecords": [ + { + "ipv4Address": "5.5.5.5" + } + ], + "TTL": 300, + "fqdn": "bar.dnscontrol-azure.com.", + "provisioningState": "Succeeded", + "targetResource": {} + }, + "type": "Microsoft.Network/dnszones/A" + } + }, + { + "index": 176, + "value": { + "etag": "fb21ce35-32de-47f9-9db8-899e6231a0b9", + "id": "/subscriptions/02efc9e4-732d-4a8d-8b82-5b37e10eb89d/resourceGroups/dnscontroltest/providers/Microsoft.Network/dnszones/dnscontrol-azure.com/A/foo", + "name": "foo", + "properties": { + "ARecords": [ + { + "ipv4Address": "2.3.4.5" + }, + { + "ipv4Address": "8.8.8.8" + } + ], + "TTL": 300, + "fqdn": "foo.dnscontrol-azure.com.", + "provisioningState": "Succeeded", + "targetResource": {} + }, + "type": "Microsoft.Network/dnszones/A" + } + }, + { + "index": 177, + "value": { + "etag": "fbb46ca6-3bbc-43d8-92c4-c0b3755165f4", + "id": "/subscriptions/02efc9e4-732d-4a8d-8b82-5b37e10eb89d/resourceGroups/dnscontroltest/providers/Microsoft.Network/dnszones/dnscontrol-azure.com/A/decoy", + "name": "decoy", + "properties": { + "ARecords": [ + { + "ipv4Address": "1.1.1.1" + } + ], + "TTL": 300, + "fqdn": "decoy.dnscontrol-azure.com.", + "provisioningState": "Succeeded", + "targetResource": {} + }, + "type": "Microsoft.Network/dnszones/A" + } + }, + { + "index": 178, + "value": { + "etag": "fc6a52bd-7fbd-488e-83dc-3e4b27b62bea", + "id": "/subscriptions/02efc9e4-732d-4a8d-8b82-5b37e10eb89d/resourceGroups/dnscontroltest/providers/Microsoft.Network/dnszones/dnscontrol-azure.com/A/dyndns-city2", + "name": "dyndns-city2", + "properties": { + "ARecords": [ + { + "ipv4Address": "91.42.1.2" + } + ], + "TTL": 300, + "fqdn": "dyndns-city2.dnscontrol-azure.com.", + "provisioningState": "Succeeded", + "targetResource": {} + }, + "type": "Microsoft.Network/dnszones/A" + } + }, + { + "index": 179, + "value": { + "etag": "fd7c30b2-53bb-4ced-b03e-97b0c1decdf5", + "id": "/subscriptions/02efc9e4-732d-4a8d-8b82-5b37e10eb89d/resourceGroups/dnscontroltest/providers/Microsoft.Network/dnszones/dnscontrol-azure.com/A/foo", + "name": "foo", + "properties": { + "ARecords": [ + { + "ipv4Address": "1.2.3.4" + } + ], + "TTL": 300, + "fqdn": "foo.dnscontrol-azure.com.", + "provisioningState": "Succeeded", + "targetResource": {} + }, + "type": "Microsoft.Network/dnszones/A" + } + }, + { + "index": 180, + "value": { + "etag": "fd89ad90-d939-458a-ad1c-1f103e0c9aa1", + "id": "/subscriptions/02efc9e4-732d-4a8d-8b82-5b37e10eb89d/resourceGroups/dnscontroltest/providers/Microsoft.Network/dnszones/dnscontrol-azure.com/A/foo", + "name": "foo", + "properties": { + "ARecords": [ + { + "ipv4Address": "1.1.1.1" + }, + { + "ipv4Address": "10.10.10.10" + } + ], + "TTL": 300, + "fqdn": "foo.dnscontrol-azure.com.", + "provisioningState": "Succeeded", + "targetResource": {} + }, + "type": "Microsoft.Network/dnszones/A" + } + }, + { + "index": 181, + "value": { + "etag": "fef75930-edf1-45b4-823c-033ef19b1d0a", + "id": "/subscriptions/02efc9e4-732d-4a8d-8b82-5b37e10eb89d/resourceGroups/dnscontroltest/providers/Microsoft.Network/dnszones/dnscontrol-azure.com/MX/nmx", + "name": "nmx", + "properties": { + "MXRecords": [ + { + "exchange": ".", + "preference": 0 + } + ], + "TTL": 300, + "fqdn": "nmx.dnscontrol-azure.com.", + "provisioningState": "Succeeded", + "targetResource": {} + }, + "type": "Microsoft.Network/dnszones/MX" + } + } +] diff --git a/providers/azureprivatedns/auditrecords.go b/providers/azureprivatedns/auditrecords.go index f90275a241..30eda42402 100644 --- a/providers/azureprivatedns/auditrecords.go +++ b/providers/azureprivatedns/auditrecords.go @@ -1,17 +1,15 @@ package azureprivatedns import ( - "github.com/DNSControl/dnscontrol/v4/models" - "github.com/DNSControl/dnscontrol/v4/pkg/rejectif" + "github.com/DNSControl/dnscontrol/v5/models" + "github.com/DNSControl/dnscontrol/v5/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 { +func AuditRecords(records models.Records) []error { a := rejectif.Auditor{} - a.Add("MX", rejectif.MxNull) // Last verified 2020-12-28 - return a.Audit(records) } diff --git a/providers/azureprivatedns/azurePrivateDnsProvider.go b/providers/azureprivatedns/azurePrivateDnsProvider.go index 912a67ed03..729a23ac08 100644 --- a/providers/azureprivatedns/azurePrivateDnsProvider.go +++ b/providers/azureprivatedns/azurePrivateDnsProvider.go @@ -9,18 +9,20 @@ import ( "strings" "time" + dnsv2 "codeberg.org/miekg/dns" "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/DNSControl/dnscontrol/v4/models" - "github.com/DNSControl/dnscontrol/v4/pkg/diff2" - "github.com/DNSControl/dnscontrol/v4/pkg/printer" - "github.com/DNSControl/dnscontrol/v4/pkg/providers" + "github.com/DNSControl/dnscontrol/v5/models" + "github.com/DNSControl/dnscontrol/v5/pkg/diff2" + "github.com/DNSControl/dnscontrol/v5/pkg/printer" + "github.com/DNSControl/dnscontrol/v5/pkg/providers" ) const azurePendingOperationConflictMessage = "Another operation is pending for requested object" type azurednsProvider struct { + observer providers.ConversionObserver zonesClient *adns.PrivateZonesClient recordsClient *adns.RecordSetsClient zones map[string]*adns.PrivateZone @@ -30,6 +32,10 @@ type azurednsProvider struct { zoneName map[string]string } +func (a *azurednsProvider) SetConversionObserver(observer providers.ConversionObserver) { + a.observer = observer +} + func newAzureDNSDsp(conf map[string]string, metadata json.RawMessage) (providers.DNSServiceProvider, error) { return newAzureDNS(conf, metadata) } @@ -197,9 +203,7 @@ func (a *azurednsProvider) ListZones() ([]string, error) { // GetZoneRecords gets the records of a zone and returns them in RecordConfig format. func (a *azurednsProvider) GetZoneRecords(dc *models.DomainConfig) (models.Records, error) { - domain := dc.Name - - existingRecords, _, _, err := a.getExistingRecords(domain) + existingRecords, _, _, err := a.getExistingRecords(dc) if err != nil { return nil, err } @@ -207,7 +211,8 @@ func (a *azurednsProvider) GetZoneRecords(dc *models.DomainConfig) (models.Recor return existingRecords, nil } -func (a *azurednsProvider) getExistingRecords(domain string) (models.Records, []*adns.RecordSet, string, error) { +func (a *azurednsProvider) getExistingRecords(dc *models.DomainConfig) (models.Records, []*adns.RecordSet, string, error) { + domain := dc.Name zone, ok := a.zones[domain] if !ok { return nil, nil, "", errNoExist{domain} @@ -220,7 +225,10 @@ func (a *azurednsProvider) getExistingRecords(domain string) (models.Records, [] var existingRecords models.Records for _, set := range rawRecords { - existingRecords = append(existingRecords, nativeToRecords(set, zoneName)...) + before := providers.BeginToRC(a.observer, "nativeToRecords", set) + records := nativeToRecords(set, dc) + providers.EndToRC(a.observer, "nativeToRecords", before, set, records, nil) + existingRecords = append(existingRecords, records...) } a.rawRecords[domain] = rawRecords @@ -359,16 +367,16 @@ func nativeToRecordTypeDiff(recordType *string) (adns.RecordType, error) { 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 "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 "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": @@ -383,17 +391,17 @@ func nativeToRecordTypeDiff(recordType *string) (adns.RecordType, error) { } } -func nativeToRecords(set *adns.RecordSet, origin string) []*models.RecordConfig { - var results []*models.RecordConfig +func nativeToRecords(set *adns.RecordSet, dc *models.DomainConfig) models.Records { + var results models.Records + label := dc.LabelFromFQDNWithDot(*set.Properties.Fqdn) + ttl := uint32(*set.Properties.TTL) 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) + rc, _ := dc.NewRecordConfig(label, ttl, dnsv2.TypeA, *rec.IPv4Address) + rc.Original = set results = append(results, rc) } } else { @@ -403,10 +411,8 @@ func nativeToRecords(set *adns.RecordSet, origin string) []*models.RecordConfig 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) + rc, _ := dc.NewRecordConfig(label, ttl, dnsv2.TypeAAAA, *rec.IPv6Address) + rc.Original = set results = append(results, rc) } } else { @@ -415,58 +421,46 @@ func nativeToRecords(set *adns.RecordSet, origin string) []*models.RecordConfig 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) + rc, _ := dc.NewRecordConfig(label, ttl, dnsv2.TypeCNAME, *set.Properties.CnameRecord.Cname) + rc.Original = set 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) + rc, _ := dc.NewRecordConfig(label, ttl, dnsv2.TypePTR, *rec.Ptrdname) + rc.Original = set 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("") + rc, _ := dc.NewRecordConfig(label, ttl, dnsv2.TypeTXT, "") + rc.Original = set 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) + rc, _ := dc.NewRecordConfig(label, ttl, dnsv2.TypeTXT, strings.Join(txts, "")) + rc.Original = set 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) + rc, _ := dc.NewRecordConfig(label, ttl, dnsv2.TypeMX, uint16(*rec.Preference), *rec.Exchange) + rc.Original = set 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) + rc, _ := dc.NewRecordConfig(label, ttl, dnsv2.TypeSRV, uint16(*rec.Priority), uint16(*rec.Weight), uint16(*rec.Port), *rec.Target) + rc.Original = set results = append(results, rc) } case "Microsoft.Network/privateDnsZones/SOA": @@ -478,7 +472,7 @@ func nativeToRecords(set *adns.RecordSet, origin string) []*models.RecordConfig // NOTE recordToNativeDiff2 is really "convert []RecordConfig to rrset". -func (a *azurednsProvider) recordToNativeDiff2(recordKey models.RecordKey, recordConfig []*models.RecordConfig) (*adns.RecordSet, adns.RecordType, error) { +func (a *azurednsProvider) recordToNativeDiff2(recordKey models.RecordKey, recordConfig models.Records) (*adns.RecordSet, adns.RecordType, error) { recordKeyType := recordKey.Type // if recordKeyType == "AZURE_ALIAS" { // fmt.Fprintf(os.Stderr, "DEBUG: XXXXXXXXXXXXXXXXXXXXXXX %v\n", recordKeyType) @@ -488,13 +482,13 @@ func (a *azurednsProvider) recordToNativeDiff2(recordKey models.RecordKey, recor for _, rec := range recordConfig { switch recordKeyType { case "A": - recordSet.Properties.ARecords = append(recordSet.Properties.ARecords, &adns.ARecord{IPv4Address: new(rec.GetTargetField())}) + recordSet.Properties.ARecords = append(recordSet.Properties.ARecords, &adns.ARecord{IPv4Address: new(rec.AsA().Addr.String())}) case "AAAA": - recordSet.Properties.AaaaRecords = append(recordSet.Properties.AaaaRecords, &adns.AaaaRecord{IPv6Address: new(rec.GetTargetField())}) + recordSet.Properties.AaaaRecords = append(recordSet.Properties.AaaaRecords, &adns.AaaaRecord{IPv6Address: new(rec.AsAAAA().Addr.String())}) case "CNAME": - recordSet.Properties.CnameRecord = &adns.CnameRecord{Cname: new(rec.GetTargetField())} + recordSet.Properties.CnameRecord = &adns.CnameRecord{Cname: new(rec.AsCNAME().Target)} case "PTR": - recordSet.Properties.PtrRecords = append(recordSet.Properties.PtrRecords, &adns.PtrRecord{Ptrdname: new(rec.GetTargetField())}) + recordSet.Properties.PtrRecords = append(recordSet.Properties.PtrRecords, &adns.PtrRecord{Ptrdname: new(rec.AsPTR().Ptr)}) case "TXT": // When a TXT record is empty, Azure requires that the .Properties.TxtRecords have no value, not "". if rec.GetTargetTXTJoined() != "" { @@ -505,12 +499,14 @@ func (a *azurednsProvider) recordToNativeDiff2(recordKey models.RecordKey, recor recordSet.Properties.TxtRecords = append(recordSet.Properties.TxtRecords, &adns.TxtRecord{Value: txts}) } case "MX": - recordSet.Properties.MxRecords = append(recordSet.Properties.MxRecords, &adns.MxRecord{Exchange: new(rec.GetTargetField()), Preference: new(int32(rec.MxPreference))}) + f := rec.AsMX() + recordSet.Properties.MxRecords = append(recordSet.Properties.MxRecords, &adns.MxRecord{Exchange: new(f.Mx), Preference: new(int32(f.Preference))}) case "SRV": - recordSet.Properties.SrvRecords = append(recordSet.Properties.SrvRecords, &adns.SrvRecord{Target: new(rec.GetTargetField()), Port: new(int32(rec.SrvPort)), Weight: new(int32(rec.SrvWeight)), Priority: new(int32(rec.SrvPriority))}) + f := rec.AsSRV() + recordSet.Properties.SrvRecords = append(recordSet.Properties.SrvRecords, &adns.SrvRecord{Target: new(f.Target), Port: new(int32(f.Port)), Weight: new(int32(f.Weight)), Priority: new(int32(f.Priority))}) /* 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 + // 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 } diff --git a/providers/azureprivatedns/convert_golden_test.go b/providers/azureprivatedns/convert_golden_test.go new file mode 100644 index 0000000000..8ace2c01c2 --- /dev/null +++ b/providers/azureprivatedns/convert_golden_test.go @@ -0,0 +1,16 @@ +package azureprivatedns + +import ( + "testing" + + adns "github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/privatedns/armprivatedns" + "github.com/DNSControl/dnscontrol/v5/models" + "github.com/DNSControl/dnscontrol/v5/pkg/providergolden" +) + +func TestNativeToRecordsGolden(t *testing.T) { + providergolden.CheckToRC(t, "nativeToRecords", + func(dc *models.DomainConfig, native adns.RecordSet) (models.Records, error) { + return nativeToRecords(&native, dc), nil + }) +} diff --git a/providers/azureprivatedns/convert_test.go b/providers/azureprivatedns/convert_test.go new file mode 100644 index 0000000000..9ec70fb715 --- /dev/null +++ b/providers/azureprivatedns/convert_test.go @@ -0,0 +1,46 @@ +package azureprivatedns + +import ( + "testing" + + dnsv2 "codeberg.org/miekg/dns" + adns "github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/privatedns/armprivatedns" + "github.com/DNSControl/dnscontrol/v5/models" +) + +func TestNativeToRecordsUsesV3RecordConfig(t *testing.T) { + dc := models.MustNewDomainConfig("example.com") + tests := []struct { + name string + azureType string + properties *adns.RecordSetProperties + want *models.RecordConfig + }{ + {"A", "Microsoft.Network/privateDnsZones/A", &adns.RecordSetProperties{ARecords: []*adns.ARecord{{IPv4Address: new("192.0.2.1")}}}, dc.MustNewRecordConfig("www", 300, dnsv2.TypeA, "192.0.2.1")}, + {"AAAA", "Microsoft.Network/privateDnsZones/AAAA", &adns.RecordSetProperties{AaaaRecords: []*adns.AaaaRecord{{IPv6Address: new("2001:db8::1")}}}, dc.MustNewRecordConfig("www", 300, dnsv2.TypeAAAA, "2001:db8::1")}, + {"CNAME", "Microsoft.Network/privateDnsZones/CNAME", &adns.RecordSetProperties{CnameRecord: &adns.CnameRecord{Cname: new("alias.example.net.")}}, dc.MustNewRecordConfig("www", 300, dnsv2.TypeCNAME, "alias.example.net.")}, + {"PTR", "Microsoft.Network/privateDnsZones/PTR", &adns.RecordSetProperties{PtrRecords: []*adns.PtrRecord{{Ptrdname: new("host.example.net.")}}}, dc.MustNewRecordConfig("www", 300, dnsv2.TypePTR, "host.example.net.")}, + {"empty TXT", "Microsoft.Network/privateDnsZones/TXT", &adns.RecordSetProperties{}, dc.MustNewRecordConfig("www", 300, dnsv2.TypeTXT, "")}, + {"segmented TXT", "Microsoft.Network/privateDnsZones/TXT", &adns.RecordSetProperties{TxtRecords: []*adns.TxtRecord{{Value: []*string{new("first"), new("second")}}}}, dc.MustNewRecordConfig("www", 300, dnsv2.TypeTXT, "firstsecond")}, + {"MX", "Microsoft.Network/privateDnsZones/MX", &adns.RecordSetProperties{MxRecords: []*adns.MxRecord{{Preference: new(int32(10)), Exchange: new("mail.example.net.")}}}, dc.MustNewRecordConfig("www", 300, dnsv2.TypeMX, uint16(10), "mail.example.net.")}, + {"SRV", "Microsoft.Network/privateDnsZones/SRV", &adns.RecordSetProperties{SrvRecords: []*adns.SrvRecord{{Priority: new(int32(1)), Weight: new(int32(2)), Port: new(int32(443)), Target: new("service.example.net.")}}}, dc.MustNewRecordConfig("www", 300, dnsv2.TypeSRV, uint16(1), uint16(2), uint16(443), "service.example.net.")}, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + tt.properties.Fqdn = new("www.example.com.") + tt.properties.TTL = new(int64(300)) + set := &adns.RecordSet{Type: new(tt.azureType), Properties: tt.properties} + got := nativeToRecords(set, dc) + if len(got) != 1 { + t.Fatalf("nativeToRecords() returned %d records, want 1", len(got)) + } + if got[0].NameFQDN != tt.want.NameFQDN || got[0].TTL != tt.want.TTL || got[0].TypeNum != tt.want.TypeNum || got[0].GetRDATA().String() != tt.want.GetRDATA().String() { + t.Errorf("nativeToRecords() = %s %d IN %s %s, want %s %d IN %s %s", got[0].NameFQDN, got[0].TTL, got[0].Type, got[0].GetRDATA(), tt.want.NameFQDN, tt.want.TTL, tt.want.Type, tt.want.GetRDATA()) + } + if got[0].Original != set { + t.Error("nativeToRecords() did not preserve the original Azure record set") + } + }) + } +} diff --git a/providers/azureprivatedns/test_data/expected_torc_output_nativeToRecords_dnscontroltest-azurep.com.records b/providers/azureprivatedns/test_data/expected_torc_output_nativeToRecords_dnscontroltest-azurep.com.records new file mode 100644 index 0000000000..3464f0048f --- /dev/null +++ b/providers/azureprivatedns/test_data/expected_torc_output_nativeToRecords_dnscontroltest-azurep.com.records @@ -0,0 +1,191 @@ +1 foo 300 IN A 1.2.3.4 +2 testtxt 300 IN TXT "simple" +3 testcname 300 IN CNAME foo.dnscontroltest-azurep.com. +4 dyndns-city1 300 IN AAAA 2003:dd:d7ff::fe71:ce77 +5 www 300 IN A 1.1.1.1 +5 www 300 IN A 2.2.2.2 +5 www 300 IN A 3.3.3.3 +6 foo255 300 IN TXT "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" +7 foo 300 IN MX 5 mx.google.com. +8 fooosbs4 300 IN TXT "4back\\\\\\\\slash" +9 4 300 IN PTR foo.com. +10 _sip._tcp 300 IN SRV 5 6 7 foo.com. +10 _sip._tcp 300 IN SRV 5 60 70 foo2.com. +10 _sip._tcp 300 IN SRV 15 65 75 foo3.com. +11 @ 300 IN A 2.2.2.2 +12 foo 300 IN A 2.3.4.5 +13 www 400 IN A 2.2.2.2 +13 www 400 IN A 5.6.7.8 +14 @ 300 IN A 1.2.3.4 +15 @ 300 IN A 1.2.3.4 +15 @ 300 IN A 2.3.4.5 +16 www 300 IN A 2.2.2.2 +16 www 300 IN A 5.6.7.8 +17 foo509 300 IN TXT "DDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDD" "DDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDD" +18 testa 300 IN A 1.1.1.1 +19 foo 300 IN TXT "simple" +20 testcname 300 IN CNAME www.google.com. +21 bar 300 IN A 5.5.5.5 +22 foo 300 IN MX 8 dnscontroltest-azurep.com. +23 foosc2 300 IN TXT "wssemi ; colon" +24 testmx 300 IN MX 5 foo.com. +25 foobt 300 IN TXT "blah`blah" +26 foo 300 IN A 1.1.1.1 +26 foo 300 IN A 13.13.13.13 +27 xn--fiq228c 300 IN A 1.2.3.4 +28 foo 300 IN A 1.2.3.4 +28 foo 300 IN A 3.4.5.6 +29 _sip._tcp 300 IN SRV 15 65 75 foo4.com. +29 _sip._tcp 300 IN SRV 52 62 72 foo.com. +30 foo 300 IN A 4.5.6.7 +31 www 700 IN A 1.2.3.4 +31 www 700 IN A 5.6.7.8 +32 foo 300 IN CNAME dnscontroltest-azurep.com. +33 mail.bat 300 IN CNAME ghs.googlehosted.com. +34 testaaaa 300 IN AAAA 2607:f8b0:4006:820::2013 +35 zzz 300 IN A 3.3.3.3 +35 zzz 300 IN A 4.4.4.4 +36 @ 500 IN A 8.8.8.8 +37 foo764 300 IN TXT "GGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGG" "GGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGG" "GGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGG" +38 fooosbs3 300 IN TXT "3back\\\\\\slash" +39 _sip._tcp 300 IN SRV 15 65 75 . +40 testmx 300 IN MX 5 bar.com. +41 foo 300 IN TXT "simple" +42 testcname 300 IN CNAME www.yahoo.com. +43 * 300 IN A 3.3.3.3 +44 zzz 300 IN AAAA 2003:dd:d7ff::fe71:cccc +45 foo256 300 IN TXT "CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC" "C" +46 @ 300 IN A 1.2.3.4 +47 foo 300 IN CNAME redact1.acm-validations.aws. +48 mail 300 IN CNAME ghs.googlehosted.com. +49 @ 300 IN MX 0 . +50 a 300 IN CNAME xn--ndaaa.com. +51 dyndns-city1 300 IN A 91.42.1.1 +52 testa 333 IN A 1.1.1.1 +53 foodqs 300 IN TXT "\"left" +54 bar 300 IN CNAME redact2.acm-validations.aws. +55 xn--ndaaa 300 IN A 2.2.2.2 +56 foo 300 IN A 1.1.1.1 +56 foo 300 IN A 10.10.10.10 +57 _sip._tcp 300 IN SRV 15 65 75 foo4.com. +57 _sip._tcp 300 IN SRV 52 62 7 foo.com. +58 final 300 IN TXT "TestDNSProviders was successful!" +59 mail 300 IN CNAME ghs.googlehosted.com. +60 foo.bat 300 IN A 1.2.3.4 +60 foo.bat 300 IN A 2.3.4.5 +61 foo 300 IN A 1.2.3.4 +61 foo 300 IN A 2.3.4.5 +62 nmx 300 IN MX 0 . +63 foo 300 IN CNAME google2.com. +64 foo 300 IN A 1.2.3.4 +65 foo 300 IN A 1.2.3.4 +66 nmx 300 IN MX 3 nmx.dnscontroltest-azurep.com. +66 nmx 300 IN MX 9 www.dnscontroltest-azurep.com. +67 foo510 300 IN TXT "EEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE" "EEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE" +68 @ 1000 IN A 8.8.8.8 +69 testmx 300 IN MX 5 foo.com. +70 final 300 IN TXT "TestDNSProviders was successful!" +71 @ 300 IN MX 2 dnscontroltest-azurep.com. +71 @ 300 IN MX 8 www.dnscontroltest-azurep.com. +72 4 300 IN PTR bar.com. +73 fooosbs1 300 IN TXT "1back\\slash" +74 @ 300 IN MX 5 bar.com. +75 @ 300 IN MX 0 . +76 _sip._tcp 300 IN SRV 5 6 7 foo.com. +76 _sip._tcp 300 IN SRV 15 65 75 foo4.com. +77 testdefined 300 IN A 9.9.9.9 +78 testmx 300 IN MX 5 foo.com. +78 testmx 300 IN MX 100 bar.com. +79 xn--o-0gab 300 IN CNAME xn--ndaaa.xn--vhquv. +80 bar 300 IN A 1.2.3.4 +81 dyndns-city2 300 IN A 91.42.1.2 +82 foodqs 300 IN TXT "right\"" +83 @ 300 IN TXT "asimple" +84 decoy 300 IN A 1.1.1.1 +85 foo 300 IN A 1.2.3.4 +86 testtxt 300 IN TXT "changed" +87 foo 300 IN A 1.1.1.1 +87 foo 300 IN A 11.11.11.11 +88 foows1 300 IN TXT "trailingws " +89 foo 300 IN A 1.2.3.4 +89 foo 300 IN A 2.3.4.5 +90 www 300 IN A 1.1.1.1 +90 www 300 IN A 2.2.2.2 +91 www 300 IN A 1.1.1.1 +92 www 300 IN A 1.1.1.1 +93 foo765 300 IN TXT "HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH" "HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH" "HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH" +94 fooosbs2 300 IN TXT "2back\\\\slash" +95 foo 300 IN MX 10 foo.dnscontroltest-azurep.com. +95 foo 300 IN MX 20 bar.dnscontroltest-azurep.com. +96 foodqs 300 IN TXT "in\"ter\"ior" +97 foodq 300 IN TXT "in\"side" +98 testa 300 IN A 3.3.3.3 +99 foo511 300 IN TXT "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF" "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF" "F" +100 foo 300 IN AAAA 2003:dd:d7ff::fe71:aaaa +101 foo254 300 IN TXT "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" +102 testignore 300 IN A 8.8.8.8 +103 foo 300 IN A 2.3.4.5 +103 foo 300 IN A 3.4.5.6 +104 testaaaa 300 IN AAAA 2607:f8b0:4006:820::2013 +105 @ 300 IN A 4.4.4.4 +106 testmx 300 IN MX 100 foo.com. +107 decoy 300 IN A 2.2.2.2 +108 foo 300 IN A 2.3.4.5 +108 foo 300 IN A 8.8.8.8 +109 foo766 300 IN TXT "JJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJ" "JJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJ" "JJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJ" "J" +110 testaaaa 300 IN AAAA 2607:f8b0:4006:820::2006 +111 www 300 IN A 1.2.3.4 +111 www 300 IN A 5.6.7.8 +112 testa 999 IN A 1.1.1.1 +113 _sip._tcp 300 IN SRV 15 65 75 foo4.com. +113 _sip._tcp 300 IN SRV 52 6 7 foo.com. +114 @ 300 IN A 1.2.3.2 +115 nmx 300 IN MX 0 . +116 foo 300 IN A 1.1.1.1 +116 foo 300 IN A 12.12.12.12 +117 nmx 300 IN A 1.2.3.3 +119 www 300 IN A 1.2.3.9 +120 foo0 300 IN TXT "" +121 decoy 300 IN A 3.3.3.3 +122 foo 300 IN A 1.1.1.1 +122 foo 300 IN A 14.14.14.14 +123 foo 300 IN TXT "v=spf1 ip4:99.99.99.99 -all" +124 testmx 300 IN MX 5 foo.com. +124 testmx 300 IN MX 100 bar.com. +125 foo 300 IN A 2.3.4.5 +125 foo 300 IN A 8.8.8.8 +126 _sip._tcp 300 IN SRV 5 6 7 foo.com. +126 _sip._tcp 300 IN SRV 5 60 70 foo2.com. +127 _sip._tcp 300 IN SRV 5 6 7 foo.com. +128 @ 300 IN A 2.2.2.2 +129 @ 300 IN TXT "simple" +130 bar.bat 300 IN A 5.5.5.5 +131 @ 666 IN A 8.8.8.8 +132 bar 300 IN A 5.5.5.5 +133 www 300 IN A 1.1.1.1 +133 www 300 IN A 2.2.2.2 +133 www 300 IN A 3.3.3.3 +134 _sip._tcp 333 IN SRV 5 6 7 foo.com. +135 @ 300 IN MX 5 foo.com. +136 www 300 IN A 5.5.5.5 +137 testdefined 300 IN A 2.2.2.2 +138 foo 300 IN A 1.2.3.4 +139 www 400 IN A 5.6.7.8 +140 dyndns-city2 300 IN AAAA 2003:dd:d7ff::fe71:ce78 +141 foo.bat 300 IN TXT "simple" +142 foo 300 IN CNAME google.com. +143 _sip._tcp 300 IN SRV 5 6 7 foo.com. +143 _sip._tcp 300 IN SRV 15 65 75 foo3.com. +144 testmx 300 IN MX 5 foo.com. +145 xn--ndaaa 300 IN A 1.2.3.4 +146 bar 300 IN MX 5 bar.com. +147 foosp 300 IN TXT "with spaces" +148 _sip._tcp 4400 IN SRV 5 6 7 foo.com. +149 foo 300 IN A 1.2.3.4 +149 foo 300 IN A 3.4.5.6 +150 www 300 IN A 1.1.1.1 +151 foo 300 IN MX 10 aspmx.l.google.com. +151 foo 300 IN MX 20 alt1.aspmx.l.google.com. +152 foosc1 300 IN TXT "semi;colon" +153 foosq 300 IN TXT "quo'te" +154 www 300 IN A 1.2.3.8 diff --git a/providers/azureprivatedns/test_data/meta.json b/providers/azureprivatedns/test_data/meta.json new file mode 100644 index 0000000000..5a7710e118 --- /dev/null +++ b/providers/azureprivatedns/test_data/meta.json @@ -0,0 +1,11 @@ +{ + "version": 1, + "recordings": [ + { + "domain": "dnscontroltest-azurep.com", + "to_rc": [ + "nativeToRecords" + ] + } + ] +} diff --git a/providers/azureprivatedns/test_data/recorded_torc_input_nativeToRecords_dnscontroltest-azurep.com.json b/providers/azureprivatedns/test_data/recorded_torc_input_nativeToRecords_dnscontroltest-azurep.com.json new file mode 100644 index 0000000000..3ef11a473f --- /dev/null +++ b/providers/azureprivatedns/test_data/recorded_torc_input_nativeToRecords_dnscontroltest-azurep.com.json @@ -0,0 +1,3177 @@ +[ + { + "index": 1, + "value": { + "etag": "0024b218-7bf2-447c-ab65-abb7c9ef6ebb", + "id": "/subscriptions/02efc9e4-732d-4a8d-8b82-5b37e10eb89d/resourceGroups/dnscontroltest/providers/Microsoft.Network/privateDnsZones/dnscontroltest-azurep.com/A/foo", + "name": "foo", + "properties": { + "aRecords": [ + { + "ipv4Address": "1.2.3.4" + } + ], + "fqdn": "foo.dnscontroltest-azurep.com.", + "isAutoRegistered": false, + "ttl": 300 + }, + "type": "Microsoft.Network/privateDnsZones/A" + } + }, + { + "index": 2, + "value": { + "etag": "0142b7a1-d571-491e-a1b2-20ba6ff38091", + "id": "/subscriptions/02efc9e4-732d-4a8d-8b82-5b37e10eb89d/resourceGroups/dnscontroltest/providers/Microsoft.Network/privateDnsZones/dnscontroltest-azurep.com/TXT/testtxt", + "name": "testtxt", + "properties": { + "fqdn": "testtxt.dnscontroltest-azurep.com.", + "isAutoRegistered": false, + "ttl": 300, + "txtRecords": [ + { + "value": [ + "simple" + ] + } + ] + }, + "type": "Microsoft.Network/privateDnsZones/TXT" + } + }, + { + "index": 3, + "value": { + "etag": "074b1baa-60e6-41eb-9d69-7b097885315d", + "id": "/subscriptions/02efc9e4-732d-4a8d-8b82-5b37e10eb89d/resourceGroups/dnscontroltest/providers/Microsoft.Network/privateDnsZones/dnscontroltest-azurep.com/CNAME/testcname", + "name": "testcname", + "properties": { + "cnameRecord": { + "cname": "foo.dnscontroltest-azurep.com." + }, + "fqdn": "testcname.dnscontroltest-azurep.com.", + "isAutoRegistered": false, + "ttl": 300 + }, + "type": "Microsoft.Network/privateDnsZones/CNAME" + } + }, + { + "index": 4, + "value": { + "etag": "08ad7797-8072-45e3-b0fb-c2e503d36dfa", + "id": "/subscriptions/02efc9e4-732d-4a8d-8b82-5b37e10eb89d/resourceGroups/dnscontroltest/providers/Microsoft.Network/privateDnsZones/dnscontroltest-azurep.com/AAAA/dyndns-city1", + "name": "dyndns-city1", + "properties": { + "aaaaRecords": [ + { + "ipv6Address": "2003:dd:d7ff::fe71:ce77" + } + ], + "fqdn": "dyndns-city1.dnscontroltest-azurep.com.", + "isAutoRegistered": false, + "ttl": 300 + }, + "type": "Microsoft.Network/privateDnsZones/AAAA" + } + }, + { + "index": 5, + "value": { + "etag": "0e7706b9-308b-418a-8d82-f3f068a00f1b", + "id": "/subscriptions/02efc9e4-732d-4a8d-8b82-5b37e10eb89d/resourceGroups/dnscontroltest/providers/Microsoft.Network/privateDnsZones/dnscontroltest-azurep.com/A/www", + "name": "www", + "properties": { + "aRecords": [ + { + "ipv4Address": "1.1.1.1" + }, + { + "ipv4Address": "2.2.2.2" + }, + { + "ipv4Address": "3.3.3.3" + } + ], + "fqdn": "www.dnscontroltest-azurep.com.", + "isAutoRegistered": false, + "ttl": 300 + }, + "type": "Microsoft.Network/privateDnsZones/A" + } + }, + { + "index": 6, + "value": { + "etag": "0ee48012-1d1a-451c-a567-8516123ef253", + "id": "/subscriptions/02efc9e4-732d-4a8d-8b82-5b37e10eb89d/resourceGroups/dnscontroltest/providers/Microsoft.Network/privateDnsZones/dnscontroltest-azurep.com/TXT/foo255", + "name": "foo255", + "properties": { + "fqdn": "foo255.dnscontroltest-azurep.com.", + "isAutoRegistered": false, + "ttl": 300, + "txtRecords": [ + { + "value": [ + "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" + ] + } + ] + }, + "type": "Microsoft.Network/privateDnsZones/TXT" + } + }, + { + "index": 7, + "value": { + "etag": "0ff8be5e-1bcd-4f14-926c-52cf451541f0", + "id": "/subscriptions/02efc9e4-732d-4a8d-8b82-5b37e10eb89d/resourceGroups/dnscontroltest/providers/Microsoft.Network/privateDnsZones/dnscontroltest-azurep.com/MX/foo", + "name": "foo", + "properties": { + "fqdn": "foo.dnscontroltest-azurep.com.", + "isAutoRegistered": false, + "mxRecords": [ + { + "exchange": "mx.google.com.", + "preference": 5 + } + ], + "ttl": 300 + }, + "type": "Microsoft.Network/privateDnsZones/MX" + } + }, + { + "index": 8, + "value": { + "etag": "1034f1e9-1e06-4b76-b299-4de5a98d00e1", + "id": "/subscriptions/02efc9e4-732d-4a8d-8b82-5b37e10eb89d/resourceGroups/dnscontroltest/providers/Microsoft.Network/privateDnsZones/dnscontroltest-azurep.com/TXT/fooosbs4", + "name": "fooosbs4", + "properties": { + "fqdn": "fooosbs4.dnscontroltest-azurep.com.", + "isAutoRegistered": false, + "ttl": 300, + "txtRecords": [ + { + "value": [ + "4back\\\\\\\\slash" + ] + } + ] + }, + "type": "Microsoft.Network/privateDnsZones/TXT" + } + }, + { + "index": 9, + "value": { + "etag": "11b0f45d-2703-4cda-a117-f00b7dbdc80b", + "id": "/subscriptions/02efc9e4-732d-4a8d-8b82-5b37e10eb89d/resourceGroups/dnscontroltest/providers/Microsoft.Network/privateDnsZones/dnscontroltest-azurep.com/PTR/4", + "name": "4", + "properties": { + "fqdn": "4.dnscontroltest-azurep.com.", + "isAutoRegistered": false, + "ptrRecords": [ + { + "ptrdname": "foo.com." + } + ], + "ttl": 300 + }, + "type": "Microsoft.Network/privateDnsZones/PTR" + } + }, + { + "index": 10, + "value": { + "etag": "12020522-5921-40ab-9109-c2d6bee2a5a0", + "id": "/subscriptions/02efc9e4-732d-4a8d-8b82-5b37e10eb89d/resourceGroups/dnscontroltest/providers/Microsoft.Network/privateDnsZones/dnscontroltest-azurep.com/SRV/_sip._tcp", + "name": "_sip._tcp", + "properties": { + "fqdn": "_sip._tcp.dnscontroltest-azurep.com.", + "isAutoRegistered": false, + "srvRecords": [ + { + "port": 7, + "priority": 5, + "target": "foo.com.", + "weight": 6 + }, + { + "port": 70, + "priority": 5, + "target": "foo2.com.", + "weight": 60 + }, + { + "port": 75, + "priority": 15, + "target": "foo3.com.", + "weight": 65 + } + ], + "ttl": 300 + }, + "type": "Microsoft.Network/privateDnsZones/SRV" + } + }, + { + "index": 11, + "value": { + "etag": "12eb493a-b358-4a79-a5ee-115d34028fe2", + "id": "/subscriptions/02efc9e4-732d-4a8d-8b82-5b37e10eb89d/resourceGroups/dnscontroltest/providers/Microsoft.Network/privateDnsZones/dnscontroltest-azurep.com/A/@", + "name": "@", + "properties": { + "aRecords": [ + { + "ipv4Address": "2.2.2.2" + } + ], + "fqdn": "dnscontroltest-azurep.com.", + "isAutoRegistered": false, + "ttl": 300 + }, + "type": "Microsoft.Network/privateDnsZones/A" + } + }, + { + "index": 12, + "value": { + "etag": "14a97fc6-9971-4e90-affc-1706a822e7bd", + "id": "/subscriptions/02efc9e4-732d-4a8d-8b82-5b37e10eb89d/resourceGroups/dnscontroltest/providers/Microsoft.Network/privateDnsZones/dnscontroltest-azurep.com/A/foo", + "name": "foo", + "properties": { + "aRecords": [ + { + "ipv4Address": "2.3.4.5" + } + ], + "fqdn": "foo.dnscontroltest-azurep.com.", + "isAutoRegistered": false, + "ttl": 300 + }, + "type": "Microsoft.Network/privateDnsZones/A" + } + }, + { + "index": 13, + "value": { + "etag": "18a32c0b-704b-40ba-96da-8c6ce846231e", + "id": "/subscriptions/02efc9e4-732d-4a8d-8b82-5b37e10eb89d/resourceGroups/dnscontroltest/providers/Microsoft.Network/privateDnsZones/dnscontroltest-azurep.com/A/www", + "name": "www", + "properties": { + "aRecords": [ + { + "ipv4Address": "2.2.2.2" + }, + { + "ipv4Address": "5.6.7.8" + } + ], + "fqdn": "www.dnscontroltest-azurep.com.", + "isAutoRegistered": false, + "ttl": 400 + }, + "type": "Microsoft.Network/privateDnsZones/A" + } + }, + { + "index": 14, + "value": { + "etag": "1934142b-3287-4bac-afc4-8ef9e30c8aff", + "id": "/subscriptions/02efc9e4-732d-4a8d-8b82-5b37e10eb89d/resourceGroups/dnscontroltest/providers/Microsoft.Network/privateDnsZones/dnscontroltest-azurep.com/A/@", + "name": "@", + "properties": { + "aRecords": [ + { + "ipv4Address": "1.2.3.4" + } + ], + "fqdn": "dnscontroltest-azurep.com.", + "isAutoRegistered": false, + "ttl": 300 + }, + "type": "Microsoft.Network/privateDnsZones/A" + } + }, + { + "index": 15, + "value": { + "etag": "1c5edbdc-9f5a-4dda-9290-0111017a3e24", + "id": "/subscriptions/02efc9e4-732d-4a8d-8b82-5b37e10eb89d/resourceGroups/dnscontroltest/providers/Microsoft.Network/privateDnsZones/dnscontroltest-azurep.com/A/@", + "name": "@", + "properties": { + "aRecords": [ + { + "ipv4Address": "1.2.3.4" + }, + { + "ipv4Address": "2.3.4.5" + } + ], + "fqdn": "dnscontroltest-azurep.com.", + "isAutoRegistered": false, + "ttl": 300 + }, + "type": "Microsoft.Network/privateDnsZones/A" + } + }, + { + "index": 16, + "value": { + "etag": "1c8ef1b5-942b-4c94-8400-78c7f148827f", + "id": "/subscriptions/02efc9e4-732d-4a8d-8b82-5b37e10eb89d/resourceGroups/dnscontroltest/providers/Microsoft.Network/privateDnsZones/dnscontroltest-azurep.com/A/www", + "name": "www", + "properties": { + "aRecords": [ + { + "ipv4Address": "2.2.2.2" + }, + { + "ipv4Address": "5.6.7.8" + } + ], + "fqdn": "www.dnscontroltest-azurep.com.", + "isAutoRegistered": false, + "ttl": 300 + }, + "type": "Microsoft.Network/privateDnsZones/A" + } + }, + { + "index": 17, + "value": { + "etag": "1e696d88-c697-43a8-b5d4-2e721d23ba7f", + "id": "/subscriptions/02efc9e4-732d-4a8d-8b82-5b37e10eb89d/resourceGroups/dnscontroltest/providers/Microsoft.Network/privateDnsZones/dnscontroltest-azurep.com/TXT/foo509", + "name": "foo509", + "properties": { + "fqdn": "foo509.dnscontroltest-azurep.com.", + "isAutoRegistered": false, + "ttl": 300, + "txtRecords": [ + { + "value": [ + "DDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDD", + "DDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDD" + ] + } + ] + }, + "type": "Microsoft.Network/privateDnsZones/TXT" + } + }, + { + "index": 18, + "value": { + "etag": "1f6f4c14-47df-4efc-b1f7-5947180c447b", + "id": "/subscriptions/02efc9e4-732d-4a8d-8b82-5b37e10eb89d/resourceGroups/dnscontroltest/providers/Microsoft.Network/privateDnsZones/dnscontroltest-azurep.com/A/testa", + "name": "testa", + "properties": { + "aRecords": [ + { + "ipv4Address": "1.1.1.1" + } + ], + "fqdn": "testa.dnscontroltest-azurep.com.", + "isAutoRegistered": false, + "ttl": 300 + }, + "type": "Microsoft.Network/privateDnsZones/A" + } + }, + { + "index": 19, + "value": { + "etag": "26d77c51-ba1a-4251-a925-574e6d7d8854", + "id": "/subscriptions/02efc9e4-732d-4a8d-8b82-5b37e10eb89d/resourceGroups/dnscontroltest/providers/Microsoft.Network/privateDnsZones/dnscontroltest-azurep.com/TXT/foo", + "name": "foo", + "properties": { + "fqdn": "foo.dnscontroltest-azurep.com.", + "isAutoRegistered": false, + "ttl": 300, + "txtRecords": [ + { + "value": [ + "simple" + ] + } + ] + }, + "type": "Microsoft.Network/privateDnsZones/TXT" + } + }, + { + "index": 20, + "value": { + "etag": "277df146-5989-48f5-b6b5-a6a7b238334d", + "id": "/subscriptions/02efc9e4-732d-4a8d-8b82-5b37e10eb89d/resourceGroups/dnscontroltest/providers/Microsoft.Network/privateDnsZones/dnscontroltest-azurep.com/CNAME/testcname", + "name": "testcname", + "properties": { + "cnameRecord": { + "cname": "www.google.com." + }, + "fqdn": "testcname.dnscontroltest-azurep.com.", + "isAutoRegistered": false, + "ttl": 300 + }, + "type": "Microsoft.Network/privateDnsZones/CNAME" + } + }, + { + "index": 21, + "value": { + "etag": "2df58227-ec5b-4f12-b117-657e6a7742db", + "id": "/subscriptions/02efc9e4-732d-4a8d-8b82-5b37e10eb89d/resourceGroups/dnscontroltest/providers/Microsoft.Network/privateDnsZones/dnscontroltest-azurep.com/A/bar", + "name": "bar", + "properties": { + "aRecords": [ + { + "ipv4Address": "5.5.5.5" + } + ], + "fqdn": "bar.dnscontroltest-azurep.com.", + "isAutoRegistered": false, + "ttl": 300 + }, + "type": "Microsoft.Network/privateDnsZones/A" + } + }, + { + "index": 22, + "value": { + "etag": "2f609ad6-69ca-4e99-9411-98105c534368", + "id": "/subscriptions/02efc9e4-732d-4a8d-8b82-5b37e10eb89d/resourceGroups/dnscontroltest/providers/Microsoft.Network/privateDnsZones/dnscontroltest-azurep.com/MX/foo", + "name": "foo", + "properties": { + "fqdn": "foo.dnscontroltest-azurep.com.", + "isAutoRegistered": false, + "mxRecords": [ + { + "exchange": "dnscontroltest-azurep.com.", + "preference": 8 + } + ], + "ttl": 300 + }, + "type": "Microsoft.Network/privateDnsZones/MX" + } + }, + { + "index": 23, + "value": { + "etag": "2f9640a6-ed84-4e64-aaca-01244d3fd5b2", + "id": "/subscriptions/02efc9e4-732d-4a8d-8b82-5b37e10eb89d/resourceGroups/dnscontroltest/providers/Microsoft.Network/privateDnsZones/dnscontroltest-azurep.com/TXT/foosc2", + "name": "foosc2", + "properties": { + "fqdn": "foosc2.dnscontroltest-azurep.com.", + "isAutoRegistered": false, + "ttl": 300, + "txtRecords": [ + { + "value": [ + "wssemi ; colon" + ] + } + ] + }, + "type": "Microsoft.Network/privateDnsZones/TXT" + } + }, + { + "index": 24, + "value": { + "etag": "2fa4cc87-3026-4c58-b27c-f70ca6230ae2", + "id": "/subscriptions/02efc9e4-732d-4a8d-8b82-5b37e10eb89d/resourceGroups/dnscontroltest/providers/Microsoft.Network/privateDnsZones/dnscontroltest-azurep.com/MX/testmx", + "name": "testmx", + "properties": { + "fqdn": "testmx.dnscontroltest-azurep.com.", + "isAutoRegistered": false, + "mxRecords": [ + { + "exchange": "foo.com.", + "preference": 5 + } + ], + "ttl": 300 + }, + "type": "Microsoft.Network/privateDnsZones/MX" + } + }, + { + "index": 25, + "value": { + "etag": "323531d2-d8e7-477e-9e54-a6eb9e3a761e", + "id": "/subscriptions/02efc9e4-732d-4a8d-8b82-5b37e10eb89d/resourceGroups/dnscontroltest/providers/Microsoft.Network/privateDnsZones/dnscontroltest-azurep.com/TXT/foobt", + "name": "foobt", + "properties": { + "fqdn": "foobt.dnscontroltest-azurep.com.", + "isAutoRegistered": false, + "ttl": 300, + "txtRecords": [ + { + "value": [ + "blah`blah" + ] + } + ] + }, + "type": "Microsoft.Network/privateDnsZones/TXT" + } + }, + { + "index": 26, + "value": { + "etag": "3440129a-ef4a-41f4-8de0-bd90f5da4a74", + "id": "/subscriptions/02efc9e4-732d-4a8d-8b82-5b37e10eb89d/resourceGroups/dnscontroltest/providers/Microsoft.Network/privateDnsZones/dnscontroltest-azurep.com/A/foo", + "name": "foo", + "properties": { + "aRecords": [ + { + "ipv4Address": "1.1.1.1" + }, + { + "ipv4Address": "13.13.13.13" + } + ], + "fqdn": "foo.dnscontroltest-azurep.com.", + "isAutoRegistered": false, + "ttl": 300 + }, + "type": "Microsoft.Network/privateDnsZones/A" + } + }, + { + "index": 27, + "value": { + "etag": "34475687-d924-495e-b5fd-5c4ee5f080d9", + "id": "/subscriptions/02efc9e4-732d-4a8d-8b82-5b37e10eb89d/resourceGroups/dnscontroltest/providers/Microsoft.Network/privateDnsZones/dnscontroltest-azurep.com/A/xn--fiq228c", + "name": "xn--fiq228c", + "properties": { + "aRecords": [ + { + "ipv4Address": "1.2.3.4" + } + ], + "fqdn": "xn--fiq228c.dnscontroltest-azurep.com.", + "isAutoRegistered": false, + "ttl": 300 + }, + "type": "Microsoft.Network/privateDnsZones/A" + } + }, + { + "index": 28, + "value": { + "etag": "3453ffdf-8584-40b4-9d47-fdffa91245f3", + "id": "/subscriptions/02efc9e4-732d-4a8d-8b82-5b37e10eb89d/resourceGroups/dnscontroltest/providers/Microsoft.Network/privateDnsZones/dnscontroltest-azurep.com/A/foo", + "name": "foo", + "properties": { + "aRecords": [ + { + "ipv4Address": "1.2.3.4" + }, + { + "ipv4Address": "3.4.5.6" + } + ], + "fqdn": "foo.dnscontroltest-azurep.com.", + "isAutoRegistered": false, + "ttl": 300 + }, + "type": "Microsoft.Network/privateDnsZones/A" + } + }, + { + "index": 29, + "value": { + "etag": "3469b773-770a-4fde-a7c9-a19110b53d8f", + "id": "/subscriptions/02efc9e4-732d-4a8d-8b82-5b37e10eb89d/resourceGroups/dnscontroltest/providers/Microsoft.Network/privateDnsZones/dnscontroltest-azurep.com/SRV/_sip._tcp", + "name": "_sip._tcp", + "properties": { + "fqdn": "_sip._tcp.dnscontroltest-azurep.com.", + "isAutoRegistered": false, + "srvRecords": [ + { + "port": 75, + "priority": 15, + "target": "foo4.com.", + "weight": 65 + }, + { + "port": 72, + "priority": 52, + "target": "foo.com.", + "weight": 62 + } + ], + "ttl": 300 + }, + "type": "Microsoft.Network/privateDnsZones/SRV" + } + }, + { + "index": 30, + "value": { + "etag": "3760a7d1-7dc8-4600-a5a4-b847bc0f76a8", + "id": "/subscriptions/02efc9e4-732d-4a8d-8b82-5b37e10eb89d/resourceGroups/dnscontroltest/providers/Microsoft.Network/privateDnsZones/dnscontroltest-azurep.com/A/foo", + "name": "foo", + "properties": { + "aRecords": [ + { + "ipv4Address": "4.5.6.7" + } + ], + "fqdn": "foo.dnscontroltest-azurep.com.", + "isAutoRegistered": false, + "ttl": 300 + }, + "type": "Microsoft.Network/privateDnsZones/A" + } + }, + { + "index": 31, + "value": { + "etag": "382ae20b-d912-4bfa-b01a-fb76a018051e", + "id": "/subscriptions/02efc9e4-732d-4a8d-8b82-5b37e10eb89d/resourceGroups/dnscontroltest/providers/Microsoft.Network/privateDnsZones/dnscontroltest-azurep.com/A/www", + "name": "www", + "properties": { + "aRecords": [ + { + "ipv4Address": "1.2.3.4" + }, + { + "ipv4Address": "5.6.7.8" + } + ], + "fqdn": "www.dnscontroltest-azurep.com.", + "isAutoRegistered": false, + "ttl": 700 + }, + "type": "Microsoft.Network/privateDnsZones/A" + } + }, + { + "index": 32, + "value": { + "etag": "3844c8db-ee0f-4b53-8f86-54a1e9b81710", + "id": "/subscriptions/02efc9e4-732d-4a8d-8b82-5b37e10eb89d/resourceGroups/dnscontroltest/providers/Microsoft.Network/privateDnsZones/dnscontroltest-azurep.com/CNAME/foo", + "name": "foo", + "properties": { + "cnameRecord": { + "cname": "dnscontroltest-azurep.com." + }, + "fqdn": "foo.dnscontroltest-azurep.com.", + "isAutoRegistered": false, + "ttl": 300 + }, + "type": "Microsoft.Network/privateDnsZones/CNAME" + } + }, + { + "index": 33, + "value": { + "etag": "39b53c8f-8a85-46f4-a809-04e5a9cb4dd6", + "id": "/subscriptions/02efc9e4-732d-4a8d-8b82-5b37e10eb89d/resourceGroups/dnscontroltest/providers/Microsoft.Network/privateDnsZones/dnscontroltest-azurep.com/CNAME/mail.bat", + "name": "mail.bat", + "properties": { + "cnameRecord": { + "cname": "ghs.googlehosted.com." + }, + "fqdn": "mail.bat.dnscontroltest-azurep.com.", + "isAutoRegistered": false, + "ttl": 300 + }, + "type": "Microsoft.Network/privateDnsZones/CNAME" + } + }, + { + "index": 34, + "value": { + "etag": "3b7a0007-02e3-4088-98a9-53419a2691c7", + "id": "/subscriptions/02efc9e4-732d-4a8d-8b82-5b37e10eb89d/resourceGroups/dnscontroltest/providers/Microsoft.Network/privateDnsZones/dnscontroltest-azurep.com/AAAA/testaaaa", + "name": "testaaaa", + "properties": { + "aaaaRecords": [ + { + "ipv6Address": "2607:f8b0:4006:820::2013" + } + ], + "fqdn": "testaaaa.dnscontroltest-azurep.com.", + "isAutoRegistered": false, + "ttl": 300 + }, + "type": "Microsoft.Network/privateDnsZones/AAAA" + } + }, + { + "index": 35, + "value": { + "etag": "3bbbb4e4-6480-4c0d-b23b-14d90e808295", + "id": "/subscriptions/02efc9e4-732d-4a8d-8b82-5b37e10eb89d/resourceGroups/dnscontroltest/providers/Microsoft.Network/privateDnsZones/dnscontroltest-azurep.com/A/zzz", + "name": "zzz", + "properties": { + "aRecords": [ + { + "ipv4Address": "3.3.3.3" + }, + { + "ipv4Address": "4.4.4.4" + } + ], + "fqdn": "zzz.dnscontroltest-azurep.com.", + "isAutoRegistered": false, + "ttl": 300 + }, + "type": "Microsoft.Network/privateDnsZones/A" + } + }, + { + "index": 36, + "value": { + "etag": "3bd06a34-5dd7-4213-8854-0e60b2ed8542", + "id": "/subscriptions/02efc9e4-732d-4a8d-8b82-5b37e10eb89d/resourceGroups/dnscontroltest/providers/Microsoft.Network/privateDnsZones/dnscontroltest-azurep.com/A/@", + "name": "@", + "properties": { + "aRecords": [ + { + "ipv4Address": "8.8.8.8" + } + ], + "fqdn": "dnscontroltest-azurep.com.", + "isAutoRegistered": false, + "ttl": 500 + }, + "type": "Microsoft.Network/privateDnsZones/A" + } + }, + { + "index": 37, + "value": { + "etag": "3c14e49f-e18c-4b87-93dc-d528e6782d30", + "id": "/subscriptions/02efc9e4-732d-4a8d-8b82-5b37e10eb89d/resourceGroups/dnscontroltest/providers/Microsoft.Network/privateDnsZones/dnscontroltest-azurep.com/TXT/foo764", + "name": "foo764", + "properties": { + "fqdn": "foo764.dnscontroltest-azurep.com.", + "isAutoRegistered": false, + "ttl": 300, + "txtRecords": [ + { + "value": [ + "GGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGG", + "GGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGG", + "GGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGG" + ] + } + ] + }, + "type": "Microsoft.Network/privateDnsZones/TXT" + } + }, + { + "index": 38, + "value": { + "etag": "3d9f197f-9aa5-46cc-ad78-2cef365796ba", + "id": "/subscriptions/02efc9e4-732d-4a8d-8b82-5b37e10eb89d/resourceGroups/dnscontroltest/providers/Microsoft.Network/privateDnsZones/dnscontroltest-azurep.com/TXT/fooosbs3", + "name": "fooosbs3", + "properties": { + "fqdn": "fooosbs3.dnscontroltest-azurep.com.", + "isAutoRegistered": false, + "ttl": 300, + "txtRecords": [ + { + "value": [ + "3back\\\\\\slash" + ] + } + ] + }, + "type": "Microsoft.Network/privateDnsZones/TXT" + } + }, + { + "index": 39, + "value": { + "etag": "42a92bd1-1b13-482e-ad28-7bbb5db3de2a", + "id": "/subscriptions/02efc9e4-732d-4a8d-8b82-5b37e10eb89d/resourceGroups/dnscontroltest/providers/Microsoft.Network/privateDnsZones/dnscontroltest-azurep.com/SRV/_sip._tcp", + "name": "_sip._tcp", + "properties": { + "fqdn": "_sip._tcp.dnscontroltest-azurep.com.", + "isAutoRegistered": false, + "srvRecords": [ + { + "port": 75, + "priority": 15, + "target": ".", + "weight": 65 + } + ], + "ttl": 300 + }, + "type": "Microsoft.Network/privateDnsZones/SRV" + } + }, + { + "index": 40, + "value": { + "etag": "433ddab4-ffe1-4b09-bf83-cd872699d9cc", + "id": "/subscriptions/02efc9e4-732d-4a8d-8b82-5b37e10eb89d/resourceGroups/dnscontroltest/providers/Microsoft.Network/privateDnsZones/dnscontroltest-azurep.com/MX/testmx", + "name": "testmx", + "properties": { + "fqdn": "testmx.dnscontroltest-azurep.com.", + "isAutoRegistered": false, + "mxRecords": [ + { + "exchange": "bar.com.", + "preference": 5 + } + ], + "ttl": 300 + }, + "type": "Microsoft.Network/privateDnsZones/MX" + } + }, + { + "index": 41, + "value": { + "etag": "434f5dcf-e913-4ed9-a181-a82d4239154e", + "id": "/subscriptions/02efc9e4-732d-4a8d-8b82-5b37e10eb89d/resourceGroups/dnscontroltest/providers/Microsoft.Network/privateDnsZones/dnscontroltest-azurep.com/TXT/foo", + "name": "foo", + "properties": { + "fqdn": "foo.dnscontroltest-azurep.com.", + "isAutoRegistered": false, + "ttl": 300, + "txtRecords": [ + { + "value": [ + "simple" + ] + } + ] + }, + "type": "Microsoft.Network/privateDnsZones/TXT" + } + }, + { + "index": 42, + "value": { + "etag": "43b6320d-0d60-4267-b27b-df181e4b35d6", + "id": "/subscriptions/02efc9e4-732d-4a8d-8b82-5b37e10eb89d/resourceGroups/dnscontroltest/providers/Microsoft.Network/privateDnsZones/dnscontroltest-azurep.com/CNAME/testcname", + "name": "testcname", + "properties": { + "cnameRecord": { + "cname": "www.yahoo.com." + }, + "fqdn": "testcname.dnscontroltest-azurep.com.", + "isAutoRegistered": false, + "ttl": 300 + }, + "type": "Microsoft.Network/privateDnsZones/CNAME" + } + }, + { + "index": 43, + "value": { + "etag": "46877faf-5aac-43cc-957f-c7175c8dcc65", + "id": "/subscriptions/02efc9e4-732d-4a8d-8b82-5b37e10eb89d/resourceGroups/dnscontroltest/providers/Microsoft.Network/privateDnsZones/dnscontroltest-azurep.com/A/*", + "name": "*", + "properties": { + "aRecords": [ + { + "ipv4Address": "3.3.3.3" + } + ], + "fqdn": "*.dnscontroltest-azurep.com.", + "isAutoRegistered": false, + "ttl": 300 + }, + "type": "Microsoft.Network/privateDnsZones/A" + } + }, + { + "index": 44, + "value": { + "etag": "484c2d23-de1c-4dbf-ad22-fc3981a681d2", + "id": "/subscriptions/02efc9e4-732d-4a8d-8b82-5b37e10eb89d/resourceGroups/dnscontroltest/providers/Microsoft.Network/privateDnsZones/dnscontroltest-azurep.com/AAAA/zzz", + "name": "zzz", + "properties": { + "aaaaRecords": [ + { + "ipv6Address": "2003:dd:d7ff::fe71:cccc" + } + ], + "fqdn": "zzz.dnscontroltest-azurep.com.", + "isAutoRegistered": false, + "ttl": 300 + }, + "type": "Microsoft.Network/privateDnsZones/AAAA" + } + }, + { + "index": 45, + "value": { + "etag": "4a6a88a0-5daf-431b-84b6-7af33e50ab90", + "id": "/subscriptions/02efc9e4-732d-4a8d-8b82-5b37e10eb89d/resourceGroups/dnscontroltest/providers/Microsoft.Network/privateDnsZones/dnscontroltest-azurep.com/TXT/foo256", + "name": "foo256", + "properties": { + "fqdn": "foo256.dnscontroltest-azurep.com.", + "isAutoRegistered": false, + "ttl": 300, + "txtRecords": [ + { + "value": [ + "CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC", + "C" + ] + } + ] + }, + "type": "Microsoft.Network/privateDnsZones/TXT" + } + }, + { + "index": 46, + "value": { + "etag": "4aae6e90-0954-4e9b-912a-0364eceba347", + "id": "/subscriptions/02efc9e4-732d-4a8d-8b82-5b37e10eb89d/resourceGroups/dnscontroltest/providers/Microsoft.Network/privateDnsZones/dnscontroltest-azurep.com/A/@", + "name": "@", + "properties": { + "aRecords": [ + { + "ipv4Address": "1.2.3.4" + } + ], + "fqdn": "dnscontroltest-azurep.com.", + "isAutoRegistered": false, + "ttl": 300 + }, + "type": "Microsoft.Network/privateDnsZones/A" + } + }, + { + "index": 47, + "value": { + "etag": "4c1449ad-e6fe-4a0c-9e0f-59bda3942c16", + "id": "/subscriptions/02efc9e4-732d-4a8d-8b82-5b37e10eb89d/resourceGroups/dnscontroltest/providers/Microsoft.Network/privateDnsZones/dnscontroltest-azurep.com/CNAME/foo", + "name": "foo", + "properties": { + "cnameRecord": { + "cname": "redact1.acm-validations.aws." + }, + "fqdn": "foo.dnscontroltest-azurep.com.", + "isAutoRegistered": false, + "ttl": 300 + }, + "type": "Microsoft.Network/privateDnsZones/CNAME" + } + }, + { + "index": 48, + "value": { + "etag": "4d0fe4f5-d440-450c-a5e6-65fd49bf6cf8", + "id": "/subscriptions/02efc9e4-732d-4a8d-8b82-5b37e10eb89d/resourceGroups/dnscontroltest/providers/Microsoft.Network/privateDnsZones/dnscontroltest-azurep.com/CNAME/mail", + "name": "mail", + "properties": { + "cnameRecord": { + "cname": "ghs.googlehosted.com." + }, + "fqdn": "mail.dnscontroltest-azurep.com.", + "isAutoRegistered": false, + "ttl": 300 + }, + "type": "Microsoft.Network/privateDnsZones/CNAME" + } + }, + { + "index": 49, + "value": { + "etag": "4e415f1d-4c5c-410d-97f3-b6ac9e7f76af", + "id": "/subscriptions/02efc9e4-732d-4a8d-8b82-5b37e10eb89d/resourceGroups/dnscontroltest/providers/Microsoft.Network/privateDnsZones/dnscontroltest-azurep.com/MX/@", + "name": "@", + "properties": { + "fqdn": "dnscontroltest-azurep.com.", + "isAutoRegistered": false, + "mxRecords": [ + { + "exchange": ".", + "preference": 0 + } + ], + "ttl": 300 + }, + "type": "Microsoft.Network/privateDnsZones/MX" + } + }, + { + "index": 50, + "value": { + "etag": "4f253eff-bde1-45cd-ad3e-ea364dd8af56", + "id": "/subscriptions/02efc9e4-732d-4a8d-8b82-5b37e10eb89d/resourceGroups/dnscontroltest/providers/Microsoft.Network/privateDnsZones/dnscontroltest-azurep.com/CNAME/a", + "name": "a", + "properties": { + "cnameRecord": { + "cname": "xn--ndaaa.com." + }, + "fqdn": "a.dnscontroltest-azurep.com.", + "isAutoRegistered": false, + "ttl": 300 + }, + "type": "Microsoft.Network/privateDnsZones/CNAME" + } + }, + { + "index": 51, + "value": { + "etag": "52637268-e748-42c7-b7d3-a7f058506462", + "id": "/subscriptions/02efc9e4-732d-4a8d-8b82-5b37e10eb89d/resourceGroups/dnscontroltest/providers/Microsoft.Network/privateDnsZones/dnscontroltest-azurep.com/A/dyndns-city1", + "name": "dyndns-city1", + "properties": { + "aRecords": [ + { + "ipv4Address": "91.42.1.1" + } + ], + "fqdn": "dyndns-city1.dnscontroltest-azurep.com.", + "isAutoRegistered": false, + "ttl": 300 + }, + "type": "Microsoft.Network/privateDnsZones/A" + } + }, + { + "index": 52, + "value": { + "etag": "542de4bb-312c-4e21-a5ea-0bf14c83794a", + "id": "/subscriptions/02efc9e4-732d-4a8d-8b82-5b37e10eb89d/resourceGroups/dnscontroltest/providers/Microsoft.Network/privateDnsZones/dnscontroltest-azurep.com/A/testa", + "name": "testa", + "properties": { + "aRecords": [ + { + "ipv4Address": "1.1.1.1" + } + ], + "fqdn": "testa.dnscontroltest-azurep.com.", + "isAutoRegistered": false, + "ttl": 333 + }, + "type": "Microsoft.Network/privateDnsZones/A" + } + }, + { + "index": 53, + "value": { + "etag": "55a47ff0-7072-45e6-8e48-d9fd155039e4", + "id": "/subscriptions/02efc9e4-732d-4a8d-8b82-5b37e10eb89d/resourceGroups/dnscontroltest/providers/Microsoft.Network/privateDnsZones/dnscontroltest-azurep.com/TXT/foodqs", + "name": "foodqs", + "properties": { + "fqdn": "foodqs.dnscontroltest-azurep.com.", + "isAutoRegistered": false, + "ttl": 300, + "txtRecords": [ + { + "value": [ + "\"left" + ] + } + ] + }, + "type": "Microsoft.Network/privateDnsZones/TXT" + } + }, + { + "index": 54, + "value": { + "etag": "59405821-2424-478c-8c16-448c5c3ae7d6", + "id": "/subscriptions/02efc9e4-732d-4a8d-8b82-5b37e10eb89d/resourceGroups/dnscontroltest/providers/Microsoft.Network/privateDnsZones/dnscontroltest-azurep.com/CNAME/bar", + "name": "bar", + "properties": { + "cnameRecord": { + "cname": "redact2.acm-validations.aws." + }, + "fqdn": "bar.dnscontroltest-azurep.com.", + "isAutoRegistered": false, + "ttl": 300 + }, + "type": "Microsoft.Network/privateDnsZones/CNAME" + } + }, + { + "index": 55, + "value": { + "etag": "5ce40553-0468-407e-a3c2-ebce0b320b14", + "id": "/subscriptions/02efc9e4-732d-4a8d-8b82-5b37e10eb89d/resourceGroups/dnscontroltest/providers/Microsoft.Network/privateDnsZones/dnscontroltest-azurep.com/A/xn--ndaaa", + "name": "xn--ndaaa", + "properties": { + "aRecords": [ + { + "ipv4Address": "2.2.2.2" + } + ], + "fqdn": "xn--ndaaa.dnscontroltest-azurep.com.", + "isAutoRegistered": false, + "ttl": 300 + }, + "type": "Microsoft.Network/privateDnsZones/A" + } + }, + { + "index": 56, + "value": { + "etag": "5d29888c-9b32-457d-8182-6027efed2127", + "id": "/subscriptions/02efc9e4-732d-4a8d-8b82-5b37e10eb89d/resourceGroups/dnscontroltest/providers/Microsoft.Network/privateDnsZones/dnscontroltest-azurep.com/A/foo", + "name": "foo", + "properties": { + "aRecords": [ + { + "ipv4Address": "1.1.1.1" + }, + { + "ipv4Address": "10.10.10.10" + } + ], + "fqdn": "foo.dnscontroltest-azurep.com.", + "isAutoRegistered": false, + "ttl": 300 + }, + "type": "Microsoft.Network/privateDnsZones/A" + } + }, + { + "index": 57, + "value": { + "etag": "5e06ea05-4475-42cf-b75b-0aaa14586344", + "id": "/subscriptions/02efc9e4-732d-4a8d-8b82-5b37e10eb89d/resourceGroups/dnscontroltest/providers/Microsoft.Network/privateDnsZones/dnscontroltest-azurep.com/SRV/_sip._tcp", + "name": "_sip._tcp", + "properties": { + "fqdn": "_sip._tcp.dnscontroltest-azurep.com.", + "isAutoRegistered": false, + "srvRecords": [ + { + "port": 75, + "priority": 15, + "target": "foo4.com.", + "weight": 65 + }, + { + "port": 7, + "priority": 52, + "target": "foo.com.", + "weight": 62 + } + ], + "ttl": 300 + }, + "type": "Microsoft.Network/privateDnsZones/SRV" + } + }, + { + "index": 58, + "value": { + "etag": "5eb0e5fb-8f30-45d8-ba6f-1f116b014b2c", + "id": "/subscriptions/02efc9e4-732d-4a8d-8b82-5b37e10eb89d/resourceGroups/dnscontroltest/providers/Microsoft.Network/privateDnsZones/dnscontroltest-azurep.com/TXT/final", + "name": "final", + "properties": { + "fqdn": "final.dnscontroltest-azurep.com.", + "isAutoRegistered": false, + "ttl": 300, + "txtRecords": [ + { + "value": [ + "TestDNSProviders was successful!" + ] + } + ] + }, + "type": "Microsoft.Network/privateDnsZones/TXT" + } + }, + { + "index": 59, + "value": { + "etag": "5f2696a0-1234-4fba-aa0e-4417df42cc31", + "id": "/subscriptions/02efc9e4-732d-4a8d-8b82-5b37e10eb89d/resourceGroups/dnscontroltest/providers/Microsoft.Network/privateDnsZones/dnscontroltest-azurep.com/CNAME/mail", + "name": "mail", + "properties": { + "cnameRecord": { + "cname": "ghs.googlehosted.com." + }, + "fqdn": "mail.dnscontroltest-azurep.com.", + "isAutoRegistered": false, + "ttl": 300 + }, + "type": "Microsoft.Network/privateDnsZones/CNAME" + } + }, + { + "index": 60, + "value": { + "etag": "62dfb9ed-7fc6-4e7e-b555-23c2f7dad3a0", + "id": "/subscriptions/02efc9e4-732d-4a8d-8b82-5b37e10eb89d/resourceGroups/dnscontroltest/providers/Microsoft.Network/privateDnsZones/dnscontroltest-azurep.com/A/foo.bat", + "name": "foo.bat", + "properties": { + "aRecords": [ + { + "ipv4Address": "1.2.3.4" + }, + { + "ipv4Address": "2.3.4.5" + } + ], + "fqdn": "foo.bat.dnscontroltest-azurep.com.", + "isAutoRegistered": false, + "ttl": 300 + }, + "type": "Microsoft.Network/privateDnsZones/A" + } + }, + { + "index": 61, + "value": { + "etag": "63697bb6-be90-45f8-8db1-9fcbafd0dc3f", + "id": "/subscriptions/02efc9e4-732d-4a8d-8b82-5b37e10eb89d/resourceGroups/dnscontroltest/providers/Microsoft.Network/privateDnsZones/dnscontroltest-azurep.com/A/foo", + "name": "foo", + "properties": { + "aRecords": [ + { + "ipv4Address": "1.2.3.4" + }, + { + "ipv4Address": "2.3.4.5" + } + ], + "fqdn": "foo.dnscontroltest-azurep.com.", + "isAutoRegistered": false, + "ttl": 300 + }, + "type": "Microsoft.Network/privateDnsZones/A" + } + }, + { + "index": 62, + "value": { + "etag": "63e5ea11-2155-48c9-948c-876279d459c5", + "id": "/subscriptions/02efc9e4-732d-4a8d-8b82-5b37e10eb89d/resourceGroups/dnscontroltest/providers/Microsoft.Network/privateDnsZones/dnscontroltest-azurep.com/MX/nmx", + "name": "nmx", + "properties": { + "fqdn": "nmx.dnscontroltest-azurep.com.", + "isAutoRegistered": false, + "mxRecords": [ + { + "exchange": ".", + "preference": 0 + } + ], + "ttl": 300 + }, + "type": "Microsoft.Network/privateDnsZones/MX" + } + }, + { + "index": 63, + "value": { + "etag": "69f4f834-59b0-4e15-ab26-5d18883f90ab", + "id": "/subscriptions/02efc9e4-732d-4a8d-8b82-5b37e10eb89d/resourceGroups/dnscontroltest/providers/Microsoft.Network/privateDnsZones/dnscontroltest-azurep.com/CNAME/foo", + "name": "foo", + "properties": { + "cnameRecord": { + "cname": "google2.com." + }, + "fqdn": "foo.dnscontroltest-azurep.com.", + "isAutoRegistered": false, + "ttl": 300 + }, + "type": "Microsoft.Network/privateDnsZones/CNAME" + } + }, + { + "index": 64, + "value": { + "etag": "6b15f0e8-a8e7-4a06-bc8e-8e66c1c076ee", + "id": "/subscriptions/02efc9e4-732d-4a8d-8b82-5b37e10eb89d/resourceGroups/dnscontroltest/providers/Microsoft.Network/privateDnsZones/dnscontroltest-azurep.com/A/foo", + "name": "foo", + "properties": { + "aRecords": [ + { + "ipv4Address": "1.2.3.4" + } + ], + "fqdn": "foo.dnscontroltest-azurep.com.", + "isAutoRegistered": false, + "ttl": 300 + }, + "type": "Microsoft.Network/privateDnsZones/A" + } + }, + { + "index": 65, + "value": { + "etag": "6d16759b-8019-44ec-b921-233a251bb626", + "id": "/subscriptions/02efc9e4-732d-4a8d-8b82-5b37e10eb89d/resourceGroups/dnscontroltest/providers/Microsoft.Network/privateDnsZones/dnscontroltest-azurep.com/A/foo", + "name": "foo", + "properties": { + "aRecords": [ + { + "ipv4Address": "1.2.3.4" + } + ], + "fqdn": "foo.dnscontroltest-azurep.com.", + "isAutoRegistered": false, + "ttl": 300 + }, + "type": "Microsoft.Network/privateDnsZones/A" + } + }, + { + "index": 66, + "value": { + "etag": "6ed028c5-da02-48e0-97b3-37560418d254", + "id": "/subscriptions/02efc9e4-732d-4a8d-8b82-5b37e10eb89d/resourceGroups/dnscontroltest/providers/Microsoft.Network/privateDnsZones/dnscontroltest-azurep.com/MX/nmx", + "name": "nmx", + "properties": { + "fqdn": "nmx.dnscontroltest-azurep.com.", + "isAutoRegistered": false, + "mxRecords": [ + { + "exchange": "nmx.dnscontroltest-azurep.com.", + "preference": 3 + }, + { + "exchange": "www.dnscontroltest-azurep.com.", + "preference": 9 + } + ], + "ttl": 300 + }, + "type": "Microsoft.Network/privateDnsZones/MX" + } + }, + { + "index": 67, + "value": { + "etag": "708dfb0c-4bd2-43da-9ba5-be0dee7bcaeb", + "id": "/subscriptions/02efc9e4-732d-4a8d-8b82-5b37e10eb89d/resourceGroups/dnscontroltest/providers/Microsoft.Network/privateDnsZones/dnscontroltest-azurep.com/TXT/foo510", + "name": "foo510", + "properties": { + "fqdn": "foo510.dnscontroltest-azurep.com.", + "isAutoRegistered": false, + "ttl": 300, + "txtRecords": [ + { + "value": [ + "EEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE", + "EEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE" + ] + } + ] + }, + "type": "Microsoft.Network/privateDnsZones/TXT" + } + }, + { + "index": 68, + "value": { + "etag": "724fb1dd-8441-48c0-a62b-16deae15c934", + "id": "/subscriptions/02efc9e4-732d-4a8d-8b82-5b37e10eb89d/resourceGroups/dnscontroltest/providers/Microsoft.Network/privateDnsZones/dnscontroltest-azurep.com/A/@", + "name": "@", + "properties": { + "aRecords": [ + { + "ipv4Address": "8.8.8.8" + } + ], + "fqdn": "dnscontroltest-azurep.com.", + "isAutoRegistered": false, + "ttl": 1000 + }, + "type": "Microsoft.Network/privateDnsZones/A" + } + }, + { + "index": 69, + "value": { + "etag": "72efc348-29c4-4f83-9c6d-703620ccbb1a", + "id": "/subscriptions/02efc9e4-732d-4a8d-8b82-5b37e10eb89d/resourceGroups/dnscontroltest/providers/Microsoft.Network/privateDnsZones/dnscontroltest-azurep.com/MX/testmx", + "name": "testmx", + "properties": { + "fqdn": "testmx.dnscontroltest-azurep.com.", + "isAutoRegistered": false, + "mxRecords": [ + { + "exchange": "foo.com.", + "preference": 5 + } + ], + "ttl": 300 + }, + "type": "Microsoft.Network/privateDnsZones/MX" + } + }, + { + "index": 70, + "value": { + "etag": "737a37a6-492a-4eb3-88ae-bf0fa53975a0", + "id": "/subscriptions/02efc9e4-732d-4a8d-8b82-5b37e10eb89d/resourceGroups/dnscontroltest/providers/Microsoft.Network/privateDnsZones/dnscontroltest-azurep.com/TXT/final", + "name": "final", + "properties": { + "fqdn": "final.dnscontroltest-azurep.com.", + "isAutoRegistered": false, + "ttl": 300, + "txtRecords": [ + { + "value": [ + "TestDNSProviders was successful!" + ] + } + ] + }, + "type": "Microsoft.Network/privateDnsZones/TXT" + } + }, + { + "index": 71, + "value": { + "etag": "76c976e9-fbe2-4794-bfaa-42200f51cc24", + "id": "/subscriptions/02efc9e4-732d-4a8d-8b82-5b37e10eb89d/resourceGroups/dnscontroltest/providers/Microsoft.Network/privateDnsZones/dnscontroltest-azurep.com/MX/@", + "name": "@", + "properties": { + "fqdn": "dnscontroltest-azurep.com.", + "isAutoRegistered": false, + "mxRecords": [ + { + "exchange": "dnscontroltest-azurep.com.", + "preference": 2 + }, + { + "exchange": "www.dnscontroltest-azurep.com.", + "preference": 8 + } + ], + "ttl": 300 + }, + "type": "Microsoft.Network/privateDnsZones/MX" + } + }, + { + "index": 72, + "value": { + "etag": "76f1ac72-12e5-4662-9a87-db7cd37ea505", + "id": "/subscriptions/02efc9e4-732d-4a8d-8b82-5b37e10eb89d/resourceGroups/dnscontroltest/providers/Microsoft.Network/privateDnsZones/dnscontroltest-azurep.com/PTR/4", + "name": "4", + "properties": { + "fqdn": "4.dnscontroltest-azurep.com.", + "isAutoRegistered": false, + "ptrRecords": [ + { + "ptrdname": "bar.com." + } + ], + "ttl": 300 + }, + "type": "Microsoft.Network/privateDnsZones/PTR" + } + }, + { + "index": 73, + "value": { + "etag": "774850c2-2f9d-465a-b076-715c4b72aa72", + "id": "/subscriptions/02efc9e4-732d-4a8d-8b82-5b37e10eb89d/resourceGroups/dnscontroltest/providers/Microsoft.Network/privateDnsZones/dnscontroltest-azurep.com/TXT/fooosbs1", + "name": "fooosbs1", + "properties": { + "fqdn": "fooosbs1.dnscontroltest-azurep.com.", + "isAutoRegistered": false, + "ttl": 300, + "txtRecords": [ + { + "value": [ + "1back\\slash" + ] + } + ] + }, + "type": "Microsoft.Network/privateDnsZones/TXT" + } + }, + { + "index": 74, + "value": { + "etag": "77867c2c-d416-45e1-8ed6-1f0246564c99", + "id": "/subscriptions/02efc9e4-732d-4a8d-8b82-5b37e10eb89d/resourceGroups/dnscontroltest/providers/Microsoft.Network/privateDnsZones/dnscontroltest-azurep.com/MX/@", + "name": "@", + "properties": { + "fqdn": "dnscontroltest-azurep.com.", + "isAutoRegistered": false, + "mxRecords": [ + { + "exchange": "bar.com.", + "preference": 5 + } + ], + "ttl": 300 + }, + "type": "Microsoft.Network/privateDnsZones/MX" + } + }, + { + "index": 75, + "value": { + "etag": "795e1ccf-75f9-4863-b322-ae429c06b524", + "id": "/subscriptions/02efc9e4-732d-4a8d-8b82-5b37e10eb89d/resourceGroups/dnscontroltest/providers/Microsoft.Network/privateDnsZones/dnscontroltest-azurep.com/MX/@", + "name": "@", + "properties": { + "fqdn": "dnscontroltest-azurep.com.", + "isAutoRegistered": false, + "mxRecords": [ + { + "exchange": ".", + "preference": 0 + } + ], + "ttl": 300 + }, + "type": "Microsoft.Network/privateDnsZones/MX" + } + }, + { + "index": 76, + "value": { + "etag": "79d981cf-1a8c-43fa-a615-9c6f79eb0622", + "id": "/subscriptions/02efc9e4-732d-4a8d-8b82-5b37e10eb89d/resourceGroups/dnscontroltest/providers/Microsoft.Network/privateDnsZones/dnscontroltest-azurep.com/SRV/_sip._tcp", + "name": "_sip._tcp", + "properties": { + "fqdn": "_sip._tcp.dnscontroltest-azurep.com.", + "isAutoRegistered": false, + "srvRecords": [ + { + "port": 7, + "priority": 5, + "target": "foo.com.", + "weight": 6 + }, + { + "port": 75, + "priority": 15, + "target": "foo4.com.", + "weight": 65 + } + ], + "ttl": 300 + }, + "type": "Microsoft.Network/privateDnsZones/SRV" + } + }, + { + "index": 77, + "value": { + "etag": "7d806324-33a4-4a24-b01d-84dcb8c6e186", + "id": "/subscriptions/02efc9e4-732d-4a8d-8b82-5b37e10eb89d/resourceGroups/dnscontroltest/providers/Microsoft.Network/privateDnsZones/dnscontroltest-azurep.com/A/testdefined", + "name": "testdefined", + "properties": { + "aRecords": [ + { + "ipv4Address": "9.9.9.9" + } + ], + "fqdn": "testdefined.dnscontroltest-azurep.com.", + "isAutoRegistered": false, + "ttl": 300 + }, + "type": "Microsoft.Network/privateDnsZones/A" + } + }, + { + "index": 78, + "value": { + "etag": "83124aff-4de0-4f58-8ee4-dd1e6119f742", + "id": "/subscriptions/02efc9e4-732d-4a8d-8b82-5b37e10eb89d/resourceGroups/dnscontroltest/providers/Microsoft.Network/privateDnsZones/dnscontroltest-azurep.com/MX/testmx", + "name": "testmx", + "properties": { + "fqdn": "testmx.dnscontroltest-azurep.com.", + "isAutoRegistered": false, + "mxRecords": [ + { + "exchange": "foo.com.", + "preference": 5 + }, + { + "exchange": "bar.com.", + "preference": 100 + } + ], + "ttl": 300 + }, + "type": "Microsoft.Network/privateDnsZones/MX" + } + }, + { + "index": 79, + "value": { + "etag": "87469a80-c808-4795-b41a-2533bf763be4", + "id": "/subscriptions/02efc9e4-732d-4a8d-8b82-5b37e10eb89d/resourceGroups/dnscontroltest/providers/Microsoft.Network/privateDnsZones/dnscontroltest-azurep.com/CNAME/xn--o-0gab", + "name": "xn--o-0gab", + "properties": { + "cnameRecord": { + "cname": "xn--ndaaa.xn--vhquv." + }, + "fqdn": "xn--o-0gab.dnscontroltest-azurep.com.", + "isAutoRegistered": false, + "ttl": 300 + }, + "type": "Microsoft.Network/privateDnsZones/CNAME" + } + }, + { + "index": 80, + "value": { + "etag": "93ff344b-2549-4d7d-a9d7-a7b660b4196d", + "id": "/subscriptions/02efc9e4-732d-4a8d-8b82-5b37e10eb89d/resourceGroups/dnscontroltest/providers/Microsoft.Network/privateDnsZones/dnscontroltest-azurep.com/A/bar", + "name": "bar", + "properties": { + "aRecords": [ + { + "ipv4Address": "1.2.3.4" + } + ], + "fqdn": "bar.dnscontroltest-azurep.com.", + "isAutoRegistered": false, + "ttl": 300 + }, + "type": "Microsoft.Network/privateDnsZones/A" + } + }, + { + "index": 81, + "value": { + "etag": "95df08a9-d760-424a-99fd-1e4f1ee7e244", + "id": "/subscriptions/02efc9e4-732d-4a8d-8b82-5b37e10eb89d/resourceGroups/dnscontroltest/providers/Microsoft.Network/privateDnsZones/dnscontroltest-azurep.com/A/dyndns-city2", + "name": "dyndns-city2", + "properties": { + "aRecords": [ + { + "ipv4Address": "91.42.1.2" + } + ], + "fqdn": "dyndns-city2.dnscontroltest-azurep.com.", + "isAutoRegistered": false, + "ttl": 300 + }, + "type": "Microsoft.Network/privateDnsZones/A" + } + }, + { + "index": 82, + "value": { + "etag": "96f90786-5021-41aa-9db0-f0c64aa34fab", + "id": "/subscriptions/02efc9e4-732d-4a8d-8b82-5b37e10eb89d/resourceGroups/dnscontroltest/providers/Microsoft.Network/privateDnsZones/dnscontroltest-azurep.com/TXT/foodqs", + "name": "foodqs", + "properties": { + "fqdn": "foodqs.dnscontroltest-azurep.com.", + "isAutoRegistered": false, + "ttl": 300, + "txtRecords": [ + { + "value": [ + "right\"" + ] + } + ] + }, + "type": "Microsoft.Network/privateDnsZones/TXT" + } + }, + { + "index": 83, + "value": { + "etag": "97bb35f2-611e-48fa-8e62-5901ea57d99f", + "id": "/subscriptions/02efc9e4-732d-4a8d-8b82-5b37e10eb89d/resourceGroups/dnscontroltest/providers/Microsoft.Network/privateDnsZones/dnscontroltest-azurep.com/TXT/@", + "name": "@", + "properties": { + "fqdn": "dnscontroltest-azurep.com.", + "isAutoRegistered": false, + "ttl": 300, + "txtRecords": [ + { + "value": [ + "asimple" + ] + } + ] + }, + "type": "Microsoft.Network/privateDnsZones/TXT" + } + }, + { + "index": 84, + "value": { + "etag": "9ae894c5-6115-48f2-907a-dc6595e32bca", + "id": "/subscriptions/02efc9e4-732d-4a8d-8b82-5b37e10eb89d/resourceGroups/dnscontroltest/providers/Microsoft.Network/privateDnsZones/dnscontroltest-azurep.com/A/decoy", + "name": "decoy", + "properties": { + "aRecords": [ + { + "ipv4Address": "1.1.1.1" + } + ], + "fqdn": "decoy.dnscontroltest-azurep.com.", + "isAutoRegistered": false, + "ttl": 300 + }, + "type": "Microsoft.Network/privateDnsZones/A" + } + }, + { + "index": 85, + "value": { + "etag": "9c48dceb-71b5-4047-b6d3-c31aac09aeab", + "id": "/subscriptions/02efc9e4-732d-4a8d-8b82-5b37e10eb89d/resourceGroups/dnscontroltest/providers/Microsoft.Network/privateDnsZones/dnscontroltest-azurep.com/A/foo", + "name": "foo", + "properties": { + "aRecords": [ + { + "ipv4Address": "1.2.3.4" + } + ], + "fqdn": "foo.dnscontroltest-azurep.com.", + "isAutoRegistered": false, + "ttl": 300 + }, + "type": "Microsoft.Network/privateDnsZones/A" + } + }, + { + "index": 86, + "value": { + "etag": "9d021a12-c1cf-4e6f-ade5-b769ebd1cb58", + "id": "/subscriptions/02efc9e4-732d-4a8d-8b82-5b37e10eb89d/resourceGroups/dnscontroltest/providers/Microsoft.Network/privateDnsZones/dnscontroltest-azurep.com/TXT/testtxt", + "name": "testtxt", + "properties": { + "fqdn": "testtxt.dnscontroltest-azurep.com.", + "isAutoRegistered": false, + "ttl": 300, + "txtRecords": [ + { + "value": [ + "changed" + ] + } + ] + }, + "type": "Microsoft.Network/privateDnsZones/TXT" + } + }, + { + "index": 87, + "value": { + "etag": "9d39e74f-9542-4630-8f26-7cee603f7907", + "id": "/subscriptions/02efc9e4-732d-4a8d-8b82-5b37e10eb89d/resourceGroups/dnscontroltest/providers/Microsoft.Network/privateDnsZones/dnscontroltest-azurep.com/A/foo", + "name": "foo", + "properties": { + "aRecords": [ + { + "ipv4Address": "1.1.1.1" + }, + { + "ipv4Address": "11.11.11.11" + } + ], + "fqdn": "foo.dnscontroltest-azurep.com.", + "isAutoRegistered": false, + "ttl": 300 + }, + "type": "Microsoft.Network/privateDnsZones/A" + } + }, + { + "index": 88, + "value": { + "etag": "9ef96b36-0921-4391-9e3f-a8c4f9a4810a", + "id": "/subscriptions/02efc9e4-732d-4a8d-8b82-5b37e10eb89d/resourceGroups/dnscontroltest/providers/Microsoft.Network/privateDnsZones/dnscontroltest-azurep.com/TXT/foows1", + "name": "foows1", + "properties": { + "fqdn": "foows1.dnscontroltest-azurep.com.", + "isAutoRegistered": false, + "ttl": 300, + "txtRecords": [ + { + "value": [ + "trailingws " + ] + } + ] + }, + "type": "Microsoft.Network/privateDnsZones/TXT" + } + }, + { + "index": 89, + "value": { + "etag": "a0e9c0c3-d9f7-4540-abd7-bcd3b2bf17cc", + "id": "/subscriptions/02efc9e4-732d-4a8d-8b82-5b37e10eb89d/resourceGroups/dnscontroltest/providers/Microsoft.Network/privateDnsZones/dnscontroltest-azurep.com/A/foo", + "name": "foo", + "properties": { + "aRecords": [ + { + "ipv4Address": "1.2.3.4" + }, + { + "ipv4Address": "2.3.4.5" + } + ], + "fqdn": "foo.dnscontroltest-azurep.com.", + "isAutoRegistered": false, + "ttl": 300 + }, + "type": "Microsoft.Network/privateDnsZones/A" + } + }, + { + "index": 90, + "value": { + "etag": "a13db500-6977-4ec6-b693-3d11763772d3", + "id": "/subscriptions/02efc9e4-732d-4a8d-8b82-5b37e10eb89d/resourceGroups/dnscontroltest/providers/Microsoft.Network/privateDnsZones/dnscontroltest-azurep.com/A/www", + "name": "www", + "properties": { + "aRecords": [ + { + "ipv4Address": "1.1.1.1" + }, + { + "ipv4Address": "2.2.2.2" + } + ], + "fqdn": "www.dnscontroltest-azurep.com.", + "isAutoRegistered": false, + "ttl": 300 + }, + "type": "Microsoft.Network/privateDnsZones/A" + } + }, + { + "index": 91, + "value": { + "etag": "a22451e9-f2cc-4503-ac5e-e5fdfb38386e", + "id": "/subscriptions/02efc9e4-732d-4a8d-8b82-5b37e10eb89d/resourceGroups/dnscontroltest/providers/Microsoft.Network/privateDnsZones/dnscontroltest-azurep.com/A/www", + "name": "www", + "properties": { + "aRecords": [ + { + "ipv4Address": "1.1.1.1" + } + ], + "fqdn": "www.dnscontroltest-azurep.com.", + "isAutoRegistered": false, + "ttl": 300 + }, + "type": "Microsoft.Network/privateDnsZones/A" + } + }, + { + "index": 92, + "value": { + "etag": "a3849ef5-5031-4c5d-8b8d-43cc1ea6423f", + "id": "/subscriptions/02efc9e4-732d-4a8d-8b82-5b37e10eb89d/resourceGroups/dnscontroltest/providers/Microsoft.Network/privateDnsZones/dnscontroltest-azurep.com/A/www", + "name": "www", + "properties": { + "aRecords": [ + { + "ipv4Address": "1.1.1.1" + } + ], + "fqdn": "www.dnscontroltest-azurep.com.", + "isAutoRegistered": false, + "ttl": 300 + }, + "type": "Microsoft.Network/privateDnsZones/A" + } + }, + { + "index": 93, + "value": { + "etag": "a454c9a1-e67c-42b0-a363-0ea4e9d5efc4", + "id": "/subscriptions/02efc9e4-732d-4a8d-8b82-5b37e10eb89d/resourceGroups/dnscontroltest/providers/Microsoft.Network/privateDnsZones/dnscontroltest-azurep.com/TXT/foo765", + "name": "foo765", + "properties": { + "fqdn": "foo765.dnscontroltest-azurep.com.", + "isAutoRegistered": false, + "ttl": 300, + "txtRecords": [ + { + "value": [ + "HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH", + "HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH", + "HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH" + ] + } + ] + }, + "type": "Microsoft.Network/privateDnsZones/TXT" + } + }, + { + "index": 94, + "value": { + "etag": "a745dc38-98e1-4a15-ab2e-576144240ed1", + "id": "/subscriptions/02efc9e4-732d-4a8d-8b82-5b37e10eb89d/resourceGroups/dnscontroltest/providers/Microsoft.Network/privateDnsZones/dnscontroltest-azurep.com/TXT/fooosbs2", + "name": "fooosbs2", + "properties": { + "fqdn": "fooosbs2.dnscontroltest-azurep.com.", + "isAutoRegistered": false, + "ttl": 300, + "txtRecords": [ + { + "value": [ + "2back\\\\slash" + ] + } + ] + }, + "type": "Microsoft.Network/privateDnsZones/TXT" + } + }, + { + "index": 95, + "value": { + "etag": "a7ca012a-9081-41c6-a1da-cc3b46727ba5", + "id": "/subscriptions/02efc9e4-732d-4a8d-8b82-5b37e10eb89d/resourceGroups/dnscontroltest/providers/Microsoft.Network/privateDnsZones/dnscontroltest-azurep.com/MX/foo", + "name": "foo", + "properties": { + "fqdn": "foo.dnscontroltest-azurep.com.", + "isAutoRegistered": false, + "mxRecords": [ + { + "exchange": "foo.dnscontroltest-azurep.com.", + "preference": 10 + }, + { + "exchange": "bar.dnscontroltest-azurep.com.", + "preference": 20 + } + ], + "ttl": 300 + }, + "type": "Microsoft.Network/privateDnsZones/MX" + } + }, + { + "index": 96, + "value": { + "etag": "a7eb987c-e7b3-409c-858a-86d469c89548", + "id": "/subscriptions/02efc9e4-732d-4a8d-8b82-5b37e10eb89d/resourceGroups/dnscontroltest/providers/Microsoft.Network/privateDnsZones/dnscontroltest-azurep.com/TXT/foodqs", + "name": "foodqs", + "properties": { + "fqdn": "foodqs.dnscontroltest-azurep.com.", + "isAutoRegistered": false, + "ttl": 300, + "txtRecords": [ + { + "value": [ + "in\"ter\"ior" + ] + } + ] + }, + "type": "Microsoft.Network/privateDnsZones/TXT" + } + }, + { + "index": 97, + "value": { + "etag": "a909806a-2b3b-41b2-818b-cb625a5cb6a5", + "id": "/subscriptions/02efc9e4-732d-4a8d-8b82-5b37e10eb89d/resourceGroups/dnscontroltest/providers/Microsoft.Network/privateDnsZones/dnscontroltest-azurep.com/TXT/foodq", + "name": "foodq", + "properties": { + "fqdn": "foodq.dnscontroltest-azurep.com.", + "isAutoRegistered": false, + "ttl": 300, + "txtRecords": [ + { + "value": [ + "in\"side" + ] + } + ] + }, + "type": "Microsoft.Network/privateDnsZones/TXT" + } + }, + { + "index": 98, + "value": { + "etag": "a9b34377-d9b6-44d7-bb75-41ec922dbe4a", + "id": "/subscriptions/02efc9e4-732d-4a8d-8b82-5b37e10eb89d/resourceGroups/dnscontroltest/providers/Microsoft.Network/privateDnsZones/dnscontroltest-azurep.com/A/testa", + "name": "testa", + "properties": { + "aRecords": [ + { + "ipv4Address": "3.3.3.3" + } + ], + "fqdn": "testa.dnscontroltest-azurep.com.", + "isAutoRegistered": false, + "ttl": 300 + }, + "type": "Microsoft.Network/privateDnsZones/A" + } + }, + { + "index": 99, + "value": { + "etag": "a9e2b96c-bfe2-4cfc-8b4e-3a454d1965f1", + "id": "/subscriptions/02efc9e4-732d-4a8d-8b82-5b37e10eb89d/resourceGroups/dnscontroltest/providers/Microsoft.Network/privateDnsZones/dnscontroltest-azurep.com/TXT/foo511", + "name": "foo511", + "properties": { + "fqdn": "foo511.dnscontroltest-azurep.com.", + "isAutoRegistered": false, + "ttl": 300, + "txtRecords": [ + { + "value": [ + "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF", + "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF", + "F" + ] + } + ] + }, + "type": "Microsoft.Network/privateDnsZones/TXT" + } + }, + { + "index": 100, + "value": { + "etag": "aa044f48-bb77-4130-87d5-4c1b35174fe5", + "id": "/subscriptions/02efc9e4-732d-4a8d-8b82-5b37e10eb89d/resourceGroups/dnscontroltest/providers/Microsoft.Network/privateDnsZones/dnscontroltest-azurep.com/AAAA/foo", + "name": "foo", + "properties": { + "aaaaRecords": [ + { + "ipv6Address": "2003:dd:d7ff::fe71:aaaa" + } + ], + "fqdn": "foo.dnscontroltest-azurep.com.", + "isAutoRegistered": false, + "ttl": 300 + }, + "type": "Microsoft.Network/privateDnsZones/AAAA" + } + }, + { + "index": 101, + "value": { + "etag": "abadf201-680b-42b2-8d0d-e3a8dc2891da", + "id": "/subscriptions/02efc9e4-732d-4a8d-8b82-5b37e10eb89d/resourceGroups/dnscontroltest/providers/Microsoft.Network/privateDnsZones/dnscontroltest-azurep.com/TXT/foo254", + "name": "foo254", + "properties": { + "fqdn": "foo254.dnscontroltest-azurep.com.", + "isAutoRegistered": false, + "ttl": 300, + "txtRecords": [ + { + "value": [ + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" + ] + } + ] + }, + "type": "Microsoft.Network/privateDnsZones/TXT" + } + }, + { + "index": 102, + "value": { + "etag": "aeb61589-861f-411c-be6a-0472b4702533", + "id": "/subscriptions/02efc9e4-732d-4a8d-8b82-5b37e10eb89d/resourceGroups/dnscontroltest/providers/Microsoft.Network/privateDnsZones/dnscontroltest-azurep.com/A/testignore", + "name": "testignore", + "properties": { + "aRecords": [ + { + "ipv4Address": "8.8.8.8" + } + ], + "fqdn": "testignore.dnscontroltest-azurep.com.", + "isAutoRegistered": false, + "ttl": 300 + }, + "type": "Microsoft.Network/privateDnsZones/A" + } + }, + { + "index": 103, + "value": { + "etag": "b3fe84bb-63fa-49d5-8215-7fec9de92b73", + "id": "/subscriptions/02efc9e4-732d-4a8d-8b82-5b37e10eb89d/resourceGroups/dnscontroltest/providers/Microsoft.Network/privateDnsZones/dnscontroltest-azurep.com/A/foo", + "name": "foo", + "properties": { + "aRecords": [ + { + "ipv4Address": "2.3.4.5" + }, + { + "ipv4Address": "3.4.5.6" + } + ], + "fqdn": "foo.dnscontroltest-azurep.com.", + "isAutoRegistered": false, + "ttl": 300 + }, + "type": "Microsoft.Network/privateDnsZones/A" + } + }, + { + "index": 104, + "value": { + "etag": "b50005ae-8945-4434-b3da-deb89dbc527f", + "id": "/subscriptions/02efc9e4-732d-4a8d-8b82-5b37e10eb89d/resourceGroups/dnscontroltest/providers/Microsoft.Network/privateDnsZones/dnscontroltest-azurep.com/AAAA/testaaaa", + "name": "testaaaa", + "properties": { + "aaaaRecords": [ + { + "ipv6Address": "2607:f8b0:4006:820::2013" + } + ], + "fqdn": "testaaaa.dnscontroltest-azurep.com.", + "isAutoRegistered": false, + "ttl": 300 + }, + "type": "Microsoft.Network/privateDnsZones/AAAA" + } + }, + { + "index": 105, + "value": { + "etag": "b92a99db-2846-441c-b9dc-65b5803cc21d", + "id": "/subscriptions/02efc9e4-732d-4a8d-8b82-5b37e10eb89d/resourceGroups/dnscontroltest/providers/Microsoft.Network/privateDnsZones/dnscontroltest-azurep.com/A/@", + "name": "@", + "properties": { + "aRecords": [ + { + "ipv4Address": "4.4.4.4" + } + ], + "fqdn": "dnscontroltest-azurep.com.", + "isAutoRegistered": false, + "ttl": 300 + }, + "type": "Microsoft.Network/privateDnsZones/A" + } + }, + { + "index": 106, + "value": { + "etag": "ba3b1afd-fabf-4fef-ab79-de5823521104", + "id": "/subscriptions/02efc9e4-732d-4a8d-8b82-5b37e10eb89d/resourceGroups/dnscontroltest/providers/Microsoft.Network/privateDnsZones/dnscontroltest-azurep.com/MX/testmx", + "name": "testmx", + "properties": { + "fqdn": "testmx.dnscontroltest-azurep.com.", + "isAutoRegistered": false, + "mxRecords": [ + { + "exchange": "foo.com.", + "preference": 100 + } + ], + "ttl": 300 + }, + "type": "Microsoft.Network/privateDnsZones/MX" + } + }, + { + "index": 107, + "value": { + "etag": "ba4861f2-84bd-4676-a576-886262179cfc", + "id": "/subscriptions/02efc9e4-732d-4a8d-8b82-5b37e10eb89d/resourceGroups/dnscontroltest/providers/Microsoft.Network/privateDnsZones/dnscontroltest-azurep.com/A/decoy", + "name": "decoy", + "properties": { + "aRecords": [ + { + "ipv4Address": "2.2.2.2" + } + ], + "fqdn": "decoy.dnscontroltest-azurep.com.", + "isAutoRegistered": false, + "ttl": 300 + }, + "type": "Microsoft.Network/privateDnsZones/A" + } + }, + { + "index": 108, + "value": { + "etag": "bacf6a15-f882-4563-9817-37748296d78a", + "id": "/subscriptions/02efc9e4-732d-4a8d-8b82-5b37e10eb89d/resourceGroups/dnscontroltest/providers/Microsoft.Network/privateDnsZones/dnscontroltest-azurep.com/A/foo", + "name": "foo", + "properties": { + "aRecords": [ + { + "ipv4Address": "2.3.4.5" + }, + { + "ipv4Address": "8.8.8.8" + } + ], + "fqdn": "foo.dnscontroltest-azurep.com.", + "isAutoRegistered": false, + "ttl": 300 + }, + "type": "Microsoft.Network/privateDnsZones/A" + } + }, + { + "index": 109, + "value": { + "etag": "bb0d80f6-acd8-4bdb-8b09-2fdacc78ce67", + "id": "/subscriptions/02efc9e4-732d-4a8d-8b82-5b37e10eb89d/resourceGroups/dnscontroltest/providers/Microsoft.Network/privateDnsZones/dnscontroltest-azurep.com/TXT/foo766", + "name": "foo766", + "properties": { + "fqdn": "foo766.dnscontroltest-azurep.com.", + "isAutoRegistered": false, + "ttl": 300, + "txtRecords": [ + { + "value": [ + "JJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJ", + "JJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJ", + "JJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJ", + "J" + ] + } + ] + }, + "type": "Microsoft.Network/privateDnsZones/TXT" + } + }, + { + "index": 110, + "value": { + "etag": "bb8975de-fb33-490a-99f2-64fa7f7859fc", + "id": "/subscriptions/02efc9e4-732d-4a8d-8b82-5b37e10eb89d/resourceGroups/dnscontroltest/providers/Microsoft.Network/privateDnsZones/dnscontroltest-azurep.com/AAAA/testaaaa", + "name": "testaaaa", + "properties": { + "aaaaRecords": [ + { + "ipv6Address": "2607:f8b0:4006:820::2006" + } + ], + "fqdn": "testaaaa.dnscontroltest-azurep.com.", + "isAutoRegistered": false, + "ttl": 300 + }, + "type": "Microsoft.Network/privateDnsZones/AAAA" + } + }, + { + "index": 111, + "value": { + "etag": "bf46d858-b715-4580-9fe2-947706fa5036", + "id": "/subscriptions/02efc9e4-732d-4a8d-8b82-5b37e10eb89d/resourceGroups/dnscontroltest/providers/Microsoft.Network/privateDnsZones/dnscontroltest-azurep.com/A/www", + "name": "www", + "properties": { + "aRecords": [ + { + "ipv4Address": "1.2.3.4" + }, + { + "ipv4Address": "5.6.7.8" + } + ], + "fqdn": "www.dnscontroltest-azurep.com.", + "isAutoRegistered": false, + "ttl": 300 + }, + "type": "Microsoft.Network/privateDnsZones/A" + } + }, + { + "index": 112, + "value": { + "etag": "bff92df5-a351-4fc8-868c-3b230f11a953", + "id": "/subscriptions/02efc9e4-732d-4a8d-8b82-5b37e10eb89d/resourceGroups/dnscontroltest/providers/Microsoft.Network/privateDnsZones/dnscontroltest-azurep.com/A/testa", + "name": "testa", + "properties": { + "aRecords": [ + { + "ipv4Address": "1.1.1.1" + } + ], + "fqdn": "testa.dnscontroltest-azurep.com.", + "isAutoRegistered": false, + "ttl": 999 + }, + "type": "Microsoft.Network/privateDnsZones/A" + } + }, + { + "index": 113, + "value": { + "etag": "c2284fbd-2538-4276-9b54-3bca236478f8", + "id": "/subscriptions/02efc9e4-732d-4a8d-8b82-5b37e10eb89d/resourceGroups/dnscontroltest/providers/Microsoft.Network/privateDnsZones/dnscontroltest-azurep.com/SRV/_sip._tcp", + "name": "_sip._tcp", + "properties": { + "fqdn": "_sip._tcp.dnscontroltest-azurep.com.", + "isAutoRegistered": false, + "srvRecords": [ + { + "port": 75, + "priority": 15, + "target": "foo4.com.", + "weight": 65 + }, + { + "port": 7, + "priority": 52, + "target": "foo.com.", + "weight": 6 + } + ], + "ttl": 300 + }, + "type": "Microsoft.Network/privateDnsZones/SRV" + } + }, + { + "index": 114, + "value": { + "etag": "c3a9e7be-6d37-4ff6-98de-94ebac4c6435", + "id": "/subscriptions/02efc9e4-732d-4a8d-8b82-5b37e10eb89d/resourceGroups/dnscontroltest/providers/Microsoft.Network/privateDnsZones/dnscontroltest-azurep.com/A/@", + "name": "@", + "properties": { + "aRecords": [ + { + "ipv4Address": "1.2.3.2" + } + ], + "fqdn": "dnscontroltest-azurep.com.", + "isAutoRegistered": false, + "ttl": 300 + }, + "type": "Microsoft.Network/privateDnsZones/A" + } + }, + { + "index": 115, + "value": { + "etag": "c6d4c802-ac69-4b01-82bf-256f429a7fc0", + "id": "/subscriptions/02efc9e4-732d-4a8d-8b82-5b37e10eb89d/resourceGroups/dnscontroltest/providers/Microsoft.Network/privateDnsZones/dnscontroltest-azurep.com/MX/nmx", + "name": "nmx", + "properties": { + "fqdn": "nmx.dnscontroltest-azurep.com.", + "isAutoRegistered": false, + "mxRecords": [ + { + "exchange": ".", + "preference": 0 + } + ], + "ttl": 300 + }, + "type": "Microsoft.Network/privateDnsZones/MX" + } + }, + { + "index": 116, + "value": { + "etag": "c86be7f2-d533-41cb-8b00-d39e6d0a95fa", + "id": "/subscriptions/02efc9e4-732d-4a8d-8b82-5b37e10eb89d/resourceGroups/dnscontroltest/providers/Microsoft.Network/privateDnsZones/dnscontroltest-azurep.com/A/foo", + "name": "foo", + "properties": { + "aRecords": [ + { + "ipv4Address": "1.1.1.1" + }, + { + "ipv4Address": "12.12.12.12" + } + ], + "fqdn": "foo.dnscontroltest-azurep.com.", + "isAutoRegistered": false, + "ttl": 300 + }, + "type": "Microsoft.Network/privateDnsZones/A" + } + }, + { + "index": 117, + "value": { + "etag": "c902ec50-fe3a-4281-882b-ac8f759bfc3a", + "id": "/subscriptions/02efc9e4-732d-4a8d-8b82-5b37e10eb89d/resourceGroups/dnscontroltest/providers/Microsoft.Network/privateDnsZones/dnscontroltest-azurep.com/A/nmx", + "name": "nmx", + "properties": { + "aRecords": [ + { + "ipv4Address": "1.2.3.3" + } + ], + "fqdn": "nmx.dnscontroltest-azurep.com.", + "isAutoRegistered": false, + "ttl": 300 + }, + "type": "Microsoft.Network/privateDnsZones/A" + } + }, + { + "index": 118, + "value": { + "etag": "cb8b193a-f5c7-40b2-a8ae-2b4eb4be9ddf", + "id": "/subscriptions/02efc9e4-732d-4a8d-8b82-5b37e10eb89d/resourceGroups/dnscontroltest/providers/Microsoft.Network/privateDnsZones/dnscontroltest-azurep.com/SOA/@", + "name": "@", + "properties": { + "fqdn": "dnscontroltest-azurep.com.", + "isAutoRegistered": false, + "soaRecord": { + "email": "azureprivatedns-host.microsoft.com", + "expireTime": 2419200, + "host": "azureprivatedns.net", + "minimumTtl": 10, + "refreshTime": 3600, + "retryTime": 300, + "serialNumber": 1 + }, + "ttl": 3600 + }, + "type": "Microsoft.Network/privateDnsZones/SOA" + } + }, + { + "index": 119, + "value": { + "etag": "cc5be073-89bc-4b0d-a35e-7675e0943b98", + "id": "/subscriptions/02efc9e4-732d-4a8d-8b82-5b37e10eb89d/resourceGroups/dnscontroltest/providers/Microsoft.Network/privateDnsZones/dnscontroltest-azurep.com/A/www", + "name": "www", + "properties": { + "aRecords": [ + { + "ipv4Address": "1.2.3.9" + } + ], + "fqdn": "www.dnscontroltest-azurep.com.", + "isAutoRegistered": false, + "ttl": 300 + }, + "type": "Microsoft.Network/privateDnsZones/A" + } + }, + { + "index": 120, + "value": { + "etag": "ccd36d92-75f4-4bc6-82f4-a82c32c5c36b", + "id": "/subscriptions/02efc9e4-732d-4a8d-8b82-5b37e10eb89d/resourceGroups/dnscontroltest/providers/Microsoft.Network/privateDnsZones/dnscontroltest-azurep.com/TXT/foo0", + "name": "foo0", + "properties": { + "fqdn": "foo0.dnscontroltest-azurep.com.", + "isAutoRegistered": false, + "ttl": 300, + "txtRecords": [] + }, + "type": "Microsoft.Network/privateDnsZones/TXT" + } + }, + { + "index": 121, + "value": { + "etag": "cd8cfa76-9cfa-4b01-b744-9ddb7011287a", + "id": "/subscriptions/02efc9e4-732d-4a8d-8b82-5b37e10eb89d/resourceGroups/dnscontroltest/providers/Microsoft.Network/privateDnsZones/dnscontroltest-azurep.com/A/decoy", + "name": "decoy", + "properties": { + "aRecords": [ + { + "ipv4Address": "3.3.3.3" + } + ], + "fqdn": "decoy.dnscontroltest-azurep.com.", + "isAutoRegistered": false, + "ttl": 300 + }, + "type": "Microsoft.Network/privateDnsZones/A" + } + }, + { + "index": 122, + "value": { + "etag": "ced4ec65-087e-49c3-b21a-19feb75ef803", + "id": "/subscriptions/02efc9e4-732d-4a8d-8b82-5b37e10eb89d/resourceGroups/dnscontroltest/providers/Microsoft.Network/privateDnsZones/dnscontroltest-azurep.com/A/foo", + "name": "foo", + "properties": { + "aRecords": [ + { + "ipv4Address": "1.1.1.1" + }, + { + "ipv4Address": "14.14.14.14" + } + ], + "fqdn": "foo.dnscontroltest-azurep.com.", + "isAutoRegistered": false, + "ttl": 300 + }, + "type": "Microsoft.Network/privateDnsZones/A" + } + }, + { + "index": 123, + "value": { + "etag": "cf8f18a3-a444-45ca-8dad-a79bb6d3c749", + "id": "/subscriptions/02efc9e4-732d-4a8d-8b82-5b37e10eb89d/resourceGroups/dnscontroltest/providers/Microsoft.Network/privateDnsZones/dnscontroltest-azurep.com/TXT/foo", + "name": "foo", + "properties": { + "fqdn": "foo.dnscontroltest-azurep.com.", + "isAutoRegistered": false, + "ttl": 300, + "txtRecords": [ + { + "value": [ + "v=spf1 ip4:99.99.99.99 -all" + ] + } + ] + }, + "type": "Microsoft.Network/privateDnsZones/TXT" + } + }, + { + "index": 124, + "value": { + "etag": "cfbe902e-38c8-4028-b0fb-3f526a46b3ba", + "id": "/subscriptions/02efc9e4-732d-4a8d-8b82-5b37e10eb89d/resourceGroups/dnscontroltest/providers/Microsoft.Network/privateDnsZones/dnscontroltest-azurep.com/MX/testmx", + "name": "testmx", + "properties": { + "fqdn": "testmx.dnscontroltest-azurep.com.", + "isAutoRegistered": false, + "mxRecords": [ + { + "exchange": "foo.com.", + "preference": 5 + }, + { + "exchange": "bar.com.", + "preference": 100 + } + ], + "ttl": 300 + }, + "type": "Microsoft.Network/privateDnsZones/MX" + } + }, + { + "index": 125, + "value": { + "etag": "d075584c-6a10-4daf-a962-6ebe497be73c", + "id": "/subscriptions/02efc9e4-732d-4a8d-8b82-5b37e10eb89d/resourceGroups/dnscontroltest/providers/Microsoft.Network/privateDnsZones/dnscontroltest-azurep.com/A/foo", + "name": "foo", + "properties": { + "aRecords": [ + { + "ipv4Address": "2.3.4.5" + }, + { + "ipv4Address": "8.8.8.8" + } + ], + "fqdn": "foo.dnscontroltest-azurep.com.", + "isAutoRegistered": false, + "ttl": 300 + }, + "type": "Microsoft.Network/privateDnsZones/A" + } + }, + { + "index": 126, + "value": { + "etag": "d3a3d49d-a606-41bf-a53a-e6dbe0e8291d", + "id": "/subscriptions/02efc9e4-732d-4a8d-8b82-5b37e10eb89d/resourceGroups/dnscontroltest/providers/Microsoft.Network/privateDnsZones/dnscontroltest-azurep.com/SRV/_sip._tcp", + "name": "_sip._tcp", + "properties": { + "fqdn": "_sip._tcp.dnscontroltest-azurep.com.", + "isAutoRegistered": false, + "srvRecords": [ + { + "port": 7, + "priority": 5, + "target": "foo.com.", + "weight": 6 + }, + { + "port": 70, + "priority": 5, + "target": "foo2.com.", + "weight": 60 + } + ], + "ttl": 300 + }, + "type": "Microsoft.Network/privateDnsZones/SRV" + } + }, + { + "index": 127, + "value": { + "etag": "d5555b52-aac1-4977-9b33-f1498a36c799", + "id": "/subscriptions/02efc9e4-732d-4a8d-8b82-5b37e10eb89d/resourceGroups/dnscontroltest/providers/Microsoft.Network/privateDnsZones/dnscontroltest-azurep.com/SRV/_sip._tcp", + "name": "_sip._tcp", + "properties": { + "fqdn": "_sip._tcp.dnscontroltest-azurep.com.", + "isAutoRegistered": false, + "srvRecords": [ + { + "port": 7, + "priority": 5, + "target": "foo.com.", + "weight": 6 + } + ], + "ttl": 300 + }, + "type": "Microsoft.Network/privateDnsZones/SRV" + } + }, + { + "index": 128, + "value": { + "etag": "d58d2bd1-02e8-42c2-9f85-0bcd03298a5c", + "id": "/subscriptions/02efc9e4-732d-4a8d-8b82-5b37e10eb89d/resourceGroups/dnscontroltest/providers/Microsoft.Network/privateDnsZones/dnscontroltest-azurep.com/A/@", + "name": "@", + "properties": { + "aRecords": [ + { + "ipv4Address": "2.2.2.2" + } + ], + "fqdn": "dnscontroltest-azurep.com.", + "isAutoRegistered": false, + "ttl": 300 + }, + "type": "Microsoft.Network/privateDnsZones/A" + } + }, + { + "index": 129, + "value": { + "etag": "d68dfdb8-c761-49da-9bb1-ab2c973b1a6f", + "id": "/subscriptions/02efc9e4-732d-4a8d-8b82-5b37e10eb89d/resourceGroups/dnscontroltest/providers/Microsoft.Network/privateDnsZones/dnscontroltest-azurep.com/TXT/@", + "name": "@", + "properties": { + "fqdn": "dnscontroltest-azurep.com.", + "isAutoRegistered": false, + "ttl": 300, + "txtRecords": [ + { + "value": [ + "simple" + ] + } + ] + }, + "type": "Microsoft.Network/privateDnsZones/TXT" + } + }, + { + "index": 130, + "value": { + "etag": "d9194c1d-eb00-4c06-9247-61866f2b919c", + "id": "/subscriptions/02efc9e4-732d-4a8d-8b82-5b37e10eb89d/resourceGroups/dnscontroltest/providers/Microsoft.Network/privateDnsZones/dnscontroltest-azurep.com/A/bar.bat", + "name": "bar.bat", + "properties": { + "aRecords": [ + { + "ipv4Address": "5.5.5.5" + } + ], + "fqdn": "bar.bat.dnscontroltest-azurep.com.", + "isAutoRegistered": false, + "ttl": 300 + }, + "type": "Microsoft.Network/privateDnsZones/A" + } + }, + { + "index": 131, + "value": { + "etag": "d989713d-35f9-42d6-b7ab-eb66047c8a96", + "id": "/subscriptions/02efc9e4-732d-4a8d-8b82-5b37e10eb89d/resourceGroups/dnscontroltest/providers/Microsoft.Network/privateDnsZones/dnscontroltest-azurep.com/A/@", + "name": "@", + "properties": { + "aRecords": [ + { + "ipv4Address": "8.8.8.8" + } + ], + "fqdn": "dnscontroltest-azurep.com.", + "isAutoRegistered": false, + "ttl": 666 + }, + "type": "Microsoft.Network/privateDnsZones/A" + } + }, + { + "index": 132, + "value": { + "etag": "db40a146-9b2c-40e5-926c-6f2435f3ab35", + "id": "/subscriptions/02efc9e4-732d-4a8d-8b82-5b37e10eb89d/resourceGroups/dnscontroltest/providers/Microsoft.Network/privateDnsZones/dnscontroltest-azurep.com/A/bar", + "name": "bar", + "properties": { + "aRecords": [ + { + "ipv4Address": "5.5.5.5" + } + ], + "fqdn": "bar.dnscontroltest-azurep.com.", + "isAutoRegistered": false, + "ttl": 300 + }, + "type": "Microsoft.Network/privateDnsZones/A" + } + }, + { + "index": 133, + "value": { + "etag": "dcd639fa-43e7-4572-b05b-2deebc8a0380", + "id": "/subscriptions/02efc9e4-732d-4a8d-8b82-5b37e10eb89d/resourceGroups/dnscontroltest/providers/Microsoft.Network/privateDnsZones/dnscontroltest-azurep.com/A/www", + "name": "www", + "properties": { + "aRecords": [ + { + "ipv4Address": "1.1.1.1" + }, + { + "ipv4Address": "2.2.2.2" + }, + { + "ipv4Address": "3.3.3.3" + } + ], + "fqdn": "www.dnscontroltest-azurep.com.", + "isAutoRegistered": false, + "ttl": 300 + }, + "type": "Microsoft.Network/privateDnsZones/A" + } + }, + { + "index": 134, + "value": { + "etag": "de25f602-397f-499b-858a-3eecf9ced838", + "id": "/subscriptions/02efc9e4-732d-4a8d-8b82-5b37e10eb89d/resourceGroups/dnscontroltest/providers/Microsoft.Network/privateDnsZones/dnscontroltest-azurep.com/SRV/_sip._tcp", + "name": "_sip._tcp", + "properties": { + "fqdn": "_sip._tcp.dnscontroltest-azurep.com.", + "isAutoRegistered": false, + "srvRecords": [ + { + "port": 7, + "priority": 5, + "target": "foo.com.", + "weight": 6 + } + ], + "ttl": 333 + }, + "type": "Microsoft.Network/privateDnsZones/SRV" + } + }, + { + "index": 135, + "value": { + "etag": "df5d1407-e451-4ea9-a9d3-430b592aba25", + "id": "/subscriptions/02efc9e4-732d-4a8d-8b82-5b37e10eb89d/resourceGroups/dnscontroltest/providers/Microsoft.Network/privateDnsZones/dnscontroltest-azurep.com/MX/@", + "name": "@", + "properties": { + "fqdn": "dnscontroltest-azurep.com.", + "isAutoRegistered": false, + "mxRecords": [ + { + "exchange": "foo.com.", + "preference": 5 + } + ], + "ttl": 300 + }, + "type": "Microsoft.Network/privateDnsZones/MX" + } + }, + { + "index": 136, + "value": { + "etag": "e0131372-4173-4a4d-8aca-07ff5717eaea", + "id": "/subscriptions/02efc9e4-732d-4a8d-8b82-5b37e10eb89d/resourceGroups/dnscontroltest/providers/Microsoft.Network/privateDnsZones/dnscontroltest-azurep.com/A/www", + "name": "www", + "properties": { + "aRecords": [ + { + "ipv4Address": "5.5.5.5" + } + ], + "fqdn": "www.dnscontroltest-azurep.com.", + "isAutoRegistered": false, + "ttl": 300 + }, + "type": "Microsoft.Network/privateDnsZones/A" + } + }, + { + "index": 137, + "value": { + "etag": "e251aeab-acf6-430e-986a-f3110dc9b799", + "id": "/subscriptions/02efc9e4-732d-4a8d-8b82-5b37e10eb89d/resourceGroups/dnscontroltest/providers/Microsoft.Network/privateDnsZones/dnscontroltest-azurep.com/A/testdefined", + "name": "testdefined", + "properties": { + "aRecords": [ + { + "ipv4Address": "2.2.2.2" + } + ], + "fqdn": "testdefined.dnscontroltest-azurep.com.", + "isAutoRegistered": false, + "ttl": 300 + }, + "type": "Microsoft.Network/privateDnsZones/A" + } + }, + { + "index": 138, + "value": { + "etag": "e2b012ab-a7ce-4367-acca-add41db9f152", + "id": "/subscriptions/02efc9e4-732d-4a8d-8b82-5b37e10eb89d/resourceGroups/dnscontroltest/providers/Microsoft.Network/privateDnsZones/dnscontroltest-azurep.com/A/foo", + "name": "foo", + "properties": { + "aRecords": [ + { + "ipv4Address": "1.2.3.4" + } + ], + "fqdn": "foo.dnscontroltest-azurep.com.", + "isAutoRegistered": false, + "ttl": 300 + }, + "type": "Microsoft.Network/privateDnsZones/A" + } + }, + { + "index": 139, + "value": { + "etag": "e49702fa-2322-4735-8600-469644d98c3f", + "id": "/subscriptions/02efc9e4-732d-4a8d-8b82-5b37e10eb89d/resourceGroups/dnscontroltest/providers/Microsoft.Network/privateDnsZones/dnscontroltest-azurep.com/A/www", + "name": "www", + "properties": { + "aRecords": [ + { + "ipv4Address": "5.6.7.8" + } + ], + "fqdn": "www.dnscontroltest-azurep.com.", + "isAutoRegistered": false, + "ttl": 400 + }, + "type": "Microsoft.Network/privateDnsZones/A" + } + }, + { + "index": 140, + "value": { + "etag": "e50adf45-5e54-46fa-8578-2c1b6f8d8a63", + "id": "/subscriptions/02efc9e4-732d-4a8d-8b82-5b37e10eb89d/resourceGroups/dnscontroltest/providers/Microsoft.Network/privateDnsZones/dnscontroltest-azurep.com/AAAA/dyndns-city2", + "name": "dyndns-city2", + "properties": { + "aaaaRecords": [ + { + "ipv6Address": "2003:dd:d7ff::fe71:ce78" + } + ], + "fqdn": "dyndns-city2.dnscontroltest-azurep.com.", + "isAutoRegistered": false, + "ttl": 300 + }, + "type": "Microsoft.Network/privateDnsZones/AAAA" + } + }, + { + "index": 141, + "value": { + "etag": "e55c09b1-89ce-4653-97fe-59db3f8c1a6c", + "id": "/subscriptions/02efc9e4-732d-4a8d-8b82-5b37e10eb89d/resourceGroups/dnscontroltest/providers/Microsoft.Network/privateDnsZones/dnscontroltest-azurep.com/TXT/foo.bat", + "name": "foo.bat", + "properties": { + "fqdn": "foo.bat.dnscontroltest-azurep.com.", + "isAutoRegistered": false, + "ttl": 300, + "txtRecords": [ + { + "value": [ + "simple" + ] + } + ] + }, + "type": "Microsoft.Network/privateDnsZones/TXT" + } + }, + { + "index": 142, + "value": { + "etag": "e802cfea-ef32-4dd2-8d22-34f91a813d2d", + "id": "/subscriptions/02efc9e4-732d-4a8d-8b82-5b37e10eb89d/resourceGroups/dnscontroltest/providers/Microsoft.Network/privateDnsZones/dnscontroltest-azurep.com/CNAME/foo", + "name": "foo", + "properties": { + "cnameRecord": { + "cname": "google.com." + }, + "fqdn": "foo.dnscontroltest-azurep.com.", + "isAutoRegistered": false, + "ttl": 300 + }, + "type": "Microsoft.Network/privateDnsZones/CNAME" + } + }, + { + "index": 143, + "value": { + "etag": "e894928a-2490-4bdd-8d60-d8f477c56577", + "id": "/subscriptions/02efc9e4-732d-4a8d-8b82-5b37e10eb89d/resourceGroups/dnscontroltest/providers/Microsoft.Network/privateDnsZones/dnscontroltest-azurep.com/SRV/_sip._tcp", + "name": "_sip._tcp", + "properties": { + "fqdn": "_sip._tcp.dnscontroltest-azurep.com.", + "isAutoRegistered": false, + "srvRecords": [ + { + "port": 7, + "priority": 5, + "target": "foo.com.", + "weight": 6 + }, + { + "port": 75, + "priority": 15, + "target": "foo3.com.", + "weight": 65 + } + ], + "ttl": 300 + }, + "type": "Microsoft.Network/privateDnsZones/SRV" + } + }, + { + "index": 144, + "value": { + "etag": "e8e0341e-4504-4417-aafd-e94d7aa881de", + "id": "/subscriptions/02efc9e4-732d-4a8d-8b82-5b37e10eb89d/resourceGroups/dnscontroltest/providers/Microsoft.Network/privateDnsZones/dnscontroltest-azurep.com/MX/testmx", + "name": "testmx", + "properties": { + "fqdn": "testmx.dnscontroltest-azurep.com.", + "isAutoRegistered": false, + "mxRecords": [ + { + "exchange": "foo.com.", + "preference": 5 + } + ], + "ttl": 300 + }, + "type": "Microsoft.Network/privateDnsZones/MX" + } + }, + { + "index": 145, + "value": { + "etag": "ec6a892a-b387-4e6d-8138-265db21cec5b", + "id": "/subscriptions/02efc9e4-732d-4a8d-8b82-5b37e10eb89d/resourceGroups/dnscontroltest/providers/Microsoft.Network/privateDnsZones/dnscontroltest-azurep.com/A/xn--ndaaa", + "name": "xn--ndaaa", + "properties": { + "aRecords": [ + { + "ipv4Address": "1.2.3.4" + } + ], + "fqdn": "xn--ndaaa.dnscontroltest-azurep.com.", + "isAutoRegistered": false, + "ttl": 300 + }, + "type": "Microsoft.Network/privateDnsZones/A" + } + }, + { + "index": 146, + "value": { + "etag": "edcdcb62-6cb4-43d2-8ccb-445e5b68371b", + "id": "/subscriptions/02efc9e4-732d-4a8d-8b82-5b37e10eb89d/resourceGroups/dnscontroltest/providers/Microsoft.Network/privateDnsZones/dnscontroltest-azurep.com/MX/bar", + "name": "bar", + "properties": { + "fqdn": "bar.dnscontroltest-azurep.com.", + "isAutoRegistered": false, + "mxRecords": [ + { + "exchange": "bar.com.", + "preference": 5 + } + ], + "ttl": 300 + }, + "type": "Microsoft.Network/privateDnsZones/MX" + } + }, + { + "index": 147, + "value": { + "etag": "f41dca76-d1e1-4b19-b2d1-c1da9efb3222", + "id": "/subscriptions/02efc9e4-732d-4a8d-8b82-5b37e10eb89d/resourceGroups/dnscontroltest/providers/Microsoft.Network/privateDnsZones/dnscontroltest-azurep.com/TXT/foosp", + "name": "foosp", + "properties": { + "fqdn": "foosp.dnscontroltest-azurep.com.", + "isAutoRegistered": false, + "ttl": 300, + "txtRecords": [ + { + "value": [ + "with spaces" + ] + } + ] + }, + "type": "Microsoft.Network/privateDnsZones/TXT" + } + }, + { + "index": 148, + "value": { + "etag": "f577d321-0af1-4560-8ca8-4f7987c16f1a", + "id": "/subscriptions/02efc9e4-732d-4a8d-8b82-5b37e10eb89d/resourceGroups/dnscontroltest/providers/Microsoft.Network/privateDnsZones/dnscontroltest-azurep.com/SRV/_sip._tcp", + "name": "_sip._tcp", + "properties": { + "fqdn": "_sip._tcp.dnscontroltest-azurep.com.", + "isAutoRegistered": false, + "srvRecords": [ + { + "port": 7, + "priority": 5, + "target": "foo.com.", + "weight": 6 + } + ], + "ttl": 4400 + }, + "type": "Microsoft.Network/privateDnsZones/SRV" + } + }, + { + "index": 149, + "value": { + "etag": "f8315ebb-633c-4cbe-93ca-5f3264741e14", + "id": "/subscriptions/02efc9e4-732d-4a8d-8b82-5b37e10eb89d/resourceGroups/dnscontroltest/providers/Microsoft.Network/privateDnsZones/dnscontroltest-azurep.com/A/foo", + "name": "foo", + "properties": { + "aRecords": [ + { + "ipv4Address": "1.2.3.4" + }, + { + "ipv4Address": "3.4.5.6" + } + ], + "fqdn": "foo.dnscontroltest-azurep.com.", + "isAutoRegistered": false, + "ttl": 300 + }, + "type": "Microsoft.Network/privateDnsZones/A" + } + }, + { + "index": 150, + "value": { + "etag": "f8779ef1-5128-41bb-84b8-4a469f408780", + "id": "/subscriptions/02efc9e4-732d-4a8d-8b82-5b37e10eb89d/resourceGroups/dnscontroltest/providers/Microsoft.Network/privateDnsZones/dnscontroltest-azurep.com/A/www", + "name": "www", + "properties": { + "aRecords": [ + { + "ipv4Address": "1.1.1.1" + } + ], + "fqdn": "www.dnscontroltest-azurep.com.", + "isAutoRegistered": false, + "ttl": 300 + }, + "type": "Microsoft.Network/privateDnsZones/A" + } + }, + { + "index": 151, + "value": { + "etag": "f94650b0-b8e9-4e54-8783-e2573c859320", + "id": "/subscriptions/02efc9e4-732d-4a8d-8b82-5b37e10eb89d/resourceGroups/dnscontroltest/providers/Microsoft.Network/privateDnsZones/dnscontroltest-azurep.com/MX/foo", + "name": "foo", + "properties": { + "fqdn": "foo.dnscontroltest-azurep.com.", + "isAutoRegistered": false, + "mxRecords": [ + { + "exchange": "aspmx.l.google.com.", + "preference": 10 + }, + { + "exchange": "alt1.aspmx.l.google.com.", + "preference": 20 + } + ], + "ttl": 300 + }, + "type": "Microsoft.Network/privateDnsZones/MX" + } + }, + { + "index": 152, + "value": { + "etag": "fa7e3589-f4b0-4efb-a279-60f993dbf006", + "id": "/subscriptions/02efc9e4-732d-4a8d-8b82-5b37e10eb89d/resourceGroups/dnscontroltest/providers/Microsoft.Network/privateDnsZones/dnscontroltest-azurep.com/TXT/foosc1", + "name": "foosc1", + "properties": { + "fqdn": "foosc1.dnscontroltest-azurep.com.", + "isAutoRegistered": false, + "ttl": 300, + "txtRecords": [ + { + "value": [ + "semi;colon" + ] + } + ] + }, + "type": "Microsoft.Network/privateDnsZones/TXT" + } + }, + { + "index": 153, + "value": { + "etag": "fbc57cd1-ff1b-4993-911e-5e02672137c8", + "id": "/subscriptions/02efc9e4-732d-4a8d-8b82-5b37e10eb89d/resourceGroups/dnscontroltest/providers/Microsoft.Network/privateDnsZones/dnscontroltest-azurep.com/TXT/foosq", + "name": "foosq", + "properties": { + "fqdn": "foosq.dnscontroltest-azurep.com.", + "isAutoRegistered": false, + "ttl": 300, + "txtRecords": [ + { + "value": [ + "quo'te" + ] + } + ] + }, + "type": "Microsoft.Network/privateDnsZones/TXT" + } + }, + { + "index": 154, + "value": { + "etag": "fe56cb8f-b13f-420c-981f-e882e982da05", + "id": "/subscriptions/02efc9e4-732d-4a8d-8b82-5b37e10eb89d/resourceGroups/dnscontroltest/providers/Microsoft.Network/privateDnsZones/dnscontroltest-azurep.com/A/www", + "name": "www", + "properties": { + "aRecords": [ + { + "ipv4Address": "1.2.3.8" + } + ], + "fqdn": "www.dnscontroltest-azurep.com.", + "isAutoRegistered": false, + "ttl": 300 + }, + "type": "Microsoft.Network/privateDnsZones/A" + } + } +] diff --git a/providers/bind/auditrecords.go b/providers/bind/auditrecords.go index 35d7e86591..0cce2f8992 100644 --- a/providers/bind/auditrecords.go +++ b/providers/bind/auditrecords.go @@ -1,10 +1,10 @@ package bind -import "github.com/DNSControl/dnscontrol/v4/models" +import "github.com/DNSControl/dnscontrol/v5/models" // AuditRecords returns a list of errors corresponding to the records // that aren't supported by this provider. If all records are // supported, an empty list is returned. -func AuditRecords(records []*models.RecordConfig) []error { +func AuditRecords(records models.Records) []error { return nil } diff --git a/providers/bind/bindProvider.go b/providers/bind/bindProvider.go index ceeb0f794c..c7cca3b6a5 100644 --- a/providers/bind/bindProvider.go +++ b/providers/bind/bindProvider.go @@ -21,17 +21,15 @@ import ( "strings" "time" - "github.com/DNSControl/dnscontrol/v4/models" - "github.com/DNSControl/dnscontrol/v4/pkg/bindserial" - "github.com/DNSControl/dnscontrol/v4/pkg/diff2" - "github.com/DNSControl/dnscontrol/v4/pkg/dnsrr" - "github.com/DNSControl/dnscontrol/v4/pkg/domaintags" - "github.com/DNSControl/dnscontrol/v4/pkg/prettyzone" - "github.com/DNSControl/dnscontrol/v4/pkg/printer" - "github.com/DNSControl/dnscontrol/v4/pkg/providers" - "github.com/DNSControl/dnscontrol/v4/pkg/rtypecontrol" - "github.com/DNSControl/dnscontrol/v4/pkg/rtypeinfo" - dnsv1 "github.com/miekg/dns" + dnsv2 "codeberg.org/miekg/dns" + "github.com/DNSControl/dnscontrol/v5/models" + "github.com/DNSControl/dnscontrol/v5/pkg/bindserial" + "github.com/DNSControl/dnscontrol/v5/pkg/diff2" + "github.com/DNSControl/dnscontrol/v5/pkg/dnsrr" + "github.com/DNSControl/dnscontrol/v5/pkg/domaintags" + "github.com/DNSControl/dnscontrol/v5/pkg/prettyzone" + "github.com/DNSControl/dnscontrol/v5/pkg/printer" + "github.com/DNSControl/dnscontrol/v5/pkg/providers" ) // defaultZonesDir is used when the BIND credentials do not specify a @@ -150,7 +148,8 @@ type SoaDefaults struct { Retry uint32 `json:"retry"` Expire uint32 `json:"expire"` Minttl uint32 `json:"minttl"` - TTL uint32 `json:"ttl,omitempty"` + // TTL isn't part of the SOA RDATA. It is a default applied to the SOA record's TTL itself. + TTL uint32 `json:"ttl,omitempty"` } func (s SoaDefaults) String() string { @@ -199,27 +198,23 @@ func (c *bindProvider) ListZones() ([]string, error) { // GetZoneRecords gets the records of a zone and returns them in RecordConfig format. func (c *bindProvider) GetZoneRecords(dc *models.DomainConfig) (models.Records, error) { domain := dc.Name - meta := dc.Metadata + // meta := dc.Metadata var zonefile string if _, err := os.Stat(c.directory); os.IsNotExist(err) { printer.Printf("\nWARNING: BIND directory %q does not exist! (will create)\n", c.directory) } - ff := domaintags.DomainNameVarieties{ - Tag: meta[models.DomainTag], - NameRaw: meta[models.DomainNameRaw], - NameASCII: domain, - NameUnicode: meta[models.DomainNameUnicode], - UniqueName: meta[models.DomainUniqueName], - // NB(tlim): When "get-zones" is called, these values are populated - // directly by commands/getZones.go near where provider.GetZoneRecords() - // is called. Changes here may need to be reflected there too. - } zonefile = filepath.Join(c.directory, makeFileName( c.filenameformat, - ff, + domaintags.DomainNameVarieties{ + Tag: dc.Tag, + NameRaw: dc.NameRaw, + NameASCII: domain, + NameUnicode: dc.NameUnicode, + UniqueName: dc.UniqueName, + }, ), ) //fmt.Printf("DEBUG: Reading zonefile %q\n", zonefile) @@ -236,39 +231,49 @@ func (c *bindProvider) GetZoneRecords(dc *models.DomainConfig) (models.Records, return nil, fmt.Errorf("can't open %s: %w", zonefile, err) } - return ParseZoneContents(string(content), domain, zonefile) + return ParseZoneContents(dc, string(content), zonefile) +} + +func findSoaRecord(recs models.Records) *models.RecordConfig { + for _, rec := range recs { + if rec.Type == "SOA" { + return rec + } + } + return nil +} + +func updateSerialNumber(recs models.Records, forcedSerial uint32) { + + recToUpdate := findSoaRecord(recs) + if recToUpdate == nil { + return + } + + f := recToUpdate.AsSOA() + + if forcedSerial != 0 { + f.Serial = forcedSerial + } else { + f.Serial = generateSerial(f.Serial) + } + + recToUpdate.SetRDATA(f) } // ParseZoneContents parses a string as a BIND zone and returns the records. -func ParseZoneContents(content string, zoneName string, zonefileName string) (models.Records, error) { - zp := dnsv1.NewZoneParser(strings.NewReader(content), zoneName, zonefileName) +func ParseZoneContents(dc *models.DomainConfig, content string, zonefileName string) (models.Records, error) { + zoneName := dc.Name + zp := dnsv2.NewZoneParser(strings.NewReader(content), zoneName, zonefileName) foundRecords := models.Records{} for rr, ok := zp.Next(); ok; rr, ok = zp.Next() { - var rec models.RecordConfig - var prec *models.RecordConfig - var err error - - rtype := rr.Header().Rrtype - rtypeStr := dnsv1.TypeToString[rtype] - if rtypeinfo.IsModernType(rtypeStr) { - // Modern types: - name := rr.Header().Name - prec, err = rtypecontrol.NewRecordConfigFromStruct(name, rr.Header().Ttl, rtypeStr, rr, domaintags.MakeDomainNameVarieties(zoneName)) - if err != nil { - return nil, err - } - rec = *prec - rec.TTL = rr.Header().Ttl - } else { - // Legacy types: - rec, err = dnsrr.RRtoRCTxtBug(rr, zoneName) - if err != nil { - return nil, err - } - } - foundRecords = append(foundRecords, &rec) + rec, err := dnsrr.RRv2toRC(dc, rr) + if err != nil { + return nil, err + } + foundRecords = append(foundRecords, rec) } if err := zp.Err(); err != nil { @@ -289,28 +294,7 @@ func (c *bindProvider) GetZoneRecordsCorrections(dc *models.DomainConfig, foundR changes := false var msg string - // Find the SOA records; use them to make or update the desired SOA. - var foundSoa *models.RecordConfig - for _, r := range foundRecords { - if r.Type == "SOA" && r.Name == "@" { - foundSoa = r - break - } - } - var desiredSoa *models.RecordConfig - for _, r := range dc.Records { - if r.Type == "SOA" && r.Name == "@" { - desiredSoa = r - break - } - } - soaRec, nextSerial := makeSoa(dc.Name, &c.DefaultSoa, foundSoa, desiredSoa) - if desiredSoa == nil { - dc.Records = append(dc.Records, soaRec) - desiredSoa = dc.Records[len(dc.Records)-1] - } else { - *desiredSoa = *soaRec - } + AddSoaIfMissing(dc, c.DefaultSoa) var msgs []string var actualChangeCount int @@ -349,13 +333,8 @@ func (c *bindProvider) GetZoneRecordsCorrections(dc *models.DomainConfig, foundR ), ) - // We only change the serial number if there is a change. - desiredSoa.SoaSerial = nextSerial - - // If the --bindserial flag is used, force the serial to that value - if bindserial.ForcedValue != 0 { - desiredSoa.SoaSerial = uint32(bindserial.ForcedValue & 0xFFFF) - } + // We know there are changes. Update the SOA record's serial number. + updateSerialNumber(result.DesiredPlus, uint32(bindserial.ForcedValue&0xFFFF)) corrections = append(corrections, &models.Correction{ diff --git a/providers/bind/fnames.go b/providers/bind/fnames.go index 82a6983a5f..c271c81b95 100644 --- a/providers/bind/fnames.go +++ b/providers/bind/fnames.go @@ -7,7 +7,7 @@ import ( "regexp" "strings" - "github.com/DNSControl/dnscontrol/v4/pkg/domaintags" + "github.com/DNSControl/dnscontrol/v5/pkg/domaintags" ) // makeFileName uses format to generate a zone's filename. See the. diff --git a/providers/bind/fnames_test.go b/providers/bind/fnames_test.go index 4e753e96ea..675a3cf788 100644 --- a/providers/bind/fnames_test.go +++ b/providers/bind/fnames_test.go @@ -4,7 +4,7 @@ import ( "reflect" "testing" - "github.com/DNSControl/dnscontrol/v4/pkg/domaintags" + "github.com/DNSControl/dnscontrol/v5/pkg/domaintags" ) func Test_makeFileName(t *testing.T) { diff --git a/providers/bind/serial.go b/providers/bind/serial.go index d53508c1e3..7fad7568f8 100644 --- a/providers/bind/serial.go +++ b/providers/bind/serial.go @@ -5,7 +5,7 @@ import ( "strconv" "time" - "github.com/DNSControl/dnscontrol/v4/pkg/bindserial" + "github.com/DNSControl/dnscontrol/v5/pkg/bindserial" ) var nowFunc = time.Now @@ -13,7 +13,7 @@ var nowFunc = time.Now // generateSerial takes an old SOA serial number and increments it. func generateSerial(oldSerial uint32) uint32 { // Serial numbers are in the format yyyymmddvv - // where vv is a version count that starts at 01 each day. + // where vv is a version count that starts at 00 each day. // Multiple serial numbers generated on the same day increase vv. // If the old serial number is not in this format, it gets replaced // with the new format. However if that would mean a new serial number diff --git a/providers/bind/soa.go b/providers/bind/soa.go index d0b687a19e..b2ccd39765 100644 --- a/providers/bind/soa.go +++ b/providers/bind/soa.go @@ -3,47 +3,41 @@ package bind import ( "strings" - "github.com/DNSControl/dnscontrol/v4/models" - "github.com/DNSControl/dnscontrol/v4/pkg/soautil" + dnsv2 "codeberg.org/miekg/dns" + "github.com/DNSControl/dnscontrol/v5/models" + "github.com/DNSControl/dnscontrol/v5/pkg/soautil" ) -func makeSoa(origin string, defSoa *SoaDefaults, existing, desired *models.RecordConfig) (*models.RecordConfig, uint32) { - // Create a SOA record. Take data from desired, existing, default, - // or hardcoded defaults. - soaRec := models.RecordConfig{} - soaRec.SetLabel("@", origin) - - if defSoa == nil { - defSoa = &SoaDefaults{} - } - if existing == nil { - existing = &models.RecordConfig{} - } - - if desired == nil { - desired = &models.RecordConfig{} +func AddSoaIfMissing(dc *models.DomainConfig, defaultSoaValues SoaDefaults) { + // Exit if SOA already exists. + for _, rec := range dc.Records { + if rec.Type == "SOA" { + return + } } - soaMail := firstNonNull(desired.SoaMbox, existing.SoaMbox, defSoa.Mbox, "DEFAULT_NOT_SET.") + soaMail := firstNonNull(defaultSoaValues.Mbox, "default_not_set.") if strings.Contains(soaMail, "@") { soaMail = soautil.RFC5322MailToBind(soaMail) } - soaRec.TTL = firstNonZero(desired.TTL, defSoa.TTL, existing.TTL, models.DefaultTTL) - err := soaRec.SetTargetSOA( - firstNonNull(desired.GetTargetField(), existing.GetTargetField(), defSoa.Ns, "DEFAULT_NOT_SET."), + soaRec, err := dc.NewRecordConfig( + "@", + firstNonZero(defaultSoaValues.TTL, models.DefaultTTL), + dnsv2.TypeSOA, + firstNonNull(defaultSoaValues.Ns, "default_not_set."), soaMail, - firstNonZero(desired.SoaSerial, existing.SoaSerial, defSoa.Serial, 1), - firstNonZero(desired.SoaRefresh, existing.SoaRefresh, defSoa.Refresh, 3600), - firstNonZero(desired.SoaRetry, existing.SoaRetry, defSoa.Retry, 600), - firstNonZero(desired.SoaExpire, existing.SoaExpire, defSoa.Expire, 604800), - firstNonZero(desired.SoaMinttl, existing.SoaMinttl, defSoa.Minttl, 1440), + firstNonZero(defaultSoaValues.Serial, 1), + firstNonZero(defaultSoaValues.Refresh, 3600), + firstNonZero(defaultSoaValues.Retry, 600), + firstNonZero(defaultSoaValues.Expire, 604800), + firstNonZero(defaultSoaValues.Minttl, 1440), ) if err != nil { panic(err) // Should never happen. } - return &soaRec, generateSerial(soaRec.SoaSerial) + dc.AddRecordConfig(soaRec) } func firstNonNull(items ...string) string { diff --git a/providers/bind/soa_test.go b/providers/bind/soa_test.go deleted file mode 100644 index 120d597f08..0000000000 --- a/providers/bind/soa_test.go +++ /dev/null @@ -1,151 +0,0 @@ -package bind - -import ( - "fmt" - "testing" - "time" - - "github.com/DNSControl/dnscontrol/v4/models" -) - -func mkRC(target string, rec *models.RecordConfig) *models.RecordConfig { - rec.MustSetTarget(target) - return rec -} - -func Test_makeSoa(t *testing.T) { - origin := "example.com" - tests := []struct { - def *SoaDefaults - existing *models.RecordConfig - desired *models.RecordConfig - expectedSoa *models.RecordConfig - expectedSerial uint32 - }{ - { - // If everything is blank, the hard-coded defaults should kick in. - &SoaDefaults{"", "", 0, 0, 0, 0, 0, models.DefaultTTL}, - mkRC("", &models.RecordConfig{SoaMbox: "", SoaSerial: 0, SoaRefresh: 0, SoaRetry: 0, SoaExpire: 0, SoaMinttl: 0}), - mkRC("", &models.RecordConfig{SoaMbox: "", SoaSerial: 0, SoaRefresh: 0, SoaRetry: 0, SoaExpire: 0, SoaMinttl: 0}), - mkRC("DEFAULT_NOT_SET.", &models.RecordConfig{SoaMbox: "DEFAULT_NOT_SET.", SoaSerial: 1, SoaRefresh: 3600, SoaRetry: 600, SoaExpire: 604800, SoaMinttl: 1440}), - 2019022300, - }, - { - // If everything is filled, leave the desired values in place. - &SoaDefaults{"ns.example.com", "root@example.com", 1, 2, 3, 4, 5, models.DefaultTTL}, - mkRC("a", &models.RecordConfig{SoaMbox: "aa", SoaSerial: 10, SoaRefresh: 11, SoaRetry: 12, SoaExpire: 13, SoaMinttl: 14}), - mkRC("b", &models.RecordConfig{SoaMbox: "bb", SoaSerial: 15, SoaRefresh: 16, SoaRetry: 17, SoaExpire: 18, SoaMinttl: 19}), - mkRC("b", &models.RecordConfig{SoaMbox: "bb", SoaSerial: 15, SoaRefresh: 16, SoaRetry: 17, SoaExpire: 18, SoaMinttl: 19}), - 2019022300, - }, - { - // Test incrementing serial. - &SoaDefaults{"ns.example.com", "root@example.com", 1, 2, 3, 4, 5, models.DefaultTTL}, - mkRC("a", &models.RecordConfig{SoaMbox: "aa", SoaSerial: 2019022301, SoaRefresh: 11, SoaRetry: 12, SoaExpire: 13, SoaMinttl: 14}), - mkRC("b", &models.RecordConfig{SoaMbox: "bb", SoaSerial: 0, SoaRefresh: 16, SoaRetry: 17, SoaExpire: 18, SoaMinttl: 19}), - mkRC("b", &models.RecordConfig{SoaMbox: "bb", SoaSerial: 2019022301, SoaRefresh: 16, SoaRetry: 17, SoaExpire: 18, SoaMinttl: 19}), - 2019022302, - }, - { - // Test incrementing serial_2. - &SoaDefaults{"ns.example.com", "root@example.com", 1, 2, 3, 4, 5, models.DefaultTTL}, - mkRC("a", &models.RecordConfig{SoaMbox: "aa", SoaSerial: 0, SoaRefresh: 11, SoaRetry: 12, SoaExpire: 13, SoaMinttl: 14}), - mkRC("b", &models.RecordConfig{SoaMbox: "bb", SoaSerial: 2019022304, SoaRefresh: 16, SoaRetry: 17, SoaExpire: 18, SoaMinttl: 19}), - mkRC("b", &models.RecordConfig{SoaMbox: "bb", SoaSerial: 2019022304, SoaRefresh: 16, SoaRetry: 17, SoaExpire: 18, SoaMinttl: 19}), - 2019022305, - }, - { - // If there are gaps in existing or desired, fill in as appropriate. - &SoaDefaults{"ns.example.com", "root@example.com", 1, 2, 3, 4, 5, models.DefaultTTL}, - mkRC("", &models.RecordConfig{SoaMbox: "aa", SoaSerial: 0, SoaRefresh: 11, SoaRetry: 0, SoaExpire: 13, SoaMinttl: 0}), - mkRC("b", &models.RecordConfig{SoaMbox: "", SoaSerial: 15, SoaRefresh: 0, SoaRetry: 17, SoaExpire: 0, SoaMinttl: 19}), - mkRC("b", &models.RecordConfig{SoaMbox: "aa", SoaSerial: 15, SoaRefresh: 11, SoaRetry: 17, SoaExpire: 13, SoaMinttl: 19}), - 2019022300, - }, - { - // Gaps + existing==nil - &SoaDefaults{"ns.example.com", "root@example.com", 1, 2, 3, 4, 5, models.DefaultTTL}, - nil, - mkRC("b", &models.RecordConfig{SoaMbox: "", SoaSerial: 15, SoaRefresh: 0, SoaRetry: 17, SoaExpire: 0, SoaMinttl: 19}), - mkRC("b", &models.RecordConfig{SoaMbox: "root.example.com", SoaSerial: 15, SoaRefresh: 2, SoaRetry: 17, SoaExpire: 4, SoaMinttl: 19}), - 2019022300, - }, - { - // Gaps + desired==nil - // NB(tom): In the code as of 2020-02-23, desired will never be nil. - &SoaDefaults{"ns.example.com", "root@example.com", 1, 2, 3, 4, 5, models.DefaultTTL}, - mkRC("", &models.RecordConfig{SoaMbox: "aa", SoaSerial: 0, SoaRefresh: 11, SoaRetry: 0, SoaExpire: 13, SoaMinttl: 0}), - nil, - mkRC("ns.example.com", &models.RecordConfig{SoaMbox: "aa", SoaSerial: 1, SoaRefresh: 11, SoaRetry: 3, SoaExpire: 13, SoaMinttl: 5}), - 2019022300, - }, - } - - // Fake out the tests so they think today is 2019-02-23 - nowFunc = func() time.Time { - fakeToday, _ := time.Parse("20060102", "20190223") - return fakeToday - } - - for i, tst := range tests { - if tst.existing != nil { - tst.existing.SetLabel("@", origin) - tst.existing.Type = "SOA" - } - if tst.desired != nil { - tst.desired.SetLabel("@", origin) - tst.desired.Type = "SOA" - } - - tst.expectedSoa.SetLabel("@", origin) - tst.expectedSoa.Type = "SOA" - - r1, r2 := makeSoa(origin, tst.def, tst.existing, tst.desired) - if !areEqualSoa(r1, tst.expectedSoa) { - t.Fatalf("Test %d soa:\nExpected (%v)\n got (%v)\n", i, tst.expectedSoa.String(), r1.String()) - } - if r2 != tst.expectedSerial { - t.Fatalf("Test:%d soa: Expected (%v) got (%v)\n", i, tst.expectedSerial, r2) - } - } -} - -func areEqualSoa(r1, r2 *models.RecordConfig) bool { - if r1.NameFQDN != r2.NameFQDN { - fmt.Printf("ERROR: fqdn %q != %q\n", r1.NameFQDN, r2.NameFQDN) - return false - } - if r1.Name != r2.Name { - fmt.Printf("ERROR: name %q != %q\n", r1.Name, r2.Name) - return false - } - if r1.GetTargetField() != r2.GetTargetField() { - fmt.Printf("ERROR: target %q != %q\n", r1, r2.GetTargetField()) - return false - } - if r1.SoaMbox != r2.SoaMbox { - fmt.Printf("ERROR: mbox %v != %v\n", r1.SoaMbox, r2.SoaMbox) - return false - } - if r1.SoaSerial != r2.SoaSerial { - fmt.Printf("ERROR: serial %v != %v\n", r1.SoaSerial, r2.SoaSerial) - return false - } - if r1.SoaRefresh != r2.SoaRefresh { - fmt.Printf("ERROR: refresh %v != %v\n", r1.SoaRefresh, r2.SoaRefresh) - return false - } - if r1.SoaRetry != r2.SoaRetry { - fmt.Printf("ERROR: retry %v != %v\n", r1.SoaRetry, r2.SoaRetry) - return false - } - if r1.SoaExpire != r2.SoaExpire { - fmt.Printf("ERROR: expire %v != %v\n", r1.SoaExpire, r2.SoaExpire) - return false - } - if r1.SoaMinttl != r2.SoaMinttl { - fmt.Printf("ERROR: minttl %v != %v\n", r1.SoaMinttl, r2.SoaMinttl) - return false - } - return true -} diff --git a/providers/bind/test_data/meta.json b/providers/bind/test_data/meta.json new file mode 100644 index 0000000000..9b8f5b9f02 --- /dev/null +++ b/providers/bind/test_data/meta.json @@ -0,0 +1,8 @@ +{ + "version": 1, + "recordings": [ + { + "domain": "example.com" + } + ] +} diff --git a/providers/bunnydns/api.go b/providers/bunnydns/api.go index cf44007a00..3db3a58d4a 100644 --- a/providers/bunnydns/api.go +++ b/providers/bunnydns/api.go @@ -10,8 +10,7 @@ import ( "slices" - "github.com/DNSControl/dnscontrol/v4/models" - "github.com/DNSControl/dnscontrol/v4/pkg/printer" + "github.com/DNSControl/dnscontrol/v5/pkg/printer" ) const ( @@ -27,10 +26,6 @@ type zone struct { HasDNSSEC bool `json:"DnsSecEnabled"` } -func (zone *zone) Nameservers() []string { - return []string{zone.Nameserver1, zone.Nameserver2} -} - type record struct { ID int64 `json:"Id,omitempty"` Type recordType `json:"Type"` @@ -60,27 +55,6 @@ type getZoneResponse struct { type queryParams map[string]string -func (b *bunnydnsProvider) getImplicitRecordConfigs(zone *zone) (models.Records, error) { - nameservers := zone.Nameservers() - records := make(models.Records, 0, len(nameservers)) - - // NS records on the zone apex must be implicitly added, as Bunny DNS does not expose them via API - for _, ns := range nameservers { - rc := &models.RecordConfig{ - Type: "NS", - Original: &record{}, - } - rc.SetLabelFromFQDN(zone.Domain, zone.Domain) - if err := rc.SetTarget(ns + "."); err != nil { - return nil, err - } - - records = append(records, rc) - } - - return records, nil -} - func (b *bunnydnsProvider) findZoneByDomain(domain string) (*zone, error) { if b.zones == nil { zones, err := b.getAllZones() diff --git a/providers/bunnydns/auditrecords.go b/providers/bunnydns/auditrecords.go index 8e8967e9d0..1a59905ae1 100644 --- a/providers/bunnydns/auditrecords.go +++ b/providers/bunnydns/auditrecords.go @@ -1,16 +1,16 @@ package bunnydns import ( - "github.com/DNSControl/dnscontrol/v4/models" - "github.com/DNSControl/dnscontrol/v4/pkg/rejectif" + "github.com/DNSControl/dnscontrol/v5/models" + "github.com/DNSControl/dnscontrol/v5/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 { +func AuditRecords(records models.Records) []error { a := rejectif.Auditor{} - a.Add("TXT", rejectif.TxtIsEmpty) // Last verified 2024-01-02 + a.Add("TXT", rejectif.TxtIsEmpty) // Last verified 2026-07-24 return a.Audit(records) } diff --git a/providers/bunnydns/bunnydnsProvider.go b/providers/bunnydns/bunnydnsProvider.go index 0d3239df9e..943ef8d351 100644 --- a/providers/bunnydns/bunnydnsProvider.go +++ b/providers/bunnydns/bunnydnsProvider.go @@ -4,8 +4,8 @@ import ( "encoding/json" "errors" - "github.com/DNSControl/dnscontrol/v4/models" - "github.com/DNSControl/dnscontrol/v4/pkg/providers" + "github.com/DNSControl/dnscontrol/v5/models" + "github.com/DNSControl/dnscontrol/v5/pkg/providers" ) var features = providers.DocumentationNotes{ @@ -79,11 +79,8 @@ func newBunnydns(settings map[string]string, _ json.RawMessage) (providers.DNSSe }, nil } +// GetNameservers returns empty array, since BunnyDNS does not permit apex NS records. +// This prevents DNSControl from trying to create default NS records for the domain. func (b *bunnydnsProvider) GetNameservers(domain string) ([]*models.Nameserver, error) { - zone, err := b.findZoneByDomain(domain) - if err != nil { - return nil, err - } - - return models.ToNameservers(zone.Nameservers()) + return []*models.Nameserver{}, nil } diff --git a/providers/bunnydns/convert.go b/providers/bunnydns/convert.go index f5c9485426..78a4e39b9c 100644 --- a/providers/bunnydns/convert.go +++ b/providers/bunnydns/convert.go @@ -1,14 +1,17 @@ package bunnydns import ( + "errors" "fmt" - "strconv" "strings" "slices" - "github.com/DNSControl/dnscontrol/v4/models" - dnsutilv1 "github.com/miekg/dns/dnsutil" + dnsv2 "codeberg.org/miekg/dns" + dnsrdatav2 "codeberg.org/miekg/dns/rdata" + "github.com/DNSControl/dnscontrol/v5/models" + "github.com/DNSControl/dnscontrol/v5/pkg/privatetypes" + privatetypesrdata "github.com/DNSControl/dnscontrol/v5/pkg/privatetypes/rdata" ) var fqdnTypes = []recordType{recordTypeCNAME, recordTypeHTTPS, recordTypeMX, recordTypeNS, recordTypePTR, recordTypeSRV, recordTypeSVCB} @@ -16,39 +19,46 @@ var nullTypes = []recordType{recordTypeHTTPS, recordTypeMX, recordTypeSVCB} func fromRecordConfig(rc *models.RecordConfig) (*record, error) { r := record{ - Type: recordTypeFromString(rc.Type), - Name: rc.GetLabel(), - Value: rc.GetTargetField(), - TTL: rc.TTL, + Type: recordTypeFromString(rc.Type), + Name: rc.GetLabel(), + TTL: rc.TTL, } switch r.Type { - case recordTypeNS: - if r.Name == "" { - r.TTL = 0 - } case recordTypeSRV: - r.Priority = rc.SrvPriority - r.Weight = rc.SrvWeight - r.Port = rc.SrvPort + rd := rc.GetRDATA().(dnsrdatav2.SRV) + r.Priority = rd.Priority + r.Weight = rd.Weight + r.Port = rd.Port + r.Value = rd.Target case recordTypeCAA: - r.Flags = rc.CaaFlag - r.Tag = rc.CaaTag + rd := rc.GetRDATA().(dnsrdatav2.CAA) + r.Flags = rd.Flag + r.Tag = rd.Tag + r.Value = rd.Value case recordTypeMX: - r.Priority = rc.MxPreference + rd := rc.GetRDATA().(dnsrdatav2.MX) + r.Priority = rd.Preference + r.Value = rd.Mx case recordTypeSVCB, recordTypeHTTPS: - r.Priority = rc.SvcPriority - case recordTypeTLSA: - r.Value = fmt.Sprintf("%d %d %d %s", rc.TlsaUsage, rc.TlsaSelector, rc.TlsaMatchingType, rc.GetTargetField()) + rd := rc.GetRDATA().(dnsrdatav2.SVCB) + r.Priority = rd.Priority + r.Value = rd.Target + // case recordTypeTLSA: + // r.Value = rc.GetRDATA().String() case recordTypePullZone: // When creating Pull Zone records, the API expects an integer PullZoneId field, // while the Value field should be empty. - pullZoneID, err := strconv.ParseInt(rc.GetTargetField(), 10, 64) - if err != nil { - return nil, fmt.Errorf("invalid Pull Zone ID for BUNNY_DNS_PZ: %w", err) + rdata, ok := rc.GetRDATA().(privatetypesrdata.BUNNYDNSPZ) + if !ok { + return nil, errors.New("invalid RDATA for BUNNY_DNS_PZ") } - r.PullZoneID = pullZoneID + r.PullZoneID = rdata.PullZoneID r.Value = "" + case recordTypeRedirect: + r.Value = rc.AsBUNNYDNSRDR().Target + default: + r.Value = rc.GetRDATA().String() } // While Bunny DNS does not use trailing dots, it still accepts and even preserves them for certain record types. @@ -59,10 +69,16 @@ func fromRecordConfig(rc *models.RecordConfig) (*record, error) { } switch r.Type { - case recordTypeSVCB, recordTypeHTTPS: + case recordTypeSVCB: + // In the case of SVCB/HTTPS records, the Target is part of the Value. + // After removing trailing dots for said target, we can add the params to the value. + f := rc.AsSVCB() + r.Value = fmt.Sprintf("%s %s", r.Value, models.Svcbv2ValueToString(f.Value)) + case recordTypeHTTPS: // In the case of SVCB/HTTPS records, the Target is part of the Value. // After removing trailing dots for said target, we can add the params to the value. - r.Value = fmt.Sprintf("%s %s", r.Value, rc.SvcParams) + f := rc.AsHTTPS() + r.Value = fmt.Sprintf("%s %s", r.Value, models.Svcbv2ValueToString(f.Value)) case recordTypeSRV: // SRV empty target is represented as "." if r.Value == "" { @@ -73,13 +89,9 @@ func fromRecordConfig(rc *models.RecordConfig) (*record, error) { return &r, nil } -func toRecordConfig(domain string, r *record) (*models.RecordConfig, error) { - rc := models.RecordConfig{ - Type: recordTypeToString(r.Type), - TTL: r.TTL, - Original: r, - } - rc.SetLabel(r.Name, domain) +func toRecordConfig(dc *models.DomainConfig, r *record) (*models.RecordConfig, error) { + rtype := recordTypeToString(r.Type) + label := dc.LabelFromShort(r.Name) // Bunny DNS always operates with fully-qualified names and does not use any trailing dots. // If a record already contains a trailing dot, which the provider UI also accepts, the record value is left as-is. @@ -89,38 +101,42 @@ func toRecordConfig(domain string, r *record) (*models.RecordConfig, error) { recordParts := strings.SplitN(recordValue, " ", 2) if slices.Contains(fqdnTypes, r.Type) && !strings.HasSuffix(recordParts[0], ".") { - recordParts[0] = dnsutilv1.AddOrigin(recordParts[0]+".", domain) + recordParts[0] = dc.ToFqdnWithDot(recordParts[0] + ".") recordValue = strings.Join(recordParts, " ") } + var rc *models.RecordConfig var err error - switch rc.Type { + switch rtype { case "BUNNY_DNS_PZ": // When reading Pull Zone records, the API provides the PullZoneId in the LinkName field as string. if r.LinkName == "" { - return nil, fmt.Errorf("missing Pull Zone ID (LinkName) for BUNNY_DNS_PZ") + return nil, errors.New("missing Pull Zone ID (LinkName) for BUNNY_DNS_PZ") } - err = rc.SetTarget(r.LinkName) + rc, err = dc.NewRecordConfig(label, r.TTL, privatetypes.TypeBUNNYDNSPZ, r.LinkName) case "BUNNY_DNS_RDR": - err = rc.SetTarget(r.Value) + rc, err = dc.NewRecordConfig(label, r.TTL, privatetypes.TypeBUNNYDNSRDR, recordValue) case "CAA": - err = rc.SetTargetCAA(r.Flags, r.Tag, recordValue) + rc, err = dc.NewRecordConfig(label, r.TTL, dnsv2.TypeCAA, r.Flags, r.Tag, recordValue) case "MX": - err = rc.SetTargetMX(r.Priority, recordValue) + rc, err = dc.NewRecordConfig(label, r.TTL, dnsv2.TypeMX, r.Priority, recordValue) case "SRV": - err = rc.SetTargetSRV(r.Priority, r.Weight, r.Port, recordValue) + rc, err = dc.NewRecordConfig(label, r.TTL, dnsv2.TypeSRV, r.Priority, r.Weight, r.Port, recordValue) case "SVCB", "HTTPS": - err = rc.SetTargetSVCBString(r.Name, fmt.Sprintf("%d %s", r.Priority, recordValue)) + rc, err = dc.NewRecordConfigParse(label, r.TTL, rtype, fmt.Sprintf("%d %s", r.Priority, recordValue)) case "TLSA": - err = rc.SetTargetTLSAString(recordValue) + rc, err = dc.NewRecordConfigParse(label, r.TTL, dnsv2.TypeTLSA, recordValue) + case "TXT": + rc, err = dc.NewRecordConfigParse(label, r.TTL, dnsv2.TypeTXT, recordValue) default: - err = rc.PopulateFromStringFunc(rc.Type, recordValue, domain, nil) + rc, err = dc.NewRecordConfigParse(label, r.TTL, rtype, recordValue) } if err != nil { return nil, err } - return &rc, nil + rc.Original = r.ID + return rc, nil } type recordType int diff --git a/providers/bunnydns/convert_test.go b/providers/bunnydns/convert_test.go index ffc363cbd3..305aafa496 100644 --- a/providers/bunnydns/convert_test.go +++ b/providers/bunnydns/convert_test.go @@ -3,15 +3,14 @@ package bunnydns import ( "testing" - "github.com/DNSControl/dnscontrol/v4/models" + "github.com/DNSControl/dnscontrol/v5/models" + "github.com/DNSControl/dnscontrol/v5/pkg/privatetypes" + privatetypesrdata "github.com/DNSControl/dnscontrol/v5/pkg/privatetypes/rdata" ) func TestFromRecordConfigPullZone(t *testing.T) { - rc := &models.RecordConfig{ - Type: "BUNNY_DNS_PZ", - } - rc.SetLabelFromFQDN("cdn.example.com", "example.com") - rc.MustSetTarget("12345") + dc := models.MustNewDomainConfig("example.com") + rc := dc.MustNewRecordConfig("cdn", 0, privatetypes.TypeBUNNYDNSPZ, int64(12345)) rec, err := fromRecordConfig(rc) if err != nil { @@ -22,16 +21,34 @@ func TestFromRecordConfigPullZone(t *testing.T) { } } -func TestFromRecordConfigPullZoneInvalidTarget(t *testing.T) { - rc := &models.RecordConfig{ - Type: "BUNNY_DNS_PZ", +func TestFromRecordConfigRedirect(t *testing.T) { + dc := models.MustNewDomainConfig("example.com") + rc := dc.MustNewRecordConfig("go", 0, privatetypes.TypeBUNNYDNSRDR, "https://example.com") + + rec, err := fromRecordConfig(rc) + if err != nil { + t.Fatalf("fromRecordConfig returned error: %v", err) + } + if rec.Value != "https://example.com" { + t.Fatalf("expected redirect value; got=%q", rec.Value) + } +} + +func TestToRecordConfigRedirect(t *testing.T) { + rec := &record{ + Type: recordTypeRedirect, + Name: "go", + TTL: 300, + Value: "https://example.com", } - rc.SetLabelFromFQDN("cdn.example.com", "example.com") - rc.MustSetTarget("abc") - _, err := fromRecordConfig(rc) - if err == nil { - t.Fatalf("expected error for invalid Pull Zone ID") + dc := models.MustNewDomainConfig("example.com") + rc, err := toRecordConfig(dc, rec) + if err != nil { + t.Fatalf("toRecordConfig returned error: %v", err) + } + if got := rc.AsBUNNYDNSRDR().Target; got != "https://example.com" { + t.Fatalf("redirect target = %q, want https://example.com", got) } } @@ -43,15 +60,17 @@ func TestToRecordConfigPullZoneLinkName(t *testing.T) { LinkName: "12345", } - rc, err := toRecordConfig("example.com", rec) + dc := models.MustNewDomainConfig("example.com") + rc, err := toRecordConfig(dc, rec) if err != nil { t.Fatalf("toRecordConfig returned error: %v", err) } if rc.Type != "BUNNY_DNS_PZ" { t.Fatalf("expected type BUNNY_DNS_PZ; got=%s", rc.Type) } - if rc.GetTargetField() != "12345" { - t.Fatalf("expected target 12345; got=%s", rc.GetTargetField()) + rdata := rc.GetRDATA().(privatetypesrdata.BUNNYDNSPZ) + if rdata.PullZoneID != 12345 { + t.Fatalf("expected PullZoneId=12345; got=%d", rdata.PullZoneID) } if rc.GetLabel() != "cdn" { t.Fatalf("expected label cdn; got=%s", rc.GetLabel()) @@ -65,7 +84,8 @@ func TestToRecordConfigPullZoneMissingID(t *testing.T) { TTL: 300, } - _, err := toRecordConfig("example.com", rec) + dc := models.MustNewDomainConfig("example.com") + _, err := toRecordConfig(dc, rec) if err == nil { t.Fatalf("expected error for missing Pull Zone LinkName") } diff --git a/providers/bunnydns/dnssec.go b/providers/bunnydns/dnssec.go index d67ef641d9..3ddc7271b2 100644 --- a/providers/bunnydns/dnssec.go +++ b/providers/bunnydns/dnssec.go @@ -1,6 +1,6 @@ package bunnydns -import "github.com/DNSControl/dnscontrol/v4/models" +import "github.com/DNSControl/dnscontrol/v5/models" func (b *bunnydnsProvider) getDNSSECCorrections(dc *models.DomainConfig, zone *zone) ([]*models.Correction, error) { if zone.HasDNSSEC && dc.AutoDNSSEC == "off" { diff --git a/providers/bunnydns/listzones.go b/providers/bunnydns/listzones.go index dc7726b42e..a94f86068b 100644 --- a/providers/bunnydns/listzones.go +++ b/providers/bunnydns/listzones.go @@ -1,8 +1,8 @@ package bunnydns import ( - "github.com/DNSControl/dnscontrol/v4/models" - "github.com/DNSControl/dnscontrol/v4/pkg/printer" + "github.com/DNSControl/dnscontrol/v5/models" + "github.com/DNSControl/dnscontrol/v5/pkg/printer" ) func (b *bunnydnsProvider) ListZones() ([]string, error) { diff --git a/providers/bunnydns/records.go b/providers/bunnydns/records.go index 680312cd74..6bbe612363 100644 --- a/providers/bunnydns/records.go +++ b/providers/bunnydns/records.go @@ -1,13 +1,12 @@ package bunnydns import ( - "errors" "fmt" "slices" - "github.com/DNSControl/dnscontrol/v4/models" - "github.com/DNSControl/dnscontrol/v4/pkg/diff2" - "github.com/DNSControl/dnscontrol/v4/pkg/printer" + "github.com/DNSControl/dnscontrol/v5/models" + "github.com/DNSControl/dnscontrol/v5/pkg/diff2" + "github.com/DNSControl/dnscontrol/v5/pkg/printer" ) func (b *bunnydnsProvider) GetZoneRecords(dc *models.DomainConfig) (models.Records, error) { @@ -23,13 +22,7 @@ func (b *bunnydnsProvider) GetZoneRecords(dc *models.DomainConfig) (models.Recor return nil, err } - implicitRecs, err := b.getImplicitRecordConfigs(zone) - if err != nil { - return nil, err - } - - recs := make(models.Records, 0, len(nativeRecs)+len(implicitRecs)) - recs = append(recs, implicitRecs...) + recs := make(models.Records, 0, len(nativeRecs)) // Define a list of record types that are currently not supported by this provider. unsupportedTypes := []recordType{ @@ -45,7 +38,7 @@ func (b *bunnydnsProvider) GetZoneRecords(dc *models.DomainConfig) (models.Recor continue } - rc, err := toRecordConfig(zone.Domain, nativeRec) + rc, err := toRecordConfig(dc, nativeRec) if err != nil { return nil, err } @@ -56,7 +49,6 @@ func (b *bunnydnsProvider) GetZoneRecords(dc *models.DomainConfig) (models.Recor } func (b *bunnydnsProvider) GetZoneRecordsCorrections(dc *models.DomainConfig, existing models.Records) ([]*models.Correction, int, error) { - // Bunny DNS never returns NS records for the apex domain, so these are artificially added when retrieving records. // As no TTL can be configured or retrieved for these NS records, we set it to 0 to avoid unnecessary updates. for _, rc := range dc.Records { if rc.Name == "@" && rc.Type == "NS" { @@ -68,7 +60,7 @@ func (b *bunnydnsProvider) GetZoneRecordsCorrections(dc *models.DomainConfig, ex } if rc.Type == "ALIAS" { - rc.ChangeType("CNAME", dc.Name) + rc.ChangeTypeToCNAME(dc, rc.AsALIAS().Target) } } @@ -133,11 +125,7 @@ func (b *bunnydnsProvider) mkChangeCorrection(zoneID int64, oldRec, newRec *mode return &models.Correction{ Msg: msg, F: func() error { - existingID := oldRec.Original.(*record).ID - if existingID == 0 { - return errors.New("BUNNY_DNS: cannot change implicit records") - } - + existingID := oldRec.Original.(int64) desired, err := fromRecordConfig(newRec) if err != nil { return err @@ -152,11 +140,7 @@ func (b *bunnydnsProvider) mkDeleteCorrection(zoneID int64, oldRec *models.Recor return &models.Correction{ Msg: msg, F: func() error { - existingID := oldRec.Original.(*record).ID - if existingID == 0 { - return errors.New("BUNNY_DNS: cannot delete implicit records") - } - + existingID := oldRec.Original.(int64) return b.deleteRecord(zoneID, existingID) }, } diff --git a/providers/cloudflare/auditrecords.go b/providers/cloudflare/auditrecords.go index 66ae65502b..95a1a5cb79 100644 --- a/providers/cloudflare/auditrecords.go +++ b/providers/cloudflare/auditrecords.go @@ -1,14 +1,14 @@ package cloudflare import ( - "github.com/DNSControl/dnscontrol/v4/models" - "github.com/DNSControl/dnscontrol/v4/pkg/rejectif" + "github.com/DNSControl/dnscontrol/v5/models" + "github.com/DNSControl/dnscontrol/v5/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 { +func AuditRecords(records models.Records) []error { a := rejectif.Auditor{} a.Add("TXT", rejectif.TxtIsEmpty) // Last verified 2026-01-21 diff --git a/providers/cloudflare/cloudflareProvider.go b/providers/cloudflare/cloudflareProvider.go index 8d609bf916..d772b955b7 100644 --- a/providers/cloudflare/cloudflareProvider.go +++ b/providers/cloudflare/cloudflareProvider.go @@ -5,23 +5,24 @@ import ( "encoding/json" "errors" "fmt" - "net/netip" "os" + "slices" "strconv" "strings" + dnsv2 "codeberg.org/miekg/dns" + "github.com/DNSControl/dnscontrol/v5/models" + "github.com/DNSControl/dnscontrol/v5/pkg/diff2" + "github.com/DNSControl/dnscontrol/v5/pkg/nrc" + "github.com/DNSControl/dnscontrol/v5/pkg/printer" + privatetypes "github.com/DNSControl/dnscontrol/v5/pkg/privatetypes" + privatetypesrdata "github.com/DNSControl/dnscontrol/v5/pkg/privatetypes/rdata" + "github.com/DNSControl/dnscontrol/v5/pkg/providers" + "github.com/DNSControl/dnscontrol/v5/pkg/transform" + "github.com/DNSControl/dnscontrol/v5/pkg/zonecache" "github.com/cloudflare/cloudflare-go" "github.com/fatih/color" "golang.org/x/net/idna" - - "github.com/DNSControl/dnscontrol/v4/models" - "github.com/DNSControl/dnscontrol/v4/pkg/diff2" - "github.com/DNSControl/dnscontrol/v4/pkg/printer" - "github.com/DNSControl/dnscontrol/v4/pkg/providers" - "github.com/DNSControl/dnscontrol/v4/pkg/transform" - "github.com/DNSControl/dnscontrol/v4/pkg/txtutil" - "github.com/DNSControl/dnscontrol/v4/pkg/zonecache" - "github.com/DNSControl/dnscontrol/v4/providers/cloudflare/rtypes/cfsingleredirect" ) /* @@ -125,6 +126,7 @@ func init() { // cloudflareProvider is the handle for API calls. type cloudflareProvider struct { + observer providers.ConversionObserver ipConversions []transform.IPConversion ignoredLabels []string manageWorkers bool @@ -141,6 +143,10 @@ type cloudflareProvider struct { zoneCache zonecache.ZoneCache[cloudflare.Zone] } +func (c *cloudflareProvider) SetConversionObserver(observer providers.ConversionObserver) { + c.observer = observer +} + // GetNameservers returns the nameservers for a domain. func (c *cloudflareProvider) GetNameservers(domain string) ([]*models.Nameserver, error) { z, err := c.zoneCache.GetZone(domain) @@ -157,9 +163,7 @@ func (c *cloudflareProvider) ListZones() ([]string, error) { // GetZoneRecords gets the records of a zone and returns them in RecordConfig format. func (c *cloudflareProvider) GetZoneRecords(dc *models.DomainConfig) (models.Records, error) { - domain := dc.Name - - domainID, err := c.getDomainID(domain) + domainID, err := c.getDomainID(dc.Name) if err != nil { return nil, err } @@ -176,14 +180,14 @@ func (c *cloudflareProvider) GetZoneRecords(dc *models.DomainConfig) (models.Rec // Fetch DNS records concurrently go func() { - recs, err := c.getRecordsForDomain(domainID, domain) + recs, err := c.getRecordsForDomain(domainID, dc) mainCh <- result{records: recs, err: err} }() // Fetch Single Redirects concurrently if enabled if c.manageSingleRedirects { go func() { - prs, err := c.getSingleRedirects(domainID, domain) + prs, err := c.getSingleRedirects(dc, domainID) redirectCh <- result{records: prs, err: err} }() } else { @@ -193,7 +197,7 @@ func (c *cloudflareProvider) GetZoneRecords(dc *models.DomainConfig) (models.Rec // Fetch Worker Routes concurrently if enabled if c.manageWorkers { go func() { - wrs, err := c.getWorkerRoutes(domainID, domain) + wrs, err := c.getWorkerRoutes(domainID, dc) workerCh <- result{records: wrs, err: err} }() } else { @@ -234,9 +238,6 @@ func (c *cloudflareProvider) GetZoneRecords(dc *models.DomainConfig) (models.Rec records = append(records, redirectRes.records...) records = append(records, workerRes.records...) - // Normalize - models.PostProcessRecords(records) - return records, nil } @@ -250,11 +251,6 @@ func (c *cloudflareProvider) getDomainID(name string) (string, error) { // GetZoneRecordsCorrections returns a list of corrections that will turn existing records into dc.Records. func (c *cloudflareProvider) GetZoneRecordsCorrections(dc *models.DomainConfig, records models.Records) ([]*models.Correction, int, error) { - for _, rec := range dc.Records { - if rec.Type == "ALIAS" { - rec.ChangeType("CNAME", dc.Name) - } - } if err := c.preprocessConfig(dc); err != nil { return nil, 0, err @@ -382,17 +378,20 @@ func genComparableWithMgmt(rec *models.RecordConfig, manageComments, manageTags } func (c *cloudflareProvider) mkCreateCorrection(newrec *models.RecordConfig, domainID, msg string) []*models.Correction { - switch newrec.Type { - case "WORKER_ROUTE": + switch newrec.TypeNum { + case privatetypes.TypeCFWORKERROUTE: return []*models.Correction{{ Msg: msg, - F: func() error { return c.createWorkerRoute(domainID, newrec.GetTargetField()) }, + F: func() error { + return c.createWorkerRoute(domainID, newrec.GetRDATA()) + }, }} - case "CLOUDFLAREAPI_SINGLE_REDIRECT": + case privatetypes.TypeCLOUDFLAREAPISINGLEREDIRECT: return []*models.Correction{{ Msg: msg, F: func() error { - return c.createSingleRedirect(domainID, *newrec.F.(*cfsingleredirect.SingleRedirectConfig)) + //return c.createSingleRedirect(domainID, *newrec.F.(*cfsingleredirect.SingleRedirectConfig)) + return c.createSingleRedirect(domainID, newrec.AsCLOUDFLAREAPISINGLEREDIRECT()) }, }} default: @@ -402,29 +401,29 @@ func (c *cloudflareProvider) mkCreateCorrection(newrec *models.RecordConfig, dom func (c *cloudflareProvider) mkChangeCorrection(oldrec, newrec *models.RecordConfig, domainID string, msg string) []*models.Correction { var idTxt string - switch oldrec.Type { - case "WORKER_ROUTE": + switch oldrec.TypeNum { + case privatetypes.TypeCFWORKERROUTE: idTxt = oldrec.Original.(cloudflare.WorkerRoute).ID - case "CLOUDFLAREAPI_SINGLE_REDIRECT": - idTxt = oldrec.F.(*cfsingleredirect.SingleRedirectConfig).SRRRulesetID + case privatetypes.TypeCLOUDFLAREAPISINGLEREDIRECT: + idTxt = oldrec.AsCLOUDFLAREAPISINGLEREDIRECT().RT_SRRRulesetID default: idTxt = oldrec.Original.(cloudflare.DNSRecord).ID } msg = msg + color.YellowString(" id=%v", idTxt) - switch newrec.Type { - case "CLOUDFLAREAPI_SINGLE_REDIRECT": + switch newrec.TypeNum { + case privatetypes.TypeCLOUDFLAREAPISINGLEREDIRECT: return []*models.Correction{{ Msg: msg, F: func() error { return c.updateSingleRedirect(domainID, oldrec, newrec) }, }} - case "WORKER_ROUTE": + case privatetypes.TypeCFWORKERROUTE: return []*models.Correction{{ Msg: msg, F: func() error { - return c.updateWorkerRoute(idTxt, domainID, newrec.GetTargetField()) + return c.updateWorkerRoute(idTxt, domainID, newrec.GetRDATA()) }, }} default: @@ -443,7 +442,7 @@ func (c *cloudflareProvider) mkDeleteCorrection(recType string, origRec *models. switch recType { case "PAGE_RULE": idTxt = origRec.Original.(cloudflare.PageRule).ID - case "WORKER_ROUTE": + case "CF_WORKER_ROUTE": idTxt = origRec.Original.(cloudflare.WorkerRoute).ID case "CLOUDFLAREAPI_SINGLE_REDIRECT": idTxt = origRec.Original.(cloudflare.RulesetRule).ID @@ -458,10 +457,10 @@ func (c *cloudflareProvider) mkDeleteCorrection(recType string, origRec *models. switch recType { // case "PAGE_RULE": // return c.deletePageRule(origRec.Original.(cloudflare.PageRule).ID, domainID) - case "WORKER_ROUTE": + case "CF_WORKER_ROUTE": return c.deleteWorkerRoute(origRec.Original.(cloudflare.WorkerRoute).ID, domainID) case "CLOUDFLAREAPI_SINGLE_REDIRECT": - return c.deleteSingleRedirects(domainID, *origRec.F.(*cfsingleredirect.SingleRedirectConfig)) + return c.deleteSingleRedirects(domainID, origRec.AsCLOUDFLAREAPISINGLEREDIRECT()) default: return c.deleteDNSRecord(origRec.Original.(cloudflare.DNSRecord), domainID) } @@ -471,7 +470,7 @@ func (c *cloudflareProvider) mkDeleteCorrection(recType string, origRec *models. } func checkNSModifications(dc *models.DomainConfig) { - newList := make([]*models.RecordConfig, 0, len(dc.Records)) + newList := make(models.Records, 0, len(dc.Records)) punyRoot, err := idna.ToASCII(dc.Name) if err != nil { @@ -480,7 +479,7 @@ func checkNSModifications(dc *models.DomainConfig) { for _, rec := range dc.Records { if rec.Type == "NS" && rec.GetLabelFQDN() == punyRoot { - if strings.HasSuffix(rec.GetTargetField(), ".ns.cloudflare.com.") { + if strings.HasSuffix(rec.AsNS().Ns, ".ns.cloudflare.com.") { continue } } @@ -542,9 +541,10 @@ func checkCNAMEFlattenVal(v string) (string, error) { func (c *cloudflareProvider) preprocessConfig(dc *models.DomainConfig) error { + // Cloudflare's CNAMEs works like our virtual ALIAS type: for _, rec := range dc.Records { if rec.Type == "ALIAS" { - rec.ChangeType("CNAME", dc.Name) + rec.ChangeTypeToCNAME(dc, rec.AsALIAS().Target) } } @@ -572,8 +572,8 @@ func (c *cloudflareProvider) preprocessConfig(dc *models.DomainConfig) error { // A and CNAMEs: Validate. If null, set to default. // else: Make sure it wasn't set. Set to default. // iterate backwards so first defined page rules have highest priority - for i := len(dc.Records) - 1; i >= 0; i-- { - rec := dc.Records[i] + for _, rec := range slices.Backward(dc.Records) { + if rec.Metadata == nil { rec.Metadata = map[string]string{} } @@ -657,24 +657,16 @@ func (c *cloudflareProvider) preprocessConfig(dc *models.DomainConfig) error { return fmt.Errorf("CNAME record %#v has both CF_PROXY_ON and CF_CNAME_FLATTEN_ON set, but these are mutually exclusive; Cloudflare ignores CNAME flattening when proxy is enabled", rec.GetLabel()) } - switch rec.Type { - case "CLOUDFLAREAPI_SINGLE_REDIRECT": + switch rec.TypeNum { + case privatetypes.TypeCLOUDFLAREAPISINGLEREDIRECT: // SINGLEREDIRECT record types. Verify they are enabled. if !c.manageSingleRedirects { return errors.New("you must add 'manage_single_redirects: true' metadata to cloudflare provider to use CLOUDFLAREAPI_SINGLE_REDIRECT records") } - case "CF_WORKER_ROUTE": - // CF_WORKER_ROUTE record types. Encode target as $PATTERN,$SCRIPT - parts := strings.Split(rec.GetTargetField(), ",") - if len(parts) != 2 { - return errors.New("invalid data specified for cloudflare worker record") - } - rec.TTL = 1 - rec.Type = "WORKER_ROUTE" } } - // look for ip conversions and transform records + // lookfor ip conversions and transform records for _, rec := range dc.Records { // Only transform A records if rec.Type != "A" { @@ -684,24 +676,25 @@ func (c *cloudflareProvider) preprocessConfig(dc *models.DomainConfig) error { if rec.Metadata[metaProxy] != "full" { continue } - ip, err := netip.ParseAddr(rec.GetTargetField()) - if err != nil { - return fmt.Errorf("%s is not a valid ip address", rec.GetTargetField()) - } + ip := rec.AsA().Addr newIP, err := transform.IP(ip, c.ipConversions) if err != nil { return err } - rec.Metadata[metaOriginalIP] = rec.GetTargetField() - if err := rec.SetTarget(newIP.String()); err != nil { + + rec.Metadata[metaOriginalIP] = rec.GetTargetIP().String() + rd, err := models.MakeA(dc.Name, rec.Metadata, nrc.Flags{}, newIP) + if err != nil { return err } + rec.SetRDATA(rd) + } return nil } -func (c *cloudflareProvider) LogTranscode(zone string, redirect *cfsingleredirect.SingleRedirectConfig) error { +func (c *cloudflareProvider) LogTranscode(zone string, redirect privatetypesrdata.CLOUDFLAREAPISINGLEREDIRECT) error { // No filename? Don't log anything. filename := c.tcLogFilename if filename == "" { @@ -877,7 +870,7 @@ func (c cfTarget) MarshalJSON() ([]byte, error) { return json.Marshal(obj) } -// DNSControlString returns cfTarget normalized to be a FQDN. Null targets are +// FQDN returns cfTarget normalized to be a FQDN. Null targets are // represented by a single period. func (c cfTarget) FQDN() string { return strings.TrimRight(string(c), ".") + "." @@ -914,7 +907,7 @@ func stringDefault(value any, def string) string { return def } -func (c *cloudflareProvider) nativeToRecord(domain string, cr cloudflare.DNSRecord) (*models.RecordConfig, error) { +func (c *cloudflareProvider) nativeToRecord(dc *models.DomainConfig, cr cloudflare.DNSRecord) (*models.RecordConfig, error) { // Check for read_only metadata // https://github.com/DNSControl/dnscontrol/issues/3850 if cr.Meta != nil { @@ -935,21 +928,35 @@ func (c *cloudflareProvider) nativeToRecord(domain string, cr cloudflare.DNSReco cr.Type = "TXT" } - // normalize cname,mx,ns records with dots to be consistent with our config format. - if cr.Type == "ALIAS" || cr.Type == "CNAME" || cr.Type == "MX" || cr.Type == "NS" || cr.Type == "PTR" { - if cr.Content != "." { - cr.Content = cr.Content + "." - } - } + label := dc.LabelFromFQDNNoDot(cr.Name) + ttl := uint32(cr.TTL) - rc := &models.RecordConfig{ - TTL: uint32(cr.TTL), - Original: cr, - Metadata: map[string]string{}, + var rc *models.RecordConfig + var err error + + switch rType := cr.Type; rType { // #rtype_variations + case "MX": + rc, err = dc.NewRecordConfig(label, ttl, dnsv2.TypeMX, *cr.Priority, cr.Content, + nrc.Flags{TargetIsFqdnNoDot: true}) + case "SRV": + data := cr.Data.(map[string]any) + target := stringDefault(data["target"], "MISSING.TARGET") + rc, err = dc.NewRecordConfig(label, ttl, dnsv2.TypeSRV, uint16Zero(data["priority"]), uint16Zero(data["weight"]), uint16Zero(data["port"]), target, + nrc.Flags{TargetIsFqdnNoDot: true}) + case "TXT": + rc, err = dc.NewRecordConfigParse(label, ttl, rType, cr.Content) + default: + rc, err = dc.NewRecordConfigParse(label, ttl, rType, cr.Content, + nrc.Flags{TargetIsFqdnNoDot: true}) + } + if err != nil { + return nil, fmt.Errorf("unparsable %q record received from cloudflare: %w", cr.Type, err) } - rc.SetLabelFromFQDN(cr.Name, domain) - if cr.Type == "A" || cr.Type == "AAAA" || cr.Type == "CNAME" { + // Save a pointer to the original cr so that "push" can refer to it for IDs, etc. + rc.Original = cr + + if rc.TypeNum == dnsv2.TypeA || rc.TypeNum == dnsv2.TypeAAAA || rc.TypeNum == dnsv2.TypeCNAME { if cr.Proxied != nil { if *(cr.Proxied) { rc.Metadata[metaProxy] = "on" @@ -976,87 +983,9 @@ func (c *cloudflareProvider) nativeToRecord(domain string, cr cloudflare.DNSReco rc.Metadata[metaTags] = strings.Join(cr.Tags, ",") } - switch rType := cr.Type; rType { // #rtype_variations - case "MX": - if err := rc.SetTargetMX(*cr.Priority, cr.Content); err != nil { - return nil, fmt.Errorf("unparsable MX record received from cloudflare: %w", err) - } - case "SRV": - data := cr.Data.(map[string]any) - - target := stringDefault(data["target"], "MISSING.TARGET") - if target != "." { - target += "." - } - if err := rc.SetTargetSRV(uint16Zero(data["priority"]), uint16Zero(data["weight"]), uint16Zero(data["port"]), - target); err != nil { - return nil, fmt.Errorf("unparsable SRV record received from cloudflare: %w", err) - } - case "TXT": - s, err := parseCfTxtContent(cr.Content) - if err != nil { - return rc, err - } - err = rc.SetTargetTXT(s) - return rc, err - default: - if err := rc.PopulateFromString(rType, cr.Content, domain); err != nil { - return nil, fmt.Errorf("unparsable record received from cloudflare: %w", err) - } - } - return rc, nil } -func parseCfTxtContent(s string) (string, error) { - // Cloudflare encodes TXT records in a mystery format. They tell you when - // you've done something wrong, but won't document what they do want. - // If you use their web dashboard and enter the string as any normal human - // would, they display a warning that you're a bad person and should feel - // bad for doing that. However, they accept it just fine, and present it in - // their API as a string like any person on this planet would expect. If - // you enter the string with quotes, they accept that like a BIND zonefile. - - // There is a difference between what you enter in their web dashboard, how - // it is rewritten by the UI, and what you get in the JSON. Examples: - - // dashboard: i love dns it is great - // rewritten: "i love dns it is great" - // seen json: "i love dns it is great" - - // dashboard: xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx - // rewritten: "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" - // seen json: "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" - - // dashboard: "i love dns" "it is great" - // rewritten: "i love dns" "it is great" - // seen json: "i love dns" "it is great" - - // dashboard: "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" - // rewritten: "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" - // seen json: "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" - - // dashboard: "xxxx" "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" - // rewritten: "xxxx" "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" - // seen json: "xxxx" "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" - - // From this we conclude: - // If it begins and ends with a quote, use ParseQuoted() to decode it. - // Otherwise, it is a raw string. They could just fucking tell us that in - // the documenation, but where's the fun in that? - - if s == "" { - return "", nil - } - if s == `"` { - return "", errors.New("invalid TXT record content: one double quote") - } - if s[0] == '"' && s[len(s)-1] == '"' { - return txtutil.ParseQuoted(s) - } - return s, nil -} - func getProxyMetadata(r *models.RecordConfig) map[string]string { if r.Type != "A" && r.Type != "AAAA" && r.Type != "CNAME" { return nil @@ -1075,6 +1004,7 @@ func getProxyMetadata(r *models.RecordConfig) map[string]string { // EnsureZoneExists creates a zone if it does not exist. func (c *cloudflareProvider) EnsureZoneExists(dc *models.DomainConfig) error { domain := dc.Name + if ok, err := c.zoneCache.HasZone(domain); err != nil || ok { return err } diff --git a/providers/cloudflare/convert_golden_test.go b/providers/cloudflare/convert_golden_test.go new file mode 100644 index 0000000000..ee17d82739 --- /dev/null +++ b/providers/cloudflare/convert_golden_test.go @@ -0,0 +1,22 @@ +package cloudflare + +import ( + "testing" + + "github.com/DNSControl/dnscontrol/v5/models" + "github.com/DNSControl/dnscontrol/v5/pkg/providergolden" + "github.com/cloudflare/cloudflare-go" +) + +func TestNativeToRecordGolden(t *testing.T) { + c := &cloudflareProvider{} + providergolden.CheckToRC(t, "nativeToRecord", + func(dc *models.DomainConfig, native cloudflare.DNSRecord) (models.Records, error) { + if native.Type == "" { + // TODO(tlim): Figure out why we're getting natives with no type. Something to do with CLOUDFLAREAPI_SINGLE_REDIRECT. + return nil, nil + } + rc, err := c.nativeToRecord(dc, native) + return models.Records{rc}, err + }) +} diff --git a/providers/cloudflare/parsecftxtcontent_test.go b/providers/cloudflare/parsecftxtcontent_test.go index 241f4b09a1..212f781e7a 100644 --- a/providers/cloudflare/parsecftxtcontent_test.go +++ b/providers/cloudflare/parsecftxtcontent_test.go @@ -1,76 +1,72 @@ package cloudflare -import ( - "testing" -) +// func TestParseCfTxtContent(t *testing.T) { +// tests := []struct { +// name string +// input string +// want string +// wantErr bool +// }{ +// { +// name: "empty string", +// input: "", +// want: "", +// wantErr: false, +// }, +// { +// name: "unquoted string", +// input: "simple text", +// want: "simple text", +// wantErr: false, +// }, +// { +// name: "quoted string", +// input: `"quoted text"`, +// want: "quoted text", +// wantErr: false, +// }, +// { +// name: "quoted string with spaces", +// input: `"text with spaces"`, +// want: "text with spaces", +// wantErr: false, +// }, +// { +// name: "only opening quote", +// input: `"incomplete`, +// want: `"incomplete`, +// wantErr: false, +// }, +// { +// name: "only closing quote", +// input: `incomplete"`, +// want: `incomplete"`, +// wantErr: false, +// }, +// { +// name: "single quote char", +// input: `"`, +// want: ``, +// wantErr: true, +// }, +// { +// name: "double quotes only", +// input: `""`, +// want: "", +// wantErr: false, +// }, +// } -func TestParseCfTxtContent(t *testing.T) { - tests := []struct { - name string - input string - want string - wantErr bool - }{ - { - name: "empty string", - input: "", - want: "", - wantErr: false, - }, - { - name: "unquoted string", - input: "simple text", - want: "simple text", - wantErr: false, - }, - { - name: "quoted string", - input: `"quoted text"`, - want: "quoted text", - wantErr: false, - }, - { - name: "quoted string with spaces", - input: `"text with spaces"`, - want: "text with spaces", - wantErr: false, - }, - { - name: "only opening quote", - input: `"incomplete`, - want: `"incomplete`, - wantErr: false, - }, - { - name: "only closing quote", - input: `incomplete"`, - want: `incomplete"`, - wantErr: false, - }, - { - name: "single quote char", - input: `"`, - want: ``, - wantErr: true, - }, - { - name: "double quotes only", - input: `""`, - want: "", - wantErr: false, - }, - } - - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - got, err := parseCfTxtContent(tt.input) - if (err != nil) != tt.wantErr { - t.Errorf("parseCfTxtContent() error = %v, wantErr %v", err, tt.wantErr) - return - } - if got != tt.want { - t.Errorf("parseCfTxtContent() = %q, want %q", got, tt.want) - } - }) - } -} +// for _, tt := range tests { +// t.Run(tt.name, func(t *testing.T) { +// got, err := parseCfTxtContent(tt.input) +// if (err != nil) != tt.wantErr { +// t.Errorf("parseCfTxtContent() error = %v, wantErr %v", err, tt.wantErr) +// return +// } +// if got != tt.want { +// t.Errorf("parseCfTxtContent() = %q, want %q", got, tt.want) +// } +// }) +// } +// } diff --git a/providers/cloudflare/preprocess_test.go b/providers/cloudflare/preprocess_test.go index 3abbedae52..03e7bc4623 100644 --- a/providers/cloudflare/preprocess_test.go +++ b/providers/cloudflare/preprocess_test.go @@ -5,32 +5,22 @@ import ( "strings" "testing" - "github.com/DNSControl/dnscontrol/v4/models" - "github.com/DNSControl/dnscontrol/v4/pkg/transform" + dnsv2 "codeberg.org/miekg/dns" + "github.com/DNSControl/dnscontrol/v5/models" + "github.com/DNSControl/dnscontrol/v5/pkg/transform" ) -func newDomainConfig() *models.DomainConfig { - return &models.DomainConfig{ - Name: "test.com", - Records: []*models.RecordConfig{}, - Metadata: map[string]string{}, - } -} - func makeRCmeta(meta map[string]string) *models.RecordConfig { - rc := models.RecordConfig{ - Type: "A", - Metadata: meta, - } - rc.SetLabel("foo", "example.tld") - rc.MustSetTarget("1.2.3.4") - return &rc + dc := models.MustNewDomainConfig("example.tld") + rc := dc.MustNewRecordConfig(dc.LabelFromShort("foo"), 0, dnsv2.TypeA, "1.2.3.4") + rc.Metadata = meta + return rc } func TestPreprocess_BoolValidation(t *testing.T) { cf := &cloudflareProvider{} - domain := newDomainConfig() + domain := models.MustNewDomainConfig("test.com") domain.Records = append(domain.Records, makeRCmeta(map[string]string{metaProxy: "on"})) domain.Records = append(domain.Records, makeRCmeta(map[string]string{metaProxy: "fUll"})) domain.Records = append(domain.Records, makeRCmeta(map[string]string{})) @@ -51,9 +41,11 @@ func TestPreprocess_BoolValidation(t *testing.T) { func TestPreprocess_BoolValidation_Fails(t *testing.T) { cf := &cloudflareProvider{} - domain := newDomainConfig() - domain.Records = append(domain.Records, &models.RecordConfig{Metadata: map[string]string{metaProxy: "true"}}) - err := cf.preprocessConfig(domain) + dc := models.MustNewDomainConfig("test.com") + rc := dc.MustNewRecordConfig("@", 0, dnsv2.TypeA, "1.2.3.4") + rc.Metadata = map[string]string{metaProxy: "true"} + dc.AddRecordConfig(rc) + err := cf.preprocessConfig(dc) if err == nil { t.Fatal("Expected validation error, but got none") } @@ -61,7 +53,7 @@ func TestPreprocess_BoolValidation_Fails(t *testing.T) { func TestPreprocess_DefaultProxy(t *testing.T) { cf := &cloudflareProvider{} - domain := newDomainConfig() + domain := models.MustNewDomainConfig("test.com") domain.Metadata[metaProxyDefault] = "full" domain.Records = append(domain.Records, makeRCmeta(map[string]string{metaProxy: "on"})) domain.Records = append(domain.Records, makeRCmeta(map[string]string{metaProxy: "off"})) @@ -80,7 +72,7 @@ func TestPreprocess_DefaultProxy(t *testing.T) { func TestPreprocess_DefaultProxy_Validation(t *testing.T) { cf := &cloudflareProvider{} - domain := newDomainConfig() + domain := models.MustNewDomainConfig("test.com") domain.Metadata[metaProxyDefault] = "true" err := cf.preprocessConfig(domain) if err == nil { @@ -90,15 +82,11 @@ func TestPreprocess_DefaultProxy_Validation(t *testing.T) { func TestPreprocess_CNAMEFlattenProxyMutualExclusion(t *testing.T) { cf := &cloudflareProvider{} - domain := newDomainConfig() - rec := &models.RecordConfig{ - Type: "CNAME", - Metadata: map[string]string{metaCNAMEFlatten: "on", metaProxy: "on"}, - } - rec.SetLabel("foo", "test.com") - rec.MustSetTarget("example.com.") - domain.Records = append(domain.Records, rec) - err := cf.preprocessConfig(domain) + dc := models.MustNewDomainConfig("test.com") + rc := dc.MustNewRecordConfig(dc.LabelFromShort("foo"), 0, dnsv2.TypeCNAME, "example.com.") + rc.Metadata = map[string]string{metaCNAMEFlatten: "on", metaProxy: "on"} + dc.AddRecordConfig(rc) + err := cf.preprocessConfig(dc) if err == nil { t.Fatal("Expected validation error for CNAME with both flatten and proxy, but got none") } @@ -110,7 +98,7 @@ func TestPreprocess_CNAMEFlattenProxyMutualExclusion(t *testing.T) { // determines whether to send the comment field to the API. func TestPreprocess_ManageComments_SetsEmptyKey(t *testing.T) { cf := &cloudflareProvider{} - domain := newDomainConfig() + domain := models.MustNewDomainConfig("test.com") domain.Metadata[metaManageComments] = "true" // Record without any comment @@ -140,7 +128,7 @@ func TestPreprocess_ManageComments_SetsEmptyKey(t *testing.T) { // the metaComment key to records. func TestPreprocess_NoManageComments_NoKey(t *testing.T) { cf := &cloudflareProvider{} - domain := newDomainConfig() + domain := models.MustNewDomainConfig("test.com") // No CF_MANAGE_COMMENTS rec := makeRCmeta(map[string]string{}) @@ -159,7 +147,7 @@ func TestPreprocess_NoManageComments_NoKey(t *testing.T) { // record has the metaTags key in its metadata (empty string if not set). func TestPreprocess_ManageTags_SetsEmptyKey(t *testing.T) { cf := &cloudflareProvider{} - domain := newDomainConfig() + domain := models.MustNewDomainConfig("test.com") domain.Metadata[metaManageTags] = "true" // Record without any tags @@ -189,7 +177,7 @@ func TestPreprocess_ManageTags_SetsEmptyKey(t *testing.T) { // the metaTags key to records. func TestPreprocess_NoManageTags_NoKey(t *testing.T) { cf := &cloudflareProvider{} - domain := newDomainConfig() + domain := models.MustNewDomainConfig("test.com") // No CF_MANAGE_TAGS rec := makeRCmeta(map[string]string{}) @@ -290,7 +278,7 @@ func TestIpRewriting(t *testing.T) { {"1.2.3.4", "255.255.255.4", "full"}, } cf := &cloudflareProvider{} - domain := newDomainConfig() + dc := models.MustNewDomainConfig("test.com") cf.ipConversions = []transform.IPConversion{{ Low: netip.MustParseAddr("1.2.3.0"), High: netip.MustParseAddr("1.2.3.40"), @@ -298,18 +286,18 @@ func TestIpRewriting(t *testing.T) { NewIPs: nil, }} for _, tst := range tests { - rec := &models.RecordConfig{Type: "A", Metadata: map[string]string{metaProxy: tst.Proxy}} - rec.MustSetTarget(tst.Given) - domain.Records = append(domain.Records, rec) + rec := dc.MustNewRecordConfig("@", 0, dnsv2.TypeA, tst.Given) + rec.Metadata = map[string]string{metaProxy: tst.Proxy} + dc.AddRecordConfig(rec) } - err := cf.preprocessConfig(domain) + err := cf.preprocessConfig(dc) if err != nil { t.Fatal(err) } for i, tst := range tests { - rec := domain.Records[i] - if rec.GetTargetField() != tst.Expected { - t.Fatalf("At index %d, expected target of %s, but found %s.", i, tst.Expected, rec.GetTargetField()) + rec := dc.Records[i] + if rec.AsA().String() != tst.Expected { + t.Fatalf("At index %d, expected target of %s, but found %s.", i, tst.Expected, rec.AsA().String()) } if tst.Proxy == "full" && tst.Given != tst.Expected && rec.Metadata[metaOriginalIP] != tst.Given { t.Fatalf("At index %d, expected original_ip to be set", i) diff --git a/providers/cloudflare/rest.go b/providers/cloudflare/rest.go index adf1517b98..a9d8aac583 100644 --- a/providers/cloudflare/rest.go +++ b/providers/cloudflare/rest.go @@ -6,11 +6,11 @@ import ( "fmt" "strings" - "github.com/DNSControl/dnscontrol/v4/models" - "github.com/DNSControl/dnscontrol/v4/pkg/domaintags" - "github.com/DNSControl/dnscontrol/v4/pkg/rtypecontrol" - "github.com/DNSControl/dnscontrol/v4/pkg/txtutil" - "github.com/DNSControl/dnscontrol/v4/providers/cloudflare/rtypes/cfsingleredirect" + dnsv2 "codeberg.org/miekg/dns" + "github.com/DNSControl/dnscontrol/v5/models" + "github.com/DNSControl/dnscontrol/v5/pkg/privatetypes" + privatetypesrdata "github.com/DNSControl/dnscontrol/v5/pkg/privatetypes/rdata" + "github.com/DNSControl/dnscontrol/v5/pkg/providers" "github.com/cloudflare/cloudflare-go" "golang.org/x/net/idna" ) @@ -38,14 +38,16 @@ func (c *cloudflareProvider) fetchAllZones() (map[string]cloudflare.Zone, error) } // get all records for a domain. -func (c *cloudflareProvider) getRecordsForDomain(id string, domain string) ([]*models.RecordConfig, error) { - records := []*models.RecordConfig{} +func (c *cloudflareProvider) getRecordsForDomain(id string, dc *models.DomainConfig) (models.Records, error) { + var records models.Records rrs, _, err := c.cfClient.ListDNSRecords(context.Background(), cloudflare.ZoneIdentifier(id), cloudflare.ListDNSRecordsParams{}) if err != nil { return nil, fmt.Errorf("failed fetching record list from cloudflare(%q): %w", c.cfClient.APIEmail, err) } for _, rec := range rrs { - rt, err := c.nativeToRecord(domain, rec) + before := providers.BeginToRC(c.observer, "nativeToRecord", rec) + rt, err := c.nativeToRecord(dc, rec) + providers.EndToRC(c.observer, "nativeToRecord", before, rec, models.Records{rt}, err) if err != nil { return nil, err } @@ -75,76 +77,84 @@ func (c *cloudflareProvider) createZone(domainName string) (string, error) { } func cfDnskeyData(rec *models.RecordConfig) *cfRecData { + f := rec.AsDNSKEY() return &cfRecData{ - Algorithm: rec.DnskeyAlgorithm, - Flags: rec.DnskeyFlags, - Protocol: rec.DnskeyProtocol, - PublicKey: rec.DnskeyPublicKey, + Algorithm: f.Algorithm, + Flags: f.Flags, + Protocol: f.Protocol, + PublicKey: f.PublicKey, } } func cfDSData(rec *models.RecordConfig) *cfRecData { + f := rec.AsDS() return &cfRecData{ - KeyTag: rec.DsKeyTag, - Algorithm: rec.DsAlgorithm, - DigestType: rec.DsDigestType, - Digest: rec.DsDigest, + KeyTag: f.KeyTag, + Algorithm: f.Algorithm, + DigestType: f.DigestType, + Digest: f.Digest, } } func cfSrvData(rec *models.RecordConfig) *cfRecData { + f := rec.AsSRV() serverParts := strings.Split(rec.GetLabelFQDN(), ".") c := &cfRecData{ Service: serverParts[0], Proto: serverParts[1], Name: strings.Join(serverParts[2:], "."), - Port: rec.SrvPort, - Priority: rec.SrvPriority, - Weight: rec.SrvWeight, + Port: f.Port, + Priority: f.Priority, + Weight: f.Weight, } - c.Target = cfTarget(rec.GetTargetField()) + c.Target = cfTarget(f.Target) return c } func cfCaaData(rec *models.RecordConfig) *cfRecData { + f := rec.AsCAA() return &cfRecData{ - Tag: rec.CaaTag, - Flags: uint16(rec.CaaFlag), - Value: rec.GetTargetField(), + Tag: f.Tag, + Flags: uint16(f.Flag), + Value: f.Value, } } func cfTlsaData(rec *models.RecordConfig) *cfRecData { + f := rec.AsTLSA() return &cfRecData{ - Usage: rec.TlsaUsage, - Selector: rec.TlsaSelector, - MatchingType: rec.TlsaMatchingType, - Certificate: rec.GetTargetField(), + Usage: f.Usage, + Selector: f.Selector, + MatchingType: f.MatchingType, + Certificate: f.Certificate, } } func cfSshfpData(rec *models.RecordConfig) *cfRecData { + f := rec.AsSSHFP() return &cfRecData{ - Algorithm: rec.SshfpAlgorithm, - HashType: rec.SshfpFingerprint, - Fingerprint: rec.GetTargetField(), + Algorithm: f.Algorithm, + HashType: f.Type, + Fingerprint: f.FingerPrint, } } func cfSvcbData(rec *models.RecordConfig) *cfRecData { + f := rec.AsSVCB() return &cfRecData{ - Priority: rec.SvcPriority, - Target: cfTarget(rec.GetTargetField()), - Value: rec.SvcParams, + Priority: f.Priority, + Target: cfTarget(f.Target), + Value: models.Svcbv2ValueToString(f.Value), } } func cfLocData(rec *models.RecordConfig) *cfRecData { - latDir, latDeg, latMin, latSec := models.ReverseLatitude(rec.LocLatitude) - longDir, longDeg, longMin, longSec := models.ReverseLongitude(rec.LocLongitude) + f := rec.AsLOC() + latDir, latDeg, latMin, latSec := models.ReverseLatitude(f.Latitude) + longDir, longDeg, longMin, longSec := models.ReverseLongitude(f.Longitude) return &cfRecData{ - Altitude: models.ReverseAltitude(rec.LocAltitude), + Altitude: models.ReverseAltitude(f.Altitude), LatDegrees: latDeg, LatDirection: latDir, LatMinutes: latMin, @@ -153,42 +163,49 @@ func cfLocData(rec *models.RecordConfig) *cfRecData { LongDirection: longDir, LongMinutes: longMin, LongSeconds: longSec, - PrecisionHorz: models.ReverseENotationInt(rec.LocHorizPre), - PrecisionVert: models.ReverseENotationInt(rec.LocVertPre), - Size: models.ReverseENotationInt(rec.LocSize), + PrecisionHorz: models.ReverseENotationInt(f.HorizPre), + PrecisionVert: models.ReverseENotationInt(f.VertPre), + Size: models.ReverseENotationInt(f.Size), } } func cfNaptrData(rec *models.RecordConfig) *cfNaptrRecData { + f := rec.AsNAPTR() return &cfNaptrRecData{ - Flags: rec.NaptrFlags, - Order: rec.NaptrOrder, - Preference: rec.NaptrPreference, - Regex: rec.NaptrRegexp, - Replacement: rec.GetTargetField(), - Service: rec.NaptrService, + Flags: f.Flags, + Order: f.Order, + Preference: f.Preference, + Regex: f.Regexp, + Replacement: f.Replacement, + Service: f.Service, } } func (c *cloudflareProvider) createRecDiff2(rec *models.RecordConfig, domainID string, msg string) []*models.Correction { - content := rec.GetTargetField() + var content string + prio := "" + priorityNum := uint16(0) + switch rec.TypeNum { + case dnsv2.TypeMX: + f := rec.AsMX() + priorityNum = f.Preference + prio = fmt.Sprintf(" %d ", priorityNum) + content = f.Mx + // case "TXT": + // content = rec.GetRDATA().String() + // case "DS": + // content = rec.GetRDATA().String() + default: + content = rec.GetRDATA().String() + } if rec.Metadata[metaOriginalIP] != "" { content = rec.Metadata[metaOriginalIP] } - prio := "" - switch rec.Type { - case "MX": - prio = fmt.Sprintf(" %d ", rec.MxPreference) - case "TXT": - content = txtutil.EncodeQuoted(rec.GetTargetTXTJoined()) - case "DS": - content = fmt.Sprintf("%d %d %d %s", rec.DsKeyTag, rec.DsAlgorithm, rec.DsDigestType, rec.DsDigest) - } if msg == "" { msg = fmt.Sprintf("CREATE record: %s %s %d%s %s", rec.GetLabel(), rec.Type, rec.TTL, prio, content) } if rec.Metadata[metaProxy] == "on" || rec.Metadata[metaProxy] == "full" { - msg = msg + fmt.Sprintf("\nACTIVATE PROXY for new record %s %s %d %s", rec.GetLabel(), rec.Type, rec.TTL, rec.GetTargetField()) + msg = msg + fmt.Sprintf("\nACTIVATE PROXY for new record %s %s %d %s", rec.GetLabel(), rec.Type, rec.TTL, rec.GetRDATA().String()) } if rec.Metadata[metaCNAMEFlatten] == "on" { msg = msg + fmt.Sprintf("\nENABLE CNAME FLATTENING for new record %s %s", rec.GetLabel(), rec.Type) @@ -207,7 +224,7 @@ func (c *cloudflareProvider) createRecDiff2(rec *models.RecordConfig, domainID s Type: rec.Type, TTL: int(rec.TTL), Content: content, - Priority: &rec.MxPreference, + Priority: &priorityNum, } // Set comment if specified if comment := rec.Metadata[metaComment]; comment != "" { @@ -222,30 +239,30 @@ func (c *cloudflareProvider) createRecDiff2(rec *models.RecordConfig, domainID s flatten := true cf.Settings = cloudflare.DNSRecordSettings{FlattenCNAME: &flatten} } - switch rec.Type { - case "SRV": + switch rec.TypeNum { + case dnsv2.TypeSRV: cf.Data = cfSrvData(rec) cf.Name = rec.GetLabelFQDN() - case "CAA": + case dnsv2.TypeCAA: cf.Data = cfCaaData(rec) cf.Name = rec.GetLabelFQDN() cf.Content = "" - case "TLSA": + case dnsv2.TypeTLSA: cf.Data = cfTlsaData(rec) cf.Name = rec.GetLabelFQDN() - case "SSHFP": + case dnsv2.TypeSSHFP: cf.Data = cfSshfpData(rec) cf.Name = rec.GetLabelFQDN() - case "DNSKEY": + case dnsv2.TypeDNSKEY: cf.Data = cfDnskeyData(rec) - case "DS": + case dnsv2.TypeDS: cf.Data = cfDSData(rec) - case "NAPTR": + case dnsv2.TypeNAPTR: cf.Data = cfNaptrData(rec) cf.Name = rec.GetLabelFQDN() - case "HTTPS", "SVCB": + case dnsv2.TypeHTTPS, dnsv2.TypeSVCB: cf.Data = cfSvcbData(rec) - case "LOC": + case dnsv2.TypeLOC: cf.Data = cfLocData(rec) } resp, err := c.cfClient.CreateDNSRecord(context.Background(), cloudflare.ZoneIdentifier(domainID), cf) @@ -270,19 +287,11 @@ func (c *cloudflareProvider) modifyRecord(domainID, recID string, proxied bool, } r := cloudflare.UpdateDNSRecordParams{ - ID: recID, - Proxied: &proxied, - Name: rec.GetLabel(), - Type: rec.Type, - Content: rec.GetTargetField(), - Priority: &rec.MxPreference, - TTL: int(rec.TTL), - } - - // Handle CNAME flattening setting - if rec.Type == "CNAME" { - flatten := rec.Metadata[metaCNAMEFlatten] == "on" - r.Settings = cloudflare.DNSRecordSettings{FlattenCNAME: &flatten} + ID: recID, + Proxied: new(proxied), + Name: rec.GetLabel(), + Type: rec.Type, + TTL: int(rec.TTL), } // Set comment if specified (nil keeps current, "" empties it, value sets it) @@ -298,36 +307,54 @@ func (c *cloudflareProvider) modifyRecord(domainID, recID string, proxied bool, } } - switch rec.Type { - case "TXT": - r.Content = txtutil.EncodeQuoted(rec.GetTargetTXTJoined()) - case "SRV": + switch rec.TypeNum { + // case "TXT": + // r.Content = rec.GetRDATA().String() + case dnsv2.TypeMX: + f := rec.AsMX() + r.Priority = new(f.Preference) + r.Content = f.Mx + case dnsv2.TypeCNAME: + // Handle CNAME flattening setting + flatten := rec.Metadata[metaCNAMEFlatten] == "on" + r.Settings = cloudflare.DNSRecordSettings{FlattenCNAME: &flatten} + r.Content = rec.AsCNAME().Target + case dnsv2.TypeSRV: r.Data = cfSrvData(rec) r.Name = rec.GetLabelFQDN() - case "CAA": + r.Content = rec.GetRDATA().String() + case dnsv2.TypeCAA: r.Data = cfCaaData(rec) r.Name = rec.GetLabelFQDN() r.Content = "" - case "TLSA": + case dnsv2.TypeTLSA: r.Data = cfTlsaData(rec) r.Name = rec.GetLabelFQDN() - case "SSHFP": + r.Content = rec.GetRDATA().String() + case dnsv2.TypeSSHFP: r.Data = cfSshfpData(rec) r.Name = rec.GetLabelFQDN() - case "DNSKEY": + r.Content = rec.GetRDATA().String() + case dnsv2.TypeDNSKEY: r.Data = cfDnskeyData(rec) r.Content = "" - case "DS": + case dnsv2.TypeDS: r.Data = cfDSData(rec) r.Content = "" - case "NAPTR": + case dnsv2.TypeNAPTR: r.Data = cfNaptrData(rec) r.Name = rec.GetLabelFQDN() - case "HTTPS", "SVCB": + r.Content = rec.GetRDATA().String() + case dnsv2.TypeHTTPS, dnsv2.TypeSVCB: r.Data = cfSvcbData(rec) - case "LOC": + r.Content = rec.GetRDATA().String() + case dnsv2.TypeLOC: r.Data = cfLocData(rec) + r.Content = rec.GetRDATA().String() + default: + r.Content = rec.GetRDATA().String() } + _, err := c.cfClient.UpdateDNSRecord(context.Background(), cloudflare.ZoneIdentifier(domainID), r) return err } @@ -344,17 +371,16 @@ func (c *cloudflareProvider) getUniversalSSL(domainID string) (bool, error) { return result.Enabled, err } -func (c *cloudflareProvider) getSingleRedirects(id string, domain string) ([]*models.RecordConfig, error) { +func (c *cloudflareProvider) getSingleRedirects(dc *models.DomainConfig, id string) (models.Records, error) { rules, err := c.cfClient.GetEntrypointRuleset(context.Background(), cloudflare.ZoneIdentifier(id), "http_request_dynamic_redirect") if err != nil { - var e *cloudflare.NotFoundError - if errors.As(err, &e) { - return []*models.RecordConfig{}, nil + if _, ok := errors.AsType[*cloudflare.NotFoundError](err); ok { + return nil, nil } return nil, fmt.Errorf("failed fetching redirect rule list cloudflare: %w (%T)", err, err) } - recs := []*models.RecordConfig{} + var recs models.Records for _, pr := range rules.Rules { thisPr := pr @@ -364,21 +390,18 @@ func (c *cloudflareProvider) getSingleRedirects(id string, domain string) ([]*mo srThen := pr.ActionParameters.FromValue.TargetURL.Expression code := uint16(pr.ActionParameters.FromValue.StatusCode) - rec, err := rtypecontrol.NewRecordConfigFromRaw(rtypecontrol.FromRawOpts{ - Type: "CLOUDFLAREAPI_SINGLE_REDIRECT", - TTL: 1, - Args: []any{srName, code, srWhen, srThen}, - DCN: domaintags.MakeDomainNameVarieties(domain), - }) + // Make the record: + rec, err := dc.NewRecordConfig("@", 1, privatetypes.TypeCLOUDFLAREAPISINGLEREDIRECT, srName, code, srWhen, srThen) if err != nil { return nil, err } rec.Original = thisPr // Store the IDs. These will be needed for update/delete operations. - sr := rec.F.(*cfsingleredirect.SingleRedirectConfig) - sr.SRRRulesetID = rules.ID - sr.SRRRulesetRuleID = pr.ID + sr := rec.AsCLOUDFLAREAPISINGLEREDIRECT() + sr.RT_SRRRulesetID = rules.ID + sr.RT_SRRRulesetRuleID = pr.ID + rec.SetRDATA(sr) recs = append(recs, rec) } @@ -386,7 +409,7 @@ func (c *cloudflareProvider) getSingleRedirects(id string, domain string) ([]*mo return recs, nil } -func (c *cloudflareProvider) createSingleRedirect(domainID string, cfr cfsingleredirect.SingleRedirectConfig) error { +func (c *cloudflareProvider) createSingleRedirect(domainID string, cfr privatetypesrdata.CLOUDFLAREAPISINGLEREDIRECT) error { newSingleRedirectRulesActionParameters := cloudflare.RulesetRuleActionParameters{} newSingleRedirectRule := cloudflare.RulesetRule{} newSingleRedirectRules := []cloudflare.RulesetRule{} @@ -429,10 +452,10 @@ func (c *cloudflareProvider) createSingleRedirect(domainID string, cfr cfsingler return err } -func (c *cloudflareProvider) deleteSingleRedirects(domainID string, cfr cfsingleredirect.SingleRedirectConfig) error { +func (c *cloudflareProvider) deleteSingleRedirects(domainID string, cfr privatetypesrdata.CLOUDFLAREAPISINGLEREDIRECT) error { err := c.cfClient.DeleteRulesetRule(context.Background(), cloudflare.ZoneIdentifier(domainID), cloudflare.DeleteRulesetRuleParams{ - RulesetID: cfr.SRRRulesetID, - RulesetRuleID: cfr.SRRRulesetRuleID, + RulesetID: cfr.RT_SRRRulesetID, + RulesetRuleID: cfr.RT_SRRRulesetRuleID, }, ) // NB(tlim): Yuck. This returns an error even when it is successful. Dig into the JSON for the real status. @@ -444,33 +467,27 @@ func (c *cloudflareProvider) deleteSingleRedirects(domainID string, cfr cfsingle } func (c *cloudflareProvider) updateSingleRedirect(domainID string, oldrec, newrec *models.RecordConfig) error { - if err := c.deleteSingleRedirects(domainID, *oldrec.F.(*cfsingleredirect.SingleRedirectConfig)); err != nil { + if err := c.deleteSingleRedirects(domainID, oldrec.AsCLOUDFLAREAPISINGLEREDIRECT()); err != nil { return err } - return c.createSingleRedirect(domainID, *newrec.F.(*cfsingleredirect.SingleRedirectConfig)) + return c.createSingleRedirect(domainID, newrec.AsCLOUDFLAREAPISINGLEREDIRECT()) } -func (c *cloudflareProvider) getWorkerRoutes(id string, domain string) ([]*models.RecordConfig, error) { +func (c *cloudflareProvider) getWorkerRoutes(id string, dc *models.DomainConfig) (models.Records, error) { res, err := c.cfClient.ListWorkerRoutes(context.Background(), cloudflare.ZoneIdentifier(id), cloudflare.ListWorkerRoutesParams{}) if err != nil { return nil, fmt.Errorf("failed fetching worker route list cloudflare: %w", err) } - recs := []*models.RecordConfig{} + var recs models.Records for _, pr := range res.Routes { thisPr := pr - r := &models.RecordConfig{ - Type: "WORKER_ROUTE", - Original: thisPr, - TTL: 1, - } - r.SetLabel("@", domain) - err := r.SetTarget(fmt.Sprintf("%s,%s", // $PATTERN,$SCRIPT - pr.Pattern, - pr.ScriptName)) + + r, err := dc.NewRecordConfig("@", 1, privatetypes.TypeCFWORKERROUTE, pr.Pattern, pr.ScriptName) if err != nil { return nil, err } + r.Original = thisPr recs = append(recs, r) } @@ -482,22 +499,18 @@ func (c *cloudflareProvider) deleteWorkerRoute(recordID, domainID string) error return err } -func (c *cloudflareProvider) updateWorkerRoute(recordID, domainID string, target string) error { +func (c *cloudflareProvider) updateWorkerRoute(recordID, domainID string, rd dnsv2.RDATA) error { if err := c.deleteWorkerRoute(recordID, domainID); err != nil { return err } - return c.createWorkerRoute(domainID, target) + return c.createWorkerRoute(domainID, rd) } -func (c *cloudflareProvider) createWorkerRoute(domainID string, target string) error { - // $PATTERN,$SCRIPT - parts := strings.Split(target, ",") - if len(parts) != 2 { - return fmt.Errorf("unexpected target: '%s' (expected: 'PATTERN,SCRIPT')", target) - } +func (c *cloudflareProvider) createWorkerRoute(domainID string, rd dnsv2.RDATA) error { + rdwr := rd.(privatetypesrdata.CFWORKERROUTE) wr := cloudflare.CreateWorkerRouteParams{ - Pattern: parts[0], - Script: parts[1], + Pattern: rdwr.When, + Script: rdwr.Then, } _, err := c.cfClient.CreateWorkerRoute(context.Background(), cloudflare.ZoneIdentifier(domainID), wr) diff --git a/providers/cloudflare/rtypes/cfsingleredirect/cfredirect.go b/providers/cloudflare/rtypes/cfsingleredirect/cfredirect.go index 2cefa33ef0..c1931de054 100644 --- a/providers/cloudflare/rtypes/cfsingleredirect/cfredirect.go +++ b/providers/cloudflare/rtypes/cfsingleredirect/cfredirect.go @@ -3,118 +3,46 @@ package cfsingleredirect import ( "fmt" - "github.com/DNSControl/dnscontrol/v4/models" - "github.com/DNSControl/dnscontrol/v4/pkg/domaintags" - "github.com/DNSControl/dnscontrol/v4/pkg/rtypecontrol" + "github.com/DNSControl/dnscontrol/v5/models" + "github.com/DNSControl/dnscontrol/v5/pkg/mustbe" + "github.com/DNSControl/dnscontrol/v5/pkg/txtutil" ) func init() { - rtypecontrol.Register(&CfRedirect{}) - rtypecontrol.Register(&CfTempRedirect{}) + models.RegisterBuilder("CF_REDIRECT", BuilderCFREDIRECT) + models.RegisterBuilder("CF_TEMP_REDIRECT", BuilderCFTEMPREDIRECT) } -// CfRedirect represents the CF_REDIRECT rtype, which is a builder that produces CLOUDFLAREAPI_SINGLE_REDIRECT. -type CfRedirect struct{} - -// Name returns the text (all caps) name of the rtype. -func (handle *CfRedirect) Name() string { - return "CF_REDIRECT" -} - -// FromArgs populates a RecordConfig from the raw ([]any) args. -func (handle *CfRedirect) FromArgs(dcn *domaintags.DomainNameVarieties, rec *models.RecordConfig, args []any) error { - return fromArgsHelper(dcn, rec, args, 301) -} - -// FromStruct populates a RecordConfig from a struct, which will be stored in rec.F. -func (handle *CfRedirect) FromStruct(dcn *domaintags.DomainNameVarieties, rec *models.RecordConfig, name string, fields any) error { - panic("CF_REDIRECT: FromStruct not implemented") -} - -// CopyToLegacyFields copies data from rec.F to the legacy fields in rec. -func (handle *CfRedirect) CopyToLegacyFields(rec *models.RecordConfig) { - // Nothing needs to be copied. The CLOUDFLAREAPI_SINGLE_REDIRECT FromArgs copies everything needed. -} - -// CopyFromLegacyFields populates rec.F from the legacy RecordType fields. -func (handle *CfRedirect) CopyFromLegacyFields(rec *models.RecordConfig) { - // Nothing needs to be copied. The CLOUDFLAREAPI_SINGLE_REDIRECT is built in FromArgs. - - // However, we add some assertions here to catch mistakes. - if rec.F == nil { - panic("assertion failed: CfRedirect CopyFromLegacyFields called with rec.F == nil") - } - if rec.ZonefilePartial == "" { - panic("assertion failed: CfRedirect CopyFromLegacyFields called with rec.ZonefilePartial == \"\"") - } - if rec.Comparable == "" { - panic("assertion failed: CfRedirect CopyFromLegacyFields called with rec.Comparable == \"\"") - } +func BuilderCFREDIRECT(dc *models.DomainConfig, ttl uint32, args []any, subdomain string) (models.Records, error) { + return builderCFREDIRECThelper(dc, 301, args, subdomain) } - -// CfTempRedirect represents the CF_TEMP_REDIRECT rtype, which is a builder that produces CLOUDFLAREAPI_SINGLE_REDIRECT. -type CfTempRedirect struct{} - -// Name returns the text (all caps) name of the rtype. -func (handle *CfTempRedirect) Name() string { - return "CF_TEMP_REDIRECT" +func BuilderCFTEMPREDIRECT(dc *models.DomainConfig, ttl uint32, args []any, subdomain string) (models.Records, error) { + return builderCFREDIRECThelper(dc, 302, args, subdomain) } -// FromArgs populates a RecordConfig from the raw ([]any) args. -func (handle *CfTempRedirect) FromArgs(dcn *domaintags.DomainNameVarieties, rec *models.RecordConfig, args []any) error { - return fromArgsHelper(dcn, rec, args, 302) -} - -// FromStruct populates a RecordConfig from a struct, which will be stored in rec.F. -func (handle *CfTempRedirect) FromStruct(dcn *domaintags.DomainNameVarieties, rec *models.RecordConfig, name string, fields any) error { - panic("CF_TEMP_REDIRECT: FromStruct not implemented") -} - -// CopyToLegacyFields copies data from rec.F to the legacy fields in rec. -func (handle *CfTempRedirect) CopyToLegacyFields(rec *models.RecordConfig) { - // Nothing needs to be copied. The CLOUDFLAREAPI_SINGLE_REDIRECT FromArgs copies everything needed. -} - -// CopyFromLegacyFields copies data from rec.F to the legacy fields in rec. -func (handle *CfTempRedirect) CopyFromLegacyFields(rec *models.RecordConfig) { - // Nothing needs to be copied. The CLOUDFLAREAPI_SINGLE_REDIRECT is built in FromArgs. - - // However, we add some assertions here to catch mistakes. - if rec.F == nil { - panic("assertion failed: CfTempRedirect CopyFromLegacyFields called with rec.F == nil") - } - if rec.ZonefilePartial == "" { - panic("assertion failed: CfTempRedirect CopyFromLegacyFields called with rec.ZonefilePartial == \"\"") - } - if rec.Comparable == "" { - panic("assertion failed: CfTempRedirect CopyFromLegacyFields called with rec.Comparable == \"\"") - } -} - -func fromArgsHelper(dcn *domaintags.DomainNameVarieties, rec *models.RecordConfig, args []any, code int) error { - - // Pave the args to be the expected types. - if err := rtypecontrol.PaveArgs(args, "ss"); err != nil { - return err - } - +func builderCFREDIRECThelper(dc *models.DomainConfig, code uint16, args []any, _ string) (models.Records, error) { // Convert old-style patterns to new-style rules: - prWhen := args[0].(string) - prThen := args[1].(string) + prWhen := mustbe.RawString(args[1]) + prThen := mustbe.RawString(args[2]) srWhen, srThen, err := makeRuleFromPattern(prWhen, prThen) if err != nil { - return err + return nil, err } // Create a rule name: name := fmt.Sprintf("%03d,%s,%s", code, prWhen, prThen) - sr := SingleRedirectConfig{} - rec.Type = sr.Name() // This record is now a CLOUDFLAREAPI_SINGLE_REDIRECT - err = sr.FromArgs(dcn, rec, []any{name, code, srWhen, srThen}) + rec, err := dc.NewRecordConfig( + "@", + 1, // CF ignores the TTL. We always force it to 1. + "CLOUDFLAREAPI_SINGLE_REDIRECT", + name, code, srWhen, srThen, + ) if err != nil { - return err + return nil, + fmt.Errorf( + "record error in GeneratorCFREDIRECT at [CLOUDFLAREAPI_SINGLE_REDIRECT(%s)]: %w", + txtutil.ZoneifyManyAny(args), err) } - - return nil + return models.Records{rec}, nil } diff --git a/providers/cloudflare/rtypes/cfsingleredirect/cfsingleredirect.go b/providers/cloudflare/rtypes/cfsingleredirect/cfsingleredirect.go deleted file mode 100644 index 77e05ca7fc..0000000000 --- a/providers/cloudflare/rtypes/cfsingleredirect/cfsingleredirect.go +++ /dev/null @@ -1,115 +0,0 @@ -package cfsingleredirect - -import ( - "fmt" - - "github.com/DNSControl/dnscontrol/v4/models" - "github.com/DNSControl/dnscontrol/v4/pkg/domaintags" - "github.com/DNSControl/dnscontrol/v4/pkg/rtypecontrol" -) - -func init() { - rtypecontrol.Register(&SingleRedirectConfig{}) -} - -// SingleRedirectConfig contains info about a Cloudflare Single Redirect. -type SingleRedirectConfig struct { - // - Code uint16 `json:"code,omitempty"` // 301 or 302 - // - // SR == SingleRedirect - SRName string `json:"sr_name,omitempty"` // How is this displayed to the user - SRWhen string `json:"sr_when,omitempty"` // Condition for redirect - SRThen string `json:"sr_then,omitempty"` // Formula for redirect - SRRRulesetID string `json:"sr_rulesetid,omitempty"` // ID of the ruleset containing this rule (populated by API) - SRRRulesetRuleID string `json:"sr_rulesetruleid,omitempty"` // ID of this rule within the ruleset (populated by API) - SRDisplay string `json:"sr_display,omitempty"` // How is this displayed to the user (SetTarget) for CF_SINGLE_REDIRECT -} - -// Name returns the text (all caps) name of the rtype. -func (handle *SingleRedirectConfig) Name() string { - return "CLOUDFLAREAPI_SINGLE_REDIRECT" -} - -// FromArgs populates a RecordConfig from the raw ([]any) args. -func (handle *SingleRedirectConfig) FromArgs(dcn *domaintags.DomainNameVarieties, rec *models.RecordConfig, args []any) error { - // Pave the args to be the expected types. - if err := rtypecontrol.PaveArgs(args, "swss"); err != nil { - return err - } - - // Unpack the args: - var name = args[0].(string) - var code = args[1].(uint16) - var when = args[2].(string) - var then = args[3].(string) - - // Validate - if code != 301 && code != 302 && code != 303 && code != 307 && code != 308 { - return fmt.Errorf("%s: code (%03d) is not 301,302,303,307,308", rec.FilePos, code) - } - - // Calclate the Comparable and ZonefilePartial values: - display := targetFromRaw(name, code, when, then) - rec.Comparable = display - rec.ZonefilePartial = display - - // Set the fields - rec.F = &SingleRedirectConfig{ - Code: code, - SRName: name, - SRWhen: when, - SRThen: then, - SRDisplay: display, - } - - // Usually these fields do not need to be changed. The caller sets appropriate values. - // But Cloudflare Single Redirects always use "@" as the name and TTL=1. We override here. - rec.Name = "@" - rec.NameRaw = "@" - rec.NameUnicode = "@" - rec.NameFQDN = dcn.NameASCII - rec.NameFQDNRaw = dcn.NameRaw - rec.NameFQDNUnicode = dcn.NameUnicode - rec.TTL = 1 - - // Fill in the legacy fields: - handle.CopyToLegacyFields(rec) - return nil -} - -// FromStruct populates a RecordConfig from a struct, which will be stored in rec.F. -func (handle *SingleRedirectConfig) FromStruct(dcn *domaintags.DomainNameVarieties, rec *models.RecordConfig, name string, fields any) error { - panic("CLOUDFLAREAPI_SINGLE_REDIRECT: FromStruct not implemented") -} - -// targetFromRaw create the display text used for a normal Redirect. -func targetFromRaw(name string, code uint16, when, then string) string { - return fmt.Sprintf("name=(%s) code=(%03d) when=(%s) then=(%s)", - name, - code, - when, - then, - ) -} - -// CopyToLegacyFields copies data from rec.F to the legacy fields in rec. -func (handle *SingleRedirectConfig) CopyToLegacyFields(rec *models.RecordConfig) { - _ = rec.SetTarget(rec.F.(*SingleRedirectConfig).SRDisplay) -} - -// CopyFromLegacyFields populates rec.F from the legacy RecordType fields. -func (handle *SingleRedirectConfig) CopyFromLegacyFields(rec *models.RecordConfig) { - // Nothing needs to be copied. The CLOUDFLAREAPI_SINGLE_REDIRECT is built in FromArgs. - - // However, we add some assertions here to catch mistakes. - if rec.F == nil { - panic("assertion failed: SingleRedirectConfig CopyFromLegacyFields called with rec.F == nil") - } - if rec.ZonefilePartial == "" { - panic("assertion failed: SingleRedirectConfig CopyFromLegacyFields called with rec.ZonefilePartial == \"\"") - } - if rec.Comparable == "" { - panic("assertion failed: SingleRedirectConfig CopyFromLegacyFields called with rec.Comparable == \"\"") - } -} diff --git a/providers/cloudflare/test_data/expected_torc_output_nativeToRecord_dnscontroltest-cf.org.records b/providers/cloudflare/test_data/expected_torc_output_nativeToRecord_dnscontroltest-cf.org.records new file mode 100644 index 0000000000..871b8ab560 --- /dev/null +++ b/providers/cloudflare/test_data/expected_torc_output_nativeToRecord_dnscontroltest-cf.org.records @@ -0,0 +1,254 @@ +1 testaaaa 300 IN AAAA 2607:f8b0:4006:820::2013 ; cloudflare_proxy="off" +2 testa 300 IN A 1.1.1.1 ; cloudflare_proxy="off" +3 testa 300 IN A 3.3.3.3 ; cloudflare_proxy="off" +4 @ 300 IN A 2.2.2.2 ; cloudflare_proxy="off" +5 @ 300 IN A 4.4.4.4 ; cloudflare_proxy="off" +6 * 300 IN A 3.3.3.3 ; cloudflare_proxy="off" +7 www 300 IN A 5.5.5.5 ; cloudflare_proxy="off" +8 testaaaa 300 IN AAAA 2607:f8b0:4006:820::2006 ; cloudflare_proxy="off" +9 testaaaa 300 IN AAAA 2607:f8b0:4006:820::2013 ; cloudflare_proxy="off" +10 testcname 300 IN CNAME www.google.com. ; cloudflare_cname_flatten="off" cloudflare_proxy="off" +11 testcname 300 IN CNAME www.yahoo.com. ; cloudflare_cname_flatten="off" cloudflare_proxy="off" +12 foo 300 IN A 1.2.3.4 ; cloudflare_proxy="off" +13 testcname 300 IN CNAME foo.dnscontroltest-cf.org. ; cloudflare_cname_flatten="off" cloudflare_proxy="off" +14 @ 300 IN MX 5 foo.com. +15 @ 300 IN MX 5 bar.com. +16 testmx 300 IN MX 5 foo.com. +17 testmx 300 IN MX 5 bar.com. +18 testmx 300 IN MX 5 foo.com. +19 testmx 300 IN MX 100 foo.com. +20 testtxt 300 IN TXT "simple" +21 testtxt 300 IN TXT "changed" +22 www 300 IN A 1.1.1.1 ; cloudflare_proxy="off" +23 www 300 IN A 2.2.2.2 ; cloudflare_proxy="off" +24 www 300 IN A 3.3.3.3 ; cloudflare_proxy="off" +25 www 300 IN A 1.1.1.1 ; cloudflare_proxy="off" +26 www 300 IN A 2.2.2.2 ; cloudflare_proxy="off" +27 www 300 IN A 3.3.3.3 ; cloudflare_proxy="off" +28 testmx 300 IN MX 100 bar.com. +29 testmx 300 IN MX 5 foo.com. +30 www 300 IN A 1.1.1.1 ; cloudflare_proxy="off" +31 www 300 IN A 1.1.1.1 ; cloudflare_proxy="off" +32 testmx 300 IN MX 5 foo.com. +33 testmx 300 IN MX 100 bar.com. +34 testa 333 IN A 1.1.1.1 ; cloudflare_proxy="off" +35 testa 999 IN A 1.1.1.1 ; cloudflare_proxy="off" +36 @ 666 IN A 8.8.8.8 ; cloudflare_proxy="off" +37 @ 1000 IN A 8.8.8.8 ; cloudflare_proxy="off" +38 @ 500 IN A 8.8.8.8 ; cloudflare_proxy="off" +39 www 300 IN A 1.2.3.4 ; cloudflare_proxy="off" +40 www 300 IN A 2.2.2.2 ; cloudflare_proxy="off" +41 www 400 IN A 2.2.2.2 ; cloudflare_proxy="off" +42 www 300 IN A 5.6.7.8 ; cloudflare_proxy="off" +43 www 400 IN A 5.6.7.8 ; cloudflare_proxy="off" +44 www 400 IN A 5.6.7.8 ; cloudflare_proxy="off" +45 www 700 IN A 5.6.7.8 ; cloudflare_proxy="off" +46 www 700 IN A 1.2.3.4 ; cloudflare_proxy="off" +47 foo 300 IN A 1.2.3.4 ; cloudflare_proxy="off" +48 foo 300 IN MX 5 mx.google.com. +49 foo 300 IN A 4.5.6.7 ; cloudflare_proxy="off" +50 foo 300 IN CNAME google.com. ; cloudflare_cname_flatten="off" cloudflare_proxy="off" +51 foo 300 IN A 1.2.3.4 ; cloudflare_proxy="off" +52 foo 300 IN CNAME google2.com. ; cloudflare_cname_flatten="off" cloudflare_proxy="off" +53 @ 300 IN HTTPS 0 test.com. +54 @ 300 IN HTTPS 1 test.com. port="80" +55 @ 300 IN HTTPS 1 test.com. port="99" +56 @ 300 IN HTTPS 1 test.com. alpn="h2" port="99" +57 @ 300 IN HTTPS 3 example.com. alpn="h2,h3" port="999" +58 @ 300 IN HTTPS 3 example.com. alpn="h2,h3" port="999" +59 @ 300 IN HTTPS 3 example.com. alpn="h2,h3" port="999" ech="some+base64+encoded+value///" +60 @ 300 IN HTTPS 3 example.com. alpn="h2" port="80" ech="some+base64+encoded+value///" +61 @ 300 IN HTTPS 3 example.com. alpn="h2" port="80" ech="another+base64+encoded+value" +62 @ 300 IN HTTPS 3 yetanother.com. alpn="h2" port="80" ech="another+base64+encoded+value" +63 @ 300 IN SVCB 0 test.com. +64 @ 300 IN SVCB 1 test.com. port="80" +65 @ 300 IN SVCB 1 test.com. port="99" +66 @ 300 IN SVCB 1 test.com. alpn="h2" port="99" +67 @ 300 IN SVCB 3 example.com. alpn="h2,h3" port="999" +68 @ 300 IN SVCB 3 example.com. alpn="h2,h3" port="999" +69 @ 300 IN SVCB 3 example.com. alpn="h2,h3" port="999" ech="some+base64+encoded+value///" +70 @ 300 IN SVCB 3 example.com. alpn="h2" port="80" ech="some+base64+encoded+value///" +71 @ 300 IN SVCB 3 example.com. alpn="h2" port="80" ech="another+base64+encoded+value" +72 @ 300 IN SVCB 3 yetanother.com. alpn="h2" port="80" ech="another+base64+encoded+value" +73 @ 300 IN A 1.2.3.4 ; cloudflare_proxy="off" +74 foo 300 IN CNAME dnscontroltest-cf.org. ; cloudflare_cname_flatten="off" cloudflare_proxy="off" +75 @ 300 IN A 1.2.3.4 ; cloudflare_proxy="off" +76 foo 300 IN MX 8 dnscontroltest-cf.org. +77 nmx 300 IN A 1.2.3.3 ; cloudflare_proxy="off" +78 nmx 300 IN MX 0 . +79 nmx 300 IN MX 3 nmx.dnscontroltest-cf.org. +80 nmx 300 IN MX 0 . +81 www 300 IN A 1.2.3.9 ; cloudflare_proxy="off" +82 nmx 300 IN MX 9 www.dnscontroltest-cf.org. +83 @ 300 IN A 1.2.3.2 ; cloudflare_proxy="off" +84 @ 300 IN MX 0 . +85 @ 300 IN MX 2 dnscontroltest-cf.org. +86 @ 300 IN MX 0 . +87 www 300 IN A 1.2.3.8 ; cloudflare_proxy="off" +88 @ 300 IN MX 8 www.dnscontroltest-cf.org. +89 xyz 300 IN NS ns2.foo.com. +90 xyz 300 IN NS ns1.foo.com. +91 foo 300 IN NS dnscontroltest-cf.org. +92 @ 300 IN A 1.2.3.4 ; cloudflare_proxy="off" +93 @ 300 IN NS ns1.foo.com. +94 @ 300 IN NS ns2.foo.com. +95 foo254 300 IN TXT "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" +96 foo255 300 IN TXT "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" +97 foo256 300 IN TXT "CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC" "C" +98 foo509 300 IN TXT "DDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDD" "DDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDD" +99 foo510 300 IN TXT "EEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE" "EEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE" +100 foo511 300 IN TXT "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF" "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF" "F" +101 foo764 300 IN TXT "GGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGG" "GGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGG" "GGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGG" +102 foo765 300 IN TXT "HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH" "HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH" "HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH" +103 foo766 300 IN TXT "JJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJ" "JJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJ" "JJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJ" "J" +104 foosq 300 IN TXT "quo'te" +105 foobt 300 IN TXT "blah`blah" +106 foodq 300 IN TXT "in\"side" +107 foodqs 300 IN TXT "in\"ter\"ior" +108 foodqs 300 IN TXT "\"left" +109 foodqs 300 IN TXT "right\"" +110 foosc1 300 IN TXT "semi;colon" +111 foosc2 300 IN TXT "wssemi ; colon" +112 foosp 300 IN TXT "with spaces" +113 foows1 300 IN TXT "trailingws " +114 foo 300 IN TXT "v=spf1 ip4:99.99.99.99 -all" +115 fooosbs1 300 IN TXT "1back\\slash" +116 fooosbs2 300 IN TXT "2back\\\\slash" +117 fooosbs3 300 IN TXT "3back\\\\\\slash" +118 fooosbs4 300 IN TXT "4back\\\\\\\\slash" +119 bar 300 IN MX 5 bar.com. +120 decoy 300 IN A 1.1.1.1 ; cloudflare_proxy="off" +121 decoy 300 IN A 2.2.2.2 ; cloudflare_proxy="off" +122 decoy 300 IN A 3.3.3.3 ; cloudflare_proxy="off" +123 foo 300 IN A 1.2.3.4 ; cloudflare_proxy="off" +124 foo 300 IN A 2.3.4.5 ; cloudflare_proxy="off" +125 foo 300 IN A 3.4.5.6 ; cloudflare_proxy="off" +126 foo 300 IN A 3.4.5.6 ; cloudflare_proxy="off" +127 bar 300 IN A 1.2.3.4 ; cloudflare_proxy="off" +128 foo 300 IN A 2.3.4.5 ; cloudflare_proxy="off" +129 foo 300 IN A 3.4.5.6 ; cloudflare_proxy="off" +130 foo 300 IN A 8.8.8.8 ; cloudflare_proxy="off" +131 foo 300 IN MX 20 bar.dnscontroltest-cf.org. +132 foo 300 IN MX 10 foo.dnscontroltest-cf.org. +133 foo 300 IN A 8.8.8.8 ; cloudflare_proxy="off" +134 xn--ndaaa 300 IN A 1.2.3.4 ; cloudflare_proxy="off" +135 xn--ndaaa 300 IN A 2.2.2.2 ; cloudflare_proxy="off" +136 xn--fiq228c 300 IN A 1.2.3.4 ; cloudflare_proxy="off" +137 a 300 IN CNAME xn--ndaaa.com. ; cloudflare_cname_flatten="off" cloudflare_proxy="off" +138 xn--o-0gab 300 IN CNAME xn--ndaaa.xn--vhquv. ; cloudflare_cname_flatten="off" cloudflare_proxy="off" +139 @ 300 IN CAA 0 issue "letsencrypt.org" +140 @ 300 IN CAA 0 issuewild "letsencrypt.org" +141 @ 300 IN CAA 0 issuewild "example.com" +142 @ 300 IN CAA 0 issuewild ";" +143 @ 300 IN CAA 0 issue "letsencrypt.org; validationmethods=dns-01; accounturi=https://acme-v02.api.letsencrypt.org/acme/acct/1234" +144 @ 300 IN CAA 0 issue "letsencrypt.org" +145 @ 300 IN CAA 128 issue "letsencrypt.org" +146 @ 300 IN LOC 42 21 54.000 N 71 06 18.000 W -24.05m 30m 0.00m 0.00m +147 @ 300 IN LOC 42 21 54.000 N 71 06 18.000 W -24.06m 30m 10m 0.00m +148 @ 300 IN LOC 42 21 54.000 N 71 06 18.000 W -24m 30m 0.00m 0.00m +149 a 300 IN LOC 42 21 43.950 N 71 05 6.340 W -24.33m 1m 200m 10m +150 b 300 IN LOC 52 14 5.000 N 00 08 50.000 E 10.22m 0.00m 0.00m 0.00m +151 c 300 IN LOC 32 07 19.000 S 116 02 25.000 E 10m 0.00m 0.00m 0.00m +152 d 300 IN LOC 42 21 28.760 N 71 00 51.620 W -44m 2000m 0.00m 0.00m +153 test 300 IN NAPTR 100 10 "U" "E2U+sip" "!^.*$!sip:customer-service@example.com!" . +154 test 300 IN NAPTR 103 10 "U" "E2U+email" "!^.*$!mailto:information@example.com!" . +155 test 300 IN NAPTR 103 20 "U" "E2U+email" "!^.*$!mailto:information@example.com!" . +156 test 300 IN NAPTR 103 20 "A" "E2U+email" "!^.*$!mailto:information@example.com!" . +157 test 300 IN NAPTR 103 20 "A" "E2U+sip" "!^.*$!mailto:information@example.com!" . +158 test 300 IN NAPTR 103 20 "A" "E2U+sip" "!^.*$!sip:customer-service@example.com!" . +159 test 300 IN NAPTR 103 20 "A" "E2U+sip" "" example.foo.com. +160 test 300 IN NAPTR 103 20 "A" "E2U+sip" "" example2.foo.com. +161 test 300 IN NAPTR 102 10 "U" "E2U+email" "!^.*$!mailto:information@example.com!" . +162 4 300 IN PTR foo.com. +163 4 300 IN PTR bar.com. +164 _sip._tcp 300 IN SRV 5 6 7 foo.com. +165 _sip._tcp 300 IN SRV 52 6 7 foo.com. +166 _sip._tcp 300 IN SRV 52 62 7 foo.com. +167 _sip._tcp 300 IN SRV 52 62 72 foo.com. +168 _sip._tcp 300 IN SRV 5 60 70 foo2.com. +169 _sip._tcp 300 IN SRV 15 65 75 foo3.com. +170 _sip._tcp 300 IN SRV 15 65 75 foo4.com. +171 _sip._tcp 300 IN SRV 15 65 75 . +172 _sip._tcp 333 IN SRV 5 6 7 foo.com. +173 _sip._tcp 4400 IN SRV 5 6 7 foo.com. +174 @ 300 IN SSHFP 1 1 66C7D5540B7D75A1FB4C84FEBFA178AD99BDD67C +175 @ 300 IN SSHFP 2 1 66C7D5540B7D75A1FB4C84FEBFA178AD99BDD67C +176 @ 300 IN SSHFP 2 2 745A635BC46A397A5C4F21D437483005BCC40D7511FF15FBFAFE913A081559BC +177 _443._tcp 300 IN TLSA 3 1 1 0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF +178 _443._tcp 300 IN TLSA 2 1 1 0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF +179 _443._tcp 300 IN TLSA 2 0 1 0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF +180 _443._tcp 300 IN TLSA 2 0 2 0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF +181 _443._tcp 300 IN TLSA 2 0 2 FEDCBA9876543210FEDCBA9876543210FEDCBA9876543210FEDCBA9876543210FEDCBA9876543210FEDCBA9876543210FEDCBA9876543210FEDCBA9876543210 +182 child 300 IN NS ns101.cloudns.net. +183 child 300 IN DS 35632 13 1 1E07663FF507A40874B8605463DD41DE482079D6 +184 child 300 IN DS 2075 13 1 2706D12E256C8FDD9BFB45EFB25FE537E21A82F6 +185 child 300 IN DS 2075 13 2 3F7A1EAC8C813A0BEBD0C3B8AAB387E31945EA0CD5E1D84A2E8E27674566C156 +186 child 300 IN DS 2159 1 4 F50BEFEA333EE2901D72D31A08E1A3CD3F7E943FF4B38CF7C8AD92807F5302F76FB0B419182C0F47FFC71CBCB6EF4BD4 +187 child 300 IN DS 63909 3 4 EEC7FA02E6788DA889B2CE41D43D92F948AB126EDCF83B7037E73CE9531C8E7E45653ABBAA76C2D6E42F98316EDE599B +188 another-child 300 IN NS ns101.cloudns.net. +189 another-child 300 IN DS 35632 13 4 F5F32ABCA6B01AA7A9963012F90B7C8523A1D946185A3AD70B67F3C9F18E7312FA9DD6AB2F7D8382F789213DB173D429 +190 another-child 300 IN DS 2159 1 4 F50BEFEA333EE2901D72D31A08E1A3CD3F7E943FF4B38CF7C8AD92807F5302F76FB0B419182C0F47FFC71CBCB6EF4BD4 +191 another-child 300 IN DS 63909 3 4 EEC7FA02E6788DA889B2CE41D43D92F948AB126EDCF83B7037E73CE9531C8E7E45653ABBAA76C2D6E42F98316EDE599B +192 @ 300 IN CNAME foo.com. ; cloudflare_cname_flatten="off" cloudflare_proxy="off" +193 @ 300 IN CNAME foo2.com. ; cloudflare_cname_flatten="off" cloudflare_proxy="off" +194 foo 300 IN A 1.2.3.4 ; cloudflare_proxy="off" +195 @ 300 IN CNAME foo.dnscontroltest-cf.org. ; cloudflare_cname_flatten="off" cloudflare_proxy="off" +196 test 300 IN CNAME foo.com. ; cloudflare_cname_flatten="off" cloudflare_proxy="off" +197 test 300 IN CNAME foo2.com. ; cloudflare_cname_flatten="off" cloudflare_proxy="off" +198 prxy 300 IN A 174.136.107.111 ; cloudflare_proxy="off" +199 prxy 1 IN A 174.136.107.111 ; cloudflare_proxy="on" +200 prxy 300 IN A 174.136.107.111 ; cloudflare_proxy="off" +201 prxy 1 IN A 174.136.107.111 ; cloudflare_proxy="on" +202 prxy 1 IN A 174.136.107.111 ; cloudflare_proxy="on" +203 prxy 300 IN A 174.136.107.111 ; cloudflare_proxy="off" +204 cproxy 300 IN CNAME example.com. ; cloudflare_cname_flatten="off" cloudflare_proxy="off" +205 cproxy 1 IN CNAME example.com. ; cloudflare_cname_flatten="off" cloudflare_proxy="on" +206 cproxy 300 IN CNAME example.com. ; cloudflare_cname_flatten="off" cloudflare_proxy="off" +207 cproxy 1 IN CNAME example.com. ; cloudflare_cname_flatten="off" cloudflare_proxy="on" +208 cproxy 1 IN CNAME example.com. ; cloudflare_cname_flatten="off" cloudflare_proxy="on" +209 cproxy 300 IN CNAME example.com. ; cloudflare_cname_flatten="off" cloudflare_proxy="off" +210 cmnt 300 IN A 174.136.107.111 ; cloudflare_comment="Test comment" cloudflare_proxy="off" +211 cmnt 300 IN A 174.136.107.111 ; cloudflare_comment="Changed comment" cloudflare_proxy="off" +212 cmnt 300 IN A 174.136.107.111 ; cloudflare_proxy="off" +213 bar 300 IN A 5.5.5.5 ; cloudflare_proxy="off" +214 foo 300 IN A 1.2.3.4 ; cloudflare_proxy="off" +215 foo 300 IN A 2.3.4.5 ; cloudflare_proxy="off" +216 foo 300 IN TXT "simple" +217 mail 300 IN CNAME ghs.googlehosted.com. ; cloudflare_cname_flatten="off" cloudflare_proxy="off" +218 @ 300 IN A 1.2.3.4 ; cloudflare_proxy="off" +219 @ 300 IN A 2.3.4.5 ; cloudflare_proxy="off" +220 @ 300 IN TXT "simple" +221 bar 300 IN A 5.5.5.5 ; cloudflare_proxy="off" +222 mail 300 IN CNAME ghs.googlehosted.com. ; cloudflare_cname_flatten="off" cloudflare_proxy="off" +223 @ 300 IN A 2.2.2.2 ; cloudflare_proxy="off" +224 @ 300 IN TXT "asimple" +225 foo 300 IN A 1.2.3.4 ; cloudflare_proxy="off" +226 foo 300 IN TXT "simple" +227 bar.bat 300 IN A 5.5.5.5 ; cloudflare_proxy="off" +228 foo.bat 300 IN A 1.2.3.4 ; cloudflare_proxy="off" +229 foo.bat 300 IN A 2.3.4.5 ; cloudflare_proxy="off" +230 foo.bat 300 IN TXT "simple" +231 mail.bat 300 IN CNAME ghs.googlehosted.com. ; cloudflare_cname_flatten="off" cloudflare_proxy="off" +232 foo 300 IN A 1.1.1.1 ; cloudflare_proxy="off" +233 foo 300 IN A 10.10.10.10 ; cloudflare_proxy="off" +234 foo 300 IN A 11.11.11.11 ; cloudflare_proxy="off" +235 foo 300 IN A 12.12.12.12 ; cloudflare_proxy="off" +236 foo 300 IN A 13.13.13.13 ; cloudflare_proxy="off" +237 foo 300 IN A 14.14.14.14 ; cloudflare_proxy="off" +238 foo 300 IN AAAA 2003:dd:d7ff::fe71:aaaa ; cloudflare_proxy="off" +239 foo 300 IN MX 10 aspmx.l.google.com. +240 foo 300 IN MX 20 alt1.aspmx.l.google.com. +241 zzz 300 IN A 3.3.3.3 ; cloudflare_proxy="off" +242 zzz 300 IN A 4.4.4.4 ; cloudflare_proxy="off" +243 zzz 300 IN AAAA 2003:dd:d7ff::fe71:cccc ; cloudflare_proxy="off" +244 bar 300 IN CNAME redact2.acm-validations.aws. ; cloudflare_cname_flatten="off" cloudflare_proxy="off" +245 foo 300 IN CNAME redact1.acm-validations.aws. ; cloudflare_cname_flatten="off" cloudflare_proxy="off" +246 dyndns-city1 300 IN A 91.42.1.1 ; cloudflare_proxy="off" +247 dyndns-city1 300 IN AAAA 2003:dd:d7ff::fe71:ce77 ; cloudflare_proxy="off" +248 dyndns-city2 300 IN A 91.42.1.2 ; cloudflare_proxy="off" +249 dyndns-city2 300 IN AAAA 2003:dd:d7ff::fe71:ce78 ; cloudflare_proxy="off" +250 testdefined 300 IN A 9.9.9.9 ; cloudflare_proxy="off" +251 testdefined 300 IN A 2.2.2.2 ; cloudflare_proxy="off" +252 testignore 300 IN A 8.8.8.8 ; cloudflare_proxy="off" +253 final 300 IN TXT "TestDNSProviders was successful!" +254 final 300 IN TXT "TestDNSProviders was successful!" diff --git a/providers/cloudflare/test_data/meta.json b/providers/cloudflare/test_data/meta.json new file mode 100644 index 0000000000..d60053ffcb --- /dev/null +++ b/providers/cloudflare/test_data/meta.json @@ -0,0 +1,11 @@ +{ + "version": 1, + "recordings": [ + { + "domain": "dnscontroltest-cf.org", + "to_rc": [ + "nativeToRecord" + ] + } + ] +} diff --git a/providers/cloudflare/test_data/recorded_torc_input_nativeToRecord_dnscontroltest-cf.org.json b/providers/cloudflare/test_data/recorded_torc_input_nativeToRecord_dnscontroltest-cf.org.json new file mode 100644 index 0000000000..50e3b27a50 --- /dev/null +++ b/providers/cloudflare/test_data/recorded_torc_input_nativeToRecord_dnscontroltest-cf.org.json @@ -0,0 +1,4461 @@ +[ + { + "index": 1, + "value": { + "created_on": "2026-08-08T12:56:45.24591Z", + "modified_on": "2026-08-08T12:56:47.019851Z", + "type": "AAAA", + "name": "testaaaa.dnscontroltest-cf.org", + "content": "2607:f8b0:4006:820::2013", + "meta": {}, + "id": "71870c9417ec439ddbe791b8b085bc3c", + "ttl": 300, + "proxied": false, + "proxiable": true, + "settings": {} + } + }, + { + "index": 2, + "value": { + "created_on": "2026-08-08T13:02:02.642385Z", + "modified_on": "2026-08-08T13:02:02.642385Z", + "type": "A", + "name": "testa.dnscontroltest-cf.org", + "content": "1.1.1.1", + "meta": {}, + "id": "4d63432a041cec9da1db39bab3a2db6d", + "ttl": 300, + "proxied": false, + "settings": {} + } + }, + { + "index": 3, + "value": { + "created_on": "2026-08-08T13:02:02.642385Z", + "modified_on": "2026-08-08T13:02:04.44276Z", + "type": "A", + "name": "testa.dnscontroltest-cf.org", + "content": "3.3.3.3", + "meta": {}, + "id": "4d63432a041cec9da1db39bab3a2db6d", + "ttl": 300, + "proxied": false, + "proxiable": true, + "settings": {} + } + }, + { + "index": 4, + "value": { + "created_on": "2026-08-08T13:02:07.202078Z", + "modified_on": "2026-08-08T13:02:07.202078Z", + "type": "A", + "name": "dnscontroltest-cf.org", + "content": "2.2.2.2", + "meta": {}, + "id": "915ccdcc86b78fc051a458eabb2698ec", + "ttl": 300, + "proxied": false, + "proxiable": true, + "settings": {} + } + }, + { + "index": 5, + "value": { + "created_on": "2026-08-08T13:02:07.202078Z", + "modified_on": "2026-08-08T13:02:08.911922Z", + "type": "A", + "name": "dnscontroltest-cf.org", + "content": "4.4.4.4", + "meta": {}, + "id": "915ccdcc86b78fc051a458eabb2698ec", + "ttl": 300, + "proxied": false, + "proxiable": true, + "settings": {} + } + }, + { + "index": 6, + "value": { + "created_on": "2026-08-08T13:02:11.661151Z", + "modified_on": "2026-08-08T13:02:11.661151Z", + "type": "A", + "name": "*.dnscontroltest-cf.org", + "content": "3.3.3.3", + "meta": {}, + "id": "5bf27c7fc56ea117917f79707b7013f4", + "ttl": 300, + "proxied": false, + "proxiable": true, + "settings": {} + } + }, + { + "index": 7, + "value": { + "created_on": "2026-08-08T13:02:11.955078Z", + "modified_on": "2026-08-08T13:02:11.955078Z", + "type": "A", + "name": "www.dnscontroltest-cf.org", + "content": "5.5.5.5", + "meta": {}, + "id": "01e619b09610f2a44fc5871148fb8eb0", + "ttl": 300, + "proxied": false, + "proxiable": true, + "settings": {} + } + }, + { + "index": 8, + "value": { + "created_on": "2026-08-08T13:02:16.436654Z", + "modified_on": "2026-08-08T13:02:16.436654Z", + "type": "AAAA", + "name": "testaaaa.dnscontroltest-cf.org", + "content": "2607:f8b0:4006:820::2006", + "meta": {}, + "id": "51767d189b6c8ab6041d12c98190b545", + "ttl": 300, + "proxied": false, + "proxiable": true, + "settings": {} + } + }, + { + "index": 9, + "value": { + "created_on": "2026-08-08T13:02:16.436654Z", + "modified_on": "2026-08-08T13:02:18.150517Z", + "type": "AAAA", + "name": "testaaaa.dnscontroltest-cf.org", + "content": "2607:f8b0:4006:820::2013", + "meta": {}, + "id": "51767d189b6c8ab6041d12c98190b545", + "ttl": 300, + "proxied": false, + "proxiable": true, + "settings": {} + } + }, + { + "index": 10, + "value": { + "created_on": "2026-08-08T13:02:20.913234Z", + "modified_on": "2026-08-08T13:02:20.913234Z", + "type": "CNAME", + "name": "testcname.dnscontroltest-cf.org", + "content": "www.google.com", + "meta": {}, + "id": "a0358ffe34d43a04526cd22ecc8fcf60", + "ttl": 300, + "proxied": false, + "proxiable": true, + "settings": { + "flatten_cname": false + } + } + }, + { + "index": 11, + "value": { + "created_on": "2026-08-08T13:02:20.913234Z", + "modified_on": "2026-08-08T13:02:22.688385Z", + "type": "CNAME", + "name": "testcname.dnscontroltest-cf.org", + "content": "www.yahoo.com", + "meta": {}, + "id": "a0358ffe34d43a04526cd22ecc8fcf60", + "ttl": 300, + "proxied": false, + "proxiable": true, + "settings": { + "flatten_cname": false + } + } + }, + { + "index": 12, + "value": { + "created_on": "2026-08-08T13:02:25.439872Z", + "modified_on": "2026-08-08T13:02:25.439872Z", + "type": "A", + "name": "foo.dnscontroltest-cf.org", + "content": "1.2.3.4", + "meta": {}, + "id": "97da90540c354010717b1e1bf0e3b6af", + "ttl": 300, + "proxied": false, + "proxiable": true, + "settings": {} + } + }, + { + "index": 13, + "value": { + "created_on": "2026-08-08T13:02:25.681328Z", + "modified_on": "2026-08-08T13:02:25.681328Z", + "type": "CNAME", + "name": "testcname.dnscontroltest-cf.org", + "content": "foo.dnscontroltest-cf.org", + "meta": {}, + "id": "d80483b0e7bb654b8a44783019e4201d", + "ttl": 300, + "proxied": false, + "proxiable": true, + "settings": { + "flatten_cname": false + } + } + }, + { + "index": 14, + "value": { + "created_on": "2026-08-08T13:02:28.653707Z", + "modified_on": "2026-08-08T13:02:28.653707Z", + "type": "MX", + "name": "dnscontroltest-cf.org", + "content": "foo.com", + "meta": {}, + "id": "eeefe6382d0946548d86c8316c76fdeb", + "priority": 5, + "ttl": 300, + "proxied": false, + "settings": {} + } + }, + { + "index": 15, + "value": { + "created_on": "2026-08-08T13:02:28.653707Z", + "modified_on": "2026-08-08T13:02:30.399078Z", + "type": "MX", + "name": "dnscontroltest-cf.org", + "content": "bar.com", + "meta": {}, + "id": "eeefe6382d0946548d86c8316c76fdeb", + "priority": 5, + "ttl": 300, + "proxied": false, + "settings": {} + } + }, + { + "index": 16, + "value": { + "created_on": "2026-08-08T13:02:32.412885Z", + "modified_on": "2026-08-08T13:02:32.412885Z", + "type": "MX", + "name": "testmx.dnscontroltest-cf.org", + "content": "foo.com", + "meta": {}, + "id": "f6a344ecdca8d699d5218819ab789ee5", + "priority": 5, + "ttl": 300, + "proxied": false, + "settings": {} + } + }, + { + "index": 17, + "value": { + "created_on": "2026-08-08T13:02:32.412885Z", + "modified_on": "2026-08-08T13:02:34.159077Z", + "type": "MX", + "name": "testmx.dnscontroltest-cf.org", + "content": "bar.com", + "meta": {}, + "id": "f6a344ecdca8d699d5218819ab789ee5", + "priority": 5, + "ttl": 300, + "proxied": false, + "settings": {} + } + }, + { + "index": 18, + "value": { + "created_on": "2026-08-08T13:02:36.898869Z", + "modified_on": "2026-08-08T13:02:36.898869Z", + "type": "MX", + "name": "testmx.dnscontroltest-cf.org", + "content": "foo.com", + "meta": {}, + "id": "a54f497113dc1b7b376a3999c625c684", + "priority": 5, + "ttl": 300, + "proxied": false, + "settings": {} + } + }, + { + "index": 19, + "value": { + "created_on": "2026-08-08T13:02:36.898869Z", + "modified_on": "2026-08-08T13:02:38.648237Z", + "type": "MX", + "name": "testmx.dnscontroltest-cf.org", + "content": "foo.com", + "meta": {}, + "id": "a54f497113dc1b7b376a3999c625c684", + "priority": 100, + "ttl": 300, + "proxied": false, + "settings": {} + } + }, + { + "index": 20, + "value": { + "created_on": "2026-08-08T13:02:41.416204Z", + "modified_on": "2026-08-08T13:02:41.416204Z", + "type": "TXT", + "name": "testtxt.dnscontroltest-cf.org", + "content": "\"simple\"", + "meta": {}, + "id": "69c169ed9e2c6ae16ed82775d41698a5", + "ttl": 300, + "proxied": false, + "settings": {} + } + }, + { + "index": 21, + "value": { + "created_on": "2026-08-08T13:02:41.416204Z", + "modified_on": "2026-08-08T13:02:43.165891Z", + "type": "TXT", + "name": "testtxt.dnscontroltest-cf.org", + "content": "\"changed\"", + "meta": {}, + "id": "69c169ed9e2c6ae16ed82775d41698a5", + "ttl": 300, + "proxied": false, + "settings": {} + } + }, + { + "index": 22, + "value": { + "created_on": "2026-08-08T13:02:46.619773Z", + "modified_on": "2026-08-08T13:02:46.619773Z", + "type": "A", + "name": "www.dnscontroltest-cf.org", + "content": "1.1.1.1", + "meta": {}, + "id": "bae001c7d76124b4c54adce39adb1a11", + "ttl": 300, + "proxied": false, + "settings": {} + } + }, + { + "index": 23, + "value": { + "created_on": "2026-08-08T13:02:47.003404Z", + "modified_on": "2026-08-08T13:02:47.003404Z", + "type": "A", + "name": "www.dnscontroltest-cf.org", + "content": "2.2.2.2", + "meta": {}, + "id": "e6026ba2b89e2e3c780f49f361565cf3", + "ttl": 300, + "proxied": false, + "proxiable": true, + "settings": {} + } + }, + { + "index": 24, + "value": { + "created_on": "2026-08-08T13:02:47.336921Z", + "modified_on": "2026-08-08T13:02:47.336921Z", + "type": "A", + "name": "www.dnscontroltest-cf.org", + "content": "3.3.3.3", + "meta": {}, + "id": "f6cd55d4488832f810a70b7764ab3f44", + "ttl": 300, + "proxied": false, + "proxiable": true, + "settings": {} + } + }, + { + "index": 25, + "value": { + "created_on": "2026-08-08T13:02:51.512025Z", + "modified_on": "2026-08-08T13:02:51.512025Z", + "type": "A", + "name": "www.dnscontroltest-cf.org", + "content": "1.1.1.1", + "meta": {}, + "id": "62e543775d7a56c034b2061629ae9b01", + "ttl": 300, + "proxied": false, + "settings": {} + } + }, + { + "index": 26, + "value": { + "created_on": "2026-08-08T13:02:53.273116Z", + "modified_on": "2026-08-08T13:02:53.273116Z", + "type": "A", + "name": "www.dnscontroltest-cf.org", + "content": "2.2.2.2", + "meta": {}, + "id": "264e471540c25f8cce18a10568476b33", + "ttl": 300, + "proxied": false, + "proxiable": true, + "settings": {} + } + }, + { + "index": 27, + "value": { + "created_on": "2026-08-08T13:02:55.088856Z", + "modified_on": "2026-08-08T13:02:55.088856Z", + "type": "A", + "name": "www.dnscontroltest-cf.org", + "content": "3.3.3.3", + "meta": {}, + "id": "b123be47dea83e11826798229bd9b03e", + "ttl": 300, + "proxied": false, + "proxiable": true, + "settings": {} + } + }, + { + "index": 28, + "value": { + "created_on": "2026-08-08T13:02:58.301941Z", + "modified_on": "2026-08-08T13:02:58.301941Z", + "type": "MX", + "name": "testmx.dnscontroltest-cf.org", + "content": "bar.com", + "meta": {}, + "id": "c7b034a3bbc60a2b421b469049b0e70f", + "priority": 100, + "ttl": 300, + "proxied": false, + "settings": {} + } + }, + { + "index": 29, + "value": { + "created_on": "2026-08-08T13:02:58.554518Z", + "modified_on": "2026-08-08T13:02:58.554518Z", + "type": "MX", + "name": "testmx.dnscontroltest-cf.org", + "content": "foo.com", + "meta": {}, + "id": "c0f91831d588af4d20c72f0c05d3c745", + "priority": 5, + "ttl": 300, + "proxied": false, + "settings": {} + } + }, + { + "index": 30, + "value": { + "created_on": "2026-08-08T13:02:58.819343Z", + "modified_on": "2026-08-08T13:02:58.819343Z", + "type": "A", + "name": "www.dnscontroltest-cf.org", + "content": "1.1.1.1", + "meta": {}, + "id": "5c14631e25083d7920c7365dfa07fd0a", + "ttl": 300, + "proxied": false, + "settings": {} + } + }, + { + "index": 31, + "value": { + "created_on": "2026-08-08T13:03:02.32705Z", + "modified_on": "2026-08-08T13:03:02.32705Z", + "type": "A", + "name": "www.dnscontroltest-cf.org", + "content": "1.1.1.1", + "meta": {}, + "id": "2dcbe20a3a1488a9c1f6fdb98dc0389d", + "ttl": 300, + "proxied": false, + "settings": {} + } + }, + { + "index": 32, + "value": { + "created_on": "2026-08-08T13:03:03.980246Z", + "modified_on": "2026-08-08T13:03:03.980246Z", + "type": "MX", + "name": "testmx.dnscontroltest-cf.org", + "content": "foo.com", + "meta": {}, + "id": "e732c8e7ce47100b15e152d873422f55", + "priority": 5, + "ttl": 300, + "proxied": false, + "settings": {} + } + }, + { + "index": 33, + "value": { + "created_on": "2026-08-08T13:03:05.77502Z", + "modified_on": "2026-08-08T13:03:05.77502Z", + "type": "MX", + "name": "testmx.dnscontroltest-cf.org", + "content": "bar.com", + "meta": {}, + "id": "d87b90bc03d611eff20ee0aed69a2c92", + "priority": 100, + "ttl": 300, + "proxied": false, + "settings": {} + } + }, + { + "index": 34, + "value": { + "created_on": "2026-08-08T13:03:08.980291Z", + "modified_on": "2026-08-08T13:03:08.980291Z", + "type": "A", + "name": "testa.dnscontroltest-cf.org", + "content": "1.1.1.1", + "meta": {}, + "id": "1e6070a032ab7a7971935fa9ee33aa3c", + "ttl": 333, + "proxied": false, + "settings": {} + } + }, + { + "index": 35, + "value": { + "created_on": "2026-08-08T13:03:08.980291Z", + "modified_on": "2026-08-08T13:03:10.737451Z", + "type": "A", + "name": "testa.dnscontroltest-cf.org", + "content": "1.1.1.1", + "meta": {}, + "id": "1e6070a032ab7a7971935fa9ee33aa3c", + "ttl": 999, + "proxied": false, + "settings": {} + } + }, + { + "index": 36, + "value": { + "created_on": "2026-08-08T13:03:13.48841Z", + "modified_on": "2026-08-08T13:03:13.48841Z", + "type": "A", + "name": "dnscontroltest-cf.org", + "content": "8.8.8.8", + "meta": {}, + "id": "78af21b85ed35d95f4e701bc73005948", + "ttl": 666, + "proxied": false, + "proxiable": true, + "settings": {} + } + }, + { + "index": 37, + "value": { + "created_on": "2026-08-08T13:03:13.48841Z", + "modified_on": "2026-08-08T13:03:15.732884Z", + "type": "A", + "name": "dnscontroltest-cf.org", + "content": "8.8.8.8", + "meta": {}, + "id": "78af21b85ed35d95f4e701bc73005948", + "ttl": 1000, + "proxied": false, + "proxiable": true, + "settings": {} + } + }, + { + "index": 38, + "value": { + "created_on": "2026-08-08T13:03:13.48841Z", + "modified_on": "2026-08-08T13:03:19.231509Z", + "type": "A", + "name": "dnscontroltest-cf.org", + "content": "8.8.8.8", + "meta": {}, + "id": "78af21b85ed35d95f4e701bc73005948", + "ttl": 500, + "proxied": false, + "proxiable": true, + "settings": {} + } + }, + { + "index": 39, + "value": { + "created_on": "2026-08-08T13:03:13.764925Z", + "modified_on": "2026-08-08T13:03:13.764925Z", + "type": "A", + "name": "www.dnscontroltest-cf.org", + "content": "1.2.3.4", + "meta": {}, + "id": "b4bbae45a0686f735639f77febc282d3", + "ttl": 300, + "proxied": false, + "proxiable": true, + "settings": {} + } + }, + { + "index": 40, + "value": { + "created_on": "2026-08-08T13:03:13.764925Z", + "modified_on": "2026-08-08T13:03:17.47529Z", + "type": "A", + "name": "www.dnscontroltest-cf.org", + "content": "2.2.2.2", + "meta": {}, + "id": "b4bbae45a0686f735639f77febc282d3", + "ttl": 300, + "proxied": false, + "proxiable": true, + "settings": {} + } + }, + { + "index": 41, + "value": { + "created_on": "2026-08-08T13:03:13.764925Z", + "modified_on": "2026-08-08T13:03:19.47989Z", + "type": "A", + "name": "www.dnscontroltest-cf.org", + "content": "2.2.2.2", + "meta": {}, + "id": "b4bbae45a0686f735639f77febc282d3", + "ttl": 400, + "proxied": false, + "proxiable": true, + "settings": {} + } + }, + { + "index": 42, + "value": { + "created_on": "2026-08-08T13:03:13.983547Z", + "modified_on": "2026-08-08T13:03:13.983547Z", + "type": "A", + "name": "www.dnscontroltest-cf.org", + "content": "5.6.7.8", + "meta": {}, + "id": "894108ccf13614aa5a5d9e34bbfedee0", + "ttl": 300, + "proxied": false, + "proxiable": true, + "settings": {} + } + }, + { + "index": 43, + "value": { + "created_on": "2026-08-08T13:03:13.983547Z", + "modified_on": "2026-08-08T13:03:19.734342Z", + "type": "A", + "name": "www.dnscontroltest-cf.org", + "content": "5.6.7.8", + "meta": {}, + "id": "894108ccf13614aa5a5d9e34bbfedee0", + "ttl": 400, + "proxied": false, + "proxiable": true, + "settings": {} + } + }, + { + "index": 44, + "value": { + "created_on": "2026-08-08T13:03:23.026971Z", + "modified_on": "2026-08-08T13:03:23.026971Z", + "type": "A", + "name": "www.dnscontroltest-cf.org", + "content": "5.6.7.8", + "meta": {}, + "id": "6ced58a030699df7fce18cafd9e36921", + "ttl": 400, + "proxied": false, + "proxiable": true, + "settings": {} + } + }, + { + "index": 45, + "value": { + "created_on": "2026-08-08T13:03:23.026971Z", + "modified_on": "2026-08-08T13:03:24.739339Z", + "type": "A", + "name": "www.dnscontroltest-cf.org", + "content": "5.6.7.8", + "meta": {}, + "id": "6ced58a030699df7fce18cafd9e36921", + "ttl": 700, + "proxied": false, + "proxiable": true, + "settings": {} + } + }, + { + "index": 46, + "value": { + "created_on": "2026-08-08T13:03:24.97332Z", + "modified_on": "2026-08-08T13:03:24.97332Z", + "type": "A", + "name": "www.dnscontroltest-cf.org", + "content": "1.2.3.4", + "meta": {}, + "id": "650ec2a717b4a601dbfaf5fa955413d5", + "ttl": 700, + "proxied": false, + "proxiable": true, + "settings": {} + } + }, + { + "index": 47, + "value": { + "created_on": "2026-08-08T13:03:28.018489Z", + "modified_on": "2026-08-08T13:03:28.018489Z", + "type": "A", + "name": "foo.dnscontroltest-cf.org", + "content": "1.2.3.4", + "meta": {}, + "id": "eb271f613dc8a90ef1641fb032cc694d", + "ttl": 300, + "proxied": false, + "proxiable": true, + "settings": {} + } + }, + { + "index": 48, + "value": { + "created_on": "2026-08-08T13:03:29.970138Z", + "modified_on": "2026-08-08T13:03:29.970138Z", + "type": "MX", + "name": "foo.dnscontroltest-cf.org", + "content": "mx.google.com", + "meta": {}, + "id": "2dfd7a98bd4e75713dd6723c83b343f0", + "priority": 5, + "ttl": 300, + "proxied": false, + "settings": {} + } + }, + { + "index": 49, + "value": { + "created_on": "2026-08-08T13:03:32.005764Z", + "modified_on": "2026-08-08T13:03:32.005764Z", + "type": "A", + "name": "foo.dnscontroltest-cf.org", + "content": "4.5.6.7", + "meta": {}, + "id": "272f0cd61535d38ed9212d674b544583", + "ttl": 300, + "proxied": false, + "proxiable": true, + "settings": {} + } + }, + { + "index": 50, + "value": { + "created_on": "2026-08-08T13:03:34.725443Z", + "modified_on": "2026-08-08T13:03:34.725443Z", + "type": "CNAME", + "name": "foo.dnscontroltest-cf.org", + "content": "google.com", + "meta": {}, + "id": "685663a64d094a04003396f35e7b8962", + "ttl": 300, + "proxied": false, + "proxiable": true, + "settings": { + "flatten_cname": false + } + } + }, + { + "index": 51, + "value": { + "created_on": "2026-08-08T13:03:36.942054Z", + "modified_on": "2026-08-08T13:03:36.942054Z", + "type": "A", + "name": "foo.dnscontroltest-cf.org", + "content": "1.2.3.4", + "meta": {}, + "id": "7f519c894b8eb5b726d915a638ee9cc8", + "ttl": 300, + "proxied": false, + "proxiable": true, + "settings": {} + } + }, + { + "index": 52, + "value": { + "created_on": "2026-08-08T13:03:38.905518Z", + "modified_on": "2026-08-08T13:03:38.905518Z", + "type": "CNAME", + "name": "foo.dnscontroltest-cf.org", + "content": "google2.com", + "meta": {}, + "id": "23871bf740c378dde39f7605402bf5a7", + "ttl": 300, + "proxied": false, + "proxiable": true, + "settings": { + "flatten_cname": false + } + } + }, + { + "index": 53, + "value": { + "created_on": "2026-08-08T13:03:41.690633Z", + "modified_on": "2026-08-08T13:03:41.690633Z", + "type": "HTTPS", + "name": "dnscontroltest-cf.org", + "content": "0 test.com.", + "meta": {}, + "data": { + "priority": 0, + "target": "test.com.", + "value": "" + }, + "id": "d47fb7ad65bfa500b4f4f4d5937b1bae", + "ttl": 300, + "proxied": false, + "settings": {} + } + }, + { + "index": 54, + "value": { + "created_on": "2026-08-08T13:03:41.690633Z", + "modified_on": "2026-08-08T13:03:43.496178Z", + "type": "HTTPS", + "name": "dnscontroltest-cf.org", + "content": "1 test.com. port=\"80\"", + "meta": {}, + "data": { + "priority": 1, + "target": "test.com.", + "value": "port=\"80\"" + }, + "id": "d47fb7ad65bfa500b4f4f4d5937b1bae", + "ttl": 300, + "proxied": false, + "settings": {} + } + }, + { + "index": 55, + "value": { + "created_on": "2026-08-08T13:03:41.690633Z", + "modified_on": "2026-08-08T13:03:45.159875Z", + "type": "HTTPS", + "name": "dnscontroltest-cf.org", + "content": "1 test.com. port=\"99\"", + "meta": {}, + "data": { + "priority": 1, + "target": "test.com.", + "value": "port=\"99\"" + }, + "id": "d47fb7ad65bfa500b4f4f4d5937b1bae", + "ttl": 300, + "proxied": false, + "settings": {} + } + }, + { + "index": 56, + "value": { + "created_on": "2026-08-08T13:03:41.690633Z", + "modified_on": "2026-08-08T13:03:46.953811Z", + "type": "HTTPS", + "name": "dnscontroltest-cf.org", + "content": "1 test.com. alpn=\"h2\" port=\"99\"", + "meta": {}, + "data": { + "priority": 1, + "target": "test.com.", + "value": "alpn=\"h2\" port=\"99\"" + }, + "id": "d47fb7ad65bfa500b4f4f4d5937b1bae", + "ttl": 300, + "proxied": false, + "settings": {} + } + }, + { + "index": 57, + "value": { + "created_on": "2026-08-08T13:03:41.690633Z", + "modified_on": "2026-08-08T13:03:48.654184Z", + "type": "HTTPS", + "name": "dnscontroltest-cf.org", + "content": "3 example.com. alpn=\"h2,h3\" port=\"999\"", + "meta": {}, + "data": { + "priority": 3, + "target": "example.com.", + "value": "alpn=\"h2,h3\" port=\"999\"" + }, + "id": "d47fb7ad65bfa500b4f4f4d5937b1bae", + "ttl": 300, + "proxied": false, + "settings": {} + } + }, + { + "index": 58, + "value": { + "created_on": "2026-08-08T13:03:51.406681Z", + "modified_on": "2026-08-08T13:03:51.406681Z", + "type": "HTTPS", + "name": "dnscontroltest-cf.org", + "content": "3 example.com. alpn=\"h2,h3\" port=\"999\"", + "meta": {}, + "data": { + "priority": 3, + "target": "example.com.", + "value": "alpn=\"h2,h3\" port=\"999\"" + }, + "id": "e8d643ce3f49c69eb5c525ab34de6d6b", + "ttl": 300, + "proxied": false, + "settings": {} + } + }, + { + "index": 59, + "value": { + "created_on": "2026-08-08T13:03:51.406681Z", + "modified_on": "2026-08-08T13:03:53.152931Z", + "type": "HTTPS", + "name": "dnscontroltest-cf.org", + "content": "3 example.com. alpn=\"h2,h3\" port=\"999\" ech=\"some+base64+encoded+value///\"", + "meta": {}, + "data": { + "priority": 3, + "target": "example.com.", + "value": "alpn=\"h2,h3\" port=\"999\" ech=\"some+base64+encoded+value///\"" + }, + "id": "e8d643ce3f49c69eb5c525ab34de6d6b", + "ttl": 300, + "proxied": false, + "settings": {} + } + }, + { + "index": 60, + "value": { + "created_on": "2026-08-08T13:03:51.406681Z", + "modified_on": "2026-08-08T13:03:56.401414Z", + "type": "HTTPS", + "name": "dnscontroltest-cf.org", + "content": "3 example.com. alpn=\"h2\" port=\"80\" ech=\"some+base64+encoded+value///\"", + "meta": {}, + "data": { + "priority": 3, + "target": "example.com.", + "value": "alpn=\"h2\" port=\"80\" ech=\"some+base64+encoded+value///\"" + }, + "id": "e8d643ce3f49c69eb5c525ab34de6d6b", + "ttl": 300, + "proxied": false, + "settings": {} + } + }, + { + "index": 61, + "value": { + "created_on": "2026-08-08T13:03:51.406681Z", + "modified_on": "2026-08-08T13:03:58.173337Z", + "type": "HTTPS", + "name": "dnscontroltest-cf.org", + "content": "3 example.com. alpn=\"h2\" port=\"80\" ech=\"another+base64+encoded+value\"", + "meta": {}, + "data": { + "priority": 3, + "target": "example.com.", + "value": "alpn=\"h2\" port=\"80\" ech=\"another+base64+encoded+value\"" + }, + "id": "e8d643ce3f49c69eb5c525ab34de6d6b", + "ttl": 300, + "proxied": false, + "settings": {} + } + }, + { + "index": 62, + "value": { + "created_on": "2026-08-08T13:03:51.406681Z", + "modified_on": "2026-08-08T13:03:59.958406Z", + "type": "HTTPS", + "name": "dnscontroltest-cf.org", + "content": "3 yetanother.com. alpn=\"h2\" port=\"80\" ech=\"another+base64+encoded+value\"", + "meta": {}, + "data": { + "priority": 3, + "target": "yetanother.com.", + "value": "alpn=\"h2\" port=\"80\" ech=\"another+base64+encoded+value\"" + }, + "id": "e8d643ce3f49c69eb5c525ab34de6d6b", + "ttl": 300, + "proxied": false, + "settings": {} + } + }, + { + "index": 63, + "value": { + "created_on": "2026-08-08T13:04:02.702296Z", + "modified_on": "2026-08-08T13:04:02.702296Z", + "type": "SVCB", + "name": "dnscontroltest-cf.org", + "content": "0 test.com.", + "meta": {}, + "data": { + "priority": 0, + "target": "test.com.", + "value": "" + }, + "id": "eed01b1c66bfd76fe6beaf41276d32e6", + "ttl": 300, + "proxied": false, + "settings": {} + } + }, + { + "index": 64, + "value": { + "created_on": "2026-08-08T13:04:02.702296Z", + "modified_on": "2026-08-08T13:04:04.486143Z", + "type": "SVCB", + "name": "dnscontroltest-cf.org", + "content": "1 test.com. port=\"80\"", + "meta": {}, + "data": { + "priority": 1, + "target": "test.com.", + "value": "port=\"80\"" + }, + "id": "eed01b1c66bfd76fe6beaf41276d32e6", + "ttl": 300, + "proxied": false, + "settings": {} + } + }, + { + "index": 65, + "value": { + "created_on": "2026-08-08T13:04:02.702296Z", + "modified_on": "2026-08-08T13:04:06.196512Z", + "type": "SVCB", + "name": "dnscontroltest-cf.org", + "content": "1 test.com. port=\"99\"", + "meta": {}, + "data": { + "priority": 1, + "target": "test.com.", + "value": "port=\"99\"" + }, + "id": "eed01b1c66bfd76fe6beaf41276d32e6", + "ttl": 300, + "proxied": false, + "settings": {} + } + }, + { + "index": 66, + "value": { + "created_on": "2026-08-08T13:04:02.702296Z", + "modified_on": "2026-08-08T13:04:07.991185Z", + "type": "SVCB", + "name": "dnscontroltest-cf.org", + "content": "1 test.com. alpn=\"h2\" port=\"99\"", + "meta": {}, + "data": { + "priority": 1, + "target": "test.com.", + "value": "alpn=\"h2\" port=\"99\"" + }, + "id": "eed01b1c66bfd76fe6beaf41276d32e6", + "ttl": 300, + "proxied": false, + "settings": {} + } + }, + { + "index": 67, + "value": { + "created_on": "2026-08-08T13:04:02.702296Z", + "modified_on": "2026-08-08T13:04:09.704154Z", + "type": "SVCB", + "name": "dnscontroltest-cf.org", + "content": "3 example.com. alpn=\"h2,h3\" port=\"999\"", + "meta": {}, + "data": { + "priority": 3, + "target": "example.com.", + "value": "alpn=\"h2,h3\" port=\"999\"" + }, + "id": "eed01b1c66bfd76fe6beaf41276d32e6", + "ttl": 300, + "proxied": false, + "settings": {} + } + }, + { + "index": 68, + "value": { + "created_on": "2026-08-08T13:04:12.457169Z", + "modified_on": "2026-08-08T13:04:12.457169Z", + "type": "SVCB", + "name": "dnscontroltest-cf.org", + "content": "3 example.com. alpn=\"h2,h3\" port=\"999\"", + "meta": {}, + "data": { + "priority": 3, + "target": "example.com.", + "value": "alpn=\"h2,h3\" port=\"999\"" + }, + "id": "c290d81627af490e273a88c253372ba9", + "ttl": 300, + "proxied": false, + "settings": {} + } + }, + { + "index": 69, + "value": { + "created_on": "2026-08-08T13:04:12.457169Z", + "modified_on": "2026-08-08T13:04:14.359448Z", + "type": "SVCB", + "name": "dnscontroltest-cf.org", + "content": "3 example.com. alpn=\"h2,h3\" port=\"999\" ech=\"some+base64+encoded+value///\"", + "meta": {}, + "data": { + "priority": 3, + "target": "example.com.", + "value": "alpn=\"h2,h3\" port=\"999\" ech=\"some+base64+encoded+value///\"" + }, + "id": "c290d81627af490e273a88c253372ba9", + "ttl": 300, + "proxied": false, + "settings": {} + } + }, + { + "index": 70, + "value": { + "created_on": "2026-08-08T13:04:12.457169Z", + "modified_on": "2026-08-08T13:04:17.559394Z", + "type": "SVCB", + "name": "dnscontroltest-cf.org", + "content": "3 example.com. alpn=\"h2\" port=\"80\" ech=\"some+base64+encoded+value///\"", + "meta": {}, + "data": { + "priority": 3, + "target": "example.com.", + "value": "alpn=\"h2\" port=\"80\" ech=\"some+base64+encoded+value///\"" + }, + "id": "c290d81627af490e273a88c253372ba9", + "ttl": 300, + "proxied": false, + "settings": {} + } + }, + { + "index": 71, + "value": { + "created_on": "2026-08-08T13:04:12.457169Z", + "modified_on": "2026-08-08T13:04:19.384543Z", + "type": "SVCB", + "name": "dnscontroltest-cf.org", + "content": "3 example.com. alpn=\"h2\" port=\"80\" ech=\"another+base64+encoded+value\"", + "meta": {}, + "data": { + "priority": 3, + "target": "example.com.", + "value": "alpn=\"h2\" port=\"80\" ech=\"another+base64+encoded+value\"" + }, + "id": "c290d81627af490e273a88c253372ba9", + "ttl": 300, + "proxied": false, + "settings": {} + } + }, + { + "index": 72, + "value": { + "created_on": "2026-08-08T13:04:12.457169Z", + "modified_on": "2026-08-08T13:04:21.104484Z", + "type": "SVCB", + "name": "dnscontroltest-cf.org", + "content": "3 yetanother.com. alpn=\"h2\" port=\"80\" ech=\"another+base64+encoded+value\"", + "meta": {}, + "data": { + "priority": 3, + "target": "yetanother.com.", + "value": "alpn=\"h2\" port=\"80\" ech=\"another+base64+encoded+value\"" + }, + "id": "c290d81627af490e273a88c253372ba9", + "ttl": 300, + "proxied": false, + "settings": {} + } + }, + { + "index": 73, + "value": { + "created_on": "2026-08-08T13:04:23.911006Z", + "modified_on": "2026-08-08T13:04:23.911006Z", + "type": "A", + "name": "dnscontroltest-cf.org", + "content": "1.2.3.4", + "meta": {}, + "id": "672f9bb3e5654751100372a88c95d0d2", + "ttl": 300, + "proxied": false, + "proxiable": true, + "settings": {} + } + }, + { + "index": 74, + "value": { + "created_on": "2026-08-08T13:04:24.201976Z", + "modified_on": "2026-08-08T13:04:24.201976Z", + "type": "CNAME", + "name": "foo.dnscontroltest-cf.org", + "content": "dnscontroltest-cf.org", + "meta": {}, + "id": "4264c1ca75b97ba36e64abf16b0010f8", + "ttl": 300, + "proxied": false, + "proxiable": true, + "settings": { + "flatten_cname": false + } + } + }, + { + "index": 75, + "value": { + "created_on": "2026-08-08T13:04:27.179664Z", + "modified_on": "2026-08-08T13:04:27.179664Z", + "type": "A", + "name": "dnscontroltest-cf.org", + "content": "1.2.3.4", + "meta": {}, + "id": "a240f72cd196520a6e8787cb5a4acfd9", + "ttl": 300, + "proxied": false, + "proxiable": true, + "settings": {} + } + }, + { + "index": 76, + "value": { + "created_on": "2026-08-08T13:04:27.430805Z", + "modified_on": "2026-08-08T13:04:27.430805Z", + "type": "MX", + "name": "foo.dnscontroltest-cf.org", + "content": "dnscontroltest-cf.org", + "meta": {}, + "id": "861a26ca0312885c31e26e3ec17bb23b", + "priority": 8, + "ttl": 300, + "proxied": false, + "settings": {} + } + }, + { + "index": 77, + "value": { + "created_on": "2026-08-08T13:04:30.411298Z", + "modified_on": "2026-08-08T13:04:30.411298Z", + "type": "A", + "name": "nmx.dnscontroltest-cf.org", + "content": "1.2.3.3", + "meta": {}, + "id": "81062feb73ef9136873211963c1a08de", + "ttl": 300, + "proxied": false, + "proxiable": true, + "settings": {} + } + }, + { + "index": 78, + "value": { + "created_on": "2026-08-08T13:04:30.715917Z", + "modified_on": "2026-08-08T13:04:30.715917Z", + "type": "MX", + "name": "nmx.dnscontroltest-cf.org", + "content": ".", + "meta": {}, + "id": "4b0315a995bd9487684d58b37a3327a4", + "priority": 0, + "ttl": 300, + "proxied": false, + "settings": {} + } + }, + { + "index": 79, + "value": { + "created_on": "2026-08-08T13:04:30.715917Z", + "modified_on": "2026-08-08T13:04:32.893687Z", + "type": "MX", + "name": "nmx.dnscontroltest-cf.org", + "content": "nmx.dnscontroltest-cf.org", + "meta": {}, + "id": "4b0315a995bd9487684d58b37a3327a4", + "priority": 3, + "ttl": 300, + "proxied": false, + "settings": {} + } + }, + { + "index": 80, + "value": { + "created_on": "2026-08-08T13:04:30.715917Z", + "modified_on": "2026-08-08T13:04:34.641372Z", + "type": "MX", + "name": "nmx.dnscontroltest-cf.org", + "content": ".", + "meta": {}, + "id": "4b0315a995bd9487684d58b37a3327a4", + "priority": 0, + "ttl": 300, + "proxied": false, + "settings": {} + } + }, + { + "index": 81, + "value": { + "created_on": "2026-08-08T13:04:30.925202Z", + "modified_on": "2026-08-08T13:04:30.925202Z", + "type": "A", + "name": "www.dnscontroltest-cf.org", + "content": "1.2.3.9", + "meta": {}, + "id": "a0b6097889eef404b8c7aacae378c199", + "ttl": 300, + "proxied": false, + "proxiable": true, + "settings": {} + } + }, + { + "index": 82, + "value": { + "created_on": "2026-08-08T13:04:32.67004Z", + "modified_on": "2026-08-08T13:04:32.67004Z", + "type": "MX", + "name": "nmx.dnscontroltest-cf.org", + "content": "www.dnscontroltest-cf.org", + "meta": {}, + "id": "dd2a69f20a7f5eff6cdf18aea7d08ba6", + "priority": 9, + "ttl": 300, + "proxied": false, + "settings": {} + } + }, + { + "index": 83, + "value": { + "created_on": "2026-08-08T13:04:38.202465Z", + "modified_on": "2026-08-08T13:04:38.202465Z", + "type": "A", + "name": "dnscontroltest-cf.org", + "content": "1.2.3.2", + "meta": {}, + "id": "0b5c2c027f1682ce797e35d4323a5e14", + "ttl": 300, + "proxied": false, + "proxiable": true, + "settings": {} + } + }, + { + "index": 84, + "value": { + "created_on": "2026-08-08T13:04:38.395214Z", + "modified_on": "2026-08-08T13:04:38.395214Z", + "type": "MX", + "name": "dnscontroltest-cf.org", + "content": ".", + "meta": {}, + "id": "bd790b25c79bca2f0bc6f1b99f87c4d8", + "priority": 0, + "ttl": 300, + "proxied": false, + "settings": {} + } + }, + { + "index": 85, + "value": { + "created_on": "2026-08-08T13:04:38.395214Z", + "modified_on": "2026-08-08T13:04:40.668139Z", + "type": "MX", + "name": "dnscontroltest-cf.org", + "content": "dnscontroltest-cf.org", + "meta": {}, + "id": "bd790b25c79bca2f0bc6f1b99f87c4d8", + "priority": 2, + "ttl": 300, + "proxied": false, + "settings": {} + } + }, + { + "index": 86, + "value": { + "created_on": "2026-08-08T13:04:38.395214Z", + "modified_on": "2026-08-08T13:04:42.450923Z", + "type": "MX", + "name": "dnscontroltest-cf.org", + "content": ".", + "meta": {}, + "id": "bd790b25c79bca2f0bc6f1b99f87c4d8", + "priority": 0, + "ttl": 300, + "proxied": false, + "settings": {} + } + }, + { + "index": 87, + "value": { + "created_on": "2026-08-08T13:04:38.699475Z", + "modified_on": "2026-08-08T13:04:38.699475Z", + "type": "A", + "name": "www.dnscontroltest-cf.org", + "content": "1.2.3.8", + "meta": {}, + "id": "a65394b2236af47d26d0449cdec76b50", + "ttl": 300, + "proxied": false, + "proxiable": true, + "settings": {} + } + }, + { + "index": 88, + "value": { + "created_on": "2026-08-08T13:04:40.447971Z", + "modified_on": "2026-08-08T13:04:40.447971Z", + "type": "MX", + "name": "dnscontroltest-cf.org", + "content": "www.dnscontroltest-cf.org", + "meta": {}, + "id": "0741ba92473f03cafa36f8348738b92a", + "priority": 8, + "ttl": 300, + "proxied": false, + "settings": {} + } + }, + { + "index": 89, + "value": { + "created_on": "2026-08-08T13:04:45.912761Z", + "modified_on": "2026-08-08T13:04:45.912761Z", + "type": "NS", + "name": "xyz.dnscontroltest-cf.org", + "content": "ns2.foo.com", + "meta": {}, + "id": "861dca1dc28ca8cbb2a65e0c680d8eeb", + "ttl": 300, + "proxied": false, + "settings": {} + } + }, + { + "index": 90, + "value": { + "created_on": "2026-08-08T13:04:47.690493Z", + "modified_on": "2026-08-08T13:04:47.690493Z", + "type": "NS", + "name": "xyz.dnscontroltest-cf.org", + "content": "ns1.foo.com", + "meta": {}, + "id": "7d8059e93f2d1e1976f444c1eb04c372", + "ttl": 300, + "proxied": false, + "settings": {} + } + }, + { + "index": 91, + "value": { + "created_on": "2026-08-08T13:04:49.398774Z", + "modified_on": "2026-08-08T13:04:49.398774Z", + "type": "NS", + "name": "foo.dnscontroltest-cf.org", + "content": "dnscontroltest-cf.org", + "meta": {}, + "id": "abe923875cccd34dfb50e4411fd09de4", + "ttl": 300, + "proxied": false, + "settings": {} + } + }, + { + "index": 92, + "value": { + "created_on": "2026-08-08T13:04:49.659023Z", + "modified_on": "2026-08-08T13:04:49.659023Z", + "type": "A", + "name": "dnscontroltest-cf.org", + "content": "1.2.3.4", + "meta": {}, + "id": "fad8e68a0e656604ca67095e31046d38", + "ttl": 300, + "proxied": false, + "proxiable": true, + "settings": {} + } + }, + { + "index": 93, + "value": { + "created_on": "2026-08-08T13:04:53.155073Z", + "modified_on": "2026-08-08T13:04:53.155073Z", + "type": "NS", + "name": "dnscontroltest-cf.org", + "content": "ns1.foo.com", + "meta": {}, + "id": "df23b36252b91b5128558165fc0b5cff", + "ttl": 300, + "proxied": false, + "settings": {} + } + }, + { + "index": 94, + "value": { + "created_on": "2026-08-08T13:04:54.901054Z", + "modified_on": "2026-08-08T13:04:54.901054Z", + "type": "NS", + "name": "dnscontroltest-cf.org", + "content": "ns2.foo.com", + "meta": {}, + "id": "033f2543b4a88df4527fc1bde0bb77bf", + "ttl": 300, + "proxied": false, + "settings": {} + } + }, + { + "index": 95, + "value": { + "created_on": "2026-08-08T13:04:57.899058Z", + "modified_on": "2026-08-08T13:04:57.899058Z", + "type": "TXT", + "name": "foo254.dnscontroltest-cf.org", + "content": "\"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\"", + "meta": {}, + "id": "e8d94ed0658286b35575c49eb8833ba6", + "ttl": 300, + "proxied": false, + "settings": {} + } + }, + { + "index": 96, + "value": { + "created_on": "2026-08-08T13:04:59.941737Z", + "modified_on": "2026-08-08T13:04:59.941737Z", + "type": "TXT", + "name": "foo255.dnscontroltest-cf.org", + "content": "\"BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB\"", + "meta": {}, + "id": "212a03414dcc0c8ff61008c1ef896ee1", + "ttl": 300, + "proxied": false, + "settings": {} + } + }, + { + "index": 97, + "value": { + "created_on": "2026-08-08T13:05:03.303701Z", + "modified_on": "2026-08-08T13:05:03.303701Z", + "type": "TXT", + "name": "foo256.dnscontroltest-cf.org", + "content": "\"CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC\" \"C\"", + "meta": {}, + "id": "8144d489b231ba0f323f12857017bfd0", + "ttl": 300, + "proxied": false, + "settings": {} + } + }, + { + "index": 98, + "value": { + "created_on": "2026-08-08T13:05:05.502296Z", + "modified_on": "2026-08-08T13:05:05.502296Z", + "type": "TXT", + "name": "foo509.dnscontroltest-cf.org", + "content": "\"DDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDD\" \"DDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDD\"", + "meta": {}, + "id": "074f7d5b1643641bdca5fc2ac5ebd73a", + "ttl": 300, + "proxied": false, + "settings": {} + } + }, + { + "index": 99, + "value": { + "created_on": "2026-08-08T13:05:07.499709Z", + "modified_on": "2026-08-08T13:05:07.499709Z", + "type": "TXT", + "name": "foo510.dnscontroltest-cf.org", + "content": "\"EEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE\" \"EEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE\"", + "meta": {}, + "id": "dd7d9f2f9d8a2d016448abe2efe734d9", + "ttl": 300, + "proxied": false, + "settings": {} + } + }, + { + "index": 100, + "value": { + "created_on": "2026-08-08T13:05:09.493751Z", + "modified_on": "2026-08-08T13:05:09.493751Z", + "type": "TXT", + "name": "foo511.dnscontroltest-cf.org", + "content": "\"FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF\" \"FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF\" \"F\"", + "meta": {}, + "id": "18d563eee086e6dce4df871e8f2595bc", + "ttl": 300, + "proxied": false, + "settings": {} + } + }, + { + "index": 101, + "value": { + "created_on": "2026-08-08T13:05:11.475321Z", + "modified_on": "2026-08-08T13:05:11.475321Z", + "type": "TXT", + "name": "foo764.dnscontroltest-cf.org", + "content": "\"GGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGG\" \"GGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGG\" \"GGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGG\"", + "meta": {}, + "id": "adadbcf062c711bb96b31765cbd627be", + "ttl": 300, + "proxied": false, + "settings": {} + } + }, + { + "index": 102, + "value": { + "created_on": "2026-08-08T13:05:13.485677Z", + "modified_on": "2026-08-08T13:05:13.485677Z", + "type": "TXT", + "name": "foo765.dnscontroltest-cf.org", + "content": "\"HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH\" \"HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH\" \"HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH\"", + "meta": {}, + "id": "c34c978b7679f0f8df96fd3a767c1bd3", + "ttl": 300, + "proxied": false, + "settings": {} + } + }, + { + "index": 103, + "value": { + "created_on": "2026-08-08T13:05:15.473228Z", + "modified_on": "2026-08-08T13:05:15.473228Z", + "type": "TXT", + "name": "foo766.dnscontroltest-cf.org", + "content": "\"JJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJ\" \"JJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJ\" \"JJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJ\" \"J\"", + "meta": {}, + "id": "e5c34c7831a36dab8145cfa45750abf2", + "ttl": 300, + "proxied": false, + "settings": {} + } + }, + { + "index": 104, + "value": { + "created_on": "2026-08-08T13:05:17.47274Z", + "modified_on": "2026-08-08T13:05:17.47274Z", + "type": "TXT", + "name": "foosq.dnscontroltest-cf.org", + "content": "\"quo'te\"", + "meta": {}, + "id": "c3a392de543e4c99e8f7152770fbce64", + "ttl": 300, + "proxied": false, + "settings": {} + } + }, + { + "index": 105, + "value": { + "created_on": "2026-08-08T13:05:19.228717Z", + "modified_on": "2026-08-08T13:05:19.228717Z", + "type": "TXT", + "name": "foobt.dnscontroltest-cf.org", + "content": "\"blah`blah\"", + "meta": {}, + "id": "6d4f1115d121f8d9b4d0ec9717f52f23", + "ttl": 300, + "proxied": false, + "settings": {} + } + }, + { + "index": 106, + "value": { + "created_on": "2026-08-08T13:05:21.484773Z", + "modified_on": "2026-08-08T13:05:21.484773Z", + "type": "TXT", + "name": "foodq.dnscontroltest-cf.org", + "content": "\"in\\\"side\"", + "meta": {}, + "id": "ee7f7df730e2e446e0bf5eabdfa1bc0b", + "ttl": 300, + "proxied": false, + "settings": {} + } + }, + { + "index": 107, + "value": { + "created_on": "2026-08-08T13:05:23.48641Z", + "modified_on": "2026-08-08T13:05:23.48641Z", + "type": "TXT", + "name": "foodqs.dnscontroltest-cf.org", + "content": "\"in\\\"ter\\\"ior\"", + "meta": {}, + "id": "3a9e072712a6f4d2c6cc3c10670a08f3", + "ttl": 300, + "proxied": false, + "settings": {} + } + }, + { + "index": 108, + "value": { + "created_on": "2026-08-08T13:05:23.48641Z", + "modified_on": "2026-08-08T13:05:25.283114Z", + "type": "TXT", + "name": "foodqs.dnscontroltest-cf.org", + "content": "\"\\\"left\"", + "meta": {}, + "id": "3a9e072712a6f4d2c6cc3c10670a08f3", + "ttl": 300, + "proxied": false, + "settings": {} + } + }, + { + "index": 109, + "value": { + "created_on": "2026-08-08T13:05:23.48641Z", + "modified_on": "2026-08-08T13:05:26.996225Z", + "type": "TXT", + "name": "foodqs.dnscontroltest-cf.org", + "content": "\"right\\\"\"", + "meta": {}, + "id": "3a9e072712a6f4d2c6cc3c10670a08f3", + "ttl": 300, + "proxied": false, + "settings": {} + } + }, + { + "index": 110, + "value": { + "created_on": "2026-08-08T13:05:28.985569Z", + "modified_on": "2026-08-08T13:05:28.985569Z", + "type": "TXT", + "name": "foosc1.dnscontroltest-cf.org", + "content": "\"semi;colon\"", + "meta": {}, + "id": "bc7a51ac0d5ac138203aa84ecb2eff2c", + "ttl": 300, + "proxied": false, + "settings": {} + } + }, + { + "index": 111, + "value": { + "created_on": "2026-08-08T13:05:30.975758Z", + "modified_on": "2026-08-08T13:05:30.975758Z", + "type": "TXT", + "name": "foosc2.dnscontroltest-cf.org", + "content": "\"wssemi ; colon\"", + "meta": {}, + "id": "cd5af7819fcb4a86628b80a954bfd4cd", + "ttl": 300, + "proxied": false, + "settings": {} + } + }, + { + "index": 112, + "value": { + "created_on": "2026-08-08T13:05:32.972837Z", + "modified_on": "2026-08-08T13:05:32.972837Z", + "type": "TXT", + "name": "foosp.dnscontroltest-cf.org", + "content": "\"with spaces\"", + "meta": {}, + "id": "436c382440ff33417b1707d72e9770a6", + "ttl": 300, + "proxied": false, + "settings": {} + } + }, + { + "index": 113, + "value": { + "created_on": "2026-08-08T13:05:35.011265Z", + "modified_on": "2026-08-08T13:05:35.011265Z", + "type": "TXT", + "name": "foows1.dnscontroltest-cf.org", + "content": "\"trailingws \"", + "meta": {}, + "id": "1491248e548e2438795bce5ecaf9aecd", + "ttl": 300, + "proxied": false, + "settings": {} + } + }, + { + "index": 114, + "value": { + "created_on": "2026-08-08T13:05:36.778075Z", + "modified_on": "2026-08-08T13:05:36.778075Z", + "type": "TXT", + "name": "foo.dnscontroltest-cf.org", + "content": "\"v=spf1 ip4:99.99.99.99 -all\"", + "meta": {}, + "id": "2a7ad4754ede76546df25bfa7a5d6e63", + "ttl": 300, + "proxied": false, + "settings": {} + } + }, + { + "index": 115, + "value": { + "created_on": "2026-08-08T13:05:39.774605Z", + "modified_on": "2026-08-08T13:05:39.774605Z", + "type": "TXT", + "name": "fooosbs1.dnscontroltest-cf.org", + "content": "\"1back\\\\slash\"", + "meta": {}, + "id": "ef70a59f4bc32955121cb6034bdcb378", + "ttl": 300, + "proxied": false, + "settings": {} + } + }, + { + "index": 116, + "value": { + "created_on": "2026-08-08T13:05:39.977411Z", + "modified_on": "2026-08-08T13:05:39.977411Z", + "type": "TXT", + "name": "fooosbs2.dnscontroltest-cf.org", + "content": "\"2back\\\\\\\\slash\"", + "meta": {}, + "id": "34c257f0fa2f0499d2ee15c24e9913e6", + "ttl": 300, + "proxied": false, + "settings": {} + } + }, + { + "index": 117, + "value": { + "created_on": "2026-08-08T13:05:40.26416Z", + "modified_on": "2026-08-08T13:05:40.26416Z", + "type": "TXT", + "name": "fooosbs3.dnscontroltest-cf.org", + "content": "\"3back\\\\\\\\\\\\slash\"", + "meta": {}, + "id": "8e665d9ab9271fc8cfa25d7116e5940e", + "ttl": 300, + "proxied": false, + "settings": {} + } + }, + { + "index": 118, + "value": { + "created_on": "2026-08-08T13:05:40.511478Z", + "modified_on": "2026-08-08T13:05:40.511478Z", + "type": "TXT", + "name": "fooosbs4.dnscontroltest-cf.org", + "content": "\"4back\\\\\\\\\\\\\\\\slash\"", + "meta": {}, + "id": "a98bdd00d5f77b5f123cf935e07b9a2d", + "ttl": 300, + "proxied": false, + "settings": {} + } + }, + { + "index": 119, + "value": { + "created_on": "2026-08-08T13:05:43.97799Z", + "modified_on": "2026-08-08T13:05:43.97799Z", + "type": "MX", + "name": "bar.dnscontroltest-cf.org", + "content": "bar.com", + "meta": {}, + "id": "9f0f182557d356841e6e72d5e9199d59", + "priority": 5, + "ttl": 300, + "proxied": false, + "settings": {} + } + }, + { + "index": 120, + "value": { + "created_on": "2026-08-08T13:05:45.725225Z", + "modified_on": "2026-08-08T13:05:45.725225Z", + "type": "A", + "name": "decoy.dnscontroltest-cf.org", + "content": "1.1.1.1", + "meta": {}, + "id": "d55f2d2111f0523f373ca41feb6a557b", + "ttl": 300, + "proxied": false, + "settings": {} + } + }, + { + "index": 121, + "value": { + "created_on": "2026-08-08T13:05:45.725225Z", + "modified_on": "2026-08-08T13:05:47.47844Z", + "type": "A", + "name": "decoy.dnscontroltest-cf.org", + "content": "2.2.2.2", + "meta": {}, + "id": "d55f2d2111f0523f373ca41feb6a557b", + "ttl": 300, + "proxied": false, + "proxiable": true, + "settings": {} + } + }, + { + "index": 122, + "value": { + "created_on": "2026-08-08T13:05:45.725225Z", + "modified_on": "2026-08-08T13:05:49.221639Z", + "type": "A", + "name": "decoy.dnscontroltest-cf.org", + "content": "3.3.3.3", + "meta": {}, + "id": "d55f2d2111f0523f373ca41feb6a557b", + "ttl": 300, + "proxied": false, + "proxiable": true, + "settings": {} + } + }, + { + "index": 123, + "value": { + "created_on": "2026-08-08T13:05:52.230875Z", + "modified_on": "2026-08-08T13:05:52.230875Z", + "type": "A", + "name": "foo.dnscontroltest-cf.org", + "content": "1.2.3.4", + "meta": {}, + "id": "a33bbd35c230f5ea34d527a08a61251b", + "ttl": 300, + "proxied": false, + "proxiable": true, + "settings": {} + } + }, + { + "index": 124, + "value": { + "created_on": "2026-08-08T13:05:52.480058Z", + "modified_on": "2026-08-08T13:05:52.480058Z", + "type": "A", + "name": "foo.dnscontroltest-cf.org", + "content": "2.3.4.5", + "meta": {}, + "id": "da7fd312c0617f45959913086879280d", + "ttl": 300, + "proxied": false, + "proxiable": true, + "settings": {} + } + }, + { + "index": 125, + "value": { + "created_on": "2026-08-08T13:05:52.480058Z", + "modified_on": "2026-08-08T13:05:54.22886Z", + "type": "A", + "name": "foo.dnscontroltest-cf.org", + "content": "3.4.5.6", + "meta": {}, + "id": "da7fd312c0617f45959913086879280d", + "ttl": 300, + "proxied": false, + "proxiable": true, + "settings": {} + } + }, + { + "index": 126, + "value": { + "created_on": "2026-08-08T13:05:57.772567Z", + "modified_on": "2026-08-08T13:05:57.772567Z", + "type": "A", + "name": "foo.dnscontroltest-cf.org", + "content": "3.4.5.6", + "meta": {}, + "id": "7d0ed6bf3b499c49d1be70806988579f", + "ttl": 300, + "proxied": false, + "proxiable": true, + "settings": {} + } + }, + { + "index": 127, + "value": { + "created_on": "2026-08-08T13:06:00.728201Z", + "modified_on": "2026-08-08T13:06:00.728201Z", + "type": "A", + "name": "bar.dnscontroltest-cf.org", + "content": "1.2.3.4", + "meta": {}, + "id": "63077193849ba5ea7292f1ee9f03eb23", + "ttl": 300, + "proxied": false, + "proxiable": true, + "settings": {} + } + }, + { + "index": 128, + "value": { + "created_on": "2026-08-08T13:06:01.014213Z", + "modified_on": "2026-08-08T13:06:01.014213Z", + "type": "A", + "name": "foo.dnscontroltest-cf.org", + "content": "2.3.4.5", + "meta": {}, + "id": "0309cd6d912d8d05a5d192a8e9bfff02", + "ttl": 300, + "proxied": false, + "proxiable": true, + "settings": {} + } + }, + { + "index": 129, + "value": { + "created_on": "2026-08-08T13:06:01.255164Z", + "modified_on": "2026-08-08T13:06:01.255164Z", + "type": "A", + "name": "foo.dnscontroltest-cf.org", + "content": "3.4.5.6", + "meta": {}, + "id": "86c21b44da797bb4b12022ae5a8c6b5f", + "ttl": 300, + "proxied": false, + "proxiable": true, + "settings": {} + } + }, + { + "index": 130, + "value": { + "created_on": "2026-08-08T13:06:01.255164Z", + "modified_on": "2026-08-08T13:06:03.688207Z", + "type": "A", + "name": "foo.dnscontroltest-cf.org", + "content": "8.8.8.8", + "meta": {}, + "id": "86c21b44da797bb4b12022ae5a8c6b5f", + "ttl": 300, + "proxied": false, + "proxiable": true, + "settings": {} + } + }, + { + "index": 131, + "value": { + "created_on": "2026-08-08T13:06:01.607876Z", + "modified_on": "2026-08-08T13:06:01.607876Z", + "type": "MX", + "name": "foo.dnscontroltest-cf.org", + "content": "bar.dnscontroltest-cf.org", + "meta": {}, + "id": "086667b64d98d42878f99160ed7f031b", + "priority": 20, + "ttl": 300, + "proxied": false, + "settings": {} + } + }, + { + "index": 132, + "value": { + "created_on": "2026-08-08T13:06:01.875279Z", + "modified_on": "2026-08-08T13:06:01.875279Z", + "type": "MX", + "name": "foo.dnscontroltest-cf.org", + "content": "foo.dnscontroltest-cf.org", + "meta": {}, + "id": "37a2d3a6ffbf59c38ace28491100d65c", + "priority": 10, + "ttl": 300, + "proxied": false, + "settings": {} + } + }, + { + "index": 133, + "value": { + "created_on": "2026-08-08T13:06:07.171531Z", + "modified_on": "2026-08-08T13:06:07.171531Z", + "type": "A", + "name": "foo.dnscontroltest-cf.org", + "content": "8.8.8.8", + "meta": {}, + "id": "618c8a4ad67ad41a076777446f8a8a6c", + "ttl": 300, + "proxied": false, + "proxiable": true, + "settings": {} + } + }, + { + "index": 134, + "value": { + "created_on": "2026-08-08T13:06:10.887585Z", + "modified_on": "2026-08-08T13:06:10.887585Z", + "type": "A", + "name": "xn--ndaaa.dnscontroltest-cf.org", + "content": "1.2.3.4", + "meta": {}, + "id": "fc46f861d7cba4554b2e739701305ce3", + "ttl": 300, + "proxied": false, + "proxiable": true, + "settings": {} + } + }, + { + "index": 135, + "value": { + "created_on": "2026-08-08T13:06:10.887585Z", + "modified_on": "2026-08-08T13:06:12.634668Z", + "type": "A", + "name": "xn--ndaaa.dnscontroltest-cf.org", + "content": "2.2.2.2", + "meta": {}, + "id": "fc46f861d7cba4554b2e739701305ce3", + "ttl": 300, + "proxied": false, + "proxiable": true, + "settings": {} + } + }, + { + "index": 136, + "value": { + "created_on": "2026-08-08T13:06:14.431117Z", + "modified_on": "2026-08-08T13:06:14.431117Z", + "type": "A", + "name": "xn--fiq228c.dnscontroltest-cf.org", + "content": "1.2.3.4", + "meta": {}, + "id": "479b72ff3211a5804ed9122de45705c9", + "ttl": 300, + "proxied": false, + "proxiable": true, + "settings": {} + } + }, + { + "index": 137, + "value": { + "created_on": "2026-08-08T13:06:16.386534Z", + "modified_on": "2026-08-08T13:06:16.386534Z", + "type": "CNAME", + "name": "a.dnscontroltest-cf.org", + "content": "xn--ndaaa.com", + "meta": {}, + "id": "a2f98de0c3cabc18d97edf6b927d2381", + "ttl": 300, + "proxied": false, + "proxiable": true, + "settings": { + "flatten_cname": false + } + } + }, + { + "index": 138, + "value": { + "created_on": "2026-08-08T13:06:19.390868Z", + "modified_on": "2026-08-08T13:06:19.390868Z", + "type": "CNAME", + "name": "xn--o-0gab.dnscontroltest-cf.org", + "content": "xn--ndaaa.xn--vhquv", + "meta": {}, + "id": "793c86f695685cbcb726e743d2ca286a", + "ttl": 300, + "proxied": false, + "proxiable": true, + "settings": { + "flatten_cname": false + } + } + }, + { + "index": 139, + "value": { + "created_on": "2026-08-08T13:06:23.115917Z", + "modified_on": "2026-08-08T13:06:23.115917Z", + "type": "CAA", + "name": "dnscontroltest-cf.org", + "content": "0 issue \"letsencrypt.org\"", + "meta": {}, + "data": { + "flags": 0, + "tag": "issue", + "value": "letsencrypt.org" + }, + "id": "f6d358f8f9ba2846c1fb44d51ea70b7b", + "ttl": 300, + "proxied": false, + "settings": {} + } + }, + { + "index": 140, + "value": { + "created_on": "2026-08-08T13:06:23.115917Z", + "modified_on": "2026-08-08T13:06:24.863695Z", + "type": "CAA", + "name": "dnscontroltest-cf.org", + "content": "0 issuewild \"letsencrypt.org\"", + "meta": {}, + "data": { + "flags": 0, + "tag": "issuewild", + "value": "letsencrypt.org" + }, + "id": "f6d358f8f9ba2846c1fb44d51ea70b7b", + "ttl": 300, + "proxied": false, + "settings": {} + } + }, + { + "index": 141, + "value": { + "created_on": "2026-08-08T13:06:23.115917Z", + "modified_on": "2026-08-08T13:06:26.690664Z", + "type": "CAA", + "name": "dnscontroltest-cf.org", + "content": "0 issuewild \"example.com\"", + "meta": {}, + "data": { + "flags": 0, + "tag": "issuewild", + "value": "example.com" + }, + "id": "f6d358f8f9ba2846c1fb44d51ea70b7b", + "ttl": 300, + "proxied": false, + "settings": {} + } + }, + { + "index": 142, + "value": { + "created_on": "2026-08-08T13:06:23.115917Z", + "modified_on": "2026-08-08T13:06:28.404982Z", + "type": "CAA", + "name": "dnscontroltest-cf.org", + "content": "0 issuewild \";\"", + "meta": {}, + "data": { + "flags": 0, + "tag": "issuewild", + "value": ";" + }, + "id": "f6d358f8f9ba2846c1fb44d51ea70b7b", + "ttl": 300, + "proxied": false, + "settings": {} + } + }, + { + "index": 143, + "value": { + "created_on": "2026-08-08T13:06:23.115917Z", + "modified_on": "2026-08-08T13:06:30.111751Z", + "type": "CAA", + "name": "dnscontroltest-cf.org", + "content": "0 issue \"letsencrypt.org; validationmethods=dns-01; accounturi=https://acme-v02.api.letsencrypt.org/acme/acct/1234\"", + "meta": {}, + "data": { + "flags": 0, + "tag": "issue", + "value": "letsencrypt.org; validationmethods=dns-01; accounturi=https://acme-v02.api.letsencrypt.org/acme/acct/1234" + }, + "id": "f6d358f8f9ba2846c1fb44d51ea70b7b", + "ttl": 300, + "proxied": false, + "settings": {} + } + }, + { + "index": 144, + "value": { + "created_on": "2026-08-08T13:06:32.875865Z", + "modified_on": "2026-08-08T13:06:32.875865Z", + "type": "CAA", + "name": "dnscontroltest-cf.org", + "content": "0 issue \"letsencrypt.org\"", + "meta": {}, + "data": { + "flags": 0, + "tag": "issue", + "value": "letsencrypt.org" + }, + "id": "9055e9e5f1e539ecd339e0c3f9e7f580", + "ttl": 300, + "proxied": false, + "settings": {} + } + }, + { + "index": 145, + "value": { + "created_on": "2026-08-08T13:06:32.875865Z", + "modified_on": "2026-08-08T13:06:34.625015Z", + "type": "CAA", + "name": "dnscontroltest-cf.org", + "content": "128 issue \"letsencrypt.org\"", + "meta": {}, + "data": { + "flags": 128, + "tag": "issue", + "value": "letsencrypt.org" + }, + "id": "9055e9e5f1e539ecd339e0c3f9e7f580", + "ttl": 300, + "proxied": false, + "settings": {} + } + }, + { + "index": 146, + "value": { + "created_on": "2026-08-08T13:06:37.395626Z", + "modified_on": "2026-08-08T13:06:37.395626Z", + "type": "LOC", + "name": "dnscontroltest-cf.org", + "content": "42 21 54.000 N 71 6 18.000 W -24.05 30.00 0.00 0.00", + "meta": {}, + "data": { + "altitude": -24.05000000000291, + "lat_degrees": 42, + "lat_direction": "N", + "lat_minutes": 21, + "lat_seconds": 54, + "long_degrees": 71, + "long_direction": "W", + "long_minutes": 6, + "long_seconds": 18, + "precision_horz": 0, + "precision_vert": 0, + "size": 30 + }, + "id": "0428f33b408690128e08f836e96a6007", + "ttl": 300, + "proxied": false, + "settings": {} + } + }, + { + "index": 147, + "value": { + "created_on": "2026-08-08T13:06:37.395626Z", + "modified_on": "2026-08-08T13:06:39.106934Z", + "type": "LOC", + "name": "dnscontroltest-cf.org", + "content": "42 21 54.000 N 71 6 18.000 W -24.06 30.00 10.00 0.00", + "meta": {}, + "data": { + "altitude": -24.05999999999767, + "lat_degrees": 42, + "lat_direction": "N", + "lat_minutes": 21, + "lat_seconds": 54, + "long_degrees": 71, + "long_direction": "W", + "long_minutes": 6, + "long_seconds": 18, + "precision_horz": 10, + "precision_vert": 0, + "size": 30 + }, + "id": "0428f33b408690128e08f836e96a6007", + "ttl": 300, + "proxied": false, + "settings": {} + } + }, + { + "index": 148, + "value": { + "created_on": "2026-08-08T13:06:37.395626Z", + "modified_on": "2026-08-08T13:06:40.864976Z", + "type": "LOC", + "name": "dnscontroltest-cf.org", + "content": "42 21 54.000 N 71 6 18.000 W -24.00 30.00 0.00 0.00", + "meta": {}, + "data": { + "altitude": -24, + "lat_degrees": 42, + "lat_direction": "N", + "lat_minutes": 21, + "lat_seconds": 54, + "long_degrees": 71, + "long_direction": "W", + "long_minutes": 6, + "long_seconds": 18, + "precision_horz": 0, + "precision_vert": 0, + "size": 30 + }, + "id": "0428f33b408690128e08f836e96a6007", + "ttl": 300, + "proxied": false, + "settings": {} + } + }, + { + "index": 149, + "value": { + "created_on": "2026-08-08T13:06:41.141488Z", + "modified_on": "2026-08-08T13:06:41.141488Z", + "type": "LOC", + "name": "a.dnscontroltest-cf.org", + "content": "42 21 43.950 N 71 5 6.340 W -24.33 1.00 200.00 10.00", + "meta": {}, + "data": { + "altitude": -24.330000000001746, + "lat_degrees": 42, + "lat_direction": "N", + "lat_minutes": 21, + "lat_seconds": 43.95, + "long_degrees": 71, + "long_direction": "W", + "long_minutes": 5, + "long_seconds": 6.34, + "precision_horz": 200, + "precision_vert": 10, + "size": 1 + }, + "id": "462a63020e5003c34b68b8cc11685b17", + "ttl": 300, + "proxied": false, + "settings": {} + } + }, + { + "index": 150, + "value": { + "created_on": "2026-08-08T13:06:41.359621Z", + "modified_on": "2026-08-08T13:06:41.359621Z", + "type": "LOC", + "name": "b.dnscontroltest-cf.org", + "content": "52 14 5.000 N 0 8 50.000 E 10.22 0.00 0.00 0.00", + "meta": {}, + "data": { + "altitude": 10.220000000001164, + "lat_degrees": 52, + "lat_direction": "N", + "lat_minutes": 14, + "lat_seconds": 5, + "long_degrees": 0, + "long_direction": "E", + "long_minutes": 8, + "long_seconds": 50, + "precision_horz": 0, + "precision_vert": 0, + "size": 0 + }, + "id": "1d260e3ef9989fa27c2bbac4a775335e", + "ttl": 300, + "proxied": false, + "settings": {} + } + }, + { + "index": 151, + "value": { + "created_on": "2026-08-08T13:06:41.612293Z", + "modified_on": "2026-08-08T13:06:41.612293Z", + "type": "LOC", + "name": "c.dnscontroltest-cf.org", + "content": "32 7 19.000 S 116 2 25.000 E 10.00 0.00 0.00 0.00", + "meta": {}, + "data": { + "altitude": 10, + "lat_degrees": 32, + "lat_direction": "S", + "lat_minutes": 7, + "lat_seconds": 19, + "long_degrees": 116, + "long_direction": "E", + "long_minutes": 2, + "long_seconds": 25, + "precision_horz": 0, + "precision_vert": 0, + "size": 0 + }, + "id": "b0ec14a1d878ba9d401952e087a5899d", + "ttl": 300, + "proxied": false, + "settings": {} + } + }, + { + "index": 152, + "value": { + "created_on": "2026-08-08T13:06:41.860177Z", + "modified_on": "2026-08-08T13:06:41.860177Z", + "type": "LOC", + "name": "d.dnscontroltest-cf.org", + "content": "42 21 28.760 N 71 0 51.620 W -44.00 2000.00 0.00 0.00", + "meta": {}, + "data": { + "altitude": -44, + "lat_degrees": 42, + "lat_direction": "N", + "lat_minutes": 21, + "lat_seconds": 28.76, + "long_degrees": 71, + "long_direction": "W", + "long_minutes": 0, + "long_seconds": 51.62, + "precision_horz": 0, + "precision_vert": 0, + "size": 2000 + }, + "id": "e61a2a24bf7eda4c67935114a776f107", + "ttl": 300, + "proxied": false, + "settings": {} + } + }, + { + "index": 153, + "value": { + "created_on": "2026-08-08T13:06:45.607448Z", + "modified_on": "2026-08-08T13:06:45.607448Z", + "type": "NAPTR", + "name": "test.dnscontroltest-cf.org", + "content": "100 10 \"U\" \"E2U+sip\" \"!^.*$!sip:customer-service@example.com!\" .", + "meta": {}, + "data": { + "flags": "U", + "order": 100, + "preference": 10, + "regex": "!^.*$!sip:customer-service@example.com!", + "replacement": ".", + "service": "E2U+sip" + }, + "id": "54d3113c127948192a757dcad9abc326", + "ttl": 300, + "proxied": false, + "settings": {} + } + }, + { + "index": 154, + "value": { + "created_on": "2026-08-08T13:06:45.607448Z", + "modified_on": "2026-08-08T13:06:50.929962Z", + "type": "NAPTR", + "name": "test.dnscontroltest-cf.org", + "content": "103 10 \"U\" \"E2U+email\" \"!^.*$!mailto:information@example.com!\" .", + "meta": {}, + "data": { + "flags": "U", + "order": 103, + "preference": 10, + "regex": "!^.*$!mailto:information@example.com!", + "replacement": ".", + "service": "E2U+email" + }, + "id": "54d3113c127948192a757dcad9abc326", + "ttl": 300, + "proxied": false, + "settings": {} + } + }, + { + "index": 155, + "value": { + "created_on": "2026-08-08T13:06:45.607448Z", + "modified_on": "2026-08-08T13:06:52.646212Z", + "type": "NAPTR", + "name": "test.dnscontroltest-cf.org", + "content": "103 20 \"U\" \"E2U+email\" \"!^.*$!mailto:information@example.com!\" .", + "meta": {}, + "data": { + "flags": "U", + "order": 103, + "preference": 20, + "regex": "!^.*$!mailto:information@example.com!", + "replacement": ".", + "service": "E2U+email" + }, + "id": "54d3113c127948192a757dcad9abc326", + "ttl": 300, + "proxied": false, + "settings": {} + } + }, + { + "index": 156, + "value": { + "created_on": "2026-08-08T13:06:45.607448Z", + "modified_on": "2026-08-08T13:06:54.372268Z", + "type": "NAPTR", + "name": "test.dnscontroltest-cf.org", + "content": "103 20 \"A\" \"E2U+email\" \"!^.*$!mailto:information@example.com!\" .", + "meta": {}, + "data": { + "flags": "A", + "order": 103, + "preference": 20, + "regex": "!^.*$!mailto:information@example.com!", + "replacement": ".", + "service": "E2U+email" + }, + "id": "54d3113c127948192a757dcad9abc326", + "ttl": 300, + "proxied": false, + "settings": {} + } + }, + { + "index": 157, + "value": { + "created_on": "2026-08-08T13:06:45.607448Z", + "modified_on": "2026-08-08T13:06:56.144127Z", + "type": "NAPTR", + "name": "test.dnscontroltest-cf.org", + "content": "103 20 \"A\" \"E2U+sip\" \"!^.*$!mailto:information@example.com!\" .", + "meta": {}, + "data": { + "flags": "A", + "order": 103, + "preference": 20, + "regex": "!^.*$!mailto:information@example.com!", + "replacement": ".", + "service": "E2U+sip" + }, + "id": "54d3113c127948192a757dcad9abc326", + "ttl": 300, + "proxied": false, + "settings": {} + } + }, + { + "index": 158, + "value": { + "created_on": "2026-08-08T13:06:45.607448Z", + "modified_on": "2026-08-08T13:06:57.915025Z", + "type": "NAPTR", + "name": "test.dnscontroltest-cf.org", + "content": "103 20 \"A\" \"E2U+sip\" \"!^.*$!sip:customer-service@example.com!\" .", + "meta": {}, + "data": { + "flags": "A", + "order": 103, + "preference": 20, + "regex": "!^.*$!sip:customer-service@example.com!", + "replacement": ".", + "service": "E2U+sip" + }, + "id": "54d3113c127948192a757dcad9abc326", + "ttl": 300, + "proxied": false, + "settings": {} + } + }, + { + "index": 159, + "value": { + "created_on": "2026-08-08T13:06:45.607448Z", + "modified_on": "2026-08-08T13:06:59.650087Z", + "type": "NAPTR", + "name": "test.dnscontroltest-cf.org", + "content": "103 20 \"A\" \"E2U+sip\" \"\" example.foo.com.", + "meta": {}, + "data": { + "flags": "A", + "order": 103, + "preference": 20, + "regex": "", + "replacement": "example.foo.com.", + "service": "E2U+sip" + }, + "id": "54d3113c127948192a757dcad9abc326", + "ttl": 300, + "proxied": false, + "settings": {} + } + }, + { + "index": 160, + "value": { + "created_on": "2026-08-08T13:06:45.607448Z", + "modified_on": "2026-08-08T13:07:01.377182Z", + "type": "NAPTR", + "name": "test.dnscontroltest-cf.org", + "content": "103 20 \"A\" \"E2U+sip\" \"\" example2.foo.com.", + "meta": {}, + "data": { + "flags": "A", + "order": 103, + "preference": 20, + "regex": "", + "replacement": "example2.foo.com.", + "service": "E2U+sip" + }, + "id": "54d3113c127948192a757dcad9abc326", + "ttl": 300, + "proxied": false, + "settings": {} + } + }, + { + "index": 161, + "value": { + "created_on": "2026-08-08T13:06:47.364357Z", + "modified_on": "2026-08-08T13:06:47.364357Z", + "type": "NAPTR", + "name": "test.dnscontroltest-cf.org", + "content": "102 10 \"U\" \"E2U+email\" \"!^.*$!mailto:information@example.com!\" .", + "meta": {}, + "data": { + "flags": "U", + "order": 102, + "preference": 10, + "regex": "!^.*$!mailto:information@example.com!", + "replacement": ".", + "service": "E2U+email" + }, + "id": "c06c45eb0fab6f46707fc9a234f1b0bd", + "ttl": 300, + "proxied": false, + "settings": {} + } + }, + { + "index": 162, + "value": { + "created_on": "2026-08-08T13:07:04.117386Z", + "modified_on": "2026-08-08T13:07:04.117386Z", + "type": "PTR", + "name": "4.dnscontroltest-cf.org", + "content": "foo.com", + "meta": {}, + "id": "6b07e6629fae2b66ab12678ba34bcd54", + "ttl": 300, + "proxied": false, + "settings": {} + } + }, + { + "index": 163, + "value": { + "created_on": "2026-08-08T13:07:04.117386Z", + "modified_on": "2026-08-08T13:07:05.958075Z", + "type": "PTR", + "name": "4.dnscontroltest-cf.org", + "content": "bar.com", + "meta": {}, + "id": "6b07e6629fae2b66ab12678ba34bcd54", + "ttl": 300, + "proxied": false, + "settings": {} + } + }, + { + "index": 164, + "value": { + "created_on": "2026-08-08T13:07:08.657891Z", + "modified_on": "2026-08-08T13:07:08.657891Z", + "type": "SRV", + "name": "_sip._tcp.dnscontroltest-cf.org", + "content": "6 7 foo.com", + "meta": {}, + "data": { + "port": 7, + "priority": 5, + "target": "foo.com", + "weight": 6 + }, + "id": "3b38f2db848853049dad77dabcecfac6", + "priority": 5, + "ttl": 300, + "proxied": false, + "settings": {} + } + }, + { + "index": 165, + "value": { + "created_on": "2026-08-08T13:07:08.657891Z", + "modified_on": "2026-08-08T13:07:17.422604Z", + "type": "SRV", + "name": "_sip._tcp.dnscontroltest-cf.org", + "content": "6 7 foo.com", + "meta": {}, + "data": { + "port": 7, + "priority": 52, + "target": "foo.com", + "weight": 6 + }, + "id": "3b38f2db848853049dad77dabcecfac6", + "priority": 52, + "ttl": 300, + "proxied": false, + "settings": {} + } + }, + { + "index": 166, + "value": { + "created_on": "2026-08-08T13:07:08.657891Z", + "modified_on": "2026-08-08T13:07:19.183295Z", + "type": "SRV", + "name": "_sip._tcp.dnscontroltest-cf.org", + "content": "62 7 foo.com", + "meta": {}, + "data": { + "port": 7, + "priority": 52, + "target": "foo.com", + "weight": 62 + }, + "id": "3b38f2db848853049dad77dabcecfac6", + "priority": 52, + "ttl": 300, + "proxied": false, + "settings": {} + } + }, + { + "index": 167, + "value": { + "created_on": "2026-08-08T13:07:08.657891Z", + "modified_on": "2026-08-08T13:07:20.959356Z", + "type": "SRV", + "name": "_sip._tcp.dnscontroltest-cf.org", + "content": "62 72 foo.com", + "meta": {}, + "data": { + "port": 72, + "priority": 52, + "target": "foo.com", + "weight": 62 + }, + "id": "3b38f2db848853049dad77dabcecfac6", + "priority": 52, + "ttl": 300, + "proxied": false, + "settings": {} + } + }, + { + "index": 168, + "value": { + "created_on": "2026-08-08T13:07:10.434959Z", + "modified_on": "2026-08-08T13:07:10.434959Z", + "type": "SRV", + "name": "_sip._tcp.dnscontroltest-cf.org", + "content": "60 70 foo2.com", + "meta": {}, + "data": { + "port": 70, + "priority": 5, + "target": "foo2.com", + "weight": 60 + }, + "id": "5932c0bb35701603b926b4b91ef7dfde", + "priority": 5, + "ttl": 300, + "proxied": false, + "settings": {} + } + }, + { + "index": 169, + "value": { + "created_on": "2026-08-08T13:07:12.144599Z", + "modified_on": "2026-08-08T13:07:12.144599Z", + "type": "SRV", + "name": "_sip._tcp.dnscontroltest-cf.org", + "content": "65 75 foo3.com", + "meta": {}, + "data": { + "port": 75, + "priority": 15, + "target": "foo3.com", + "weight": 65 + }, + "id": "92a9c6818d937cac7bd13229f8869f9b", + "priority": 15, + "ttl": 300, + "proxied": false, + "settings": {} + } + }, + { + "index": 170, + "value": { + "created_on": "2026-08-08T13:07:12.144599Z", + "modified_on": "2026-08-08T13:07:15.642508Z", + "type": "SRV", + "name": "_sip._tcp.dnscontroltest-cf.org", + "content": "65 75 foo4.com", + "meta": {}, + "data": { + "port": 75, + "priority": 15, + "target": "foo4.com", + "weight": 65 + }, + "id": "92a9c6818d937cac7bd13229f8869f9b", + "priority": 15, + "ttl": 300, + "proxied": false, + "settings": {} + } + }, + { + "index": 171, + "value": { + "created_on": "2026-08-08T13:07:23.978693Z", + "modified_on": "2026-08-08T13:07:23.978693Z", + "type": "SRV", + "name": "_sip._tcp.dnscontroltest-cf.org", + "content": "65 75 .", + "meta": {}, + "data": { + "port": 75, + "priority": 15, + "target": ".", + "weight": 65 + }, + "id": "5804e2ccef69c90cd78cb9b1811c6b1a", + "priority": 15, + "ttl": 300, + "proxied": false, + "settings": {} + } + }, + { + "index": 172, + "value": { + "created_on": "2026-08-08T13:07:26.757059Z", + "modified_on": "2026-08-08T13:07:26.757059Z", + "type": "SRV", + "name": "_sip._tcp.dnscontroltest-cf.org", + "content": "6 7 foo.com", + "meta": {}, + "data": { + "port": 7, + "priority": 5, + "target": "foo.com", + "weight": 6 + }, + "id": "88c45b330aa1d1f921f17d51175e1439", + "priority": 5, + "ttl": 333, + "proxied": false, + "settings": {} + } + }, + { + "index": 173, + "value": { + "created_on": "2026-08-08T13:07:26.757059Z", + "modified_on": "2026-08-08T13:07:28.42927Z", + "type": "SRV", + "name": "_sip._tcp.dnscontroltest-cf.org", + "content": "6 7 foo.com", + "meta": {}, + "data": { + "port": 7, + "priority": 5, + "target": "foo.com", + "weight": 6 + }, + "id": "88c45b330aa1d1f921f17d51175e1439", + "priority": 5, + "ttl": 4400, + "proxied": false, + "settings": {} + } + }, + { + "index": 174, + "value": { + "created_on": "2026-08-08T13:07:31.175418Z", + "modified_on": "2026-08-08T13:07:31.175418Z", + "type": "SSHFP", + "name": "dnscontroltest-cf.org", + "content": "1 1 66C7D5540B7D75A1FB4C84FEBFA178AD99BDD67C", + "meta": {}, + "data": { + "algorithm": 1, + "fingerprint": "66C7D5540B7D75A1FB4C84FEBFA178AD99BDD67C", + "type": 1 + }, + "id": "c31ec38cf174cc5c839010ad3e94a50c", + "ttl": 300, + "proxied": false, + "settings": {} + } + }, + { + "index": 175, + "value": { + "created_on": "2026-08-08T13:07:31.175418Z", + "modified_on": "2026-08-08T13:07:32.930167Z", + "type": "SSHFP", + "name": "dnscontroltest-cf.org", + "content": "2 1 66C7D5540B7D75A1FB4C84FEBFA178AD99BDD67C", + "meta": {}, + "data": { + "algorithm": 2, + "fingerprint": "66C7D5540B7D75A1FB4C84FEBFA178AD99BDD67C", + "type": 1 + }, + "id": "c31ec38cf174cc5c839010ad3e94a50c", + "ttl": 300, + "proxied": false, + "settings": {} + } + }, + { + "index": 176, + "value": { + "created_on": "2026-08-08T13:07:31.175418Z", + "modified_on": "2026-08-08T13:07:34.762281Z", + "type": "SSHFP", + "name": "dnscontroltest-cf.org", + "content": "2 2 745A635BC46A397A5C4F21D437483005BCC40D7511FF15FBFAFE913A081559BC", + "meta": {}, + "data": { + "algorithm": 2, + "fingerprint": "745A635BC46A397A5C4F21D437483005BCC40D7511FF15FBFAFE913A081559BC", + "type": 2 + }, + "id": "c31ec38cf174cc5c839010ad3e94a50c", + "ttl": 300, + "proxied": false, + "settings": {} + } + }, + { + "index": 177, + "value": { + "created_on": "2026-08-08T13:07:37.454703Z", + "modified_on": "2026-08-08T13:07:37.454703Z", + "type": "TLSA", + "name": "_443._tcp.dnscontroltest-cf.org", + "content": "3 1 1 0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF", + "meta": {}, + "data": { + "certificate": "0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF", + "matching_type": 1, + "selector": 1, + "usage": 3 + }, + "id": "5a2a40a3a919829ce5dbe608252a001f", + "ttl": 300, + "proxied": false, + "settings": {} + } + }, + { + "index": 178, + "value": { + "created_on": "2026-08-08T13:07:37.454703Z", + "modified_on": "2026-08-08T13:07:39.174568Z", + "type": "TLSA", + "name": "_443._tcp.dnscontroltest-cf.org", + "content": "2 1 1 0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF", + "meta": {}, + "data": { + "certificate": "0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF", + "matching_type": 1, + "selector": 1, + "usage": 2 + }, + "id": "5a2a40a3a919829ce5dbe608252a001f", + "ttl": 300, + "proxied": false, + "settings": {} + } + }, + { + "index": 179, + "value": { + "created_on": "2026-08-08T13:07:37.454703Z", + "modified_on": "2026-08-08T13:07:40.930359Z", + "type": "TLSA", + "name": "_443._tcp.dnscontroltest-cf.org", + "content": "2 0 1 0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF", + "meta": {}, + "data": { + "certificate": "0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF", + "matching_type": 1, + "selector": 0, + "usage": 2 + }, + "id": "5a2a40a3a919829ce5dbe608252a001f", + "ttl": 300, + "proxied": false, + "settings": {} + } + }, + { + "index": 180, + "value": { + "created_on": "2026-08-08T13:07:37.454703Z", + "modified_on": "2026-08-08T13:07:42.718434Z", + "type": "TLSA", + "name": "_443._tcp.dnscontroltest-cf.org", + "content": "2 0 2 0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF", + "meta": {}, + "data": { + "certificate": "0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF", + "matching_type": 2, + "selector": 0, + "usage": 2 + }, + "id": "5a2a40a3a919829ce5dbe608252a001f", + "ttl": 300, + "proxied": false, + "settings": {} + } + }, + { + "index": 181, + "value": { + "created_on": "2026-08-08T13:07:37.454703Z", + "modified_on": "2026-08-08T13:07:44.428046Z", + "type": "TLSA", + "name": "_443._tcp.dnscontroltest-cf.org", + "content": "2 0 2 FEDCBA9876543210FEDCBA9876543210FEDCBA9876543210FEDCBA9876543210FEDCBA9876543210FEDCBA9876543210FEDCBA9876543210FEDCBA9876543210", + "meta": {}, + "data": { + "certificate": "FEDCBA9876543210FEDCBA9876543210FEDCBA9876543210FEDCBA9876543210FEDCBA9876543210FEDCBA9876543210FEDCBA9876543210FEDCBA9876543210", + "matching_type": 2, + "selector": 0, + "usage": 2 + }, + "id": "5a2a40a3a919829ce5dbe608252a001f", + "ttl": 300, + "proxied": false, + "settings": {} + } + }, + { + "index": 182, + "value": { + "created_on": "2026-08-08T13:07:47.182474Z", + "modified_on": "2026-08-08T13:07:47.182474Z", + "type": "NS", + "name": "child.dnscontroltest-cf.org", + "content": "ns101.cloudns.net", + "meta": {}, + "id": "9a3989366c0a14ea56834f08cbf5a113", + "ttl": 300, + "proxied": false, + "settings": {} + } + }, + { + "index": 183, + "value": { + "created_on": "2026-08-08T13:07:47.42167Z", + "modified_on": "2026-08-08T13:07:47.42167Z", + "type": "DS", + "name": "child.dnscontroltest-cf.org", + "content": "35632 13 1 1E07663FF507A40874B8605463DD41DE482079D6", + "meta": {}, + "data": { + "algorithm": 13, + "digest": "1E07663FF507A40874B8605463DD41DE482079D6", + "digest_type": 1, + "key_tag": 35632 + }, + "id": "476093df11a52af32fc979470757f83e", + "ttl": 300, + "proxied": false, + "settings": {} + } + }, + { + "index": 184, + "value": { + "created_on": "2026-08-08T13:07:47.42167Z", + "modified_on": "2026-08-08T13:07:49.380122Z", + "type": "DS", + "name": "child.dnscontroltest-cf.org", + "content": "2075 13 1 2706D12E256C8FDD9BFB45EFB25FE537E21A82F6", + "meta": {}, + "data": { + "algorithm": 13, + "digest": "2706D12E256C8FDD9BFB45EFB25FE537E21A82F6", + "digest_type": 1, + "key_tag": 2075 + }, + "id": "476093df11a52af32fc979470757f83e", + "ttl": 300, + "proxied": false, + "settings": {} + } + }, + { + "index": 185, + "value": { + "created_on": "2026-08-08T13:07:47.42167Z", + "modified_on": "2026-08-08T13:07:51.367571Z", + "type": "DS", + "name": "child.dnscontroltest-cf.org", + "content": "2075 13 2 3F7A1EAC8C813A0BEBD0C3B8AAB387E31945EA0CD5E1D84A2E8E27674566C156", + "meta": {}, + "data": { + "algorithm": 13, + "digest": "3F7A1EAC8C813A0BEBD0C3B8AAB387E31945EA0CD5E1D84A2E8E27674566C156", + "digest_type": 2, + "key_tag": 2075 + }, + "id": "476093df11a52af32fc979470757f83e", + "ttl": 300, + "proxied": false, + "settings": {} + } + }, + { + "index": 186, + "value": { + "created_on": "2026-08-08T13:07:47.42167Z", + "modified_on": "2026-08-08T13:07:53.36262Z", + "type": "DS", + "name": "child.dnscontroltest-cf.org", + "content": "2159 1 4 F50BEFEA333EE2901D72D31A08E1A3CD3F7E943FF4B38CF7C8AD92807F5302F76FB0B419182C0F47FFC71CBCB6EF4BD4", + "meta": {}, + "data": { + "algorithm": 1, + "digest": "F50BEFEA333EE2901D72D31A08E1A3CD3F7E943FF4B38CF7C8AD92807F5302F76FB0B419182C0F47FFC71CBCB6EF4BD4", + "digest_type": 4, + "key_tag": 2159 + }, + "id": "476093df11a52af32fc979470757f83e", + "ttl": 300, + "proxied": false, + "settings": {} + } + }, + { + "index": 187, + "value": { + "created_on": "2026-08-08T13:07:47.42167Z", + "modified_on": "2026-08-08T13:07:55.386642Z", + "type": "DS", + "name": "child.dnscontroltest-cf.org", + "content": "63909 3 4 EEC7FA02E6788DA889B2CE41D43D92F948AB126EDCF83B7037E73CE9531C8E7E45653ABBAA76C2D6E42F98316EDE599B", + "meta": {}, + "data": { + "algorithm": 3, + "digest": "EEC7FA02E6788DA889B2CE41D43D92F948AB126EDCF83B7037E73CE9531C8E7E45653ABBAA76C2D6E42F98316EDE599B", + "digest_type": 4, + "key_tag": 63909 + }, + "id": "476093df11a52af32fc979470757f83e", + "ttl": 300, + "proxied": false, + "settings": {} + } + }, + { + "index": 188, + "value": { + "created_on": "2026-08-08T13:07:57.601727Z", + "modified_on": "2026-08-08T13:07:57.601727Z", + "type": "NS", + "name": "another-child.dnscontroltest-cf.org", + "content": "ns101.cloudns.net", + "meta": {}, + "id": "8698b0714e5a7121683e6efccda2ce9f", + "ttl": 300, + "proxied": false, + "settings": {} + } + }, + { + "index": 189, + "value": { + "created_on": "2026-08-08T13:07:57.892227Z", + "modified_on": "2026-08-08T13:07:57.892227Z", + "type": "DS", + "name": "another-child.dnscontroltest-cf.org", + "content": "35632 13 4 F5F32ABCA6B01AA7A9963012F90B7C8523A1D946185A3AD70B67F3C9F18E7312FA9DD6AB2F7D8382F789213DB173D429", + "meta": {}, + "data": { + "algorithm": 13, + "digest": "F5F32ABCA6B01AA7A9963012F90B7C8523A1D946185A3AD70B67F3C9F18E7312FA9DD6AB2F7D8382F789213DB173D429", + "digest_type": 4, + "key_tag": 35632 + }, + "id": "ae9cea258454f5355b57da0bd89f59ff", + "ttl": 300, + "proxied": false, + "settings": {} + } + }, + { + "index": 190, + "value": { + "created_on": "2026-08-08T13:08:00.120569Z", + "modified_on": "2026-08-08T13:08:00.120569Z", + "type": "DS", + "name": "another-child.dnscontroltest-cf.org", + "content": "2159 1 4 F50BEFEA333EE2901D72D31A08E1A3CD3F7E943FF4B38CF7C8AD92807F5302F76FB0B419182C0F47FFC71CBCB6EF4BD4", + "meta": {}, + "data": { + "algorithm": 1, + "digest": "F50BEFEA333EE2901D72D31A08E1A3CD3F7E943FF4B38CF7C8AD92807F5302F76FB0B419182C0F47FFC71CBCB6EF4BD4", + "digest_type": 4, + "key_tag": 2159 + }, + "id": "3f1bfdc8042c809d98dffc60b54487df", + "ttl": 300, + "proxied": false, + "settings": {} + } + }, + { + "index": 191, + "value": { + "created_on": "2026-08-08T13:08:00.563981Z", + "modified_on": "2026-08-08T13:08:00.563981Z", + "type": "DS", + "name": "another-child.dnscontroltest-cf.org", + "content": "63909 3 4 EEC7FA02E6788DA889B2CE41D43D92F948AB126EDCF83B7037E73CE9531C8E7E45653ABBAA76C2D6E42F98316EDE599B", + "meta": {}, + "data": { + "algorithm": 3, + "digest": "EEC7FA02E6788DA889B2CE41D43D92F948AB126EDCF83B7037E73CE9531C8E7E45653ABBAA76C2D6E42F98316EDE599B", + "digest_type": 4, + "key_tag": 63909 + }, + "id": "569fb5d4fce9113c2873c402e54fd4b0", + "ttl": 300, + "proxied": false, + "settings": {} + } + }, + { + "index": 192, + "value": { + "created_on": "2026-08-08T13:08:04.293348Z", + "modified_on": "2026-08-08T13:08:04.293348Z", + "type": "CNAME", + "name": "dnscontroltest-cf.org", + "content": "foo.com", + "meta": {}, + "id": "2a62d1ecd56ba88d86941f8590c2ebef", + "ttl": 300, + "proxied": false, + "proxiable": true, + "settings": { + "flatten_cname": false + } + } + }, + { + "index": 193, + "value": { + "created_on": "2026-08-08T13:08:04.293348Z", + "modified_on": "2026-08-08T13:08:06.077878Z", + "type": "CNAME", + "name": "dnscontroltest-cf.org", + "content": "foo2.com", + "meta": {}, + "id": "2a62d1ecd56ba88d86941f8590c2ebef", + "ttl": 300, + "proxied": false, + "proxiable": true, + "settings": { + "flatten_cname": false + } + } + }, + { + "index": 194, + "value": { + "created_on": "2026-08-08T13:08:08.780503Z", + "modified_on": "2026-08-08T13:08:08.780503Z", + "type": "A", + "name": "foo.dnscontroltest-cf.org", + "content": "1.2.3.4", + "meta": {}, + "id": "77594da57f912db16ebd1043e845869e", + "ttl": 300, + "proxied": false, + "proxiable": true, + "settings": {} + } + }, + { + "index": 195, + "value": { + "created_on": "2026-08-08T13:08:09.06415Z", + "modified_on": "2026-08-08T13:08:09.06415Z", + "type": "CNAME", + "name": "dnscontroltest-cf.org", + "content": "foo.dnscontroltest-cf.org", + "meta": {}, + "id": "7510745437699abd38b4d6e4632bbc59", + "ttl": 300, + "proxied": false, + "proxiable": true, + "settings": { + "flatten_cname": false + } + } + }, + { + "index": 196, + "value": { + "created_on": "2026-08-08T13:08:12.033452Z", + "modified_on": "2026-08-08T13:08:12.033452Z", + "type": "CNAME", + "name": "test.dnscontroltest-cf.org", + "content": "foo.com", + "meta": {}, + "id": "6ad40143ec69b0384ce92f51f899722c", + "ttl": 300, + "proxied": false, + "proxiable": true, + "settings": { + "flatten_cname": false + } + } + }, + { + "index": 197, + "value": { + "created_on": "2026-08-08T13:08:12.033452Z", + "modified_on": "2026-08-08T13:08:13.778898Z", + "type": "CNAME", + "name": "test.dnscontroltest-cf.org", + "content": "foo2.com", + "meta": {}, + "id": "6ad40143ec69b0384ce92f51f899722c", + "ttl": 300, + "proxied": false, + "proxiable": true, + "settings": { + "flatten_cname": false + } + } + }, + { + "index": 198, + "value": { + "created_on": "2026-08-08T13:08:29.698896Z", + "modified_on": "2026-08-08T13:08:29.698896Z", + "type": "A", + "name": "prxy.dnscontroltest-cf.org", + "content": "174.136.107.111", + "meta": {}, + "id": "431c4f2cee965195f6c50b47cb60f35d", + "ttl": 300, + "proxied": false, + "proxiable": true, + "settings": {} + } + }, + { + "index": 199, + "value": { + "created_on": "2026-08-08T13:08:32.443666Z", + "modified_on": "2026-08-08T13:08:32.706643Z", + "type": "A", + "name": "prxy.dnscontroltest-cf.org", + "content": "174.136.107.111", + "meta": {}, + "id": "6c07c3c699a54d53f8034e078ba27dc9", + "ttl": 1, + "proxied": true, + "proxiable": true, + "settings": {} + } + }, + { + "index": 200, + "value": { + "created_on": "2026-08-08T13:08:36.194392Z", + "modified_on": "2026-08-08T13:08:36.194392Z", + "type": "A", + "name": "prxy.dnscontroltest-cf.org", + "content": "174.136.107.111", + "meta": {}, + "id": "79235cdb90c4da81a9b65c067eed79bd", + "ttl": 300, + "proxied": false, + "proxiable": true, + "settings": {} + } + }, + { + "index": 201, + "value": { + "created_on": "2026-08-08T13:08:36.194392Z", + "modified_on": "2026-08-08T13:08:37.991362Z", + "type": "A", + "name": "prxy.dnscontroltest-cf.org", + "content": "174.136.107.111", + "meta": {}, + "id": "79235cdb90c4da81a9b65c067eed79bd", + "ttl": 1, + "proxied": true, + "proxiable": true, + "settings": {} + } + }, + { + "index": 202, + "value": { + "created_on": "2026-08-08T13:08:40.721766Z", + "modified_on": "2026-08-08T13:08:40.958535Z", + "type": "A", + "name": "prxy.dnscontroltest-cf.org", + "content": "174.136.107.111", + "meta": {}, + "id": "ae1a7188d9979110806f86503834888c", + "ttl": 1, + "proxied": true, + "proxiable": true, + "settings": {} + } + }, + { + "index": 203, + "value": { + "created_on": "2026-08-08T13:08:40.721766Z", + "modified_on": "2026-08-08T13:08:42.706505Z", + "type": "A", + "name": "prxy.dnscontroltest-cf.org", + "content": "174.136.107.111", + "meta": {}, + "id": "ae1a7188d9979110806f86503834888c", + "ttl": 300, + "proxied": false, + "proxiable": true, + "settings": {} + } + }, + { + "index": 204, + "value": { + "created_on": "2026-08-08T13:08:45.445308Z", + "modified_on": "2026-08-08T13:08:45.445308Z", + "type": "CNAME", + "name": "cproxy.dnscontroltest-cf.org", + "content": "example.com", + "meta": {}, + "id": "064d189b1aadf6350536de758380259b", + "ttl": 300, + "proxied": false, + "proxiable": true, + "settings": { + "flatten_cname": false + } + } + }, + { + "index": 205, + "value": { + "created_on": "2026-08-08T13:08:48.218611Z", + "modified_on": "2026-08-08T13:08:48.451062Z", + "type": "CNAME", + "name": "cproxy.dnscontroltest-cf.org", + "content": "example.com", + "meta": {}, + "id": "5ba8b586cb50d0e7075693899cb165a3", + "ttl": 1, + "proxied": true, + "proxiable": true, + "settings": { + "flatten_cname": false + } + } + }, + { + "index": 206, + "value": { + "created_on": "2026-08-08T13:08:51.94956Z", + "modified_on": "2026-08-08T13:08:51.94956Z", + "type": "CNAME", + "name": "cproxy.dnscontroltest-cf.org", + "content": "example.com", + "meta": {}, + "id": "a8ff59b7e663d27755efcd3cd4aa34ae", + "ttl": 300, + "proxied": false, + "proxiable": true, + "settings": { + "flatten_cname": false + } + } + }, + { + "index": 207, + "value": { + "created_on": "2026-08-08T13:08:51.94956Z", + "modified_on": "2026-08-08T13:08:53.693045Z", + "type": "CNAME", + "name": "cproxy.dnscontroltest-cf.org", + "content": "example.com", + "meta": {}, + "id": "a8ff59b7e663d27755efcd3cd4aa34ae", + "ttl": 1, + "proxied": true, + "proxiable": true, + "settings": { + "flatten_cname": false + } + } + }, + { + "index": 208, + "value": { + "created_on": "2026-08-08T13:08:56.444307Z", + "modified_on": "2026-08-08T13:08:56.706874Z", + "type": "CNAME", + "name": "cproxy.dnscontroltest-cf.org", + "content": "example.com", + "meta": {}, + "id": "12d5b46aea4aa29695f1331f72de72e5", + "ttl": 1, + "proxied": true, + "proxiable": true, + "settings": { + "flatten_cname": false + } + } + }, + { + "index": 209, + "value": { + "created_on": "2026-08-08T13:08:56.444307Z", + "modified_on": "2026-08-08T13:08:58.454629Z", + "type": "CNAME", + "name": "cproxy.dnscontroltest-cf.org", + "content": "example.com", + "meta": {}, + "id": "12d5b46aea4aa29695f1331f72de72e5", + "ttl": 300, + "proxied": false, + "proxiable": true, + "settings": { + "flatten_cname": false + } + } + }, + { + "index": 210, + "value": { + "created_on": "2026-08-08T13:09:01.198395Z", + "modified_on": "2026-08-08T13:09:01.198395Z", + "type": "A", + "name": "cmnt.dnscontroltest-cf.org", + "content": "174.136.107.111", + "meta": {}, + "id": "dfc053be142f334a20f795208c759d8e", + "ttl": 300, + "proxied": false, + "proxiable": true, + "comment": "Test comment", + "settings": {} + } + }, + { + "index": 211, + "value": { + "created_on": "2026-08-08T13:09:01.198395Z", + "modified_on": "2026-08-08T13:09:03.011398Z", + "type": "A", + "name": "cmnt.dnscontroltest-cf.org", + "content": "174.136.107.111", + "meta": {}, + "id": "dfc053be142f334a20f795208c759d8e", + "ttl": 300, + "proxied": false, + "proxiable": true, + "comment": "Changed comment", + "settings": {} + } + }, + { + "index": 212, + "value": { + "created_on": "2026-08-08T13:09:01.198395Z", + "modified_on": "2026-08-08T13:09:04.699341Z", + "type": "A", + "name": "cmnt.dnscontroltest-cf.org", + "content": "174.136.107.111", + "meta": {}, + "id": "dfc053be142f334a20f795208c759d8e", + "ttl": 300, + "proxied": false, + "proxiable": true, + "settings": {} + } + }, + { + "index": 213, + "value": { + "created_on": "2026-08-08T13:09:22.999508Z", + "modified_on": "2026-08-08T13:09:22.999508Z", + "type": "A", + "name": "bar.dnscontroltest-cf.org", + "content": "5.5.5.5", + "meta": {}, + "id": "aada208bab3b426dec73d41530beda7a", + "ttl": 300, + "proxied": false, + "proxiable": true, + "settings": {} + } + }, + { + "index": 214, + "value": { + "created_on": "2026-08-08T13:09:23.251489Z", + "modified_on": "2026-08-08T13:09:23.251489Z", + "type": "A", + "name": "foo.dnscontroltest-cf.org", + "content": "1.2.3.4", + "meta": {}, + "id": "d11c5dfdd01dd9cc7e0d204540b03ae5", + "ttl": 300, + "proxied": false, + "proxiable": true, + "settings": {} + } + }, + { + "index": 215, + "value": { + "created_on": "2026-08-08T13:09:23.506668Z", + "modified_on": "2026-08-08T13:09:23.506668Z", + "type": "A", + "name": "foo.dnscontroltest-cf.org", + "content": "2.3.4.5", + "meta": {}, + "id": "64ce20aa48790cabbfdbce548c0bb3af", + "ttl": 300, + "proxied": false, + "proxiable": true, + "settings": {} + } + }, + { + "index": 216, + "value": { + "created_on": "2026-08-08T13:09:23.744247Z", + "modified_on": "2026-08-08T13:09:23.744247Z", + "type": "TXT", + "name": "foo.dnscontroltest-cf.org", + "content": "\"simple\"", + "meta": {}, + "id": "46039996d0a84e353d9d39fdd92290c5", + "ttl": 300, + "proxied": false, + "settings": {} + } + }, + { + "index": 217, + "value": { + "created_on": "2026-08-08T13:09:24.006229Z", + "modified_on": "2026-08-08T13:09:24.006229Z", + "type": "CNAME", + "name": "mail.dnscontroltest-cf.org", + "content": "ghs.googlehosted.com", + "meta": {}, + "id": "c4514822174bb21ac5017d5a2398cae6", + "ttl": 300, + "proxied": false, + "proxiable": true, + "settings": { + "flatten_cname": false + } + } + }, + { + "index": 218, + "value": { + "created_on": "2026-08-08T13:09:51.801158Z", + "modified_on": "2026-08-08T13:09:51.801158Z", + "type": "A", + "name": "dnscontroltest-cf.org", + "content": "1.2.3.4", + "meta": {}, + "id": "8e92c863e41b42f57ab7183d3a5861bd", + "ttl": 300, + "proxied": false, + "proxiable": true, + "settings": {} + } + }, + { + "index": 219, + "value": { + "created_on": "2026-08-08T13:09:52.004713Z", + "modified_on": "2026-08-08T13:09:52.004713Z", + "type": "A", + "name": "dnscontroltest-cf.org", + "content": "2.3.4.5", + "meta": {}, + "id": "c597b273e1bf6834cd86725d2f1bbdd1", + "ttl": 300, + "proxied": false, + "proxiable": true, + "settings": {} + } + }, + { + "index": 220, + "value": { + "created_on": "2026-08-08T13:09:52.268452Z", + "modified_on": "2026-08-08T13:09:52.268452Z", + "type": "TXT", + "name": "dnscontroltest-cf.org", + "content": "\"simple\"", + "meta": {}, + "id": "eb796e651ffb6a6637311f0282070ef6", + "ttl": 300, + "proxied": false, + "settings": {} + } + }, + { + "index": 221, + "value": { + "created_on": "2026-08-08T13:09:52.555392Z", + "modified_on": "2026-08-08T13:09:52.555392Z", + "type": "A", + "name": "bar.dnscontroltest-cf.org", + "content": "5.5.5.5", + "meta": {}, + "id": "9d7520d8ea4d0f939c8093e971aa7ade", + "ttl": 300, + "proxied": false, + "proxiable": true, + "settings": {} + } + }, + { + "index": 222, + "value": { + "created_on": "2026-08-08T13:09:52.762481Z", + "modified_on": "2026-08-08T13:09:52.762481Z", + "type": "CNAME", + "name": "mail.dnscontroltest-cf.org", + "content": "ghs.googlehosted.com", + "meta": {}, + "id": "55ed1d42971606d5d72d05ffde24f443", + "ttl": 300, + "proxied": false, + "proxiable": true, + "settings": { + "flatten_cname": false + } + } + }, + { + "index": 223, + "value": { + "created_on": "2026-08-08T13:10:20.589889Z", + "modified_on": "2026-08-08T13:10:20.589889Z", + "type": "A", + "name": "dnscontroltest-cf.org", + "content": "2.2.2.2", + "meta": {}, + "id": "fee9806073fa3d4def30c7dfa5112209", + "ttl": 300, + "proxied": false, + "proxiable": true, + "settings": {} + } + }, + { + "index": 224, + "value": { + "created_on": "2026-08-08T13:10:20.845069Z", + "modified_on": "2026-08-08T13:10:20.845069Z", + "type": "TXT", + "name": "dnscontroltest-cf.org", + "content": "\"asimple\"", + "meta": {}, + "id": "4a35c98f172b9ca80eb80c5b1767c66e", + "ttl": 300, + "proxied": false, + "settings": {} + } + }, + { + "index": 225, + "value": { + "created_on": "2026-08-08T13:10:21.096279Z", + "modified_on": "2026-08-08T13:10:21.096279Z", + "type": "A", + "name": "foo.dnscontroltest-cf.org", + "content": "1.2.3.4", + "meta": {}, + "id": "b045b9ea2a63b3900d87ad7ad04df3b4", + "ttl": 300, + "proxied": false, + "proxiable": true, + "settings": {} + } + }, + { + "index": 226, + "value": { + "created_on": "2026-08-08T13:10:21.379544Z", + "modified_on": "2026-08-08T13:10:21.379544Z", + "type": "TXT", + "name": "foo.dnscontroltest-cf.org", + "content": "\"simple\"", + "meta": {}, + "id": "a3cc25b1417de5660b44e6a9fef47568", + "ttl": 300, + "proxied": false, + "settings": {} + } + }, + { + "index": 227, + "value": { + "created_on": "2026-08-08T13:10:30.85461Z", + "modified_on": "2026-08-08T13:10:30.85461Z", + "type": "A", + "name": "bar.bat.dnscontroltest-cf.org", + "content": "5.5.5.5", + "meta": {}, + "id": "ed375ceb747f5d204ce5d87dfa85c08a", + "ttl": 300, + "proxied": false, + "proxiable": true, + "settings": {} + } + }, + { + "index": 228, + "value": { + "created_on": "2026-08-08T13:10:31.136069Z", + "modified_on": "2026-08-08T13:10:31.136069Z", + "type": "A", + "name": "foo.bat.dnscontroltest-cf.org", + "content": "1.2.3.4", + "meta": {}, + "id": "4912166552c61c7f4e8ca4f7cc82edd3", + "ttl": 300, + "proxied": false, + "proxiable": true, + "settings": {} + } + }, + { + "index": 229, + "value": { + "created_on": "2026-08-08T13:10:31.342682Z", + "modified_on": "2026-08-08T13:10:31.342682Z", + "type": "A", + "name": "foo.bat.dnscontroltest-cf.org", + "content": "2.3.4.5", + "meta": {}, + "id": "b21bcf3cdec020f12c334a7f98488abb", + "ttl": 300, + "proxied": false, + "proxiable": true, + "settings": {} + } + }, + { + "index": 230, + "value": { + "created_on": "2026-08-08T13:10:31.595162Z", + "modified_on": "2026-08-08T13:10:31.595162Z", + "type": "TXT", + "name": "foo.bat.dnscontroltest-cf.org", + "content": "\"simple\"", + "meta": {}, + "id": "41d921ae175701a4c460f6d4d0d54a59", + "ttl": 300, + "proxied": false, + "settings": {} + } + }, + { + "index": 231, + "value": { + "created_on": "2026-08-08T13:10:31.83799Z", + "modified_on": "2026-08-08T13:10:31.83799Z", + "type": "CNAME", + "name": "mail.bat.dnscontroltest-cf.org", + "content": "ghs.googlehosted.com", + "meta": {}, + "id": "63837c90319afc5ca454ba5c43874969", + "ttl": 300, + "proxied": false, + "proxiable": true, + "settings": { + "flatten_cname": false + } + } + }, + { + "index": 232, + "value": { + "created_on": "2026-08-08T13:10:44.593884Z", + "modified_on": "2026-08-08T13:10:44.593884Z", + "type": "A", + "name": "foo.dnscontroltest-cf.org", + "content": "1.1.1.1", + "meta": {}, + "id": "56a312357615af80a2ba28a39967f304", + "ttl": 300, + "proxied": false, + "settings": {} + } + }, + { + "index": 233, + "value": { + "created_on": "2026-08-08T13:10:44.846816Z", + "modified_on": "2026-08-08T13:10:44.846816Z", + "type": "A", + "name": "foo.dnscontroltest-cf.org", + "content": "10.10.10.10", + "meta": {}, + "id": "4a907997c376b46406642ad631e77498", + "ttl": 300, + "proxied": false, + "settings": {} + } + }, + { + "index": 234, + "value": { + "created_on": "2026-08-08T13:10:44.846816Z", + "modified_on": "2026-08-08T13:10:48.118964Z", + "type": "A", + "name": "foo.dnscontroltest-cf.org", + "content": "11.11.11.11", + "meta": {}, + "id": "4a907997c376b46406642ad631e77498", + "ttl": 300, + "proxied": false, + "proxiable": true, + "settings": {} + } + }, + { + "index": 235, + "value": { + "created_on": "2026-08-08T13:10:44.846816Z", + "modified_on": "2026-08-08T13:10:51.331103Z", + "type": "A", + "name": "foo.dnscontroltest-cf.org", + "content": "12.12.12.12", + "meta": {}, + "id": "4a907997c376b46406642ad631e77498", + "ttl": 300, + "proxied": false, + "proxiable": true, + "settings": {} + } + }, + { + "index": 236, + "value": { + "created_on": "2026-08-08T13:10:44.846816Z", + "modified_on": "2026-08-08T13:10:54.599364Z", + "type": "A", + "name": "foo.dnscontroltest-cf.org", + "content": "13.13.13.13", + "meta": {}, + "id": "4a907997c376b46406642ad631e77498", + "ttl": 300, + "proxied": false, + "proxiable": true, + "settings": {} + } + }, + { + "index": 237, + "value": { + "created_on": "2026-08-08T13:10:44.846816Z", + "modified_on": "2026-08-08T13:10:57.874804Z", + "type": "A", + "name": "foo.dnscontroltest-cf.org", + "content": "14.14.14.14", + "meta": {}, + "id": "4a907997c376b46406642ad631e77498", + "ttl": 300, + "proxied": false, + "proxiable": true, + "settings": {} + } + }, + { + "index": 238, + "value": { + "created_on": "2026-08-08T13:10:45.100559Z", + "modified_on": "2026-08-08T13:10:45.100559Z", + "type": "AAAA", + "name": "foo.dnscontroltest-cf.org", + "content": "2003:dd:d7ff::fe71:aaaa", + "meta": {}, + "id": "59508589533749c0f06587ddb9d756e7", + "ttl": 300, + "proxied": false, + "proxiable": true, + "settings": {} + } + }, + { + "index": 239, + "value": { + "created_on": "2026-08-08T13:10:45.340125Z", + "modified_on": "2026-08-08T13:10:45.340125Z", + "type": "MX", + "name": "foo.dnscontroltest-cf.org", + "content": "aspmx.l.google.com", + "meta": {}, + "id": "25771ad8704db812117914248aeb45d8", + "priority": 10, + "ttl": 300, + "proxied": false, + "settings": {} + } + }, + { + "index": 240, + "value": { + "created_on": "2026-08-08T13:10:45.597514Z", + "modified_on": "2026-08-08T13:10:45.597514Z", + "type": "MX", + "name": "foo.dnscontroltest-cf.org", + "content": "alt1.aspmx.l.google.com", + "meta": {}, + "id": "8744eee5045673123d8677469a01e63a", + "priority": 20, + "ttl": 300, + "proxied": false, + "settings": {} + } + }, + { + "index": 241, + "value": { + "created_on": "2026-08-08T13:10:45.841395Z", + "modified_on": "2026-08-08T13:10:45.841395Z", + "type": "A", + "name": "zzz.dnscontroltest-cf.org", + "content": "3.3.3.3", + "meta": {}, + "id": "f02e86cb3028b5979496a808b7800b1f", + "ttl": 300, + "proxied": false, + "proxiable": true, + "settings": {} + } + }, + { + "index": 242, + "value": { + "created_on": "2026-08-08T13:10:46.147816Z", + "modified_on": "2026-08-08T13:10:46.147816Z", + "type": "A", + "name": "zzz.dnscontroltest-cf.org", + "content": "4.4.4.4", + "meta": {}, + "id": "9496749a9687a0cea11ce79413d496ca", + "ttl": 300, + "proxied": false, + "proxiable": true, + "settings": {} + } + }, + { + "index": 243, + "value": { + "created_on": "2026-08-08T13:10:46.339081Z", + "modified_on": "2026-08-08T13:10:46.339081Z", + "type": "AAAA", + "name": "zzz.dnscontroltest-cf.org", + "content": "2003:dd:d7ff::fe71:cccc", + "meta": {}, + "id": "60504086e3d3bb4826e4ec459a83fa24", + "ttl": 300, + "proxied": false, + "proxiable": true, + "settings": {} + } + }, + { + "index": 244, + "value": { + "created_on": "2026-08-08T13:11:04.072653Z", + "modified_on": "2026-08-08T13:11:04.072653Z", + "type": "CNAME", + "name": "bar.dnscontroltest-cf.org", + "content": "redact2.acm-validations.aws", + "meta": {}, + "id": "ed12ddef78419c00dab39ef4e7e90383", + "ttl": 300, + "proxied": false, + "settings": { + "flatten_cname": false + } + } + }, + { + "index": 245, + "value": { + "created_on": "2026-08-08T13:11:04.334484Z", + "modified_on": "2026-08-08T13:11:04.334484Z", + "type": "CNAME", + "name": "foo.dnscontroltest-cf.org", + "content": "redact1.acm-validations.aws", + "meta": {}, + "id": "8c22b6399e25df25d13c15a1b124d181", + "ttl": 300, + "proxied": false, + "settings": { + "flatten_cname": false + } + } + }, + { + "index": 246, + "value": { + "created_on": "2026-08-08T13:11:09.535382Z", + "modified_on": "2026-08-08T13:11:09.535382Z", + "type": "A", + "name": "dyndns-city1.dnscontroltest-cf.org", + "content": "91.42.1.1", + "meta": {}, + "id": "8053288b239ba998b5bee3426fe68a15", + "ttl": 300, + "proxied": false, + "proxiable": true, + "settings": {} + } + }, + { + "index": 247, + "value": { + "created_on": "2026-08-08T13:11:09.82336Z", + "modified_on": "2026-08-08T13:11:09.82336Z", + "type": "AAAA", + "name": "dyndns-city1.dnscontroltest-cf.org", + "content": "2003:dd:d7ff::fe71:ce77", + "meta": {}, + "id": "7032769137888d4104d669afa2065424", + "ttl": 300, + "proxied": false, + "proxiable": true, + "settings": {} + } + }, + { + "index": 248, + "value": { + "created_on": "2026-08-08T13:11:10.023947Z", + "modified_on": "2026-08-08T13:11:10.023947Z", + "type": "A", + "name": "dyndns-city2.dnscontroltest-cf.org", + "content": "91.42.1.2", + "meta": {}, + "id": "c32956f045602e667163cd418c1049e3", + "ttl": 300, + "proxied": false, + "proxiable": true, + "settings": {} + } + }, + { + "index": 249, + "value": { + "created_on": "2026-08-08T13:11:10.333158Z", + "modified_on": "2026-08-08T13:11:10.333158Z", + "type": "AAAA", + "name": "dyndns-city2.dnscontroltest-cf.org", + "content": "2003:dd:d7ff::fe71:ce78", + "meta": {}, + "id": "1d0c02c814dbdcaf8a125bfd42240b6a", + "ttl": 300, + "proxied": false, + "proxiable": true, + "settings": {} + } + }, + { + "index": 250, + "value": { + "created_on": "2026-08-08T13:11:16.82589Z", + "modified_on": "2026-08-08T13:11:16.82589Z", + "type": "A", + "name": "testdefined.dnscontroltest-cf.org", + "content": "9.9.9.9", + "meta": {}, + "id": "38301e400b7017351d39629df94a3b78", + "ttl": 300, + "proxied": false, + "proxiable": true, + "settings": {} + } + }, + { + "index": 251, + "value": { + "created_on": "2026-08-08T13:11:16.82589Z", + "modified_on": "2026-08-08T13:11:24.793588Z", + "type": "A", + "name": "testdefined.dnscontroltest-cf.org", + "content": "2.2.2.2", + "meta": {}, + "id": "38301e400b7017351d39629df94a3b78", + "ttl": 300, + "proxied": false, + "proxiable": true, + "settings": {} + } + }, + { + "index": 252, + "value": { + "created_on": "2026-08-08T13:11:17.041202Z", + "modified_on": "2026-08-08T13:11:17.041202Z", + "type": "A", + "name": "testignore.dnscontroltest-cf.org", + "content": "8.8.8.8", + "meta": {}, + "id": "8dd9b96dec39723f80b55c0263781ba5", + "ttl": 300, + "proxied": false, + "proxiable": true, + "settings": {} + } + }, + { + "index": 253, + "value": { + "created_on": "2026-08-08T13:11:30.035262Z", + "modified_on": "2026-08-08T13:11:30.035262Z", + "type": "TXT", + "name": "final.dnscontroltest-cf.org", + "content": "\"TestDNSProviders was successful!\"", + "meta": {}, + "id": "0c29dfe7f2cd0cffd1c9bb3354f19bcd", + "ttl": 300, + "proxied": false, + "settings": {} + } + }, + { + "index": 254, + "value": { + "created_on": "2026-08-08T13:11:32.78795Z", + "modified_on": "2026-08-08T13:11:32.78795Z", + "type": "TXT", + "name": "final.dnscontroltest-cf.org", + "content": "\"TestDNSProviders was successful!\"", + "meta": {}, + "id": "64f9cd6f158a6309ea0481607338b9af", + "ttl": 300, + "proxied": false, + "settings": {} + } + } +] diff --git a/providers/cloudns/api.go b/providers/cloudns/api.go index 45a1b6d71e..382e7444cd 100644 --- a/providers/cloudns/api.go +++ b/providers/cloudns/api.go @@ -11,12 +11,14 @@ import ( "strings" "sync" - "github.com/DNSControl/dnscontrol/v4/pkg/printer" + "github.com/DNSControl/dnscontrol/v5/pkg/printer" + "github.com/DNSControl/dnscontrol/v5/pkg/providers" ) // cloudnsProvider is the handle for the ClouDNS API. type cloudnsProvider struct { - creds struct { + observer providers.ConversionObserver + creds struct { id string password string subid string @@ -29,6 +31,10 @@ type cloudnsProvider struct { nameserversNames []string } +func (c *cloudnsProvider) SetConversionObserver(observer providers.ConversionObserver) { + c.observer = observer +} + type requestParams map[string]string type errorResponse struct { diff --git a/providers/cloudns/auditrecords.go b/providers/cloudns/auditrecords.go index 7c7285c15c..ed89e29827 100644 --- a/providers/cloudns/auditrecords.go +++ b/providers/cloudns/auditrecords.go @@ -1,23 +1,23 @@ package cloudns import ( - "github.com/DNSControl/dnscontrol/v4/models" - "github.com/DNSControl/dnscontrol/v4/pkg/rejectif" + "github.com/DNSControl/dnscontrol/v5/models" + "github.com/DNSControl/dnscontrol/v5/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 { +func AuditRecords(records models.Records) []error { a := rejectif.Auditor{} - a.Add("TXT", rejectif.TxtHasBackticks) // Last verified 2021-03-01 + a.Add("TXT", rejectif.TxtHasBackticks) // Last verified 2026-08-03 - a.Add("TXT", rejectif.TxtIsEmpty) // Last verified 2021-03-01 + a.Add("TXT", rejectif.TxtIsEmpty) // Last verified 2026-08-03 - a.Add("TXT", rejectif.TxtHasTrailingSpace) // Last verified 2021-03-01 + a.Add("TXT", rejectif.TxtHasTrailingSpace) // Last verified 2026-08-03 - a.Add("TXT", rejectif.TxtHasDoubleQuotes) // Last verified 2021-03-01 + a.Add("TXT", rejectif.TxtHasDoubleQuotes) // Last verified 2026-08-03 return a.Audit(records) } diff --git a/providers/cloudns/cloudnsProvider.go b/providers/cloudns/cloudnsProvider.go index 39f4567f7d..05eaf44f31 100644 --- a/providers/cloudns/cloudnsProvider.go +++ b/providers/cloudns/cloudnsProvider.go @@ -8,14 +8,13 @@ import ( "strconv" "strings" + dnsv2 "codeberg.org/miekg/dns" + "github.com/DNSControl/dnscontrol/v5/models" + "github.com/DNSControl/dnscontrol/v5/pkg/diff2" + "github.com/DNSControl/dnscontrol/v5/pkg/printer" + "github.com/DNSControl/dnscontrol/v5/pkg/privatetypes" + "github.com/DNSControl/dnscontrol/v5/pkg/providers" "github.com/fatih/color" - - "github.com/DNSControl/dnscontrol/v4/models" - "github.com/DNSControl/dnscontrol/v4/pkg/diff" - "github.com/DNSControl/dnscontrol/v4/pkg/diff2" - "github.com/DNSControl/dnscontrol/v4/pkg/printer" - "github.com/DNSControl/dnscontrol/v4/pkg/providers" - dnsutilv1 "github.com/miekg/dns/dnsutil" ) /* @@ -165,115 +164,82 @@ func (c *cloudnsProvider) GetZoneRecordsCorrections(dc *models.DomainConfig, exi return nil, 0, err } - var ( - reportMsgs []string - create diff.Changeset - del diff.Changeset - modify diff.Changeset - ) + // diff2.ByRecord returns the instructions in a safe order (e.g. a delete is + // emitted before the create that replaces it, and dependency-ordered so an + // A/AAAA precedes the NS that needs it and an NS precedes its DS), so emit + // the corrections in that order rather than re-sorting them by type. + var reportCorrections, recordCorrections []*models.Correction for _, inst := range instructions { - cor := diff.Correlation{} switch inst.Type { case diff2.REPORT: - reportMsgs = append(reportMsgs, inst.Msgs...) + for _, msg := range inst.Msgs { + reportCorrections = append(reportCorrections, &models.Correction{Msg: msg}) + } + case diff2.CREATE: - cor.Desired = inst.New[0] - create = append(create, cor) + desired := inst.New[0] + input := models.Records{desired} + before := providers.BeginToNative(c.observer, "toReq", input) + req, err := toReq(desired) + providers.EndToNative(c.observer, "toReq", before, input, req, err) + if err != nil { + return nil, 0, err + } + // ClouDNS does not require the trailing period to be specified when creating an NS record where the A or AAAA record exists in the zone. + // So, modify it to remove the trailing period. + if req["record-type"] == "NS" && strings.HasSuffix(req["record"], domainID+".") { + req["record"] = strings.TrimSuffix(req["record"], ".") + } + recordCorrections = append(recordCorrections, &models.Correction{ + Msg: fmt.Sprintf("%s%s", inst.Msgs[0], addMetadataCorrection(nil, desired)), + F: func() error { + return c.createRecord(domainID, req) + }, + }) + case diff2.CHANGE: - cor.Existing = inst.Old[0] - cor.Desired = inst.New[0] - modify = append(modify, cor) + existing := inst.Old[0] + desired := inst.New[0] + id := existing.Original.(*domainRecord).ID + input := models.Records{desired} + before := providers.BeginToNative(c.observer, "toReq", input) + req, err := toReq(desired) + providers.EndToNative(c.observer, "toReq", before, input, req, err) + if err != nil { + return nil, 0, err + } + // ClouDNS does not require the trailing period to be specified when updating an NS record where the A or AAAA record exists in the zone. + // So, modify it to remove the trailing period. + if req["record-type"] == "NS" && strings.HasSuffix(req["record"], domainID+".") { + req["record"] = strings.TrimSuffix(req["record"], ".") + } + recordCorrections = append(recordCorrections, &models.Correction{ + Msg: fmt.Sprintf("%s%s, ClouDNS ID: %s: ", inst.Msgs[0], addMetadataCorrection(existing, desired), id), + F: func() error { + return c.modifyRecord(domainID, id, req) + }, + }) + case diff2.DELETE: - cor.Existing = inst.Old[0] - del = append(del, cor) + existing := inst.Old[0] + id := existing.Original.(*domainRecord).ID + recordCorrections = append(recordCorrections, &models.Correction{ + Msg: fmt.Sprintf("%s%s, ClouDNS ID: %s", inst.Msgs[0], addMetadataCorrection(existing, nil), id), + F: func() error { + return c.deleteRecord(domainID, id) + }, + }) + default: panic(fmt.Sprintf("unhandled inst.Type %s", inst.Type)) } } - // Start corrections with the reports - corrections := diff.GenerateMessageCorrections(reportMsgs) + // Order: reports, DNSSEC changes, then the record changes in diff2's order. + var corrections []*models.Correction + corrections = append(corrections, reportCorrections...) corrections = append(corrections, dnssecFixes...) - - // Deletes first so changing type works etc. - for _, m := range del { - id := m.Existing.Original.(*domainRecord).ID - corr := &models.Correction{ - Msg: fmt.Sprintf("%s%s, ClouDNS ID: %s", m.String(), addMetadataCorrection(m.Existing, m.Desired), id), - F: func() error { - return c.deleteRecord(domainID, id) - }, - } - // at ClouDNS, we MUST have a NS for a DS - // So, when deleting, we must delete the DS first, otherwise deleting the NS throws an error - if m.Existing.Type == "DS" { - // type DS is prepended - so executed first - corrections = append([]*models.Correction{corr}, corrections...) - } else { - corrections = append(corrections, corr) - } - } - - var ( - createCorrections []*models.Correction - createARecordCorrections []*models.Correction - createNSRecordCorrections []*models.Correction - ) - for _, m := range create { - req, err := toReq(m.Desired) - if err != nil { - return nil, 0, err - } - - // ClouDNS does not require the trailing period to be specified when creating an NS record where the A or AAAA record exists in the zone. - // So, modify it to remove the trailing period. - if req["record-type"] == "NS" && strings.HasSuffix(req["record"], domainID+".") { - req["record"] = strings.TrimSuffix(req["record"], ".") - } - - corr := &models.Correction{ - Msg: fmt.Sprintf("%s%s", m.String(), addMetadataCorrection(m.Existing, m.Desired)), - F: func() error { - return c.createRecord(domainID, req) - }, - } - // A & AAAA need to be created before NS #2244 - // NS need to be created before DS #1018 - // or else errors will be thrown - switch m.Desired.Type { - case "A", "AAAA": - createARecordCorrections = append(createARecordCorrections, corr) - case "NS": - createNSRecordCorrections = append(createNSRecordCorrections, corr) - default: - createCorrections = append(createCorrections, corr) - } - } - corrections = append(corrections, createARecordCorrections...) - corrections = append(corrections, createNSRecordCorrections...) - corrections = append(corrections, createCorrections...) - - for _, m := range modify { - id := m.Existing.Original.(*domainRecord).ID - req, err := toReq(m.Desired) - if err != nil { - return nil, 0, err - } - - // ClouDNS does not require the trailing period to be specified when updating an NS record where the A or AAAA record exists in the zone. - // So, modify it to remove the trailing period. - if req["record-type"] == "NS" && strings.HasSuffix(req["record"], domainID+".") { - req["record"] = strings.TrimSuffix(req["record"], ".") - } - - corr := &models.Correction{ - Msg: fmt.Sprintf("%s%s, ClouDNS ID: %s: ", m.String(), addMetadataCorrection(m.Existing, m.Desired), id), - F: func() error { - return c.modifyRecord(domainID, id, req) - }, - } - corrections = append(corrections, corr) - } + corrections = append(corrections, recordCorrections...) return corrections, actualChangeCount, nil } @@ -338,15 +304,15 @@ func (c *cloudnsProvider) getDNSSECCorrections(dc *models.DomainConfig) ([]*mode // GetZoneRecords gets the records of a zone and returns them in RecordConfig format. func (c *cloudnsProvider) GetZoneRecords(dc *models.DomainConfig) (models.Records, error) { - domain := dc.Name - - records, err := c.getRecords(domain) + records, err := c.getRecords(dc.Name) if err != nil { return nil, err } - existingRecords := make([]*models.RecordConfig, len(records)) + existingRecords := make(models.Records, len(records)) for i := range records { - existingRecords[i], err = toRc(domain, &records[i]) + before := providers.BeginToRC(c.observer, "toRc", &records[i]) + existingRecords[i], err = toRc(dc, &records[i]) + providers.EndToRC(c.observer, "toRc", before, &records[i], models.Records{existingRecords[i]}, err) if err != nil { return nil, err } @@ -380,89 +346,112 @@ func (c *cloudnsProvider) ListZones() ([]string, error) { } // parses the ClouDNS format into our standard RecordConfig. -func toRc(domain string, r *domainRecord) (*models.RecordConfig, error) { - ttl, _ := strconv.ParseUint(r.TTL, 10, 32) - priority, _ := strconv.ParseUint(r.Priority, 10, 16) - weight, _ := strconv.ParseUint(r.Weight, 10, 16) - port, _ := strconv.ParseUint(r.Port, 10, 16) - - rc := &models.RecordConfig{ - Type: r.Type, - TTL: uint32(ttl), - MxPreference: uint16(priority), - SrvPriority: uint16(priority), - SrvWeight: uint16(weight), - SrvPort: uint16(port), - Original: r, - } - rc.SetLabel(r.Host, domain) +func toRc(dc *models.DomainConfig, r *domainRecord) (*models.RecordConfig, error) { + var err error - // Add metadata for GeoDNS - // Note: By default, it works only with A, AAAA, CNAME, NAPTR or SRV record - // but you can ask the support for others type of record and they enable it - // for your ClouDNS account. - if r.GeodnsCode != "" { - if rc.Metadata == nil { - rc.Metadata = map[string]string{} - } - rc.Metadata[metaGeodnsCode] = r.GeodnsCode + ttl_, err := strconv.ParseUint(r.TTL, 10, 32) + if err != nil { + return nil, err } + ttl := uint32(ttl_) + label := dc.LabelFromShort(r.Host) - var err error + var rc *models.RecordConfig switch rtype := r.Type; rtype { // #rtype_variations case "TXT": - err = rc.SetTargetTXT(r.Target) - case "CNAME", "DNAME", "MX", "NS", "SRV", "ALIAS", "PTR": - if err := rc.SetTarget(dnsutilv1.AddOrigin(r.Target+".", domain)); err != nil { - return nil, err - } + rc, err = dc.NewRecordConfig(label, ttl, dnsv2.TypeTXT, r.Target) + case "MX": + rc, err = dc.NewRecordConfig(label, ttl, dnsv2.TypeMX, r.Priority, dc.ToFqdnWithDot(r.Target+".")) // ignore:legacyfield + case "SRV": + rc, err = dc.NewRecordConfig(label, ttl, dnsv2.TypeSRV, r.Priority, r.Weight, r.Port, dc.ToFqdnWithDot(r.Target+".")) // ignore:legacyfield + case "ALIAS": + rc, err = dc.NewRecordConfig(label, ttl, privatetypes.TypeALIAS, dc.ToFqdnWithDot(r.Target+".")) + case "CNAME", "DNAME", "NS", "PTR": + rc, err = dc.NewRecordConfig(label, ttl, rtype, dc.ToFqdnWithDot(r.Target+".")) case "CAA": - caaFlag, _ := strconv.ParseUint(r.CaaFlag, 10, 8) - rc.CaaFlag = uint8(caaFlag) - rc.CaaTag = r.CaaTag - err = rc.SetTarget(r.CaaValue) + rc, err = dc.NewRecordConfig(label, ttl, dnsv2.TypeCAA, r.CaaFlag, r.CaaTag, r.CaaValue) // ignore:legacyfield case "TLSA": - tlsaUsage, _ := strconv.ParseUint(r.TlsaUsage, 10, 8) - rc.TlsaUsage = uint8(tlsaUsage) - tlsaSelector, _ := strconv.ParseUint(r.TlsaSelector, 10, 8) - rc.TlsaSelector = uint8(tlsaSelector) - tlsaMatchingType, _ := strconv.ParseUint(r.TlsaMatchingType, 10, 8) - rc.TlsaMatchingType = uint8(tlsaMatchingType) - err = rc.SetTarget(r.Target) + rc, err = dc.NewRecordConfig(label, ttl, dnsv2.TypeTLSA, r.TlsaUsage, r.TlsaSelector, r.TlsaMatchingType, r.Target) // ignore:legacyfield case "SSHFP": - sshfpAlgorithm, _ := strconv.ParseUint(r.SshfpAlgorithm, 10, 8) - rc.SshfpAlgorithm = uint8(sshfpAlgorithm) - sshfpFingerprint, _ := strconv.ParseUint(r.SshfpFingerprint, 10, 8) - rc.SshfpFingerprint = uint8(sshfpFingerprint) - err = rc.SetTarget(r.Target) + rc, err = dc.NewRecordConfig(label, ttl, dnsv2.TypeSSHFP, r.SshfpAlgorithm, r.SshfpFingerprint, r.Target) // ignore:legacyfield case "DS": - dsKeyTag, _ := strconv.ParseUint(r.DsKeyTag, 10, 16) - rc.DsKeyTag = uint16(dsKeyTag) - dsAlgorithm, _ := strconv.ParseUint(r.SshfpAlgorithm, 10, 8) // SshFpAlgorithm and DsAlgorithm both use json field "algorithm" - rc.DsAlgorithm = uint8(dsAlgorithm) - dsDigestType, _ := strconv.ParseUint(r.DsDigestType, 10, 8) - rc.DsDigestType = uint8(dsDigestType) - rc.DsDigest = r.Target - err = rc.SetTarget(r.Target) + // SshfpAlgorithm and DS algorithm both use the API's "algorithm" field. + rc, err = dc.NewRecordConfig(label, ttl, dnsv2.TypeDS, r.DsKeyTag, r.SshfpAlgorithm, r.DsDigestType, r.Target) // ignore:legacyfield case "CLOUD_WR": - rc.Type = "CLOUDNS_WR" - err = rc.SetTarget(r.Target) + rc, err = dc.NewRecordConfig(label, ttl, privatetypes.TypeCLOUDNSWR, r.Target) case "LOC": - loc := fmt.Sprintf("%s %s %s %s %s %s %s %s %s %s %s %s", - r.LocLatDeg, r.LocLatMin, r.LocLatSec, r.LocLatDir, - r.LocLongDeg, r.LocLongMin, r.LocLongSec, r.LocLongDir, - r.LocAltitude, r.LocSize, r.LocHPrecision, r.LocVPrecision) - err = rc.SetTargetLOCString(r.Target, loc) + latSec, err := parseFloat32(r.LocLatSec) + if err != nil { + return nil, err + } + + longSec, err := parseFloat32(r.LocLongSec) + if err != nil { + return nil, err + } + + altitude, err := parseFloat32(r.LocAltitude) // ignore:legacyfield + if err != nil { + return nil, err + } + + size, err := parseFloat32(r.LocSize) // ignore:legacyfield + if err != nil { + return nil, err + } + + hPrec, err := parseFloat32(r.LocHPrecision) + if err != nil { + return nil, err + } + + vPrec, err := parseFloat32(r.LocVPrecision) + if err != nil { + return nil, err + } + + rc, err = dc.NewRecordConfig(label, ttl, dnsv2.TypeLOC, + r.LocLatDeg, r.LocLatMin, latSec, r.LocLatDir, + r.LocLongDeg, r.LocLongMin, longSec, r.LocLongDir, + altitude, size, hPrec, vPrec) + if err != nil { + return nil, err + } + case "NAPTR": - naptrOrder, _ := strconv.ParseUint(r.NaptrOrder, 10, 16) - naptrPreference, _ := strconv.ParseUint(r.NaptrPreference, 10, 16) - target := dnsutilv1.AddOrigin(r.NaptrReplacement+".", domain) - err = rc.SetTargetNAPTR(uint16(naptrOrder), uint16(naptrPreference), r.NaptrFlags, r.NaptrService, r.NaptrRegexp, target) + target := dc.ToFqdnWithDot(r.NaptrReplacement + ".") + rc, err = dc.NewRecordConfig(label, ttl, dnsv2.TypeNAPTR, r.NaptrOrder, r.NaptrPreference, r.NaptrFlags, r.NaptrService, r.NaptrRegexp, target) // ignore:legacyfield default: - err = rc.SetTarget(r.Target) + rc, err = dc.NewRecordConfigParse(label, ttl, rtype, r.Target) + } + if err != nil { + return nil, err } - return rc, err + // Add metadata for GeoDNS + // Note: By default, it works only with A, AAAA, CNAME, NAPTR or SRV record + // but you can ask the support for others type of record and they enable it + // for your ClouDNS account. + if r.GeodnsCode != "" { + rc.Metadata[metaGeodnsCode] = r.GeodnsCode + } + + rc.Original = r + + // Add metadata for GeoDNS. By default, it works only with A, AAAA, CNAME, + // NAPTR, or SRV records, but support can enable other types per account. + if r.GeodnsCode != "" { + rc.Metadata[metaGeodnsCode] = r.GeodnsCode + } + + return rc, nil +} + +// parseFloat32 parses s into a float32. This has an advantage over +// NewRecordConfig because errors are detected earlier. +func parseFloat32(s string) (float32, error) { + f, err := strconv.ParseFloat(s, 32) + return float32(f), err } func formatLocParam(param string) string { @@ -476,56 +465,67 @@ func formatLocParam(param string) string { // toReq takes a RecordConfig and turns it into the native format used by the API. func toReq(rc *models.RecordConfig) (requestParams, error) { + + host := rc.GetLabel() + // ClouDNS doesn't use "@", it uses an empty name + if host == "@" { + host = "" + } + req := requestParams{ "record-type": rc.Type, - "host": rc.GetLabel(), - "record": rc.GetTargetField(), + "host": host, "ttl": strconv.Itoa(int(rc.TTL)), } - // ClouDNS doesn't use "@", it uses an empty name - if req["host"] == "@" { - req["host"] = "" - } - // Add metadata for GeoDNS // Note: By default, it works only with A, AAAA, CNAME, NAPTR or SRV record // but you can ask the support for others type of record and they enable it // for your ClouDNS account. - geodnsCodeFromMetadataValue, geodnsCodeFromMetadataExist := rc.Metadata[metaGeodnsCode] - if geodnsCodeFromMetadataExist { + if geodnsCodeFromMetadataValue, ok := rc.Metadata[metaGeodnsCode]; ok { req["geodns-code"] = geodnsCodeFromMetadataValue } - switch rc.Type { // #rtype_variations - case "A", "AAAA", "NS", "PTR", "TXT", "SOA", "ALIAS", "CNAME", "DNAME": - // Nothing special. - case "CLOUDNS_WR": + switch rc.TypeNum { + case privatetypes.TypeCLOUDNSWR: + f := rc.AsCLOUDNSWR() req["record-type"] = "WR" - case "MX": - req["priority"] = strconv.Itoa(int(rc.MxPreference)) - case "SRV": - req["priority"] = strconv.Itoa(int(rc.SrvPriority)) - req["weight"] = strconv.Itoa(int(rc.SrvWeight)) - req["port"] = strconv.Itoa(int(rc.SrvPort)) - case "CAA": - req["caa_flag"] = strconv.Itoa(int(rc.CaaFlag)) - req["caa_type"] = rc.CaaTag - req["caa_value"] = rc.GetTargetField() - case "TLSA": - req["tlsa_usage"] = strconv.Itoa(int(rc.TlsaUsage)) - req["tlsa_selector"] = strconv.Itoa(int(rc.TlsaSelector)) - req["tlsa_matching_type"] = strconv.Itoa(int(rc.TlsaMatchingType)) - case "SSHFP": - req["algorithm"] = strconv.Itoa(int(rc.SshfpAlgorithm)) - req["fptype"] = strconv.Itoa(int(rc.SshfpFingerprint)) - case "DS": - req["key-tag"] = strconv.Itoa(int(rc.DsKeyTag)) - req["algorithm"] = strconv.Itoa(int(rc.DsAlgorithm)) - req["digest-type"] = strconv.Itoa(int(rc.DsDigestType)) - req["record"] = rc.DsDigest - case "LOC": - parts := strings.Fields(rc.GetTargetCombined()) + req["record"] = f.Target + case dnsv2.TypeMX: + f := rc.AsMX() + req["priority"] = strconv.Itoa(int(f.Preference)) + req["record"] = f.Mx + case dnsv2.TypeSRV: + f := rc.AsSRV() + req["priority"] = strconv.Itoa(int(f.Priority)) + req["weight"] = strconv.Itoa(int(f.Weight)) + req["port"] = strconv.Itoa(int(f.Port)) + req["record"] = f.Target + case dnsv2.TypeCAA: + f := rc.AsCAA() + req["caa_flag"] = strconv.Itoa(int(f.Flag)) + req["caa_type"] = f.Tag + req["caa_value"] = f.Value + req["record"] = rc.GetRDATA().String() + case dnsv2.TypeTLSA: + f := rc.AsTLSA() + req["tlsa_usage"] = strconv.Itoa(int(f.Usage)) + req["tlsa_selector"] = strconv.Itoa(int(f.Selector)) + req["tlsa_matching_type"] = strconv.Itoa(int(f.MatchingType)) + req["record"] = f.Certificate + case dnsv2.TypeSSHFP: + f := rc.AsSSHFP() + req["algorithm"] = strconv.Itoa(int(f.Algorithm)) + req["fptype"] = strconv.Itoa(int(f.Type)) + req["record"] = f.FingerPrint + case dnsv2.TypeDS: + f := rc.AsDS() + req["key-tag"] = strconv.Itoa(int(f.KeyTag)) + req["algorithm"] = strconv.Itoa(int(f.Algorithm)) + req["digest-type"] = strconv.Itoa(int(f.DigestType)) + req["record"] = f.Digest + case dnsv2.TypeLOC: + parts := strings.Fields(rc.GetRDATA().String()) req["lat-deg"] = parts[0] req["lat-min"] = parts[1] req["lat-sec"] = parts[2] @@ -538,15 +538,20 @@ func toReq(rc *models.RecordConfig) (requestParams, error) { req["size"] = formatLocParam(parts[9]) req["h-precision"] = formatLocParam(parts[10]) req["v-precision"] = formatLocParam(parts[11]) - case "NAPTR": - req["order"] = strconv.Itoa(int(rc.NaptrOrder)) - req["pref"] = strconv.Itoa(int(rc.NaptrPreference)) - req["flag"] = rc.NaptrFlags - req["params"] = rc.NaptrService - req["regexp"] = rc.NaptrRegexp - req["replace"] = rc.GetTargetField() + req["record"] = rc.GetRDATA().String() + case dnsv2.TypeNAPTR: + f := rc.AsNAPTR() + req["order"] = strconv.Itoa(int(f.Order)) + req["pref"] = strconv.Itoa(int(f.Preference)) + req["flag"] = f.Flags + req["params"] = f.Service + req["regexp"] = f.Regexp + req["replace"] = f.Replacement + req["record"] = rc.GetRDATA().String() + case dnsv2.TypeTXT: + req["record"] = rc.GetTargetTXTJoined() default: - return nil, fmt.Errorf("ClouDNS.toReq rtype %q unimplemented", rc.Type) + req["record"] = rc.GetRDATA().String() } return req, nil diff --git a/providers/cloudns/cloudnsProvider_test.go b/providers/cloudns/cloudnsProvider_test.go index af7e6179f7..3bb0513bb8 100644 --- a/providers/cloudns/cloudnsProvider_test.go +++ b/providers/cloudns/cloudnsProvider_test.go @@ -2,8 +2,39 @@ package cloudns import ( "testing" + + dnsv2 "codeberg.org/miekg/dns" + "github.com/DNSControl/dnscontrol/v5/models" ) +func TestToRcUsesV3RecordConfig(t *testing.T) { + dc := models.MustNewDomainConfig("example.com") + tests := []struct { + name string + in domainRecord + want *models.RecordConfig + }{ + {"MX", domainRecord{Type: "MX", Host: "mail", Target: "mx.example.net", Priority: "10", TTL: "300"}, dc.MustNewRecordConfig("mail", 300, dnsv2.TypeMX, uint16(10), "mx.example.net.")}, + {"SRV", domainRecord{Type: "SRV", Host: "_https._tcp", Target: "service.example.net", Priority: "1", Weight: "2", Port: "443", TTL: "300"}, dc.MustNewRecordConfig("_https._tcp", 300, dnsv2.TypeSRV, uint16(1), uint16(2), uint16(443), "service.example.net.")}, + {"CAA", domainRecord{Type: "CAA", Host: "@", CaaFlag: "0", CaaTag: "issue", CaaValue: "letsencrypt.org", TTL: "300"}, dc.MustNewRecordConfig("@", 300, dnsv2.TypeCAA, uint8(0), "issue", "letsencrypt.org")}, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + got, err := toRc(dc, &tt.in) + if err != nil { + t.Fatal(err) + } + if got.NameFQDN != tt.want.NameFQDN || got.TTL != tt.want.TTL || got.TypeNum != tt.want.TypeNum || got.GetRDATA().String() != tt.want.GetRDATA().String() { + t.Errorf("toRc() = %s %d IN %s %s, want %s %d IN %s %s", got.NameFQDN, got.TTL, got.Type, got.GetRDATA(), tt.want.NameFQDN, tt.want.TTL, tt.want.Type, tt.want.GetRDATA()) + } + if got.Original != &tt.in { + t.Error("toRc() did not preserve the original ClouDNS record") + } + }) + } +} + func TestToRcConvertsCloudWRToCloudnsWR(t *testing.T) { // ClouDNS API returns "CLOUD_WR" as the type for web redirect records. // dnscontrol uses "CLOUDNS_WR" as the custom record type. @@ -13,15 +44,40 @@ func TestToRcConvertsCloudWRToCloudnsWR(t *testing.T) { ID: "123", Type: "CLOUD_WR", Host: "www", - Target: "https://example.com", + Target: "\"https://example.com\"", TTL: "3600", } - rc, err := toRc("example.com", r) + dc := models.MustNewDomainConfig("example.com") + rc, err := toRc(dc, r) if err != nil { t.Fatalf("unexpected error: %v", err) } if rc.Type != "CLOUDNS_WR" { t.Errorf("expected type CLOUDNS_WR, got %s", rc.Type) } + gotTarget := rc.AsCLOUDNSWR().Target + wantTarget := r.Target + if gotTarget != wantTarget { + t.Errorf("wanted target %s, got %s", wantTarget, gotTarget) + } +} + +func TestToRcMX(t *testing.T) { + r := &domainRecord{ + Type: "MX", + Host: "www", + Target: "mail.example.net", + Priority: "10", + TTL: "3600", + } + + dc := models.MustNewDomainConfig("example.com") + rc, err := toRc(dc, r) + if err != nil { + t.Fatalf("unexpected error: %v", err) + } + if got := rc.GetRDATA().String(); got != "10 mail.example.net." { + t.Errorf("expected MX data %q, got %q", "10 mail.example.net.", got) + } } diff --git a/providers/cloudns/convert_golden_test.go b/providers/cloudns/convert_golden_test.go new file mode 100644 index 0000000000..7c7f63b371 --- /dev/null +++ b/providers/cloudns/convert_golden_test.go @@ -0,0 +1,22 @@ +package cloudns + +import ( + "testing" + + "github.com/DNSControl/dnscontrol/v5/models" + "github.com/DNSControl/dnscontrol/v5/pkg/providergolden" +) + +func TestToRcGolden(t *testing.T) { + providergolden.CheckToRC(t, "toRc", + func(dc *models.DomainConfig, native domainRecord) (models.Records, error) { + rc, err := toRc(dc, &native) + return models.Records{rc}, err + }) +} + +func TestToReqGolden(t *testing.T) { + providergolden.CheckToNative(t, "toReq", func(_ *models.DomainConfig, records models.Records) (requestParams, error) { + return toReq(records[0]) + }) +} diff --git a/providers/cloudns/test_data/expected_tonative_output_toReq_cloudnstest.yesthattom.com.json b/providers/cloudns/test_data/expected_tonative_output_toReq_cloudnstest.yesthattom.com.json new file mode 100644 index 0000000000..b53117d8f5 --- /dev/null +++ b/providers/cloudns/test_data/expected_tonative_output_toReq_cloudnstest.yesthattom.com.json @@ -0,0 +1,1890 @@ +[ + { + "index": 1, + "value": { + "host": "*", + "record": "3.3.3.3", + "record-type": "A", + "ttl": "300" + } + }, + { + "index": 2, + "value": { + "host": "", + "record": "8.8.8.8", + "record-type": "A", + "ttl": "1800" + } + }, + { + "index": 3, + "value": { + "host": "", + "record": "1.2.3.2", + "record-type": "A", + "ttl": "300" + } + }, + { + "index": 4, + "value": { + "host": "", + "record": "1.2.3.4", + "record-type": "A", + "ttl": "300" + } + }, + { + "index": 5, + "value": { + "host": "", + "record": "2.2.2.2", + "record-type": "A", + "ttl": "300" + } + }, + { + "index": 6, + "value": { + "host": "", + "record": "2.3.4.5", + "record-type": "A", + "ttl": "300" + } + }, + { + "index": 7, + "value": { + "host": "", + "record": "4.4.4.4", + "record-type": "A", + "ttl": "300" + } + }, + { + "index": 8, + "value": { + "host": "", + "record": "foo.cloudnstest.yesthattom.com.", + "record-type": "ALIAS", + "ttl": "300" + } + }, + { + "index": 9, + "value": { + "host": "", + "record": "foo.com.", + "record-type": "ALIAS", + "ttl": "300" + } + }, + { + "index": 10, + "value": { + "host": "", + "record": "foo2.com.", + "record-type": "ALIAS", + "ttl": "300" + } + }, + { + "index": 11, + "value": { + "caa_flag": "0", + "caa_type": "issue", + "caa_value": "letsencrypt.org", + "host": "", + "record": "0 issue \"letsencrypt.org\"", + "record-type": "CAA", + "ttl": "300" + } + }, + { + "index": 12, + "value": { + "caa_flag": "0", + "caa_type": "issue", + "caa_value": "letsencrypt.org; validationmethods=dns-01; accounturi=https://acme-v02.api.letsencrypt.org/acme/acct/1234", + "host": "", + "record": "0 issue \"letsencrypt.org; validationmethods=dns-01; accounturi=https://acme-v02.api.letsencrypt.org/acme/acct/1234\"", + "record-type": "CAA", + "ttl": "300" + } + }, + { + "index": 13, + "value": { + "caa_flag": "0", + "caa_type": "issuewild", + "caa_value": ";", + "host": "", + "record": "0 issuewild \";\"", + "record-type": "CAA", + "ttl": "300" + } + }, + { + "index": 14, + "value": { + "caa_flag": "0", + "caa_type": "issuewild", + "caa_value": "example.com", + "host": "", + "record": "0 issuewild \"example.com\"", + "record-type": "CAA", + "ttl": "300" + } + }, + { + "index": 15, + "value": { + "caa_flag": "0", + "caa_type": "issuewild", + "caa_value": "letsencrypt.org", + "host": "", + "record": "0 issuewild \"letsencrypt.org\"", + "record-type": "CAA", + "ttl": "300" + } + }, + { + "index": 16, + "value": { + "caa_flag": "128", + "caa_type": "issue", + "caa_value": "letsencrypt.org", + "host": "", + "record": "128 issue \"letsencrypt.org\"", + "record-type": "CAA", + "ttl": "300" + } + }, + { + "index": 17, + "value": { + "altitude": "-24.05", + "h-precision": "0", + "host": "", + "lat-deg": "42", + "lat-dir": "N", + "lat-min": "21", + "lat-sec": "54.000", + "long-deg": "71", + "long-dir": "W", + "long-min": "06", + "long-sec": "18.000", + "record": "42 21 54.000 N 71 06 18.000 W -24.05m 30m 0.00m 0.00m", + "record-type": "LOC", + "size": "30", + "ttl": "300", + "v-precision": "0" + } + }, + { + "index": 18, + "value": { + "altitude": "-24.06", + "h-precision": "10", + "host": "", + "lat-deg": "42", + "lat-dir": "N", + "lat-min": "21", + "lat-sec": "54.000", + "long-deg": "71", + "long-dir": "W", + "long-min": "06", + "long-sec": "18.000", + "record": "42 21 54.000 N 71 06 18.000 W -24.06m 30m 10m 0.00m", + "record-type": "LOC", + "size": "30", + "ttl": "300", + "v-precision": "0" + } + }, + { + "index": 19, + "value": { + "altitude": "-24", + "h-precision": "0", + "host": "", + "lat-deg": "42", + "lat-dir": "N", + "lat-min": "21", + "lat-sec": "54.000", + "long-deg": "71", + "long-dir": "W", + "long-min": "06", + "long-sec": "18.000", + "record": "42 21 54.000 N 71 06 18.000 W -24m 30m 0.00m 0.00m", + "record-type": "LOC", + "size": "30", + "ttl": "300", + "v-precision": "0" + } + }, + { + "index": 20, + "value": { + "host": "", + "priority": "0", + "record": ".", + "record-type": "MX", + "ttl": "300" + } + }, + { + "index": 21, + "value": { + "host": "", + "priority": "2", + "record": "cloudnstest.yesthattom.com.", + "record-type": "MX", + "ttl": "300" + } + }, + { + "index": 22, + "value": { + "host": "", + "priority": "5", + "record": "bar.com.", + "record-type": "MX", + "ttl": "300" + } + }, + { + "index": 23, + "value": { + "host": "", + "priority": "5", + "record": "foo.com.", + "record-type": "MX", + "ttl": "300" + } + }, + { + "index": 24, + "value": { + "host": "", + "priority": "8", + "record": "www.cloudnstest.yesthattom.com.", + "record-type": "MX", + "ttl": "300" + } + }, + { + "index": 25, + "value": { + "host": "", + "record": "ns1.example.com.", + "record-type": "NS", + "ttl": "300" + } + }, + { + "index": 26, + "value": { + "host": "", + "record": "ns1.foo.com.", + "record-type": "NS", + "ttl": "300" + } + }, + { + "index": 27, + "value": { + "host": "", + "record": "ns2.example.com.", + "record-type": "NS", + "ttl": "300" + } + }, + { + "index": 28, + "value": { + "host": "", + "record": "ns2.foo.com.", + "record-type": "NS", + "ttl": "300" + } + }, + { + "index": 29, + "value": { + "algorithm": "1", + "fptype": "1", + "host": "", + "record": "66C7D5540B7D75A1FB4C84FEBFA178AD99BDD67C", + "record-type": "SSHFP", + "ttl": "300" + } + }, + { + "index": 30, + "value": { + "algorithm": "2", + "fptype": "1", + "host": "", + "record": "66C7D5540B7D75A1FB4C84FEBFA178AD99BDD67C", + "record-type": "SSHFP", + "ttl": "300" + } + }, + { + "index": 31, + "value": { + "algorithm": "2", + "fptype": "2", + "host": "", + "record": "745A635BC46A397A5C4F21D437483005BCC40D7511FF15FBFAFE913A081559BC", + "record-type": "SSHFP", + "ttl": "300" + } + }, + { + "index": 32, + "value": { + "host": "", + "record": "asimple", + "record-type": "TXT", + "ttl": "300" + } + }, + { + "index": 33, + "value": { + "host": "", + "record": "simple", + "record-type": "TXT", + "ttl": "300" + } + }, + { + "index": 34, + "value": { + "host": "", + "record": "8.8.8.8", + "record-type": "A", + "ttl": "600" + } + }, + { + "index": 35, + "value": { + "host": "", + "record": "8.8.8.8", + "record-type": "A", + "ttl": "900" + } + }, + { + "index": 36, + "value": { + "host": "_443._tcp", + "record": "0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF", + "record-type": "TLSA", + "tlsa_matching_type": "1", + "tlsa_selector": "0", + "tlsa_usage": "2", + "ttl": "300" + } + }, + { + "index": 37, + "value": { + "host": "_443._tcp", + "record": "0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF", + "record-type": "TLSA", + "tlsa_matching_type": "2", + "tlsa_selector": "0", + "tlsa_usage": "2", + "ttl": "300" + } + }, + { + "index": 38, + "value": { + "host": "_443._tcp", + "record": "FEDCBA9876543210FEDCBA9876543210FEDCBA9876543210FEDCBA9876543210FEDCBA9876543210FEDCBA9876543210FEDCBA9876543210FEDCBA9876543210", + "record-type": "TLSA", + "tlsa_matching_type": "2", + "tlsa_selector": "0", + "tlsa_usage": "2", + "ttl": "300" + } + }, + { + "index": 39, + "value": { + "host": "_443._tcp", + "record": "0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF", + "record-type": "TLSA", + "tlsa_matching_type": "1", + "tlsa_selector": "1", + "tlsa_usage": "2", + "ttl": "300" + } + }, + { + "index": 40, + "value": { + "host": "_443._tcp", + "record": "0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF", + "record-type": "TLSA", + "tlsa_matching_type": "1", + "tlsa_selector": "1", + "tlsa_usage": "3", + "ttl": "300" + } + }, + { + "index": 41, + "value": { + "host": "_sip._tcp", + "port": "7", + "priority": "5", + "record": "foo.com.", + "record-type": "SRV", + "ttl": "21600", + "weight": "6" + } + }, + { + "index": 42, + "value": { + "host": "_sip._tcp", + "port": "75", + "priority": "15", + "record": ".", + "record-type": "SRV", + "ttl": "300", + "weight": "65" + } + }, + { + "index": 43, + "value": { + "host": "_sip._tcp", + "port": "75", + "priority": "15", + "record": "foo3.com.", + "record-type": "SRV", + "ttl": "300", + "weight": "65" + } + }, + { + "index": 44, + "value": { + "host": "_sip._tcp", + "port": "75", + "priority": "15", + "record": "foo4.com.", + "record-type": "SRV", + "ttl": "300", + "weight": "65" + } + }, + { + "index": 45, + "value": { + "host": "_sip._tcp", + "port": "7", + "priority": "5", + "record": "foo.com.", + "record-type": "SRV", + "ttl": "300", + "weight": "6" + } + }, + { + "index": 46, + "value": { + "host": "_sip._tcp", + "port": "70", + "priority": "5", + "record": "foo2.com.", + "record-type": "SRV", + "ttl": "300", + "weight": "60" + } + }, + { + "index": 47, + "value": { + "host": "_sip._tcp", + "port": "7", + "priority": "52", + "record": "foo.com.", + "record-type": "SRV", + "ttl": "300", + "weight": "6" + } + }, + { + "index": 48, + "value": { + "host": "_sip._tcp", + "port": "7", + "priority": "52", + "record": "foo.com.", + "record-type": "SRV", + "ttl": "300", + "weight": "62" + } + }, + { + "index": 49, + "value": { + "host": "_sip._tcp", + "port": "72", + "priority": "52", + "record": "foo.com.", + "record-type": "SRV", + "ttl": "300", + "weight": "62" + } + }, + { + "index": 50, + "value": { + "host": "_sip._tcp", + "port": "7", + "priority": "5", + "record": "foo.com.", + "record-type": "SRV", + "ttl": "600", + "weight": "6" + } + }, + { + "index": 51, + "value": { + "host": "a", + "record": "xn--ndaaa.com.", + "record-type": "CNAME", + "ttl": "300" + } + }, + { + "index": 52, + "value": { + "host": "a", + "record": "b.cloudnstest.yesthattom.com.", + "record-type": "DNAME", + "ttl": "300" + } + }, + { + "index": 53, + "value": { + "altitude": "-24.33", + "h-precision": "200", + "host": "a", + "lat-deg": "42", + "lat-dir": "N", + "lat-min": "21", + "lat-sec": "43.950", + "long-deg": "71", + "long-dir": "W", + "long-min": "05", + "long-sec": "6.340", + "record": "42 21 43.950 N 71 05 6.340 W -24.33m 1m 200m 10m", + "record-type": "LOC", + "size": "1", + "ttl": "300", + "v-precision": "10" + } + }, + { + "index": 54, + "value": { + "algorithm": "1", + "digest-type": "4", + "host": "another-child", + "key-tag": "2159", + "record": "F50BEFEA333EE2901D72D31A08E1A3CD3F7E943FF4B38CF7C8AD92807F5302F76FB0B419182C0F47FFC71CBCB6EF4BD4", + "record-type": "DS", + "ttl": "300" + } + }, + { + "index": 55, + "value": { + "algorithm": "13", + "digest-type": "4", + "host": "another-child", + "key-tag": "35632", + "record": "F5F32ABCA6B01AA7A9963012F90B7C8523A1D946185A3AD70B67F3C9F18E7312FA9DD6AB2F7D8382F789213DB173D429", + "record-type": "DS", + "ttl": "300" + } + }, + { + "index": 56, + "value": { + "algorithm": "3", + "digest-type": "4", + "host": "another-child", + "key-tag": "63909", + "record": "EEC7FA02E6788DA889B2CE41D43D92F948AB126EDCF83B7037E73CE9531C8E7E45653ABBAA76C2D6E42F98316EDE599B", + "record-type": "DS", + "ttl": "300" + } + }, + { + "index": 57, + "value": { + "host": "another-child", + "record": "ns101.cloudns.net.", + "record-type": "NS", + "ttl": "300" + } + }, + { + "index": 58, + "value": { + "altitude": "10.22", + "h-precision": "0", + "host": "b", + "lat-deg": "52", + "lat-dir": "N", + "lat-min": "14", + "lat-sec": "5.000", + "long-deg": "00", + "long-dir": "E", + "long-min": "08", + "long-sec": "50.000", + "record": "52 14 5.000 N 00 08 50.000 E 10.22m 0.00m 0.00m 0.00m", + "record-type": "LOC", + "size": "0", + "ttl": "300", + "v-precision": "0" + } + }, + { + "index": 59, + "value": { + "host": "bar", + "record": "1.2.3.4", + "record-type": "A", + "ttl": "300" + } + }, + { + "index": 60, + "value": { + "host": "bar", + "record": "5.5.5.5", + "record-type": "A", + "ttl": "300" + } + }, + { + "index": 61, + "value": { + "host": "bar", + "record": "redact2.acm-validations.aws.", + "record-type": "CNAME", + "ttl": "300" + } + }, + { + "index": 62, + "value": { + "host": "bar", + "priority": "5", + "record": "bar.com.", + "record-type": "MX", + "ttl": "300" + } + }, + { + "index": 63, + "value": { + "host": "bar.bat", + "record": "5.5.5.5", + "record-type": "A", + "ttl": "300" + } + }, + { + "index": 64, + "value": { + "altitude": "10", + "h-precision": "0", + "host": "c", + "lat-deg": "32", + "lat-dir": "S", + "lat-min": "07", + "lat-sec": "19.000", + "long-deg": "116", + "long-dir": "E", + "long-min": "02", + "long-sec": "25.000", + "record": "32 07 19.000 S 116 02 25.000 E 10m 0.00m 0.00m 0.00m", + "record-type": "LOC", + "size": "0", + "ttl": "300", + "v-precision": "0" + } + }, + { + "index": 65, + "value": { + "algorithm": "13", + "digest-type": "1", + "host": "child", + "key-tag": "2075", + "record": "2706D12E256C8FDD9BFB45EFB25FE537E21A82F6", + "record-type": "DS", + "ttl": "300" + } + }, + { + "index": 66, + "value": { + "algorithm": "13", + "digest-type": "2", + "host": "child", + "key-tag": "2075", + "record": "3F7A1EAC8C813A0BEBD0C3B8AAB387E31945EA0CD5E1D84A2E8E27674566C156", + "record-type": "DS", + "ttl": "300" + } + }, + { + "index": 67, + "value": { + "algorithm": "1", + "digest-type": "4", + "host": "child", + "key-tag": "2159", + "record": "F50BEFEA333EE2901D72D31A08E1A3CD3F7E943FF4B38CF7C8AD92807F5302F76FB0B419182C0F47FFC71CBCB6EF4BD4", + "record-type": "DS", + "ttl": "300" + } + }, + { + "index": 68, + "value": { + "algorithm": "13", + "digest-type": "1", + "host": "child", + "key-tag": "35632", + "record": "1E07663FF507A40874B8605463DD41DE482079D6", + "record-type": "DS", + "ttl": "300" + } + }, + { + "index": 69, + "value": { + "algorithm": "3", + "digest-type": "4", + "host": "child", + "key-tag": "63909", + "record": "EEC7FA02E6788DA889B2CE41D43D92F948AB126EDCF83B7037E73CE9531C8E7E45653ABBAA76C2D6E42F98316EDE599B", + "record-type": "DS", + "ttl": "300" + } + }, + { + "index": 70, + "value": { + "host": "child", + "record": "ns101.cloudns.net.", + "record-type": "NS", + "ttl": "300" + } + }, + { + "index": 71, + "value": { + "altitude": "-44", + "h-precision": "0", + "host": "d", + "lat-deg": "42", + "lat-dir": "N", + "lat-min": "21", + "lat-sec": "28.760", + "long-deg": "71", + "long-dir": "W", + "long-min": "00", + "long-sec": "51.620", + "record": "42 21 28.760 N 71 00 51.620 W -44m 2000m 0.00m 0.00m", + "record-type": "LOC", + "size": "2000", + "ttl": "300", + "v-precision": "0" + } + }, + { + "index": 72, + "value": { + "host": "decoy", + "record": "1.1.1.1", + "record-type": "A", + "ttl": "300" + } + }, + { + "index": 73, + "value": { + "host": "decoy", + "record": "2.2.2.2", + "record-type": "A", + "ttl": "300" + } + }, + { + "index": 74, + "value": { + "host": "decoy", + "record": "3.3.3.3", + "record-type": "A", + "ttl": "300" + } + }, + { + "index": 75, + "value": { + "host": "dyndns-city1", + "record": "91.42.1.1", + "record-type": "A", + "ttl": "300" + } + }, + { + "index": 76, + "value": { + "host": "dyndns-city1", + "record": "2003:dd:d7ff::fe71:ce77", + "record-type": "AAAA", + "ttl": "300" + } + }, + { + "index": 77, + "value": { + "host": "dyndns-city2", + "record": "91.42.1.2", + "record-type": "A", + "ttl": "300" + } + }, + { + "index": 78, + "value": { + "host": "dyndns-city2", + "record": "2003:dd:d7ff::fe71:ce78", + "record-type": "AAAA", + "ttl": "300" + } + }, + { + "index": 79, + "value": { + "host": "final", + "record": "TestDNSProviders was successful!", + "record-type": "TXT", + "ttl": "300" + } + }, + { + "index": 80, + "value": { + "host": "foo", + "record": "1.1.1.1", + "record-type": "A", + "ttl": "300" + } + }, + { + "index": 81, + "value": { + "host": "foo", + "record": "1.2.3.4", + "record-type": "A", + "ttl": "300" + } + }, + { + "index": 82, + "value": { + "host": "foo", + "record": "10.10.10.10", + "record-type": "A", + "ttl": "300" + } + }, + { + "index": 83, + "value": { + "host": "foo", + "record": "11.11.11.11", + "record-type": "A", + "ttl": "300" + } + }, + { + "index": 84, + "value": { + "host": "foo", + "record": "12.12.12.12", + "record-type": "A", + "ttl": "300" + } + }, + { + "index": 85, + "value": { + "host": "foo", + "record": "13.13.13.13", + "record-type": "A", + "ttl": "300" + } + }, + { + "index": 86, + "value": { + "host": "foo", + "record": "14.14.14.14", + "record-type": "A", + "ttl": "300" + } + }, + { + "index": 87, + "value": { + "host": "foo", + "record": "2.3.4.5", + "record-type": "A", + "ttl": "300" + } + }, + { + "index": 88, + "value": { + "host": "foo", + "record": "3.4.5.6", + "record-type": "A", + "ttl": "300" + } + }, + { + "index": 89, + "value": { + "host": "foo", + "record": "4.5.6.7", + "record-type": "A", + "ttl": "300" + } + }, + { + "index": 90, + "value": { + "host": "foo", + "record": "8.8.8.8", + "record-type": "A", + "ttl": "300" + } + }, + { + "index": 91, + "value": { + "host": "foo", + "record": "2003:dd:d7ff::fe71:aaaa", + "record-type": "AAAA", + "ttl": "300" + } + }, + { + "index": 92, + "value": { + "host": "foo", + "record": "cloudnstest.yesthattom.com.", + "record-type": "CNAME", + "ttl": "300" + } + }, + { + "index": 93, + "value": { + "host": "foo", + "record": "google.com.", + "record-type": "CNAME", + "ttl": "300" + } + }, + { + "index": 94, + "value": { + "host": "foo", + "record": "google2.com.", + "record-type": "CNAME", + "ttl": "300" + } + }, + { + "index": 95, + "value": { + "host": "foo", + "record": "redact1.acm-validations.aws.", + "record-type": "CNAME", + "ttl": "300" + } + }, + { + "index": 96, + "value": { + "host": "foo", + "priority": "10", + "record": "aspmx.l.google.com.", + "record-type": "MX", + "ttl": "300" + } + }, + { + "index": 97, + "value": { + "host": "foo", + "priority": "10", + "record": "foo.cloudnstest.yesthattom.com.", + "record-type": "MX", + "ttl": "300" + } + }, + { + "index": 98, + "value": { + "host": "foo", + "priority": "20", + "record": "alt1.aspmx.l.google.com.", + "record-type": "MX", + "ttl": "300" + } + }, + { + "index": 99, + "value": { + "host": "foo", + "priority": "20", + "record": "bar.cloudnstest.yesthattom.com.", + "record-type": "MX", + "ttl": "300" + } + }, + { + "index": 100, + "value": { + "host": "foo", + "priority": "5", + "record": "mx.google.com.", + "record-type": "MX", + "ttl": "300" + } + }, + { + "index": 101, + "value": { + "host": "foo", + "priority": "8", + "record": "cloudnstest.yesthattom.com.", + "record-type": "MX", + "ttl": "300" + } + }, + { + "index": 102, + "value": { + "host": "foo", + "record": "cloudnstest.yesthattom.com.", + "record-type": "NS", + "ttl": "300" + } + }, + { + "index": 103, + "value": { + "host": "foo", + "record": "simple", + "record-type": "TXT", + "ttl": "300" + } + }, + { + "index": 104, + "value": { + "host": "foo", + "record": "v=spf1 ip4:99.99.99.99 -all", + "record-type": "TXT", + "ttl": "300" + } + }, + { + "index": 105, + "value": { + "host": "foo.bat", + "record": "1.2.3.4", + "record-type": "A", + "ttl": "300" + } + }, + { + "index": 106, + "value": { + "host": "foo.bat", + "record": "2.3.4.5", + "record-type": "A", + "ttl": "300" + } + }, + { + "index": 107, + "value": { + "host": "foo.bat", + "record": "simple", + "record-type": "TXT", + "ttl": "300" + } + }, + { + "index": 108, + "value": { + "host": "foo254", + "record": "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", + "record-type": "TXT", + "ttl": "300" + } + }, + { + "index": 109, + "value": { + "host": "foo255", + "record": "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB", + "record-type": "TXT", + "ttl": "300" + } + }, + { + "index": 110, + "value": { + "host": "foo256", + "record": "CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC", + "record-type": "TXT", + "ttl": "300" + } + }, + { + "index": 111, + "value": { + "host": "foo509", + "record": "DDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDD", + "record-type": "TXT", + "ttl": "300" + } + }, + { + "index": 112, + "value": { + "host": "foo510", + "record": "EEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE", + "record-type": "TXT", + "ttl": "300" + } + }, + { + "index": 113, + "value": { + "host": "foo511", + "record": "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF", + "record-type": "TXT", + "ttl": "300" + } + }, + { + "index": 114, + "value": { + "host": "foo764", + "record": "GGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGG", + "record-type": "TXT", + "ttl": "300" + } + }, + { + "index": 115, + "value": { + "host": "foo765", + "record": "HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH", + "record-type": "TXT", + "ttl": "300" + } + }, + { + "index": 116, + "value": { + "host": "foo766", + "record": "JJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJ", + "record-type": "TXT", + "ttl": "300" + } + }, + { + "index": 117, + "value": { + "host": "fooosbs1", + "record": "1back\\slash", + "record-type": "TXT", + "ttl": "300" + } + }, + { + "index": 118, + "value": { + "host": "fooosbs2", + "record": "2back\\\\slash", + "record-type": "TXT", + "ttl": "300" + } + }, + { + "index": 119, + "value": { + "host": "fooosbs3", + "record": "3back\\\\\\slash", + "record-type": "TXT", + "ttl": "300" + } + }, + { + "index": 120, + "value": { + "host": "fooosbs4", + "record": "4back\\\\\\\\slash", + "record-type": "TXT", + "ttl": "300" + } + }, + { + "index": 121, + "value": { + "host": "foosc1", + "record": "semi;colon", + "record-type": "TXT", + "ttl": "300" + } + }, + { + "index": 122, + "value": { + "host": "foosc2", + "record": "wssemi ; colon", + "record-type": "TXT", + "ttl": "300" + } + }, + { + "index": 123, + "value": { + "host": "foosp", + "record": "with spaces", + "record-type": "TXT", + "ttl": "300" + } + }, + { + "index": 124, + "value": { + "host": "foosq", + "record": "quo'te", + "record-type": "TXT", + "ttl": "300" + } + }, + { + "index": 125, + "value": { + "host": "mail", + "record": "ghs.googlehosted.com.", + "record-type": "CNAME", + "ttl": "300" + } + }, + { + "index": 126, + "value": { + "host": "mail.bat", + "record": "ghs.googlehosted.com.", + "record-type": "CNAME", + "ttl": "300" + } + }, + { + "index": 127, + "value": { + "host": "nmx", + "record": "1.2.3.3", + "record-type": "A", + "ttl": "300" + } + }, + { + "index": 128, + "value": { + "host": "nmx", + "priority": "0", + "record": ".", + "record-type": "MX", + "ttl": "300" + } + }, + { + "index": 129, + "value": { + "host": "nmx", + "priority": "3", + "record": "nmx.cloudnstest.yesthattom.com.", + "record-type": "MX", + "ttl": "300" + } + }, + { + "index": 130, + "value": { + "host": "nmx", + "priority": "9", + "record": "www.cloudnstest.yesthattom.com.", + "record-type": "MX", + "ttl": "300" + } + }, + { + "index": 131, + "value": { + "host": "test", + "record": "foo.com.", + "record-type": "ALIAS", + "ttl": "300" + } + }, + { + "index": 132, + "value": { + "host": "test", + "record": "foo2.com.", + "record-type": "ALIAS", + "ttl": "300" + } + }, + { + "index": 133, + "value": { + "host": "test", + "record": "example.com.", + "record-type": "DNAME", + "ttl": "300" + } + }, + { + "index": 134, + "value": { + "host": "test", + "record": "example.net.", + "record-type": "DNAME", + "ttl": "300" + } + }, + { + "index": 135, + "value": { + "flag": "U", + "host": "test", + "order": "100", + "params": "E2U+sip", + "pref": "10", + "record": "100 10 \"U\" \"E2U+sip\" \"!^.*$!sip:customer-service@example.com!\" .", + "record-type": "NAPTR", + "regexp": "!^.*$!sip:customer-service@example.com!", + "replace": ".", + "ttl": "300" + } + }, + { + "index": 136, + "value": { + "flag": "U", + "host": "test", + "order": "102", + "params": "E2U+email", + "pref": "10", + "record": "102 10 \"U\" \"E2U+email\" \"!^.*$!mailto:information@example.com!\" .", + "record-type": "NAPTR", + "regexp": "!^.*$!mailto:information@example.com!", + "replace": ".", + "ttl": "300" + } + }, + { + "index": 137, + "value": { + "flag": "U", + "host": "test", + "order": "103", + "params": "E2U+email", + "pref": "10", + "record": "103 10 \"U\" \"E2U+email\" \"!^.*$!mailto:information@example.com!\" .", + "record-type": "NAPTR", + "regexp": "!^.*$!mailto:information@example.com!", + "replace": ".", + "ttl": "300" + } + }, + { + "index": 138, + "value": { + "flag": "A", + "host": "test", + "order": "103", + "params": "E2U+email", + "pref": "20", + "record": "103 20 \"A\" \"E2U+email\" \"!^.*$!mailto:information@example.com!\" .", + "record-type": "NAPTR", + "regexp": "!^.*$!mailto:information@example.com!", + "replace": ".", + "ttl": "300" + } + }, + { + "index": 139, + "value": { + "flag": "A", + "host": "test", + "order": "103", + "params": "E2U+sip", + "pref": "20", + "record": "103 20 \"A\" \"E2U+sip\" \"!^.*$!mailto:information@example.com!\" .", + "record-type": "NAPTR", + "regexp": "!^.*$!mailto:information@example.com!", + "replace": ".", + "ttl": "300" + } + }, + { + "index": 140, + "value": { + "flag": "A", + "host": "test", + "order": "103", + "params": "E2U+sip", + "pref": "20", + "record": "103 20 \"A\" \"E2U+sip\" \"!^.*$!sip:customer-service@example.com!\" .", + "record-type": "NAPTR", + "regexp": "!^.*$!sip:customer-service@example.com!", + "replace": ".", + "ttl": "300" + } + }, + { + "index": 141, + "value": { + "flag": "A", + "host": "test", + "order": "103", + "params": "E2U+sip", + "pref": "20", + "record": "103 20 \"A\" \"E2U+sip\" \"\" example.foo.com.", + "record-type": "NAPTR", + "regexp": "", + "replace": "example.foo.com.", + "ttl": "300" + } + }, + { + "index": 142, + "value": { + "flag": "A", + "host": "test", + "order": "103", + "params": "E2U+sip", + "pref": "20", + "record": "103 20 \"A\" \"E2U+sip\" \"\" example2.foo.com.", + "record-type": "NAPTR", + "regexp": "", + "replace": "example2.foo.com.", + "ttl": "300" + } + }, + { + "index": 143, + "value": { + "flag": "U", + "host": "test", + "order": "103", + "params": "E2U+email", + "pref": "20", + "record": "103 20 \"U\" \"E2U+email\" \"!^.*$!mailto:information@example.com!\" .", + "record-type": "NAPTR", + "regexp": "!^.*$!mailto:information@example.com!", + "replace": ".", + "ttl": "300" + } + }, + { + "index": 144, + "value": { + "host": "testa", + "record": "1.1.1.1", + "record-type": "A", + "ttl": "1800" + } + }, + { + "index": 145, + "value": { + "host": "testa", + "record": "1.1.1.1", + "record-type": "A", + "ttl": "300" + } + }, + { + "index": 146, + "value": { + "host": "testa", + "record": "3.3.3.3", + "record-type": "A", + "ttl": "300" + } + }, + { + "index": 147, + "value": { + "host": "testa", + "record": "1.1.1.1", + "record-type": "A", + "ttl": "600" + } + }, + { + "index": 148, + "value": { + "host": "testaaaa", + "record": "2607:f8b0:4006:820::2006", + "record-type": "AAAA", + "ttl": "300" + } + }, + { + "index": 149, + "value": { + "host": "testaaaa", + "record": "2607:f8b0:4006:820::2013", + "record-type": "AAAA", + "ttl": "300" + } + }, + { + "index": 150, + "value": { + "host": "testcname", + "record": "foo.cloudnstest.yesthattom.com.", + "record-type": "CNAME", + "ttl": "300" + } + }, + { + "index": 151, + "value": { + "host": "testcname", + "record": "www.google.com.", + "record-type": "CNAME", + "ttl": "300" + } + }, + { + "index": 152, + "value": { + "host": "testcname", + "record": "www.yahoo.com.", + "record-type": "CNAME", + "ttl": "300" + } + }, + { + "index": 153, + "value": { + "host": "testdefined", + "record": "2.2.2.2", + "record-type": "A", + "ttl": "300" + } + }, + { + "index": 154, + "value": { + "host": "testdefined", + "record": "9.9.9.9", + "record-type": "A", + "ttl": "300" + } + }, + { + "index": 155, + "value": { + "host": "testignore", + "record": "8.8.8.8", + "record-type": "A", + "ttl": "300" + } + }, + { + "index": 156, + "value": { + "host": "testmx", + "priority": "100", + "record": "bar.com.", + "record-type": "MX", + "ttl": "300" + } + }, + { + "index": 157, + "value": { + "host": "testmx", + "priority": "100", + "record": "foo.com.", + "record-type": "MX", + "ttl": "300" + } + }, + { + "index": 158, + "value": { + "host": "testmx", + "priority": "5", + "record": "bar.com.", + "record-type": "MX", + "ttl": "300" + } + }, + { + "index": 159, + "value": { + "host": "testmx", + "priority": "5", + "record": "foo.com.", + "record-type": "MX", + "ttl": "300" + } + }, + { + "index": 160, + "value": { + "host": "testtxt", + "record": "changed", + "record-type": "TXT", + "ttl": "300" + } + }, + { + "index": 161, + "value": { + "host": "testtxt", + "record": "simple", + "record-type": "TXT", + "ttl": "300" + } + }, + { + "index": 162, + "value": { + "host": "www", + "record": "1.1.1.1", + "record-type": "A", + "ttl": "300" + } + }, + { + "index": 163, + "value": { + "host": "www", + "record": "1.2.3.4", + "record-type": "A", + "ttl": "300" + } + }, + { + "index": 164, + "value": { + "host": "www", + "record": "1.2.3.8", + "record-type": "A", + "ttl": "300" + } + }, + { + "index": 165, + "value": { + "host": "www", + "record": "1.2.3.9", + "record-type": "A", + "ttl": "300" + } + }, + { + "index": 166, + "value": { + "host": "www", + "record": "2.2.2.2", + "record-type": "A", + "ttl": "300" + } + }, + { + "index": 167, + "value": { + "host": "www", + "record": "3.3.3.3", + "record-type": "A", + "ttl": "300" + } + }, + { + "index": 168, + "value": { + "host": "www", + "record": "5.5.5.5", + "record-type": "A", + "ttl": "300" + } + }, + { + "index": 169, + "value": { + "host": "www", + "record": "5.6.7.8", + "record-type": "A", + "ttl": "300" + } + }, + { + "index": 170, + "value": { + "host": "www", + "record": "2.2.2.2", + "record-type": "A", + "ttl": "600" + } + }, + { + "index": 171, + "value": { + "host": "www", + "record": "5.6.7.8", + "record-type": "A", + "ttl": "600" + } + }, + { + "index": 172, + "value": { + "host": "www", + "record": "1.2.3.4", + "record-type": "A", + "ttl": "900" + } + }, + { + "index": 173, + "value": { + "host": "www", + "record": "5.6.7.8", + "record-type": "A", + "ttl": "900" + } + }, + { + "index": 174, + "value": { + "host": "xn--fiq228c", + "record": "1.2.3.4", + "record-type": "A", + "ttl": "300" + } + }, + { + "index": 175, + "value": { + "host": "xn--ndaaa", + "record": "1.2.3.4", + "record-type": "A", + "ttl": "300" + } + }, + { + "index": 176, + "value": { + "host": "xn--ndaaa", + "record": "2.2.2.2", + "record-type": "A", + "ttl": "300" + } + }, + { + "index": 177, + "value": { + "host": "xn--o-0gab", + "record": "xn--ndaaa.xn--vhquv.", + "record-type": "CNAME", + "ttl": "300" + } + }, + { + "index": 178, + "value": { + "host": "xyz", + "record": "ns1.foo.com.", + "record-type": "NS", + "ttl": "300" + } + }, + { + "index": 179, + "value": { + "host": "xyz", + "record": "ns2.foo.com.", + "record-type": "NS", + "ttl": "300" + } + }, + { + "index": 180, + "value": { + "host": "zzz", + "record": "3.3.3.3", + "record-type": "A", + "ttl": "300" + } + }, + { + "index": 181, + "value": { + "host": "zzz", + "record": "4.4.4.4", + "record-type": "A", + "ttl": "300" + } + }, + { + "index": 182, + "value": { + "host": "zzz", + "record": "2003:dd:d7ff::fe71:cccc", + "record-type": "AAAA", + "ttl": "300" + } + } +] diff --git a/providers/cloudns/test_data/expected_torc_output_toRc_cloudnstest.yesthattom.com.records b/providers/cloudns/test_data/expected_torc_output_toRc_cloudnstest.yesthattom.com.records new file mode 100644 index 0000000000..a97f40d1d9 --- /dev/null +++ b/providers/cloudns/test_data/expected_torc_output_toRc_cloudnstest.yesthattom.com.records @@ -0,0 +1,217 @@ +1 @ 300 IN NS pns71.cloudns.net. +2 @ 300 IN NS pns72.cloudns.com. +3 @ 300 IN NS pns73.cloudns.net. +4 @ 300 IN NS pns74.cloudns.uk. +5 testa 300 IN A 1.1.1.1 +6 testa 300 IN A 3.3.3.3 +7 @ 300 IN A 2.2.2.2 +8 @ 300 IN A 4.4.4.4 +9 * 300 IN A 3.3.3.3 +10 www 300 IN A 5.5.5.5 +11 testaaaa 300 IN AAAA 2607:f8b0:4006:820::2006 +12 testaaaa 300 IN AAAA 2607:f8b0:4006:820::2013 +13 testcname 300 IN CNAME www.google.com. +14 testcname 300 IN CNAME www.yahoo.com. +15 foo 300 IN A 1.2.3.4 +16 testcname 300 IN CNAME foo.cloudnstest.yesthattom.com. +17 @ 300 IN MX 5 bar.com. +18 @ 300 IN MX 5 foo.com. +19 testmx 300 IN MX 5 bar.com. +20 testmx 300 IN MX 5 foo.com. +21 testmx 300 IN MX 100 foo.com. +22 testmx 300 IN MX 5 foo.com. +23 testtxt 300 IN TXT "changed" +24 testtxt 300 IN TXT "simple" +25 www 300 IN A 1.1.1.1 +26 www 300 IN A 2.2.2.2 +27 www 300 IN A 3.3.3.3 +28 www 300 IN A 1.1.1.1 +29 www 300 IN A 2.2.2.2 +30 www 300 IN A 3.3.3.3 +31 www 300 IN A 1.1.1.1 +32 testmx 300 IN MX 100 bar.com. +33 testmx 300 IN MX 5 foo.com. +34 www 300 IN A 1.1.1.1 +35 testmx 300 IN MX 5 foo.com. +36 testmx 300 IN MX 100 bar.com. +37 testa 1800 IN A 1.1.1.1 +38 testa 600 IN A 1.1.1.1 +39 @ 1800 IN A 8.8.8.8 +40 @ 600 IN A 8.8.8.8 +41 @ 900 IN A 8.8.8.8 +42 www 300 IN A 1.2.3.4 +43 www 300 IN A 2.2.2.2 +44 www 600 IN A 2.2.2.2 +45 www 300 IN A 5.6.7.8 +46 www 600 IN A 5.6.7.8 +47 www 600 IN A 5.6.7.8 +48 www 900 IN A 5.6.7.8 +49 www 900 IN A 1.2.3.4 +50 foo 300 IN A 1.2.3.4 +51 foo 300 IN MX 5 mx.google.com. +52 foo 300 IN A 4.5.6.7 +53 foo 300 IN CNAME google.com. +54 foo 300 IN A 1.2.3.4 +55 foo 300 IN CNAME google2.com. +56 @ 300 IN A 1.2.3.4 +57 foo 300 IN CNAME cloudnstest.yesthattom.com. +58 @ 300 IN A 1.2.3.4 +59 foo 300 IN MX 8 cloudnstest.yesthattom.com. +60 nmx 300 IN A 1.2.3.3 +61 www 300 IN A 1.2.3.9 +62 nmx 300 IN MX 0 . +63 nmx 300 IN MX 3 nmx.cloudnstest.yesthattom.com. +64 nmx 300 IN MX 9 www.cloudnstest.yesthattom.com. +65 @ 300 IN A 1.2.3.2 +66 www 300 IN A 1.2.3.8 +67 @ 300 IN MX 0 . +68 @ 300 IN MX 2 cloudnstest.yesthattom.com. +69 @ 300 IN MX 8 www.cloudnstest.yesthattom.com. +70 xyz 300 IN NS ns2.foo.com. +71 xyz 300 IN NS ns1.foo.com. +72 @ 300 IN A 1.2.3.4 +73 foo 300 IN NS cloudnstest.yesthattom.com. +74 @ 300 IN NS ns1.foo.com. +75 @ 300 IN NS ns2.foo.com. +76 foo254 300 IN TXT "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" +77 foo255 300 IN TXT "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" +78 foo256 300 IN TXT "CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC" "C" +79 foo509 300 IN TXT "DDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDD" "DDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDD" +80 foo510 300 IN TXT "EEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE" "EEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE" +81 foo511 300 IN TXT "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF" "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF" "F" +82 foo764 300 IN TXT "GGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGG" "GGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGG" "GGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGG" +83 foo765 300 IN TXT "HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH" "HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH" "HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH" +84 foo766 300 IN TXT "JJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJ" "JJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJ" "JJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJ" "J" +85 foosq 300 IN TXT "quo'te" +86 foosc1 300 IN TXT "semi;colon" +87 foosc2 300 IN TXT "wssemi ; colon" +88 foosp 300 IN TXT "with spaces" +89 foo 300 IN TXT "v=spf1 ip4:99.99.99.99 -all" +90 fooosbs1 300 IN TXT "1back\\slash" +91 fooosbs2 300 IN TXT "2back\\\\slash" +92 fooosbs3 300 IN TXT "3back\\\\\\slash" +93 fooosbs4 300 IN TXT "4back\\\\\\\\slash" +94 bar 300 IN MX 5 bar.com. +95 decoy 300 IN A 1.1.1.1 +96 decoy 300 IN A 2.2.2.2 +97 decoy 300 IN A 3.3.3.3 +98 foo 300 IN A 1.2.3.4 +99 foo 300 IN A 2.3.4.5 +100 foo 300 IN A 3.4.5.6 +101 foo 300 IN A 3.4.5.6 +102 bar 300 IN A 1.2.3.4 +103 foo 300 IN A 2.3.4.5 +104 foo 300 IN A 3.4.5.6 +105 foo 300 IN A 8.8.8.8 +106 foo 300 IN MX 20 bar.cloudnstest.yesthattom.com. +107 foo 300 IN MX 10 foo.cloudnstest.yesthattom.com. +108 foo 300 IN A 8.8.8.8 +109 xn--ndaaa 300 IN A 1.2.3.4 +110 xn--ndaaa 300 IN A 2.2.2.2 +111 xn--fiq228c 300 IN A 1.2.3.4 +112 a 300 IN CNAME xn--ndaaa.com. +113 xn--o-0gab 300 IN CNAME xn--ndaaa.xn--vhquv. +114 @ 300 IN CAA 0 issue "letsencrypt.org" +115 @ 300 IN CAA 0 issue "letsencrypt.org; validationmethods=dns-01; accounturi=https://acme-v02.api.letsencrypt.org/acme/acct/1234" +116 @ 300 IN CAA 0 issuewild ";" +117 @ 300 IN CAA 0 issuewild "example.com" +118 @ 300 IN CAA 0 issuewild "letsencrypt.org" +119 @ 300 IN CAA 0 issue "letsencrypt.org" +120 @ 300 IN CAA 128 issue "letsencrypt.org" +121 @ 300 IN LOC 42 21 54.000 N 71 06 18.000 W -24.05m 30m 0.00m 0.00m +122 @ 300 IN LOC 42 21 54.000 N 71 06 18.000 W -24.06m 30m 10m 0.00m +123 @ 300 IN LOC 42 21 54.000 N 71 06 18.000 W -24m 30m 0.00m 0.00m +124 a 300 IN LOC 42 21 43.950 N 71 05 6.340 W -24.33m 1m 200m 10m +125 b 300 IN LOC 52 14 5.000 N 00 08 50.000 E 10.22m 0.00m 0.00m 0.00m +126 c 300 IN LOC 32 07 19.000 S 116 02 25.000 E 10m 0.00m 0.00m 0.00m +127 d 300 IN LOC 42 21 28.760 N 71 00 51.620 W -44m 2000m 0.00m 0.00m +128 test 300 IN NAPTR 100 10 "U" "E2U+sip" "!^.*$!sip:customer-service@example.com!" . +129 test 300 IN NAPTR 103 10 "U" "E2U+email" "!^.*$!mailto:information@example.com!" . +130 test 300 IN NAPTR 103 20 "A" "E2U+email" "!^.*$!mailto:information@example.com!" . +131 test 300 IN NAPTR 103 20 "A" "E2U+sip" "!^.*$!mailto:information@example.com!" . +132 test 300 IN NAPTR 103 20 "A" "E2U+sip" "!^.*$!sip:customer-service@example.com!" . +133 test 300 IN NAPTR 103 20 "A" "E2U+sip" "" example.foo.com. +134 test 300 IN NAPTR 103 20 "A" "E2U+sip" "" example2.foo.com. +135 test 300 IN NAPTR 103 20 "U" "E2U+email" "!^.*$!mailto:information@example.com!" . +136 test 300 IN NAPTR 102 10 "U" "E2U+email" "!^.*$!mailto:information@example.com!" . +137 _sip._tcp 300 IN SRV 5 6 7 foo.com. +138 _sip._tcp 300 IN SRV 52 6 7 foo.com. +139 _sip._tcp 300 IN SRV 52 62 7 foo.com. +140 _sip._tcp 300 IN SRV 52 62 72 foo.com. +141 _sip._tcp 300 IN SRV 5 60 70 foo2.com. +142 _sip._tcp 300 IN SRV 15 65 75 foo3.com. +143 _sip._tcp 300 IN SRV 15 65 75 foo4.com. +144 _sip._tcp 300 IN SRV 15 65 75 . +145 _sip._tcp 21600 IN SRV 5 6 7 foo.com. +146 _sip._tcp 600 IN SRV 5 6 7 foo.com. +147 @ 300 IN SSHFP 1 1 66C7D5540B7D75A1FB4C84FEBFA178AD99BDD67C +148 @ 300 IN SSHFP 2 1 66C7D5540B7D75A1FB4C84FEBFA178AD99BDD67C +149 @ 300 IN SSHFP 2 2 745A635BC46A397A5C4F21D437483005BCC40D7511FF15FBFAFE913A081559BC +150 _443._tcp 300 IN TLSA 2 0 1 0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF +151 _443._tcp 300 IN TLSA 2 1 1 0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF +152 _443._tcp 300 IN TLSA 3 1 1 0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF +153 _443._tcp 300 IN TLSA 2 0 2 0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF +154 _443._tcp 300 IN TLSA 2 0 2 FEDCBA9876543210FEDCBA9876543210FEDCBA9876543210FEDCBA9876543210FEDCBA9876543210FEDCBA9876543210FEDCBA9876543210FEDCBA9876543210 +155 child 300 IN NS ns101.cloudns.net. +156 child 300 IN DS 35632 13 1 1E07663FF507A40874B8605463DD41DE482079D6 +157 child 300 IN DS 2075 13 1 2706D12E256C8FDD9BFB45EFB25FE537E21A82F6 +158 child 300 IN DS 2075 13 2 3F7A1EAC8C813A0BEBD0C3B8AAB387E31945EA0CD5E1D84A2E8E27674566C156 +159 child 300 IN DS 63909 3 4 EEC7FA02E6788DA889B2CE41D43D92F948AB126EDCF83B7037E73CE9531C8E7E45653ABBAA76C2D6E42F98316EDE599B +160 child 300 IN DS 2159 1 4 F50BEFEA333EE2901D72D31A08E1A3CD3F7E943FF4B38CF7C8AD92807F5302F76FB0B419182C0F47FFC71CBCB6EF4BD4 +161 another-child 300 IN NS ns101.cloudns.net. +162 another-child 300 IN DS 35632 13 4 F5F32ABCA6B01AA7A9963012F90B7C8523A1D946185A3AD70B67F3C9F18E7312FA9DD6AB2F7D8382F789213DB173D429 +163 another-child 300 IN DS 2159 1 4 F50BEFEA333EE2901D72D31A08E1A3CD3F7E943FF4B38CF7C8AD92807F5302F76FB0B419182C0F47FFC71CBCB6EF4BD4 +164 another-child 300 IN DS 63909 3 4 EEC7FA02E6788DA889B2CE41D43D92F948AB126EDCF83B7037E73CE9531C8E7E45653ABBAA76C2D6E42F98316EDE599B +165 test 300 IN DNAME example.com. +166 test 300 IN DNAME example.net. +167 a 300 IN DNAME b.cloudnstest.yesthattom.com. +168 @ 300 IN ALIAS foo.com. +169 @ 300 IN ALIAS foo2.com. +170 foo 300 IN A 1.2.3.4 +171 @ 300 IN ALIAS foo.cloudnstest.yesthattom.com. +172 test 300 IN ALIAS foo.com. +173 test 300 IN ALIAS foo2.com. +174 bar 300 IN A 5.5.5.5 +175 foo 300 IN A 1.2.3.4 +176 foo 300 IN A 2.3.4.5 +177 foo 300 IN TXT "simple" +178 mail 300 IN CNAME ghs.googlehosted.com. +179 @ 300 IN A 1.2.3.4 +180 @ 300 IN A 2.3.4.5 +181 bar 300 IN A 5.5.5.5 +182 @ 300 IN TXT "simple" +183 mail 300 IN CNAME ghs.googlehosted.com. +184 @ 300 IN A 2.2.2.2 +185 foo 300 IN A 1.2.3.4 +186 @ 300 IN TXT "asimple" +187 foo 300 IN TXT "simple" +188 bar.bat 300 IN A 5.5.5.5 +189 foo.bat 300 IN A 1.2.3.4 +190 foo.bat 300 IN A 2.3.4.5 +191 foo.bat 300 IN TXT "simple" +192 mail.bat 300 IN CNAME ghs.googlehosted.com. +193 foo 300 IN A 1.1.1.1 +194 foo 300 IN A 10.10.10.10 +195 foo 300 IN A 11.11.11.11 +196 foo 300 IN A 12.12.12.12 +197 foo 300 IN A 13.13.13.13 +198 foo 300 IN A 14.14.14.14 +199 foo 300 IN AAAA 2003:dd:d7ff::fe71:aaaa +200 zzz 300 IN A 3.3.3.3 +201 zzz 300 IN A 4.4.4.4 +202 zzz 300 IN AAAA 2003:dd:d7ff::fe71:cccc +203 foo 300 IN MX 10 aspmx.l.google.com. +204 foo 300 IN MX 20 alt1.aspmx.l.google.com. +205 bar 300 IN CNAME redact2.acm-validations.aws. +206 foo 300 IN CNAME redact1.acm-validations.aws. +207 dyndns-city1 300 IN A 91.42.1.1 +208 dyndns-city1 300 IN AAAA 2003:dd:d7ff::fe71:ce77 +209 dyndns-city2 300 IN A 91.42.1.2 +210 dyndns-city2 300 IN AAAA 2003:dd:d7ff::fe71:ce78 +211 testdefined 300 IN A 2.2.2.2 +212 testdefined 300 IN A 9.9.9.9 +213 testignore 300 IN A 8.8.8.8 +214 final 300 IN TXT "TestDNSProviders was successful!" +215 final 300 IN TXT "TestDNSProviders was successful!" +216 @ 300 IN NS ns1.example.com. +217 @ 300 IN NS ns2.example.com. diff --git a/providers/cloudns/test_data/meta.json b/providers/cloudns/test_data/meta.json new file mode 100644 index 0000000000..bf54e47173 --- /dev/null +++ b/providers/cloudns/test_data/meta.json @@ -0,0 +1,14 @@ +{ + "version": 1, + "recordings": [ + { + "domain": "cloudnstest.yesthattom.com", + "to_rc": [ + "toRc" + ], + "to_native": [ + "toReq" + ] + } + ] +} diff --git a/providers/cloudns/test_data/recorded_tonative_input_toReq_cloudnstest.yesthattom.com.records b/providers/cloudns/test_data/recorded_tonative_input_toReq_cloudnstest.yesthattom.com.records new file mode 100644 index 0000000000..7976553466 --- /dev/null +++ b/providers/cloudns/test_data/recorded_tonative_input_toReq_cloudnstest.yesthattom.com.records @@ -0,0 +1,182 @@ +1 * 300 IN A 3.3.3.3 +2 @ 1800 IN A 8.8.8.8 +3 @ 300 IN A 1.2.3.2 +4 @ 300 IN A 1.2.3.4 +5 @ 300 IN A 2.2.2.2 +6 @ 300 IN A 2.3.4.5 +7 @ 300 IN A 4.4.4.4 +8 @ 300 IN ALIAS foo.cloudnstest.yesthattom.com. +9 @ 300 IN ALIAS foo.com. +10 @ 300 IN ALIAS foo2.com. +11 @ 300 IN CAA 0 issue "letsencrypt.org" +12 @ 300 IN CAA 0 issue "letsencrypt.org; validationmethods=dns-01; accounturi=https://acme-v02.api.letsencrypt.org/acme/acct/1234" +13 @ 300 IN CAA 0 issuewild ";" +14 @ 300 IN CAA 0 issuewild "example.com" +15 @ 300 IN CAA 0 issuewild "letsencrypt.org" +16 @ 300 IN CAA 128 issue "letsencrypt.org" +17 @ 300 IN LOC 42 21 54.000 N 71 06 18.000 W -24.05m 30m 0.00m 0.00m +18 @ 300 IN LOC 42 21 54.000 N 71 06 18.000 W -24.06m 30m 10m 0.00m +19 @ 300 IN LOC 42 21 54.000 N 71 06 18.000 W -24m 30m 0.00m 0.00m +20 @ 300 IN MX 0 . +21 @ 300 IN MX 2 cloudnstest.yesthattom.com. +22 @ 300 IN MX 5 bar.com. +23 @ 300 IN MX 5 foo.com. +24 @ 300 IN MX 8 www.cloudnstest.yesthattom.com. +25 @ 300 IN NS ns1.example.com. +26 @ 300 IN NS ns1.foo.com. +27 @ 300 IN NS ns2.example.com. +28 @ 300 IN NS ns2.foo.com. +29 @ 300 IN SSHFP 1 1 66C7D5540B7D75A1FB4C84FEBFA178AD99BDD67C +30 @ 300 IN SSHFP 2 1 66C7D5540B7D75A1FB4C84FEBFA178AD99BDD67C +31 @ 300 IN SSHFP 2 2 745A635BC46A397A5C4F21D437483005BCC40D7511FF15FBFAFE913A081559BC +32 @ 300 IN TXT "asimple" +33 @ 300 IN TXT "simple" +34 @ 600 IN A 8.8.8.8 +35 @ 900 IN A 8.8.8.8 +36 _443._tcp 300 IN TLSA 2 0 1 0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF +37 _443._tcp 300 IN TLSA 2 0 2 0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF +38 _443._tcp 300 IN TLSA 2 0 2 FEDCBA9876543210FEDCBA9876543210FEDCBA9876543210FEDCBA9876543210FEDCBA9876543210FEDCBA9876543210FEDCBA9876543210FEDCBA9876543210 +39 _443._tcp 300 IN TLSA 2 1 1 0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF +40 _443._tcp 300 IN TLSA 3 1 1 0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF +41 _sip._tcp 21600 IN SRV 5 6 7 foo.com. +42 _sip._tcp 300 IN SRV 15 65 75 . +43 _sip._tcp 300 IN SRV 15 65 75 foo3.com. +44 _sip._tcp 300 IN SRV 15 65 75 foo4.com. +45 _sip._tcp 300 IN SRV 5 6 7 foo.com. +46 _sip._tcp 300 IN SRV 5 60 70 foo2.com. +47 _sip._tcp 300 IN SRV 52 6 7 foo.com. +48 _sip._tcp 300 IN SRV 52 62 7 foo.com. +49 _sip._tcp 300 IN SRV 52 62 72 foo.com. +50 _sip._tcp 600 IN SRV 5 6 7 foo.com. +51 a 300 IN CNAME xn--ndaaa.com. +52 a 300 IN DNAME b.cloudnstest.yesthattom.com. +53 a 300 IN LOC 42 21 43.950 N 71 05 6.340 W -24.33m 1m 200m 10m +54 another-child 300 IN DS 2159 1 4 F50BEFEA333EE2901D72D31A08E1A3CD3F7E943FF4B38CF7C8AD92807F5302F76FB0B419182C0F47FFC71CBCB6EF4BD4 +55 another-child 300 IN DS 35632 13 4 F5F32ABCA6B01AA7A9963012F90B7C8523A1D946185A3AD70B67F3C9F18E7312FA9DD6AB2F7D8382F789213DB173D429 +56 another-child 300 IN DS 63909 3 4 EEC7FA02E6788DA889B2CE41D43D92F948AB126EDCF83B7037E73CE9531C8E7E45653ABBAA76C2D6E42F98316EDE599B +57 another-child 300 IN NS ns101.cloudns.net. +58 b 300 IN LOC 52 14 5.000 N 00 08 50.000 E 10.22m 0.00m 0.00m 0.00m +59 bar 300 IN A 1.2.3.4 +60 bar 300 IN A 5.5.5.5 +61 bar 300 IN CNAME redact2.acm-validations.aws. +62 bar 300 IN MX 5 bar.com. +63 bar.bat 300 IN A 5.5.5.5 +64 c 300 IN LOC 32 07 19.000 S 116 02 25.000 E 10m 0.00m 0.00m 0.00m +65 child 300 IN DS 2075 13 1 2706D12E256C8FDD9BFB45EFB25FE537E21A82F6 +66 child 300 IN DS 2075 13 2 3F7A1EAC8C813A0BEBD0C3B8AAB387E31945EA0CD5E1D84A2E8E27674566C156 +67 child 300 IN DS 2159 1 4 F50BEFEA333EE2901D72D31A08E1A3CD3F7E943FF4B38CF7C8AD92807F5302F76FB0B419182C0F47FFC71CBCB6EF4BD4 +68 child 300 IN DS 35632 13 1 1E07663FF507A40874B8605463DD41DE482079D6 +69 child 300 IN DS 63909 3 4 EEC7FA02E6788DA889B2CE41D43D92F948AB126EDCF83B7037E73CE9531C8E7E45653ABBAA76C2D6E42F98316EDE599B +70 child 300 IN NS ns101.cloudns.net. +71 d 300 IN LOC 42 21 28.760 N 71 00 51.620 W -44m 2000m 0.00m 0.00m +72 decoy 300 IN A 1.1.1.1 +73 decoy 300 IN A 2.2.2.2 +74 decoy 300 IN A 3.3.3.3 +75 dyndns-city1 300 IN A 91.42.1.1 +76 dyndns-city1 300 IN AAAA 2003:dd:d7ff::fe71:ce77 +77 dyndns-city2 300 IN A 91.42.1.2 +78 dyndns-city2 300 IN AAAA 2003:dd:d7ff::fe71:ce78 +79 final 300 IN TXT "TestDNSProviders was successful!" +80 foo 300 IN A 1.1.1.1 +81 foo 300 IN A 1.2.3.4 +82 foo 300 IN A 10.10.10.10 +83 foo 300 IN A 11.11.11.11 +84 foo 300 IN A 12.12.12.12 +85 foo 300 IN A 13.13.13.13 +86 foo 300 IN A 14.14.14.14 +87 foo 300 IN A 2.3.4.5 +88 foo 300 IN A 3.4.5.6 +89 foo 300 IN A 4.5.6.7 +90 foo 300 IN A 8.8.8.8 +91 foo 300 IN AAAA 2003:dd:d7ff::fe71:aaaa +92 foo 300 IN CNAME cloudnstest.yesthattom.com. +93 foo 300 IN CNAME google.com. +94 foo 300 IN CNAME google2.com. +95 foo 300 IN CNAME redact1.acm-validations.aws. +96 foo 300 IN MX 10 aspmx.l.google.com. +97 foo 300 IN MX 10 foo.cloudnstest.yesthattom.com. +98 foo 300 IN MX 20 alt1.aspmx.l.google.com. +99 foo 300 IN MX 20 bar.cloudnstest.yesthattom.com. +100 foo 300 IN MX 5 mx.google.com. +101 foo 300 IN MX 8 cloudnstest.yesthattom.com. +102 foo 300 IN NS cloudnstest.yesthattom.com. +103 foo 300 IN TXT "simple" +104 foo 300 IN TXT "v=spf1 ip4:99.99.99.99 -all" +105 foo.bat 300 IN A 1.2.3.4 +106 foo.bat 300 IN A 2.3.4.5 +107 foo.bat 300 IN TXT "simple" +108 foo254 300 IN TXT "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" +109 foo255 300 IN TXT "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" +110 foo256 300 IN TXT "CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC" "C" +111 foo509 300 IN TXT "DDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDD" "DDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDD" +112 foo510 300 IN TXT "EEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE" "EEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE" +113 foo511 300 IN TXT "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF" "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF" "F" +114 foo764 300 IN TXT "GGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGG" "GGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGG" "GGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGG" +115 foo765 300 IN TXT "HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH" "HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH" "HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH" +116 foo766 300 IN TXT "JJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJ" "JJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJ" "JJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJ" "J" +117 fooosbs1 300 IN TXT "1back\\slash" +118 fooosbs2 300 IN TXT "2back\\\\slash" +119 fooosbs3 300 IN TXT "3back\\\\\\slash" +120 fooosbs4 300 IN TXT "4back\\\\\\\\slash" +121 foosc1 300 IN TXT "semi;colon" +122 foosc2 300 IN TXT "wssemi ; colon" +123 foosp 300 IN TXT "with spaces" +124 foosq 300 IN TXT "quo'te" +125 mail 300 IN CNAME ghs.googlehosted.com. +126 mail.bat 300 IN CNAME ghs.googlehosted.com. +127 nmx 300 IN A 1.2.3.3 +128 nmx 300 IN MX 0 . +129 nmx 300 IN MX 3 nmx.cloudnstest.yesthattom.com. +130 nmx 300 IN MX 9 www.cloudnstest.yesthattom.com. +131 test 300 IN ALIAS foo.com. +132 test 300 IN ALIAS foo2.com. +133 test 300 IN DNAME example.com. +134 test 300 IN DNAME example.net. +135 test 300 IN NAPTR 100 10 "U" "E2U+sip" "!^.*$!sip:customer-service@example.com!" . +136 test 300 IN NAPTR 102 10 "U" "E2U+email" "!^.*$!mailto:information@example.com!" . +137 test 300 IN NAPTR 103 10 "U" "E2U+email" "!^.*$!mailto:information@example.com!" . +138 test 300 IN NAPTR 103 20 "A" "E2U+email" "!^.*$!mailto:information@example.com!" . +139 test 300 IN NAPTR 103 20 "A" "E2U+sip" "!^.*$!mailto:information@example.com!" . +140 test 300 IN NAPTR 103 20 "A" "E2U+sip" "!^.*$!sip:customer-service@example.com!" . +141 test 300 IN NAPTR 103 20 "A" "E2U+sip" "" example.foo.com. +142 test 300 IN NAPTR 103 20 "A" "E2U+sip" "" example2.foo.com. +143 test 300 IN NAPTR 103 20 "U" "E2U+email" "!^.*$!mailto:information@example.com!" . +144 testa 1800 IN A 1.1.1.1 +145 testa 300 IN A 1.1.1.1 +146 testa 300 IN A 3.3.3.3 +147 testa 600 IN A 1.1.1.1 +148 testaaaa 300 IN AAAA 2607:f8b0:4006:820::2006 +149 testaaaa 300 IN AAAA 2607:f8b0:4006:820::2013 +150 testcname 300 IN CNAME foo.cloudnstest.yesthattom.com. +151 testcname 300 IN CNAME www.google.com. +152 testcname 300 IN CNAME www.yahoo.com. +153 testdefined 300 IN A 2.2.2.2 +154 testdefined 300 IN A 9.9.9.9 +155 testignore 300 IN A 8.8.8.8 +156 testmx 300 IN MX 100 bar.com. +157 testmx 300 IN MX 100 foo.com. +158 testmx 300 IN MX 5 bar.com. +159 testmx 300 IN MX 5 foo.com. +160 testtxt 300 IN TXT "changed" +161 testtxt 300 IN TXT "simple" +162 www 300 IN A 1.1.1.1 +163 www 300 IN A 1.2.3.4 +164 www 300 IN A 1.2.3.8 +165 www 300 IN A 1.2.3.9 +166 www 300 IN A 2.2.2.2 +167 www 300 IN A 3.3.3.3 +168 www 300 IN A 5.5.5.5 +169 www 300 IN A 5.6.7.8 +170 www 600 IN A 2.2.2.2 +171 www 600 IN A 5.6.7.8 +172 www 900 IN A 1.2.3.4 +173 www 900 IN A 5.6.7.8 +174 xn--fiq228c 300 IN A 1.2.3.4 +175 xn--ndaaa 300 IN A 1.2.3.4 +176 xn--ndaaa 300 IN A 2.2.2.2 +177 xn--o-0gab 300 IN CNAME xn--ndaaa.xn--vhquv. +178 xyz 300 IN NS ns1.foo.com. +179 xyz 300 IN NS ns2.foo.com. +180 zzz 300 IN A 3.3.3.3 +181 zzz 300 IN A 4.4.4.4 +182 zzz 300 IN AAAA 2003:dd:d7ff::fe71:cccc diff --git a/providers/cloudns/test_data/recorded_torc_input_toRc_cloudnstest.yesthattom.com.json b/providers/cloudns/test_data/recorded_torc_input_toRc_cloudnstest.yesthattom.com.json new file mode 100644 index 0000000000..b20a9a4839 --- /dev/null +++ b/providers/cloudns/test_data/recorded_torc_input_toRc_cloudnstest.yesthattom.com.json @@ -0,0 +1,3669 @@ +[ + { + "index": 1, + "value": { + "id": "859917722", + "type": "NS", + "host": "", + "record": "pns71.cloudns.net", + "priority": "", + "weight": "", + "port": "", + "service": "", + "protocol": "", + "ttl": "300", + "status": 1 + } + }, + { + "index": 2, + "value": { + "id": "859917727", + "type": "NS", + "host": "", + "record": "pns72.cloudns.com", + "priority": "", + "weight": "", + "port": "", + "service": "", + "protocol": "", + "ttl": "300", + "status": 1 + } + }, + { + "index": 3, + "value": { + "id": "859917732", + "type": "NS", + "host": "", + "record": "pns73.cloudns.net", + "priority": "", + "weight": "", + "port": "", + "service": "", + "protocol": "", + "ttl": "300", + "status": 1 + } + }, + { + "index": 4, + "value": { + "id": "859917735", + "type": "NS", + "host": "", + "record": "pns74.cloudns.uk", + "priority": "", + "weight": "", + "port": "", + "service": "", + "protocol": "", + "ttl": "300", + "status": 1 + } + }, + { + "index": 5, + "value": { + "id": "863226987", + "type": "A", + "host": "testa", + "record": "1.1.1.1", + "priority": "", + "weight": "", + "port": "", + "service": "", + "protocol": "", + "ttl": "300", + "status": 1 + } + }, + { + "index": 6, + "value": { + "id": "863226987", + "type": "A", + "host": "testa", + "record": "3.3.3.3", + "priority": "", + "weight": "", + "port": "", + "service": "", + "protocol": "", + "ttl": "300", + "status": 1 + } + }, + { + "index": 7, + "value": { + "id": "863226992", + "type": "A", + "host": "", + "record": "2.2.2.2", + "priority": "", + "weight": "", + "port": "", + "service": "", + "protocol": "", + "ttl": "300", + "status": 1 + } + }, + { + "index": 8, + "value": { + "id": "863226992", + "type": "A", + "host": "", + "record": "4.4.4.4", + "priority": "", + "weight": "", + "port": "", + "service": "", + "protocol": "", + "ttl": "300", + "status": 1 + } + }, + { + "index": 9, + "value": { + "id": "863227032", + "type": "A", + "host": "*", + "record": "3.3.3.3", + "priority": "", + "weight": "", + "port": "", + "service": "", + "protocol": "", + "ttl": "300", + "status": 1 + } + }, + { + "index": 10, + "value": { + "id": "863227037", + "type": "A", + "host": "www", + "record": "5.5.5.5", + "priority": "", + "weight": "", + "port": "", + "service": "", + "protocol": "", + "ttl": "300", + "status": 1 + } + }, + { + "index": 11, + "value": { + "id": "863227082", + "type": "AAAA", + "host": "testaaaa", + "record": "2607:f8b0:4006:820::2006", + "priority": "", + "weight": "", + "port": "", + "service": "", + "protocol": "", + "ttl": "300", + "status": 1 + } + }, + { + "index": 12, + "value": { + "id": "863227082", + "type": "AAAA", + "host": "testaaaa", + "record": "2607:f8b0:4006:820::2013", + "priority": "", + "weight": "", + "port": "", + "service": "", + "protocol": "", + "ttl": "300", + "status": 1 + } + }, + { + "index": 13, + "value": { + "id": "863227137", + "type": "CNAME", + "host": "testcname", + "record": "www.google.com", + "priority": "", + "weight": "", + "port": "", + "service": "", + "protocol": "", + "ttl": "300", + "status": 1 + } + }, + { + "index": 14, + "value": { + "id": "863227137", + "type": "CNAME", + "host": "testcname", + "record": "www.yahoo.com", + "priority": "", + "weight": "", + "port": "", + "service": "", + "protocol": "", + "ttl": "300", + "status": 1 + } + }, + { + "index": 15, + "value": { + "id": "863227177", + "type": "A", + "host": "foo", + "record": "1.2.3.4", + "priority": "", + "weight": "", + "port": "", + "service": "", + "protocol": "", + "ttl": "300", + "status": 1 + } + }, + { + "index": 16, + "value": { + "id": "863227182", + "type": "CNAME", + "host": "testcname", + "record": "foo.cloudnstest.yesthattom.com", + "priority": "", + "weight": "", + "port": "", + "service": "", + "protocol": "", + "ttl": "300", + "status": 1 + } + }, + { + "index": 17, + "value": { + "id": "863227217", + "type": "MX", + "host": "", + "record": "bar.com", + "priority": "5", + "weight": "", + "port": "", + "service": "", + "protocol": "", + "ttl": "300", + "status": 1 + } + }, + { + "index": 18, + "value": { + "id": "863227217", + "type": "MX", + "host": "", + "record": "foo.com", + "priority": "5", + "weight": "", + "port": "", + "service": "", + "protocol": "", + "ttl": "300", + "status": 1 + } + }, + { + "index": 19, + "value": { + "id": "863227262", + "type": "MX", + "host": "testmx", + "record": "bar.com", + "priority": "5", + "weight": "", + "port": "", + "service": "", + "protocol": "", + "ttl": "300", + "status": 1 + } + }, + { + "index": 20, + "value": { + "id": "863227262", + "type": "MX", + "host": "testmx", + "record": "foo.com", + "priority": "5", + "weight": "", + "port": "", + "service": "", + "protocol": "", + "ttl": "300", + "status": 1 + } + }, + { + "index": 21, + "value": { + "id": "863227307", + "type": "MX", + "host": "testmx", + "record": "foo.com", + "priority": "100", + "weight": "", + "port": "", + "service": "", + "protocol": "", + "ttl": "300", + "status": 1 + } + }, + { + "index": 22, + "value": { + "id": "863227307", + "type": "MX", + "host": "testmx", + "record": "foo.com", + "priority": "5", + "weight": "", + "port": "", + "service": "", + "protocol": "", + "ttl": "300", + "status": 1 + } + }, + { + "index": 23, + "value": { + "id": "863227357", + "type": "TXT", + "host": "testtxt", + "record": "changed", + "priority": "", + "weight": "", + "port": "", + "service": "", + "protocol": "", + "ttl": "300", + "status": 1 + } + }, + { + "index": 24, + "value": { + "id": "863227357", + "type": "TXT", + "host": "testtxt", + "record": "simple", + "priority": "", + "weight": "", + "port": "", + "service": "", + "protocol": "", + "ttl": "300", + "status": 1 + } + }, + { + "index": 25, + "value": { + "id": "863227362", + "type": "A", + "host": "www", + "record": "1.1.1.1", + "priority": "", + "weight": "", + "port": "", + "service": "", + "protocol": "", + "ttl": "300", + "status": 1 + } + }, + { + "index": 26, + "value": { + "id": "863227367", + "type": "A", + "host": "www", + "record": "2.2.2.2", + "priority": "", + "weight": "", + "port": "", + "service": "", + "protocol": "", + "ttl": "300", + "status": 1 + } + }, + { + "index": 27, + "value": { + "id": "863227372", + "type": "A", + "host": "www", + "record": "3.3.3.3", + "priority": "", + "weight": "", + "port": "", + "service": "", + "protocol": "", + "ttl": "300", + "status": 1 + } + }, + { + "index": 28, + "value": { + "id": "863227377", + "type": "A", + "host": "www", + "record": "1.1.1.1", + "priority": "", + "weight": "", + "port": "", + "service": "", + "protocol": "", + "ttl": "300", + "status": 1 + } + }, + { + "index": 29, + "value": { + "id": "863227382", + "type": "A", + "host": "www", + "record": "2.2.2.2", + "priority": "", + "weight": "", + "port": "", + "service": "", + "protocol": "", + "ttl": "300", + "status": 1 + } + }, + { + "index": 30, + "value": { + "id": "863227387", + "type": "A", + "host": "www", + "record": "3.3.3.3", + "priority": "", + "weight": "", + "port": "", + "service": "", + "protocol": "", + "ttl": "300", + "status": 1 + } + }, + { + "index": 31, + "value": { + "id": "863227392", + "type": "A", + "host": "www", + "record": "1.1.1.1", + "priority": "", + "weight": "", + "port": "", + "service": "", + "protocol": "", + "ttl": "300", + "status": 1 + } + }, + { + "index": 32, + "value": { + "id": "863227397", + "type": "MX", + "host": "testmx", + "record": "bar.com", + "priority": "100", + "weight": "", + "port": "", + "service": "", + "protocol": "", + "ttl": "300", + "status": 1 + } + }, + { + "index": 33, + "value": { + "id": "863227402", + "type": "MX", + "host": "testmx", + "record": "foo.com", + "priority": "5", + "weight": "", + "port": "", + "service": "", + "protocol": "", + "ttl": "300", + "status": 1 + } + }, + { + "index": 34, + "value": { + "id": "863227417", + "type": "A", + "host": "www", + "record": "1.1.1.1", + "priority": "", + "weight": "", + "port": "", + "service": "", + "protocol": "", + "ttl": "300", + "status": 1 + } + }, + { + "index": 35, + "value": { + "id": "863227422", + "type": "MX", + "host": "testmx", + "record": "foo.com", + "priority": "5", + "weight": "", + "port": "", + "service": "", + "protocol": "", + "ttl": "300", + "status": 1 + } + }, + { + "index": 36, + "value": { + "id": "863227427", + "type": "MX", + "host": "testmx", + "record": "bar.com", + "priority": "100", + "weight": "", + "port": "", + "service": "", + "protocol": "", + "ttl": "300", + "status": 1 + } + }, + { + "index": 37, + "value": { + "id": "863227437", + "type": "A", + "host": "testa", + "record": "1.1.1.1", + "priority": "", + "weight": "", + "port": "", + "service": "", + "protocol": "", + "ttl": "1800", + "status": 1 + } + }, + { + "index": 38, + "value": { + "id": "863227437", + "type": "A", + "host": "testa", + "record": "1.1.1.1", + "priority": "", + "weight": "", + "port": "", + "service": "", + "protocol": "", + "ttl": "600", + "status": 1 + } + }, + { + "index": 39, + "value": { + "id": "863227442", + "type": "A", + "host": "", + "record": "8.8.8.8", + "priority": "", + "weight": "", + "port": "", + "service": "", + "protocol": "", + "ttl": "1800", + "status": 1 + } + }, + { + "index": 40, + "value": { + "id": "863227442", + "type": "A", + "host": "", + "record": "8.8.8.8", + "priority": "", + "weight": "", + "port": "", + "service": "", + "protocol": "", + "ttl": "600", + "status": 1 + } + }, + { + "index": 41, + "value": { + "id": "863227442", + "type": "A", + "host": "", + "record": "8.8.8.8", + "priority": "", + "weight": "", + "port": "", + "service": "", + "protocol": "", + "ttl": "900", + "status": 1 + } + }, + { + "index": 42, + "value": { + "id": "863227447", + "type": "A", + "host": "www", + "record": "1.2.3.4", + "priority": "", + "weight": "", + "port": "", + "service": "", + "protocol": "", + "ttl": "300", + "status": 1 + } + }, + { + "index": 43, + "value": { + "id": "863227447", + "type": "A", + "host": "www", + "record": "2.2.2.2", + "priority": "", + "weight": "", + "port": "", + "service": "", + "protocol": "", + "ttl": "300", + "status": 1 + } + }, + { + "index": 44, + "value": { + "id": "863227447", + "type": "A", + "host": "www", + "record": "2.2.2.2", + "priority": "", + "weight": "", + "port": "", + "service": "", + "protocol": "", + "ttl": "600", + "status": 1 + } + }, + { + "index": 45, + "value": { + "id": "863227452", + "type": "A", + "host": "www", + "record": "5.6.7.8", + "priority": "", + "weight": "", + "port": "", + "service": "", + "protocol": "", + "ttl": "300", + "status": 1 + } + }, + { + "index": 46, + "value": { + "id": "863227452", + "type": "A", + "host": "www", + "record": "5.6.7.8", + "priority": "", + "weight": "", + "port": "", + "service": "", + "protocol": "", + "ttl": "600", + "status": 1 + } + }, + { + "index": 47, + "value": { + "id": "863227502", + "type": "A", + "host": "www", + "record": "5.6.7.8", + "priority": "", + "weight": "", + "port": "", + "service": "", + "protocol": "", + "ttl": "600", + "status": 1 + } + }, + { + "index": 48, + "value": { + "id": "863227502", + "type": "A", + "host": "www", + "record": "5.6.7.8", + "priority": "", + "weight": "", + "port": "", + "service": "", + "protocol": "", + "ttl": "900", + "status": 1 + } + }, + { + "index": 49, + "value": { + "id": "863227507", + "type": "A", + "host": "www", + "record": "1.2.3.4", + "priority": "", + "weight": "", + "port": "", + "service": "", + "protocol": "", + "ttl": "900", + "status": 1 + } + }, + { + "index": 50, + "value": { + "id": "863227512", + "type": "A", + "host": "foo", + "record": "1.2.3.4", + "priority": "", + "weight": "", + "port": "", + "service": "", + "protocol": "", + "ttl": "300", + "status": 1 + } + }, + { + "index": 51, + "value": { + "id": "863227517", + "type": "MX", + "host": "foo", + "record": "mx.google.com", + "priority": "5", + "weight": "", + "port": "", + "service": "", + "protocol": "", + "ttl": "300", + "status": 1 + } + }, + { + "index": 52, + "value": { + "id": "863227522", + "type": "A", + "host": "foo", + "record": "4.5.6.7", + "priority": "", + "weight": "", + "port": "", + "service": "", + "protocol": "", + "ttl": "300", + "status": 1 + } + }, + { + "index": 53, + "value": { + "id": "863227547", + "type": "CNAME", + "host": "foo", + "record": "google.com", + "priority": "", + "weight": "", + "port": "", + "service": "", + "protocol": "", + "ttl": "300", + "status": 1 + } + }, + { + "index": 54, + "value": { + "id": "863227552", + "type": "A", + "host": "foo", + "record": "1.2.3.4", + "priority": "", + "weight": "", + "port": "", + "service": "", + "protocol": "", + "ttl": "300", + "status": 1 + } + }, + { + "index": 55, + "value": { + "id": "863227557", + "type": "CNAME", + "host": "foo", + "record": "google2.com", + "priority": "", + "weight": "", + "port": "", + "service": "", + "protocol": "", + "ttl": "300", + "status": 1 + } + }, + { + "index": 56, + "value": { + "id": "863227592", + "type": "A", + "host": "", + "record": "1.2.3.4", + "priority": "", + "weight": "", + "port": "", + "service": "", + "protocol": "", + "ttl": "300", + "status": 1 + } + }, + { + "index": 57, + "value": { + "id": "863227597", + "type": "CNAME", + "host": "foo", + "record": "cloudnstest.yesthattom.com", + "priority": "", + "weight": "", + "port": "", + "service": "", + "protocol": "", + "ttl": "300", + "status": 1 + } + }, + { + "index": 58, + "value": { + "id": "863227637", + "type": "A", + "host": "", + "record": "1.2.3.4", + "priority": "", + "weight": "", + "port": "", + "service": "", + "protocol": "", + "ttl": "300", + "status": 1 + } + }, + { + "index": 59, + "value": { + "id": "863227642", + "type": "MX", + "host": "foo", + "record": "cloudnstest.yesthattom.com", + "priority": "8", + "weight": "", + "port": "", + "service": "", + "protocol": "", + "ttl": "300", + "status": 1 + } + }, + { + "index": 60, + "value": { + "id": "863227662", + "type": "A", + "host": "nmx", + "record": "1.2.3.3", + "priority": "", + "weight": "", + "port": "", + "service": "", + "protocol": "", + "ttl": "300", + "status": 1 + } + }, + { + "index": 61, + "value": { + "id": "863227667", + "type": "A", + "host": "www", + "record": "1.2.3.9", + "priority": "", + "weight": "", + "port": "", + "service": "", + "protocol": "", + "ttl": "300", + "status": 1 + } + }, + { + "index": 62, + "value": { + "id": "863227672", + "type": "MX", + "host": "nmx", + "record": "", + "priority": "0", + "weight": "", + "port": "", + "service": "", + "protocol": "", + "ttl": "300", + "status": 1 + } + }, + { + "index": 63, + "value": { + "id": "863227672", + "type": "MX", + "host": "nmx", + "record": "nmx.cloudnstest.yesthattom.com", + "priority": "3", + "weight": "", + "port": "", + "service": "", + "protocol": "", + "ttl": "300", + "status": 1 + } + }, + { + "index": 64, + "value": { + "id": "863227687", + "type": "MX", + "host": "nmx", + "record": "www.cloudnstest.yesthattom.com", + "priority": "9", + "weight": "", + "port": "", + "service": "", + "protocol": "", + "ttl": "300", + "status": 1 + } + }, + { + "index": 65, + "value": { + "id": "863227752", + "type": "A", + "host": "", + "record": "1.2.3.2", + "priority": "", + "weight": "", + "port": "", + "service": "", + "protocol": "", + "ttl": "300", + "status": 1 + } + }, + { + "index": 66, + "value": { + "id": "863227757", + "type": "A", + "host": "www", + "record": "1.2.3.8", + "priority": "", + "weight": "", + "port": "", + "service": "", + "protocol": "", + "ttl": "300", + "status": 1 + } + }, + { + "index": 67, + "value": { + "id": "863227762", + "type": "MX", + "host": "", + "record": "", + "priority": "0", + "weight": "", + "port": "", + "service": "", + "protocol": "", + "ttl": "300", + "status": 1 + } + }, + { + "index": 68, + "value": { + "id": "863227762", + "type": "MX", + "host": "", + "record": "cloudnstest.yesthattom.com", + "priority": "2", + "weight": "", + "port": "", + "service": "", + "protocol": "", + "ttl": "300", + "status": 1 + } + }, + { + "index": 69, + "value": { + "id": "863227792", + "type": "MX", + "host": "", + "record": "www.cloudnstest.yesthattom.com", + "priority": "8", + "weight": "", + "port": "", + "service": "", + "protocol": "", + "ttl": "300", + "status": 1 + } + }, + { + "index": 70, + "value": { + "id": "863227847", + "type": "NS", + "host": "xyz", + "record": "ns2.foo.com", + "priority": "", + "weight": "", + "port": "", + "service": "", + "protocol": "", + "ttl": "300", + "status": 1 + } + }, + { + "index": 71, + "value": { + "id": "863227862", + "type": "NS", + "host": "xyz", + "record": "ns1.foo.com", + "priority": "", + "weight": "", + "port": "", + "service": "", + "protocol": "", + "ttl": "300", + "status": 1 + } + }, + { + "index": 72, + "value": { + "id": "863227887", + "type": "A", + "host": "", + "record": "1.2.3.4", + "priority": "", + "weight": "", + "port": "", + "service": "", + "protocol": "", + "ttl": "300", + "status": 1 + } + }, + { + "index": 73, + "value": { + "id": "863227892", + "type": "NS", + "host": "foo", + "record": "cloudnstest.yesthattom.com", + "priority": "", + "weight": "", + "port": "", + "service": "", + "protocol": "", + "ttl": "300", + "status": 1 + } + }, + { + "index": 74, + "value": { + "id": "863227937", + "type": "NS", + "host": "", + "record": "ns1.foo.com", + "priority": "", + "weight": "", + "port": "", + "service": "", + "protocol": "", + "ttl": "300", + "status": 1 + } + }, + { + "index": 75, + "value": { + "id": "863227967", + "type": "NS", + "host": "", + "record": "ns2.foo.com", + "priority": "", + "weight": "", + "port": "", + "service": "", + "protocol": "", + "ttl": "300", + "status": 1 + } + }, + { + "index": 76, + "value": { + "id": "863227977", + "type": "TXT", + "host": "foo254", + "record": "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", + "priority": "", + "weight": "", + "port": "", + "service": "", + "protocol": "", + "ttl": "300", + "status": 1 + } + }, + { + "index": 77, + "value": { + "id": "863227987", + "type": "TXT", + "host": "foo255", + "record": "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB", + "priority": "", + "weight": "", + "port": "", + "service": "", + "protocol": "", + "ttl": "300", + "status": 1 + } + }, + { + "index": 78, + "value": { + "id": "863227997", + "type": "TXT", + "host": "foo256", + "record": "CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC", + "priority": "", + "weight": "", + "port": "", + "service": "", + "protocol": "", + "ttl": "300", + "status": 1 + } + }, + { + "index": 79, + "value": { + "id": "863228002", + "type": "TXT", + "host": "foo509", + "record": "DDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDD", + "priority": "", + "weight": "", + "port": "", + "service": "", + "protocol": "", + "ttl": "300", + "status": 1 + } + }, + { + "index": 80, + "value": { + "id": "863228012", + "type": "TXT", + "host": "foo510", + "record": "EEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE", + "priority": "", + "weight": "", + "port": "", + "service": "", + "protocol": "", + "ttl": "300", + "status": 1 + } + }, + { + "index": 81, + "value": { + "id": "863228017", + "type": "TXT", + "host": "foo511", + "record": "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF", + "priority": "", + "weight": "", + "port": "", + "service": "", + "protocol": "", + "ttl": "300", + "status": 1 + } + }, + { + "index": 82, + "value": { + "id": "863228037", + "type": "TXT", + "host": "foo764", + "record": "GGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGG", + "priority": "", + "weight": "", + "port": "", + "service": "", + "protocol": "", + "ttl": "300", + "status": 1 + } + }, + { + "index": 83, + "value": { + "id": "863228042", + "type": "TXT", + "host": "foo765", + "record": "HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH", + "priority": "", + "weight": "", + "port": "", + "service": "", + "protocol": "", + "ttl": "300", + "status": 1 + } + }, + { + "index": 84, + "value": { + "id": "863228047", + "type": "TXT", + "host": "foo766", + "record": "JJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJ", + "priority": "", + "weight": "", + "port": "", + "service": "", + "protocol": "", + "ttl": "300", + "status": 1 + } + }, + { + "index": 85, + "value": { + "id": "863228052", + "type": "TXT", + "host": "foosq", + "record": "quo'te", + "priority": "", + "weight": "", + "port": "", + "service": "", + "protocol": "", + "ttl": "300", + "status": 1 + } + }, + { + "index": 86, + "value": { + "id": "863228057", + "type": "TXT", + "host": "foosc1", + "record": "semi;colon", + "priority": "", + "weight": "", + "port": "", + "service": "", + "protocol": "", + "ttl": "300", + "status": 1 + } + }, + { + "index": 87, + "value": { + "id": "863228067", + "type": "TXT", + "host": "foosc2", + "record": "wssemi ; colon", + "priority": "", + "weight": "", + "port": "", + "service": "", + "protocol": "", + "ttl": "300", + "status": 1 + } + }, + { + "index": 88, + "value": { + "id": "863228072", + "type": "TXT", + "host": "foosp", + "record": "with spaces", + "priority": "", + "weight": "", + "port": "", + "service": "", + "protocol": "", + "ttl": "300", + "status": 1 + } + }, + { + "index": 89, + "value": { + "id": "863228082", + "type": "TXT", + "host": "foo", + "record": "v=spf1 ip4:99.99.99.99 -all", + "priority": "", + "weight": "", + "port": "", + "service": "", + "protocol": "", + "ttl": "300", + "status": 1 + } + }, + { + "index": 90, + "value": { + "id": "863228087", + "type": "TXT", + "host": "fooosbs1", + "record": "1back\\slash", + "priority": "", + "weight": "", + "port": "", + "service": "", + "protocol": "", + "ttl": "300", + "status": 1 + } + }, + { + "index": 91, + "value": { + "id": "863228092", + "type": "TXT", + "host": "fooosbs2", + "record": "2back\\\\slash", + "priority": "", + "weight": "", + "port": "", + "service": "", + "protocol": "", + "ttl": "300", + "status": 1 + } + }, + { + "index": 92, + "value": { + "id": "863228097", + "type": "TXT", + "host": "fooosbs3", + "record": "3back\\\\\\slash", + "priority": "", + "weight": "", + "port": "", + "service": "", + "protocol": "", + "ttl": "300", + "status": 1 + } + }, + { + "index": 93, + "value": { + "id": "863228102", + "type": "TXT", + "host": "fooosbs4", + "record": "4back\\\\\\\\slash", + "priority": "", + "weight": "", + "port": "", + "service": "", + "protocol": "", + "ttl": "300", + "status": 1 + } + }, + { + "index": 94, + "value": { + "id": "863228132", + "type": "MX", + "host": "bar", + "record": "bar.com", + "priority": "5", + "weight": "", + "port": "", + "service": "", + "protocol": "", + "ttl": "300", + "status": 1 + } + }, + { + "index": 95, + "value": { + "id": "863228152", + "type": "A", + "host": "decoy", + "record": "1.1.1.1", + "priority": "", + "weight": "", + "port": "", + "service": "", + "protocol": "", + "ttl": "300", + "status": 1 + } + }, + { + "index": 96, + "value": { + "id": "863228152", + "type": "A", + "host": "decoy", + "record": "2.2.2.2", + "priority": "", + "weight": "", + "port": "", + "service": "", + "protocol": "", + "ttl": "300", + "status": 1 + } + }, + { + "index": 97, + "value": { + "id": "863228152", + "type": "A", + "host": "decoy", + "record": "3.3.3.3", + "priority": "", + "weight": "", + "port": "", + "service": "", + "protocol": "", + "ttl": "300", + "status": 1 + } + }, + { + "index": 98, + "value": { + "id": "863228187", + "type": "A", + "host": "foo", + "record": "1.2.3.4", + "priority": "", + "weight": "", + "port": "", + "service": "", + "protocol": "", + "ttl": "300", + "status": 1 + } + }, + { + "index": 99, + "value": { + "id": "863228192", + "type": "A", + "host": "foo", + "record": "2.3.4.5", + "priority": "", + "weight": "", + "port": "", + "service": "", + "protocol": "", + "ttl": "300", + "status": 1 + } + }, + { + "index": 100, + "value": { + "id": "863228192", + "type": "A", + "host": "foo", + "record": "3.4.5.6", + "priority": "", + "weight": "", + "port": "", + "service": "", + "protocol": "", + "ttl": "300", + "status": 1 + } + }, + { + "index": 101, + "value": { + "id": "863228217", + "type": "A", + "host": "foo", + "record": "3.4.5.6", + "priority": "", + "weight": "", + "port": "", + "service": "", + "protocol": "", + "ttl": "300", + "status": 1 + } + }, + { + "index": 102, + "value": { + "id": "863228222", + "type": "A", + "host": "bar", + "record": "1.2.3.4", + "priority": "", + "weight": "", + "port": "", + "service": "", + "protocol": "", + "ttl": "300", + "status": 1 + } + }, + { + "index": 103, + "value": { + "id": "863228227", + "type": "A", + "host": "foo", + "record": "2.3.4.5", + "priority": "", + "weight": "", + "port": "", + "service": "", + "protocol": "", + "ttl": "300", + "status": 1 + } + }, + { + "index": 104, + "value": { + "id": "863228232", + "type": "A", + "host": "foo", + "record": "3.4.5.6", + "priority": "", + "weight": "", + "port": "", + "service": "", + "protocol": "", + "ttl": "300", + "status": 1 + } + }, + { + "index": 105, + "value": { + "id": "863228232", + "type": "A", + "host": "foo", + "record": "8.8.8.8", + "priority": "", + "weight": "", + "port": "", + "service": "", + "protocol": "", + "ttl": "300", + "status": 1 + } + }, + { + "index": 106, + "value": { + "id": "863228237", + "type": "MX", + "host": "foo", + "record": "bar.cloudnstest.yesthattom.com", + "priority": "20", + "weight": "", + "port": "", + "service": "", + "protocol": "", + "ttl": "300", + "status": 1 + } + }, + { + "index": 107, + "value": { + "id": "863228247", + "type": "MX", + "host": "foo", + "record": "foo.cloudnstest.yesthattom.com", + "priority": "10", + "weight": "", + "port": "", + "service": "", + "protocol": "", + "ttl": "300", + "status": 1 + } + }, + { + "index": 108, + "value": { + "id": "863228262", + "type": "A", + "host": "foo", + "record": "8.8.8.8", + "priority": "", + "weight": "", + "port": "", + "service": "", + "protocol": "", + "ttl": "300", + "status": 1 + } + }, + { + "index": 109, + "value": { + "id": "863228287", + "type": "A", + "host": "xn--ndaaa", + "record": "1.2.3.4", + "priority": "", + "weight": "", + "port": "", + "service": "", + "protocol": "", + "ttl": "300", + "status": 1 + } + }, + { + "index": 110, + "value": { + "id": "863228287", + "type": "A", + "host": "xn--ndaaa", + "record": "2.2.2.2", + "priority": "", + "weight": "", + "port": "", + "service": "", + "protocol": "", + "ttl": "300", + "status": 1 + } + }, + { + "index": 111, + "value": { + "id": "863228307", + "type": "A", + "host": "xn--fiq228c", + "record": "1.2.3.4", + "priority": "", + "weight": "", + "port": "", + "service": "", + "protocol": "", + "ttl": "300", + "status": 1 + } + }, + { + "index": 112, + "value": { + "id": "863228317", + "type": "CNAME", + "host": "a", + "record": "xn--ndaaa.com", + "priority": "", + "weight": "", + "port": "", + "service": "", + "protocol": "", + "ttl": "300", + "status": 1 + } + }, + { + "index": 113, + "value": { + "id": "863228327", + "type": "CNAME", + "host": "xn--o-0gab", + "record": "xn--ndaaa.xn--vhquv", + "priority": "", + "weight": "", + "port": "", + "service": "", + "protocol": "", + "ttl": "300", + "status": 1 + } + }, + { + "index": 114, + "value": { + "id": "863228332", + "type": "CAA", + "host": "", + "record": "", + "priority": "", + "weight": "", + "port": "", + "service": "", + "protocol": "", + "ttl": "300", + "status": 1, + "caa_flag": "0", + "caa_type": "issue", + "caa_value": "letsencrypt.org" + } + }, + { + "index": 115, + "value": { + "id": "863228332", + "type": "CAA", + "host": "", + "record": "", + "priority": "", + "weight": "", + "port": "", + "service": "", + "protocol": "", + "ttl": "300", + "status": 1, + "caa_flag": "0", + "caa_type": "issue", + "caa_value": "letsencrypt.org; validationmethods=dns-01; accounturi=https://acme-v02.api.letsencrypt.org/acme/acct/1234" + } + }, + { + "index": 116, + "value": { + "id": "863228332", + "type": "CAA", + "host": "", + "record": "", + "priority": "", + "weight": "", + "port": "", + "service": "", + "protocol": "", + "ttl": "300", + "status": 1, + "caa_flag": "0", + "caa_type": "issuewild", + "caa_value": ";" + } + }, + { + "index": 117, + "value": { + "id": "863228332", + "type": "CAA", + "host": "", + "record": "", + "priority": "", + "weight": "", + "port": "", + "service": "", + "protocol": "", + "ttl": "300", + "status": 1, + "caa_flag": "0", + "caa_type": "issuewild", + "caa_value": "example.com" + } + }, + { + "index": 118, + "value": { + "id": "863228332", + "type": "CAA", + "host": "", + "record": "", + "priority": "", + "weight": "", + "port": "", + "service": "", + "protocol": "", + "ttl": "300", + "status": 1, + "caa_flag": "0", + "caa_type": "issuewild", + "caa_value": "letsencrypt.org" + } + }, + { + "index": 119, + "value": { + "id": "863228372", + "type": "CAA", + "host": "", + "record": "", + "priority": "", + "weight": "", + "port": "", + "service": "", + "protocol": "", + "ttl": "300", + "status": 1, + "caa_flag": "0", + "caa_type": "issue", + "caa_value": "letsencrypt.org" + } + }, + { + "index": 120, + "value": { + "id": "863228372", + "type": "CAA", + "host": "", + "record": "", + "priority": "", + "weight": "", + "port": "", + "service": "", + "protocol": "", + "ttl": "300", + "status": 1, + "caa_flag": "128", + "caa_type": "issue", + "caa_value": "letsencrypt.org" + } + }, + { + "index": 121, + "value": { + "id": "863228382", + "type": "LOC", + "host": "", + "record": "422154.000N710618.000W-24.05m30m0.00m0.00m", + "priority": "", + "weight": "", + "port": "", + "service": "", + "protocol": "", + "ttl": "300", + "status": 1, + "lat_deg": "42", + "lat_min": "21", + "lat_sec": "54", + "lat_dir": "N", + "long_deg": "71", + "long_min": "6", + "long_sec": "18", + "long_dir": "W", + "altitude": "-24.05", + "size": "30", + "h_precision": "0", + "v_precision": "0" + } + }, + { + "index": 122, + "value": { + "id": "863228382", + "type": "LOC", + "host": "", + "record": "422154.000N710618.000W-24.06m30m10m0.00m", + "priority": "", + "weight": "", + "port": "", + "service": "", + "protocol": "", + "ttl": "300", + "status": 1, + "lat_deg": "42", + "lat_min": "21", + "lat_sec": "54", + "lat_dir": "N", + "long_deg": "71", + "long_min": "6", + "long_sec": "18", + "long_dir": "W", + "altitude": "-24.06", + "size": "30", + "h_precision": "10", + "v_precision": "0" + } + }, + { + "index": 123, + "value": { + "id": "863228382", + "type": "LOC", + "host": "", + "record": "422154.000N710618.000W-24m30m0.00m0.00m", + "priority": "", + "weight": "", + "port": "", + "service": "", + "protocol": "", + "ttl": "300", + "status": 1, + "lat_deg": "42", + "lat_min": "21", + "lat_sec": "54", + "lat_dir": "N", + "long_deg": "71", + "long_min": "6", + "long_sec": "18", + "long_dir": "W", + "altitude": "-24", + "size": "30", + "h_precision": "0", + "v_precision": "0" + } + }, + { + "index": 124, + "value": { + "id": "863228387", + "type": "LOC", + "host": "a", + "record": "422143.950N71056.340W-24.33m1m200m10m", + "priority": "", + "weight": "", + "port": "", + "service": "", + "protocol": "", + "ttl": "300", + "status": 1, + "lat_deg": "42", + "lat_min": "21", + "lat_sec": "43.95", + "lat_dir": "N", + "long_deg": "71", + "long_min": "5", + "long_sec": "6.34", + "long_dir": "W", + "altitude": "-24.33", + "size": "1", + "h_precision": "200", + "v_precision": "10" + } + }, + { + "index": 125, + "value": { + "id": "863228392", + "type": "LOC", + "host": "b", + "record": "52145.000N000850.000E10.22m0.00m0.00m0.00m", + "priority": "", + "weight": "", + "port": "", + "service": "", + "protocol": "", + "ttl": "300", + "status": 1, + "lat_deg": "52", + "lat_min": "14", + "lat_sec": "5", + "lat_dir": "N", + "long_deg": "0", + "long_min": "8", + "long_sec": "50", + "long_dir": "E", + "altitude": "10.22", + "size": "0", + "h_precision": "0", + "v_precision": "0" + } + }, + { + "index": 126, + "value": { + "id": "863228397", + "type": "LOC", + "host": "c", + "record": "320719.000S1160225.000E10m0.00m0.00m0.00m", + "priority": "", + "weight": "", + "port": "", + "service": "", + "protocol": "", + "ttl": "300", + "status": 1, + "lat_deg": "32", + "lat_min": "7", + "lat_sec": "19", + "lat_dir": "S", + "long_deg": "116", + "long_min": "2", + "long_sec": "25", + "long_dir": "E", + "altitude": "10", + "size": "0", + "h_precision": "0", + "v_precision": "0" + } + }, + { + "index": 127, + "value": { + "id": "863228402", + "type": "LOC", + "host": "d", + "record": "422128.760N710051.620W-44m2000m0.00m0.00m", + "priority": "", + "weight": "", + "port": "", + "service": "", + "protocol": "", + "ttl": "300", + "status": 1, + "lat_deg": "42", + "lat_min": "21", + "lat_sec": "28.76", + "lat_dir": "N", + "long_deg": "71", + "long_min": "0", + "long_sec": "51.62", + "long_dir": "W", + "altitude": "-44", + "size": "2000", + "h_precision": "0", + "v_precision": "0" + } + }, + { + "index": 128, + "value": { + "id": "863228407", + "type": "NAPTR", + "host": "test", + "record": "", + "priority": "", + "weight": "", + "port": "", + "service": "", + "protocol": "", + "ttl": "300", + "status": 1, + "order": "100", + "pref": "10", + "flag": "U", + "params": "E2U+sip", + "regexp": "!^.*$!sip:customer-service@example.com!" + } + }, + { + "index": 129, + "value": { + "id": "863228407", + "type": "NAPTR", + "host": "test", + "record": "", + "priority": "", + "weight": "", + "port": "", + "service": "", + "protocol": "", + "ttl": "300", + "status": 1, + "order": "103", + "pref": "10", + "flag": "U", + "params": "E2U+email", + "regexp": "!^.*$!mailto:information@example.com!" + } + }, + { + "index": 130, + "value": { + "id": "863228407", + "type": "NAPTR", + "host": "test", + "record": "", + "priority": "", + "weight": "", + "port": "", + "service": "", + "protocol": "", + "ttl": "300", + "status": 1, + "order": "103", + "pref": "20", + "flag": "A", + "params": "E2U+email", + "regexp": "!^.*$!mailto:information@example.com!" + } + }, + { + "index": 131, + "value": { + "id": "863228407", + "type": "NAPTR", + "host": "test", + "record": "", + "priority": "", + "weight": "", + "port": "", + "service": "", + "protocol": "", + "ttl": "300", + "status": 1, + "order": "103", + "pref": "20", + "flag": "A", + "params": "E2U+sip", + "regexp": "!^.*$!mailto:information@example.com!" + } + }, + { + "index": 132, + "value": { + "id": "863228407", + "type": "NAPTR", + "host": "test", + "record": "", + "priority": "", + "weight": "", + "port": "", + "service": "", + "protocol": "", + "ttl": "300", + "status": 1, + "order": "103", + "pref": "20", + "flag": "A", + "params": "E2U+sip", + "regexp": "!^.*$!sip:customer-service@example.com!" + } + }, + { + "index": 133, + "value": { + "id": "863228407", + "type": "NAPTR", + "host": "test", + "record": "", + "priority": "", + "weight": "", + "port": "", + "service": "", + "protocol": "", + "ttl": "300", + "status": 1, + "order": "103", + "pref": "20", + "flag": "A", + "params": "E2U+sip", + "replace": "example.foo.com" + } + }, + { + "index": 134, + "value": { + "id": "863228407", + "type": "NAPTR", + "host": "test", + "record": "", + "priority": "", + "weight": "", + "port": "", + "service": "", + "protocol": "", + "ttl": "300", + "status": 1, + "order": "103", + "pref": "20", + "flag": "A", + "params": "E2U+sip", + "replace": "example2.foo.com" + } + }, + { + "index": 135, + "value": { + "id": "863228407", + "type": "NAPTR", + "host": "test", + "record": "", + "priority": "", + "weight": "", + "port": "", + "service": "", + "protocol": "", + "ttl": "300", + "status": 1, + "order": "103", + "pref": "20", + "flag": "U", + "params": "E2U+email", + "regexp": "!^.*$!mailto:information@example.com!" + } + }, + { + "index": 136, + "value": { + "id": "863228412", + "type": "NAPTR", + "host": "test", + "record": "", + "priority": "", + "weight": "", + "port": "", + "service": "", + "protocol": "", + "ttl": "300", + "status": 1, + "order": "102", + "pref": "10", + "flag": "U", + "params": "E2U+email", + "regexp": "!^.*$!mailto:information@example.com!" + } + }, + { + "index": 137, + "value": { + "id": "863228447", + "type": "SRV", + "host": "_sip._tcp", + "record": "foo.com", + "priority": "5", + "weight": "6", + "port": "7", + "service": "", + "protocol": "", + "ttl": "300", + "status": 1 + } + }, + { + "index": 138, + "value": { + "id": "863228447", + "type": "SRV", + "host": "_sip._tcp", + "record": "foo.com", + "priority": "52", + "weight": "6", + "port": "7", + "service": "", + "protocol": "", + "ttl": "300", + "status": 1 + } + }, + { + "index": 139, + "value": { + "id": "863228447", + "type": "SRV", + "host": "_sip._tcp", + "record": "foo.com", + "priority": "52", + "weight": "62", + "port": "7", + "service": "", + "protocol": "", + "ttl": "300", + "status": 1 + } + }, + { + "index": 140, + "value": { + "id": "863228447", + "type": "SRV", + "host": "_sip._tcp", + "record": "foo.com", + "priority": "52", + "weight": "62", + "port": "72", + "service": "", + "protocol": "", + "ttl": "300", + "status": 1 + } + }, + { + "index": 141, + "value": { + "id": "863228472", + "type": "SRV", + "host": "_sip._tcp", + "record": "foo2.com", + "priority": "5", + "weight": "60", + "port": "70", + "service": "", + "protocol": "", + "ttl": "300", + "status": 1 + } + }, + { + "index": 142, + "value": { + "id": "863228482", + "type": "SRV", + "host": "_sip._tcp", + "record": "foo3.com", + "priority": "15", + "weight": "65", + "port": "75", + "service": "", + "protocol": "", + "ttl": "300", + "status": 1 + } + }, + { + "index": 143, + "value": { + "id": "863228482", + "type": "SRV", + "host": "_sip._tcp", + "record": "foo4.com", + "priority": "15", + "weight": "65", + "port": "75", + "service": "", + "protocol": "", + "ttl": "300", + "status": 1 + } + }, + { + "index": 144, + "value": { + "id": "863228617", + "type": "SRV", + "host": "_sip._tcp", + "record": "", + "priority": "15", + "weight": "65", + "port": "75", + "service": "", + "protocol": "", + "ttl": "300", + "status": 1 + } + }, + { + "index": 145, + "value": { + "id": "863228632", + "type": "SRV", + "host": "_sip._tcp", + "record": "foo.com", + "priority": "5", + "weight": "6", + "port": "7", + "service": "", + "protocol": "", + "ttl": "21600", + "status": 1 + } + }, + { + "index": 146, + "value": { + "id": "863228632", + "type": "SRV", + "host": "_sip._tcp", + "record": "foo.com", + "priority": "5", + "weight": "6", + "port": "7", + "service": "", + "protocol": "", + "ttl": "600", + "status": 1 + } + }, + { + "index": 147, + "value": { + "id": "863228652", + "type": "SSHFP", + "host": "", + "record": "66C7D5540B7D75A1FB4C84FEBFA178AD99BDD67C", + "priority": "", + "weight": "", + "port": "", + "service": "", + "protocol": "", + "ttl": "300", + "status": 1, + "algorithm": "1", + "fp_type": "1" + } + }, + { + "index": 148, + "value": { + "id": "863228652", + "type": "SSHFP", + "host": "", + "record": "66C7D5540B7D75A1FB4C84FEBFA178AD99BDD67C", + "priority": "", + "weight": "", + "port": "", + "service": "", + "protocol": "", + "ttl": "300", + "status": 1, + "algorithm": "2", + "fp_type": "1" + } + }, + { + "index": 149, + "value": { + "id": "863228652", + "type": "SSHFP", + "host": "", + "record": "745A635BC46A397A5C4F21D437483005BCC40D7511FF15FBFAFE913A081559BC", + "priority": "", + "weight": "", + "port": "", + "service": "", + "protocol": "", + "ttl": "300", + "status": 1, + "algorithm": "2", + "fp_type": "2" + } + }, + { + "index": 150, + "value": { + "id": "863228657", + "type": "TLSA", + "host": "_443._tcp", + "record": "0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF", + "priority": "", + "weight": "", + "port": "", + "service": "", + "protocol": "", + "ttl": "300", + "status": 1, + "tlsa_usage": "2", + "tlsa_selector": "0", + "tlsa_matching_type": "1" + } + }, + { + "index": 151, + "value": { + "id": "863228657", + "type": "TLSA", + "host": "_443._tcp", + "record": "0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF", + "priority": "", + "weight": "", + "port": "", + "service": "", + "protocol": "", + "ttl": "300", + "status": 1, + "tlsa_usage": "2", + "tlsa_selector": "1", + "tlsa_matching_type": "1" + } + }, + { + "index": 152, + "value": { + "id": "863228657", + "type": "TLSA", + "host": "_443._tcp", + "record": "0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF", + "priority": "", + "weight": "", + "port": "", + "service": "", + "protocol": "", + "ttl": "300", + "status": 1, + "tlsa_usage": "3", + "tlsa_selector": "1", + "tlsa_matching_type": "1" + } + }, + { + "index": 153, + "value": { + "id": "863228657", + "type": "TLSA", + "host": "_443._tcp", + "record": "0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF", + "priority": "", + "weight": "", + "port": "", + "service": "", + "protocol": "", + "ttl": "300", + "status": 1, + "tlsa_usage": "2", + "tlsa_selector": "0", + "tlsa_matching_type": "2" + } + }, + { + "index": 154, + "value": { + "id": "863228657", + "type": "TLSA", + "host": "_443._tcp", + "record": "FEDCBA9876543210FEDCBA9876543210FEDCBA9876543210FEDCBA9876543210FEDCBA9876543210FEDCBA9876543210FEDCBA9876543210FEDCBA9876543210", + "priority": "", + "weight": "", + "port": "", + "service": "", + "protocol": "", + "ttl": "300", + "status": 1, + "tlsa_usage": "2", + "tlsa_selector": "0", + "tlsa_matching_type": "2" + } + }, + { + "index": 155, + "value": { + "id": "863228742", + "type": "NS", + "host": "child", + "record": "ns101.cloudns.net", + "priority": "", + "weight": "", + "port": "", + "service": "", + "protocol": "", + "ttl": "300", + "status": 1 + } + }, + { + "index": 156, + "value": { + "id": "863228747", + "type": "DS", + "host": "child", + "record": "1E07663FF507A40874B8605463DD41DE482079D6", + "priority": "", + "weight": "", + "port": "", + "service": "", + "protocol": "", + "ttl": "300", + "status": 1, + "algorithm": "13", + "key_tag": "35632", + "digest_type": "1" + } + }, + { + "index": 157, + "value": { + "id": "863228747", + "type": "DS", + "host": "child", + "record": "2706D12E256C8FDD9BFB45EFB25FE537E21A82F6", + "priority": "", + "weight": "", + "port": "", + "service": "", + "protocol": "", + "ttl": "300", + "status": 1, + "algorithm": "13", + "key_tag": "2075", + "digest_type": "1" + } + }, + { + "index": 158, + "value": { + "id": "863228747", + "type": "DS", + "host": "child", + "record": "3F7A1EAC8C813A0BEBD0C3B8AAB387E31945EA0CD5E1D84A2E8E27674566C156", + "priority": "", + "weight": "", + "port": "", + "service": "", + "protocol": "", + "ttl": "300", + "status": 1, + "algorithm": "13", + "key_tag": "2075", + "digest_type": "2" + } + }, + { + "index": 159, + "value": { + "id": "863228747", + "type": "DS", + "host": "child", + "record": "EEC7FA02E6788DA889B2CE41D43D92F948AB126EDCF83B7037E73CE9531C8E7E45653ABBAA76C2D6E42F98316EDE599B", + "priority": "", + "weight": "", + "port": "", + "service": "", + "protocol": "", + "ttl": "300", + "status": 1, + "algorithm": "3", + "key_tag": "63909", + "digest_type": "4" + } + }, + { + "index": 160, + "value": { + "id": "863228747", + "type": "DS", + "host": "child", + "record": "F50BEFEA333EE2901D72D31A08E1A3CD3F7E943FF4B38CF7C8AD92807F5302F76FB0B419182C0F47FFC71CBCB6EF4BD4", + "priority": "", + "weight": "", + "port": "", + "service": "", + "protocol": "", + "ttl": "300", + "status": 1, + "algorithm": "1", + "key_tag": "2159", + "digest_type": "4" + } + }, + { + "index": 161, + "value": { + "id": "863228757", + "type": "NS", + "host": "another-child", + "record": "ns101.cloudns.net", + "priority": "", + "weight": "", + "port": "", + "service": "", + "protocol": "", + "ttl": "300", + "status": 1 + } + }, + { + "index": 162, + "value": { + "id": "863228762", + "type": "DS", + "host": "another-child", + "record": "F5F32ABCA6B01AA7A9963012F90B7C8523A1D946185A3AD70B67F3C9F18E7312FA9DD6AB2F7D8382F789213DB173D429", + "priority": "", + "weight": "", + "port": "", + "service": "", + "protocol": "", + "ttl": "300", + "status": 1, + "algorithm": "13", + "key_tag": "35632", + "digest_type": "4" + } + }, + { + "index": 163, + "value": { + "id": "863228772", + "type": "DS", + "host": "another-child", + "record": "F50BEFEA333EE2901D72D31A08E1A3CD3F7E943FF4B38CF7C8AD92807F5302F76FB0B419182C0F47FFC71CBCB6EF4BD4", + "priority": "", + "weight": "", + "port": "", + "service": "", + "protocol": "", + "ttl": "300", + "status": 1, + "algorithm": "1", + "key_tag": "2159", + "digest_type": "4" + } + }, + { + "index": 164, + "value": { + "id": "863228777", + "type": "DS", + "host": "another-child", + "record": "EEC7FA02E6788DA889B2CE41D43D92F948AB126EDCF83B7037E73CE9531C8E7E45653ABBAA76C2D6E42F98316EDE599B", + "priority": "", + "weight": "", + "port": "", + "service": "", + "protocol": "", + "ttl": "300", + "status": 1, + "algorithm": "3", + "key_tag": "63909", + "digest_type": "4" + } + }, + { + "index": 165, + "value": { + "id": "863228782", + "type": "DNAME", + "host": "test", + "record": "example.com", + "priority": "", + "weight": "", + "port": "", + "service": "", + "protocol": "", + "ttl": "300", + "status": 1 + } + }, + { + "index": 166, + "value": { + "id": "863228782", + "type": "DNAME", + "host": "test", + "record": "example.net", + "priority": "", + "weight": "", + "port": "", + "service": "", + "protocol": "", + "ttl": "300", + "status": 1 + } + }, + { + "index": 167, + "value": { + "id": "863228832", + "type": "DNAME", + "host": "a", + "record": "b.cloudnstest.yesthattom.com", + "priority": "", + "weight": "", + "port": "", + "service": "", + "protocol": "", + "ttl": "300", + "status": 1 + } + }, + { + "index": 168, + "value": { + "id": "863228852", + "type": "ALIAS", + "host": "", + "record": "foo.com", + "priority": "", + "weight": "", + "port": "", + "service": "", + "protocol": "", + "ttl": "300", + "status": 1 + } + }, + { + "index": 169, + "value": { + "id": "863228852", + "type": "ALIAS", + "host": "", + "record": "foo2.com", + "priority": "", + "weight": "", + "port": "", + "service": "", + "protocol": "", + "ttl": "300", + "status": 1 + } + }, + { + "index": 170, + "value": { + "id": "863228857", + "type": "A", + "host": "foo", + "record": "1.2.3.4", + "priority": "", + "weight": "", + "port": "", + "service": "", + "protocol": "", + "ttl": "300", + "status": 1 + } + }, + { + "index": 171, + "value": { + "id": "863228862", + "type": "ALIAS", + "host": "", + "record": "foo.cloudnstest.yesthattom.com", + "priority": "", + "weight": "", + "port": "", + "service": "", + "protocol": "", + "ttl": "300", + "status": 1 + } + }, + { + "index": 172, + "value": { + "id": "863228882", + "type": "ALIAS", + "host": "test", + "record": "foo.com", + "priority": "", + "weight": "", + "port": "", + "service": "", + "protocol": "", + "ttl": "300", + "status": 1 + } + }, + { + "index": 173, + "value": { + "id": "863228882", + "type": "ALIAS", + "host": "test", + "record": "foo2.com", + "priority": "", + "weight": "", + "port": "", + "service": "", + "protocol": "", + "ttl": "300", + "status": 1 + } + }, + { + "index": 174, + "value": { + "id": "863228907", + "type": "A", + "host": "bar", + "record": "5.5.5.5", + "priority": "", + "weight": "", + "port": "", + "service": "", + "protocol": "", + "ttl": "300", + "status": 1 + } + }, + { + "index": 175, + "value": { + "id": "863228912", + "type": "A", + "host": "foo", + "record": "1.2.3.4", + "priority": "", + "weight": "", + "port": "", + "service": "", + "protocol": "", + "ttl": "300", + "status": 1 + } + }, + { + "index": 176, + "value": { + "id": "863228917", + "type": "A", + "host": "foo", + "record": "2.3.4.5", + "priority": "", + "weight": "", + "port": "", + "service": "", + "protocol": "", + "ttl": "300", + "status": 1 + } + }, + { + "index": 177, + "value": { + "id": "863228922", + "type": "TXT", + "host": "foo", + "record": "simple", + "priority": "", + "weight": "", + "port": "", + "service": "", + "protocol": "", + "ttl": "300", + "status": 1 + } + }, + { + "index": 178, + "value": { + "id": "863228927", + "type": "CNAME", + "host": "mail", + "record": "ghs.googlehosted.com", + "priority": "", + "weight": "", + "port": "", + "service": "", + "protocol": "", + "ttl": "300", + "status": 1 + } + }, + { + "index": 179, + "value": { + "id": "863229507", + "type": "A", + "host": "", + "record": "1.2.3.4", + "priority": "", + "weight": "", + "port": "", + "service": "", + "protocol": "", + "ttl": "300", + "status": 1 + } + }, + { + "index": 180, + "value": { + "id": "863229512", + "type": "A", + "host": "", + "record": "2.3.4.5", + "priority": "", + "weight": "", + "port": "", + "service": "", + "protocol": "", + "ttl": "300", + "status": 1 + } + }, + { + "index": 181, + "value": { + "id": "863229517", + "type": "A", + "host": "bar", + "record": "5.5.5.5", + "priority": "", + "weight": "", + "port": "", + "service": "", + "protocol": "", + "ttl": "300", + "status": 1 + } + }, + { + "index": 182, + "value": { + "id": "863229522", + "type": "TXT", + "host": "", + "record": "simple", + "priority": "", + "weight": "", + "port": "", + "service": "", + "protocol": "", + "ttl": "300", + "status": 1 + } + }, + { + "index": 183, + "value": { + "id": "863229527", + "type": "CNAME", + "host": "mail", + "record": "ghs.googlehosted.com", + "priority": "", + "weight": "", + "port": "", + "service": "", + "protocol": "", + "ttl": "300", + "status": 1 + } + }, + { + "index": 184, + "value": { + "id": "863229617", + "type": "A", + "host": "", + "record": "2.2.2.2", + "priority": "", + "weight": "", + "port": "", + "service": "", + "protocol": "", + "ttl": "300", + "status": 1 + } + }, + { + "index": 185, + "value": { + "id": "863229622", + "type": "A", + "host": "foo", + "record": "1.2.3.4", + "priority": "", + "weight": "", + "port": "", + "service": "", + "protocol": "", + "ttl": "300", + "status": 1 + } + }, + { + "index": 186, + "value": { + "id": "863229627", + "type": "TXT", + "host": "", + "record": "asimple", + "priority": "", + "weight": "", + "port": "", + "service": "", + "protocol": "", + "ttl": "300", + "status": 1 + } + }, + { + "index": 187, + "value": { + "id": "863229632", + "type": "TXT", + "host": "foo", + "record": "simple", + "priority": "", + "weight": "", + "port": "", + "service": "", + "protocol": "", + "ttl": "300", + "status": 1 + } + }, + { + "index": 188, + "value": { + "id": "863229647", + "type": "A", + "host": "bar.bat", + "record": "5.5.5.5", + "priority": "", + "weight": "", + "port": "", + "service": "", + "protocol": "", + "ttl": "300", + "status": 1 + } + }, + { + "index": 189, + "value": { + "id": "863229652", + "type": "A", + "host": "foo.bat", + "record": "1.2.3.4", + "priority": "", + "weight": "", + "port": "", + "service": "", + "protocol": "", + "ttl": "300", + "status": 1 + } + }, + { + "index": 190, + "value": { + "id": "863229657", + "type": "A", + "host": "foo.bat", + "record": "2.3.4.5", + "priority": "", + "weight": "", + "port": "", + "service": "", + "protocol": "", + "ttl": "300", + "status": 1 + } + }, + { + "index": 191, + "value": { + "id": "863229662", + "type": "TXT", + "host": "foo.bat", + "record": "simple", + "priority": "", + "weight": "", + "port": "", + "service": "", + "protocol": "", + "ttl": "300", + "status": 1 + } + }, + { + "index": 192, + "value": { + "id": "863229667", + "type": "CNAME", + "host": "mail.bat", + "record": "ghs.googlehosted.com", + "priority": "", + "weight": "", + "port": "", + "service": "", + "protocol": "", + "ttl": "300", + "status": 1 + } + }, + { + "index": 193, + "value": { + "id": "863229702", + "type": "A", + "host": "foo", + "record": "1.1.1.1", + "priority": "", + "weight": "", + "port": "", + "service": "", + "protocol": "", + "ttl": "300", + "status": 1 + } + }, + { + "index": 194, + "value": { + "id": "863229707", + "type": "A", + "host": "foo", + "record": "10.10.10.10", + "priority": "", + "weight": "", + "port": "", + "service": "", + "protocol": "", + "ttl": "300", + "status": 1 + } + }, + { + "index": 195, + "value": { + "id": "863229707", + "type": "A", + "host": "foo", + "record": "11.11.11.11", + "priority": "", + "weight": "", + "port": "", + "service": "", + "protocol": "", + "ttl": "300", + "status": 1 + } + }, + { + "index": 196, + "value": { + "id": "863229707", + "type": "A", + "host": "foo", + "record": "12.12.12.12", + "priority": "", + "weight": "", + "port": "", + "service": "", + "protocol": "", + "ttl": "300", + "status": 1 + } + }, + { + "index": 197, + "value": { + "id": "863229707", + "type": "A", + "host": "foo", + "record": "13.13.13.13", + "priority": "", + "weight": "", + "port": "", + "service": "", + "protocol": "", + "ttl": "300", + "status": 1 + } + }, + { + "index": 198, + "value": { + "id": "863229707", + "type": "A", + "host": "foo", + "record": "14.14.14.14", + "priority": "", + "weight": "", + "port": "", + "service": "", + "protocol": "", + "ttl": "300", + "status": 1 + } + }, + { + "index": 199, + "value": { + "id": "863229712", + "type": "AAAA", + "host": "foo", + "record": "2003:dd:d7ff::fe71:aaaa", + "priority": "", + "weight": "", + "port": "", + "service": "", + "protocol": "", + "ttl": "300", + "status": 1 + } + }, + { + "index": 200, + "value": { + "id": "863229717", + "type": "A", + "host": "zzz", + "record": "3.3.3.3", + "priority": "", + "weight": "", + "port": "", + "service": "", + "protocol": "", + "ttl": "300", + "status": 1 + } + }, + { + "index": 201, + "value": { + "id": "863229722", + "type": "A", + "host": "zzz", + "record": "4.4.4.4", + "priority": "", + "weight": "", + "port": "", + "service": "", + "protocol": "", + "ttl": "300", + "status": 1 + } + }, + { + "index": 202, + "value": { + "id": "863229727", + "type": "AAAA", + "host": "zzz", + "record": "2003:dd:d7ff::fe71:cccc", + "priority": "", + "weight": "", + "port": "", + "service": "", + "protocol": "", + "ttl": "300", + "status": 1 + } + }, + { + "index": 203, + "value": { + "id": "863229732", + "type": "MX", + "host": "foo", + "record": "aspmx.l.google.com", + "priority": "10", + "weight": "", + "port": "", + "service": "", + "protocol": "", + "ttl": "300", + "status": 1 + } + }, + { + "index": 204, + "value": { + "id": "863229737", + "type": "MX", + "host": "foo", + "record": "alt1.aspmx.l.google.com", + "priority": "20", + "weight": "", + "port": "", + "service": "", + "protocol": "", + "ttl": "300", + "status": 1 + } + }, + { + "index": 205, + "value": { + "id": "863229742", + "type": "CNAME", + "host": "bar", + "record": "redact2.acm-validations.aws", + "priority": "", + "weight": "", + "port": "", + "service": "", + "protocol": "", + "ttl": "300", + "status": 1 + } + }, + { + "index": 206, + "value": { + "id": "863229747", + "type": "CNAME", + "host": "foo", + "record": "redact1.acm-validations.aws", + "priority": "", + "weight": "", + "port": "", + "service": "", + "protocol": "", + "ttl": "300", + "status": 1 + } + }, + { + "index": 207, + "value": { + "id": "863229752", + "type": "A", + "host": "dyndns-city1", + "record": "91.42.1.1", + "priority": "", + "weight": "", + "port": "", + "service": "", + "protocol": "", + "ttl": "300", + "status": 1 + } + }, + { + "index": 208, + "value": { + "id": "863229757", + "type": "AAAA", + "host": "dyndns-city1", + "record": "2003:dd:d7ff::fe71:ce77", + "priority": "", + "weight": "", + "port": "", + "service": "", + "protocol": "", + "ttl": "300", + "status": 1 + } + }, + { + "index": 209, + "value": { + "id": "863229762", + "type": "A", + "host": "dyndns-city2", + "record": "91.42.1.2", + "priority": "", + "weight": "", + "port": "", + "service": "", + "protocol": "", + "ttl": "300", + "status": 1 + } + }, + { + "index": 210, + "value": { + "id": "863229767", + "type": "AAAA", + "host": "dyndns-city2", + "record": "2003:dd:d7ff::fe71:ce78", + "priority": "", + "weight": "", + "port": "", + "service": "", + "protocol": "", + "ttl": "300", + "status": 1 + } + }, + { + "index": 211, + "value": { + "id": "863229772", + "type": "A", + "host": "testdefined", + "record": "2.2.2.2", + "priority": "", + "weight": "", + "port": "", + "service": "", + "protocol": "", + "ttl": "300", + "status": 1 + } + }, + { + "index": 212, + "value": { + "id": "863229772", + "type": "A", + "host": "testdefined", + "record": "9.9.9.9", + "priority": "", + "weight": "", + "port": "", + "service": "", + "protocol": "", + "ttl": "300", + "status": 1 + } + }, + { + "index": 213, + "value": { + "id": "863229777", + "type": "A", + "host": "testignore", + "record": "8.8.8.8", + "priority": "", + "weight": "", + "port": "", + "service": "", + "protocol": "", + "ttl": "300", + "status": 1 + } + }, + { + "index": 214, + "value": { + "id": "863229817", + "type": "TXT", + "host": "final", + "record": "TestDNSProviders was successful!", + "priority": "", + "weight": "", + "port": "", + "service": "", + "protocol": "", + "ttl": "300", + "status": 1 + } + }, + { + "index": 215, + "value": { + "id": "863229827", + "type": "TXT", + "host": "final", + "record": "TestDNSProviders was successful!", + "priority": "", + "weight": "", + "port": "", + "service": "", + "protocol": "", + "ttl": "300", + "status": 1 + } + }, + { + "index": 216, + "value": { + "id": "863229832", + "type": "NS", + "host": "", + "record": "ns1.example.com", + "priority": "", + "weight": "", + "port": "", + "service": "", + "protocol": "", + "ttl": "300", + "status": 1 + } + }, + { + "index": 217, + "value": { + "id": "863229837", + "type": "NS", + "host": "", + "record": "ns2.example.com", + "priority": "", + "weight": "", + "port": "", + "service": "", + "protocol": "", + "ttl": "300", + "status": 1 + } + } +] diff --git a/providers/cnr/auditrecords.go b/providers/cnr/auditrecords.go index c01092acd2..5d36dbca26 100644 --- a/providers/cnr/auditrecords.go +++ b/providers/cnr/auditrecords.go @@ -5,25 +5,24 @@ import ( "fmt" "strings" - "github.com/DNSControl/dnscontrol/v4/models" - "github.com/DNSControl/dnscontrol/v4/pkg/rejectif" + "github.com/DNSControl/dnscontrol/v5/models" + "github.com/DNSControl/dnscontrol/v5/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 { +func AuditRecords(records models.Records) []error { a := rejectif.Auditor{} - a.Add("TXT", rejectif.TxtIsEmpty) // Last verified 2021-10-01 + a.Add("TXT", rejectif.TxtIsEmpty) // Last verified 2026-07-20 - a.Add("TXT", rejectif.TxtHasDoubleQuotes) // Last verified 2023-11-30 + a.Add("TXT", rejectif.TxtHasDoubleQuotes) // Last verified 2026-07-20 - a.Add("SRV", rejectif.SrvHasNullTarget) // Last verified 2020-12-28 + a.Add("DNAME", dnameHasWildcardLabel) // Last verified 2026-02-10 - a.Add("DNAME", dnameHasWildcardLabel) // Last verified 2026-02-10 a.Add("SVCB", func(rc *models.RecordConfig) error { // Last verified 2026-06-29 - for param := range strings.FieldsSeq(rc.SvcParams) { + for param := range strings.FieldsSeq(models.Svcbv2ValueToString(rc.AsSVCB().Value)) { key, value, _ := strings.Cut(param, "=") key = strings.ToLower(strings.TrimSpace(key)) value = strings.Trim(value, `"`) diff --git a/providers/cnr/cnrProvider.go b/providers/cnr/cnrProvider.go index a72582bce1..6abafbc031 100644 --- a/providers/cnr/cnrProvider.go +++ b/providers/cnr/cnrProvider.go @@ -6,13 +6,14 @@ import ( "encoding/json" "errors" - "github.com/DNSControl/dnscontrol/v4/pkg/providers" - "github.com/DNSControl/dnscontrol/v4/pkg/version" + "github.com/DNSControl/dnscontrol/v5/pkg/providers" + "github.com/DNSControl/dnscontrol/v5/pkg/version" cnrcl "github.com/centralnicgroup-opensource/rtldev-middleware-go-sdk/v5/apiclient" ) // Client describes a connection to the CNR API. type Client struct { + observer providers.ConversionObserver conf map[string]string APILogin string APIPassword string @@ -20,6 +21,10 @@ type Client struct { client *cnrcl.APIClient } +func (client *Client) SetConversionObserver(observer providers.ConversionObserver) { + client.observer = observer +} + var features = providers.DocumentationNotes{ // See providers/capabilities.go for the entire list of capabilities. // The default for unlisted capabilities is 'Cannot'. diff --git a/providers/cnr/convert_golden_test.go b/providers/cnr/convert_golden_test.go new file mode 100644 index 0000000000..ef58125a03 --- /dev/null +++ b/providers/cnr/convert_golden_test.go @@ -0,0 +1,15 @@ +package cnr + +import ( + "testing" + + "github.com/DNSControl/dnscontrol/v5/models" + "github.com/DNSControl/dnscontrol/v5/pkg/providergolden" +) + +func TestCreateRecordStringGolden(t *testing.T) { + providergolden.CheckToNative(t, "createRecordString", + func(dc *models.DomainConfig, records models.Records) (string, error) { + return (&Client{}).createRecordString(records[0], dc.Name) + }) +} diff --git a/providers/cnr/dnssec.go b/providers/cnr/dnssec.go index facdb2facd..4a3fcdccb7 100644 --- a/providers/cnr/dnssec.go +++ b/providers/cnr/dnssec.go @@ -4,18 +4,18 @@ import ( "fmt" "strings" - "github.com/DNSControl/dnscontrol/v4/models" + "github.com/DNSControl/dnscontrol/v5/models" ) // isZoneSigned reports whether the DNS zone is DNSSEC-signed, based on the // SIGNED property returned by StatusDNSZone. -func (n *Client) isZoneSigned(domain string) (bool, error) { - r := n.client.Request(map[string]any{ +func (client *Client) isZoneSigned(domain string) (bool, error) { + r := client.client.Request(map[string]any{ "COMMAND": "StatusDNSZone", "DNSZONE": domain, }) if !r.IsSuccess() { - return false, n.GetAPIError("Could not get status for DNS zone", domain, r) + return false, client.GetAPIError("Could not get status for DNS zone", domain, r) } signed, err := r.GetColumnIndex("SIGNED", 0) if err != nil { @@ -26,11 +26,11 @@ func (n *Client) isZoneSigned(domain string) (bool, error) { // getDNSSECCorrections returns the corrections needed to reconcile the zone's // DNSSEC signing state with dc.AutoDNSSEC ("on", "off", or "" for no change). -func (n *Client) getDNSSECCorrections(dc *models.DomainConfig) ([]*models.Correction, error) { +func (client *Client) getDNSSECCorrections(dc *models.DomainConfig) ([]*models.Correction, error) { if dc.AutoDNSSEC == "" { return nil, nil } - signed, err := n.isZoneSigned(dc.Name) + signed, err := client.isZoneSigned(dc.Name) if err != nil { return nil, err } @@ -38,12 +38,12 @@ func (n *Client) getDNSSECCorrections(dc *models.DomainConfig) ([]*models.Correc case signed && dc.AutoDNSSEC == "off": return []*models.Correction{{ Msg: fmt.Sprintf("Disable DNSSEC signing for zone %s", dc.Name), - F: n.setZoneSigned(dc.Name, false), + F: client.setZoneSigned(dc.Name, false), }}, nil case !signed && dc.AutoDNSSEC == "on": return []*models.Correction{{ Msg: fmt.Sprintf("Enable DNSSEC signing for zone %s", dc.Name), - F: n.setZoneSigned(dc.Name, true), + F: client.setZoneSigned(dc.Name, true), }}, nil } return nil, nil @@ -51,12 +51,12 @@ func (n *Client) getDNSSECCorrections(dc *models.DomainConfig) ([]*models.Correc // setZoneSigned returns a function that enables or disables DNSSEC signing for // the zone via ModifyDNSZone. -func (n *Client) setZoneSigned(domain string, signed bool) func() error { +func (client *Client) setZoneSigned(domain string, signed bool) func() error { return func() error { value := "0" if signed { value = "1" } - return n.updateZoneBy(map[string]any{"SIGNED": value}, domain) + return client.updateZoneBy(map[string]any{"SIGNED": value}, domain) } } diff --git a/providers/cnr/domains.go b/providers/cnr/domains.go index 279b111012..b3b8b65d17 100644 --- a/providers/cnr/domains.go +++ b/providers/cnr/domains.go @@ -1,40 +1,40 @@ package cnr -import "github.com/DNSControl/dnscontrol/v4/models" +import "github.com/DNSControl/dnscontrol/v5/models" // EnsureZoneExists returns an error // * if access to dnszone is not allowed (not authorized) or // * if it doesn't exist and creating it fails. -func (n *Client) EnsureZoneExists(dc *models.DomainConfig) error { +func (client *Client) EnsureZoneExists(dc *models.DomainConfig) error { domain := dc.Name command := map[string]any{ "COMMAND": "AddDNSZone", "DNSZONE": domain, } - if n.APIEntity == "OTE" { + if client.APIEntity == "OTE" { command["SOATTL"] = "33200" command["SOASERIAL"] = "0000000000" } // Create the zone - r := n.client.Request(command) + r := client.client.Request(command) if r.GetCode() == 549 || r.IsSuccess() { return nil } - return n.GetAPIError("Failed to create not existing zone ", domain, r) + return client.GetAPIError("Failed to create not existing zone ", domain, r) } // ListZones lists all the. -func (n *Client) ListZones() ([]string, error) { +func (client *Client) ListZones() ([]string, error) { var zones []string // Basic - rs := n.client.RequestAllResponsePages(map[string]string{ + rs := client.client.RequestAllResponsePages(map[string]string{ "COMMAND": "QueryDNSZoneList", }) for _, r := range rs { if r.IsError() { - return nil, n.GetAPIError("Error while QueryDNSZoneList", "Basic", &r) + return nil, client.GetAPIError("Error while QueryDNSZoneList", "Basic", &r) } zoneColumn := r.GetColumn("DNSZONE") if zoneColumn != nil { diff --git a/providers/cnr/error.go b/providers/cnr/error.go index 0febda1f75..03a7fa3f15 100644 --- a/providers/cnr/error.go +++ b/providers/cnr/error.go @@ -7,6 +7,6 @@ import ( ) // GetAPIError returns an error including API error code and error description. -func (n *Client) GetAPIError(format string, objectid string, r *response.Response) error { +func (client *Client) GetAPIError(format string, objectid string, r *response.Response) error { return fmt.Errorf(format+" %q. [%v %s]", objectid, r.GetCode(), r.GetDescription()) } diff --git a/providers/cnr/nameservers.go b/providers/cnr/nameservers.go index 96af8daf9e..6056c29239 100644 --- a/providers/cnr/nameservers.go +++ b/providers/cnr/nameservers.go @@ -7,7 +7,7 @@ import ( "sort" "strings" - "github.com/DNSControl/dnscontrol/v4/models" + "github.com/DNSControl/dnscontrol/v5/models" ) var defaultNameservers = []*models.Nameserver{ @@ -19,12 +19,12 @@ var defaultNameservers = []*models.Nameserver{ var nsRegex = regexp.MustCompile(`ns([1-3]{1})[0-9]+\.rrpproxy\.net`) // GetNameservers gets the nameservers set on a domain. -func (n *Client) GetNameservers(domain string) ([]*models.Nameserver, error) { +func (client *Client) GetNameservers(domain string) ([]*models.Nameserver, error) { // NOTE: This information is taken over from HX and adapted to CNR... might be wrong... // This is an interesting edge case. CNR expects you to SET the nameservers to ns[1-3].rrpproxy.net, // but it will internally set it to (ns1xyz|ns2uvw|ns3asd).rrpproxy.net, where xyz/uvw/asd is a uniqueish number. // In order to avoid endless loops, we will use the unique nameservers if present, or else the generic ones if not. - nss, err := n.getNameserversRaw(domain) + nss, err := client.getNameserversRaw(domain) if err != nil { return nil, err } @@ -42,14 +42,14 @@ func (n *Client) GetNameservers(domain string) ([]*models.Nameserver, error) { return models.ToNameservers(toUse) } -func (n *Client) getNameserversRaw(domain string) ([]string, error) { - r := n.client.Request(map[string]any{ +func (client *Client) getNameserversRaw(domain string) ([]string, error) { + r := client.client.Request(map[string]any{ "COMMAND": "StatusDomain", "DOMAIN": domain, }) code := r.GetCode() if code != 200 { - return nil, n.GetAPIError("Could not get status for domain", domain, r) + return nil, client.GetAPIError("Could not get status for domain", domain, r) } nsColumn := r.GetColumn("NAMESERVER") if nsColumn == nil { @@ -61,8 +61,8 @@ func (n *Client) getNameserversRaw(domain string) ([]string, error) { } // GetRegistrarCorrections gathers corrections that would bring n to match dc. -func (n *Client) GetRegistrarCorrections(dc *models.DomainConfig) ([]*models.Correction, error) { - nss, err := n.getNameserversRaw(dc.Name) +func (client *Client) GetRegistrarCorrections(dc *models.DomainConfig) ([]*models.Correction, error) { + nss, err := client.getNameserversRaw(dc.Name) if err != nil { return nil, err } @@ -85,14 +85,14 @@ func (n *Client) GetRegistrarCorrections(dc *models.DomainConfig) ([]*models.Cor return []*models.Correction{ { Msg: fmt.Sprintf("Update nameservers %s -> %s", foundNameservers, expectedNameservers), - F: n.updateNameservers(expected, dc.Name), + F: client.updateNameservers(expected, dc.Name), }, }, nil } return nil, nil } -func (n *Client) updateNameservers(ns []string, domain string) func() error { +func (client *Client) updateNameservers(ns []string, domain string) func() error { return func() error { cmd := map[string]any{ "COMMAND": "ModifyDomain", @@ -101,7 +101,7 @@ func (n *Client) updateNameservers(ns []string, domain string) func() error { for idx, ns := range ns { cmd[fmt.Sprintf("NAMESERVER%d", idx)] = ns } - response := n.client.Request(cmd) + response := client.client.Request(cmd) code := response.GetCode() if code != 200 { return fmt.Errorf("%d %s", code, response.GetDescription()) diff --git a/providers/cnr/records.go b/providers/cnr/records.go index 9438c167fd..bb415f22cc 100644 --- a/providers/cnr/records.go +++ b/providers/cnr/records.go @@ -2,7 +2,6 @@ package cnr import ( "bytes" - "errors" "fmt" "maps" "os" @@ -10,18 +9,13 @@ import ( "strconv" "strings" - "github.com/DNSControl/dnscontrol/v4/models" - "github.com/DNSControl/dnscontrol/v4/pkg/diff" - "github.com/DNSControl/dnscontrol/v4/pkg/txtutil" + dnsv2 "codeberg.org/miekg/dns" + "github.com/DNSControl/dnscontrol/v5/models" + "github.com/DNSControl/dnscontrol/v5/pkg/diff2" + "github.com/DNSControl/dnscontrol/v5/pkg/nrc" + "github.com/DNSControl/dnscontrol/v5/pkg/providers" ) -// dotSuffixTypes lists record types whose content requires a trailing dot -// to be appended when returned by the API without one. -var dotSuffixTypes = map[string]bool{ - "ALIAS": true, "CNAME": true, "DNAME": true, - "MX": true, "NS": true, "SRV": true, "PTR": true, -} - // Record covers an individual DNS resource record. type Record struct { // DomainName is the zone that the record belongs to. @@ -44,44 +38,12 @@ type Record struct { } // GetZoneRecords gets the records of a zone and returns them in RecordConfig format. -func (n *Client) GetZoneRecords(dc *models.DomainConfig) (models.Records, error) { - domain := dc.Name - - records, err := n.getRecords(dc) - if err != nil { - return nil, err - } - actual := make([]*models.RecordConfig, len(records)) - for i, r := range records { - actual[i] = toRecord(r, domain) - } - - return actual, nil +func (client *Client) GetZoneRecords(dc *models.DomainConfig) (models.Records, error) { + return client.getRecords(dc) } // GetZoneRecordsCorrections returns a list of corrections that will turn existing records into dc.Records. -func (n *Client) GetZoneRecordsCorrections(dc *models.DomainConfig, actual models.Records) ([]*models.Correction, int, error) { - for _, rc := range actual { - if rc.Type == "SVCB" { - rc.SvcParams = strings.Join(strings.Fields(rc.SvcParams), " ") - } - } - for _, rc := range dc.Records { - if rc.Type != "SVCB" { - continue - } - fields := strings.Fields(rc.SvcParams) - params := make([]string, 0, len(fields)) - for _, field := range fields { - key, value, _ := strings.Cut(field, "=") - if strings.EqualFold(strings.TrimSpace(key), "ech") && strings.Trim(value, `"`) == "IGNORE" { - continue - } - params = append(params, field) - } - rc.SvcParams = strings.Join(params, " ") - } - +func (client *Client) GetZoneRecordsCorrections(dc *models.DomainConfig, actual models.Records) ([]*models.Correction, int, error) { var aliasSkip *models.Correction hasAlias := false for _, rc := range dc.Records { @@ -99,7 +61,7 @@ func (n *Client) GetZoneRecordsCorrections(dc *models.DomainConfig, actual model } } if hasAlias { - signed, err := n.isZoneSigned(dc.Name) + signed, err := client.isZoneSigned(dc.Name) if err != nil { return nil, 0, err } @@ -131,79 +93,88 @@ func (n *Client) GetZoneRecordsCorrections(dc *models.DomainConfig, actual model } } } - toReport, create, del, mod, actualChangeCount, err := diff.NewCompat(dc).IncrementalDiff(actual) + + changeset, actualChangeCount, err := diff2.ByRecord(actual, dc, nil) if err != nil { return nil, 0, err } - // Start corrections with the reports - corrections := diff.GenerateMessageCorrections(toReport) + + var corrections []*models.Correction + if aliasSkip != nil { corrections = append(corrections, aliasSkip) } buf := &bytes.Buffer{} - // Print a list of changes. Generate an actual change that is the zone - changes := false + // Accumulate every add/delete into a single "generate zone" API call. CNR + // has no in-place update, so a CHANGE is a delete of the old record string + // followed by an add of the new one. var builder strings.Builder params := map[string]any{} delrridx := 0 addrridx := 0 - for _, cre := range create { - changes = true - fmt.Fprintln(buf, cre) - newRecordString, err := n.createRecordString(cre.Desired, dc.Name) + addRR := func(rc *models.RecordConfig) error { + input := models.Records{rc} + before := providers.BeginToNative(client.observer, "createRecordString", input) + newRecordString, err := client.createRecordString(rc, dc.Name) + providers.EndToNative(client.observer, "createRecordString", before, input, newRecordString, err) if err != nil { - return corrections, 0, err + return err } key := fmt.Sprintf("ADDRR%d", addrridx) params[key] = newRecordString fmt.Fprintf(&builder, "\033[32m+ %s = %s\033[0m\n", key, newRecordString) addrridx++ + return nil } - for _, d := range del { - changes = true - fmt.Fprintln(buf, d) + delRR := func(rc *models.RecordConfig) { key := fmt.Sprintf("DELRR%d", delrridx) - oldRecordString := n.deleteRecordString(d.Existing.Original.(*Record)) + oldRecordString := rc.Original.(string) params[key] = oldRecordString fmt.Fprintf(&builder, "\033[31m- %s = %s\033[0m\n", key, oldRecordString) delrridx++ } - for _, chng := range mod { - changes = true - fmt.Fprintln(buf, chng) - // old record deletion - key := fmt.Sprintf("DELRR%d", delrridx) - oldRecordString := n.deleteRecordString(chng.Existing.Original.(*Record)) - params[key] = oldRecordString - fmt.Fprintf(&builder, "\033[31m- %s = %s\033[0m\n", key, oldRecordString) - delrridx++ - // new record creation - newRecordString, err := n.createRecordString(chng.Desired, dc.Name) - if err != nil { - return corrections, 0, err + + for _, change := range changeset { + switch change.Type { + case diff2.REPORT: + fmt.Fprintln(buf, change.MsgsJoined) + case diff2.CREATE: + fmt.Fprintln(buf, change.MsgsJoined) + if err := addRR(change.New[0]); err != nil { + return corrections, 0, err + } + case diff2.DELETE: + fmt.Fprintln(buf, change.MsgsJoined) + delRR(change.Old[0]) + case diff2.CHANGE: + fmt.Fprintln(buf, change.MsgsJoined) + delRR(change.Old[0]) + if err := addRR(change.New[0]); err != nil { + return corrections, 0, err + } + default: + panic(fmt.Sprintf("unhandled change type %v", change.Type)) } - key = fmt.Sprintf("ADDRR%d", addrridx) - params[key] = newRecordString - fmt.Fprintf(&builder, "\033[32m+ %s = %s\033[0m\n", key, newRecordString) - addrridx++ } - if changes { + // Every CREATE/DELETE/CHANGE adds at least one ADDRR/DELRR parameter; a + // non-empty params map therefore means there is a zone update to send. + if len(params) > 0 { msg := fmt.Sprintf("GENERATE_ZONE: %s\n%s", dc.Name, buf.String()) - if n.isDebugOn() { + if client.isDebugOn() { msg = fmt.Sprintf("GENERATE_ZONE: %s\n%sPROVIDER CNR, API COMMAND PARAMETERS:\n%s", dc.Name, buf.String(), builder.String()) } corrections = append(corrections, &models.Correction{ Msg: msg, F: func() error { - return n.updateZoneBy(params, dc.Name) + return client.updateZoneBy(params, dc.Name) }, }) } - dnssecCorrections, err := n.getDNSSECCorrections(dc) + dnssecCorrections, err := client.getDNSSECCorrections(dc) if err != nil { return nil, 0, err } @@ -213,65 +184,42 @@ func (n *Client) GetZoneRecordsCorrections(dc *models.DomainConfig, actual model return corrections, actualChangeCount, nil } -func toRecord(r *Record, origin string) *models.RecordConfig { - rc := &models.RecordConfig{ - Type: r.Type, - TTL: r.TTL, - Original: r, +func toRC(dc *models.DomainConfig, data map[string]string) (*models.RecordConfig, error) { + + ttl, err := strconv.ParseUint(data["TTL"], 10, 32) + if err != nil { + return nil, fmt.Errorf("invalid TTL value for domain %s: %s", dc.Name, data["TTL"]) } - fqdn := r.Fqdn[:len(r.Fqdn)-1] - rc.SetLabelFromFQDN(fqdn, origin) - switch r.Type { - case "MX", "SRV": - if r.Priority > 65535 { - panic(fmt.Errorf("priority value out of range for %s record: %d", r.Type, r.Priority)) - } - if r.Type == "MX" { - if err := rc.SetTargetMX(uint16(r.Priority), r.Answer); err != nil { - panic(fmt.Errorf("unparsable MX record received from centralnic reseller API: %w", err)) - } - } else { - // _service._proto.name. TTL Type Priority Weight Port Target. - // e.g. _sip._tcp.phone.example.org. 86400 IN SRV 5 6 7 sip.example.org. - // r.Anser covers the format "Priority Weight Port Target" and we've to remove the priority from the string - r.Answer = strings.TrimPrefix(r.Answer, fmt.Sprintf("%d ", r.Priority)) - if err := rc.SetTargetSRVPriorityString(uint16(r.Priority), r.Answer); err != nil { - panic(fmt.Errorf("unparsable SRV record received from centralnic reseller API: %w", err)) - } - } - case "LOC", "SVCB": - // SetTargetLOCString and SetTargetSVCBString internally format as "%s. TYPE %s", - // so we strip the trailing dot from r.Fqdn to avoid a double dot. - if err := rc.PopulateFromStringFunc(r.Type, r.Answer, strings.TrimSuffix(r.Fqdn, "."), txtutil.ParseQuoted); err != nil { - panic(fmt.Errorf("unparsable %s record received from centralnic reseller API: %w", r.Type, err)) - } - default: // "A", "AAAA", "ANAME", "ALIAS", "CNAME", "NS", "TXT", "CAA", "TLSA", "SMIMEA", "PTR" - if err := rc.PopulateFromStringFunc(r.Type, r.Answer, fqdn, txtutil.ParseQuoted); err != nil { - panic(fmt.Errorf("unparsable record received from centralnic reseller API: %w", err)) - } + rc, err := dc.NewRecordConfigParse(dc.LabelFromShort(data["NAME"]), uint32(ttl), data["TYPE"], data["CONTENT"], + nrc.Flags{TargetIsFqdnNoDot: true}) + if err != nil { + return nil, fmt.Errorf("parse error: %w", err) } - return rc + + rc.Original = deleteRecordString(rc) // This is the code we'll need to delete the record. + + return rc, nil } // updateZoneBy updates the zone with the provided changes. -func (n *Client) updateZoneBy(params map[string]any, domain string) error { +func (client *Client) updateZoneBy(params map[string]any, domain string) error { zone := domain cmd := map[string]any{ "COMMAND": "ModifyDNSZone", "DNSZONE": zone, } maps.Copy(cmd, params) - r := n.client.Request(cmd) + r := client.client.Request(cmd) if !r.IsSuccess() { - return n.GetAPIError("Error while updating zone", zone, r) + return client.GetAPIError("Error while updating zone", zone, r) } return nil } // getRecords queries the API for all resource records of a zone. -func (n *Client) getRecords(dc *models.DomainConfig) ([]*Record, error) { - var records []*Record +func (client *Client) getRecords(dc *models.DomainConfig) (models.Records, error) { + var records models.Records domain := dc.Name // Command to find out the total numbers of resource records for the zone @@ -284,24 +232,24 @@ func (n *Client) getRecords(dc *models.DomainConfig) ([]*Record, error) { "LIMIT": "10000", "WIDE": "1", } - r := n.client.Request(cmd) + r := client.client.Request(cmd) // Check if the request was successful if !r.IsSuccess() { if r.GetCode() == 545 { // If dns zone does not exist create a new one automatically if !isNoPopulate() { - err := n.EnsureZoneExists(dc) + err := client.EnsureZoneExists(dc) if err != nil { return nil, err } } else { // Return specific error if the zone does not exist - return nil, n.GetAPIError("Use `dnscontrol create-domains` to create not-existing zone", domain, r) + return nil, client.GetAPIError("Use `dnscontrol create-domains` to create not-existing zone", domain, r) } } // Return general error for any other issues - return nil, n.GetAPIError("Failed loading resource records for zone", domain, r) + return nil, client.GetAPIError("Failed loading resource records for zone", domain, r) } totalRecords := r.GetRecordsTotalCount() if totalRecords <= 0 { @@ -316,43 +264,10 @@ func (n *Client) getRecords(dc *models.DomainConfig) ([]*Record, error) { continue } - if data["TYPE"] == "MX" { - tmp := strings.Split(data["CONTENT"], " ") - data["PRIO"] = tmp[0] - data["CONTENT"] = tmp[1] - } - - // Parse the TTL string to an unsigned integer - ttl, err := strconv.ParseUint(data["TTL"], 10, 32) + record, err := toRC(dc, data) if err != nil { - return nil, fmt.Errorf("invalid TTL value for domain %s: %s", domain, data["TTL"]) - } - - // Parse the TTL string to an unsigned integer - priority, _ := strconv.ParseUint(data["PRIO"], 10, 32) - - // Add trailing dot to Answer for record types that require it - if dotSuffixTypes[data["TYPE"]] && !strings.HasSuffix(data["CONTENT"], ".") { - data["CONTENT"] += "." - } - - // Only append domain if it's not already a fully qualified domain name - fqdn := domain + "." - if data["NAME"] != "@" && !strings.HasSuffix(data["NAME"], domain+".") { - fqdn = fmt.Sprintf("%s.%s.", data["NAME"], domain) + return nil, fmt.Errorf("toRC error: %w", err) } - - // Initialize a new Record - record := &Record{ - DomainName: domain, - Host: data["NAME"], - Fqdn: fqdn, - Type: data["TYPE"], - Answer: data["CONTENT"], - TTL: uint32(ttl), - Priority: uint32(priority), - } - // Append the record to the records slice records = append(records, record) } @@ -361,95 +276,66 @@ func (n *Client) getRecords(dc *models.DomainConfig) ([]*Record, error) { } // Function to create record string from given RecordConfig for the ADDRR# API parameter. -func (n *Client) createRecordString(rc *models.RecordConfig, domain string) (string, error) { - host := rc.GetLabel() - answer := "" - - switch rc.Type { // #rtype_variations - case "A", "AAAA", "ANAME", "ALIAS", "CNAME", "DHCID", "DNAME", "MX", "NS", "PTR": - answer = rc.GetTargetField() - case "LOC": - // Use GetTargetCombined() which returns the properly formatted LOC string - // via the dns library (e.g. "52 14 5.000 N 000 08 50.000 E 10.00m 0.00m 0.00m 0.00m") - parts := strings.Fields(rc.GetTargetCombined()) - altitude, _ := strconv.ParseFloat(strings.TrimSuffix(parts[8], "m"), 64) - size, _ := strconv.ParseFloat(strings.TrimSuffix(parts[9], "m"), 64) - hp, _ := strconv.ParseFloat(strings.TrimSuffix(parts[10], "m"), 64) - vp, _ := strconv.ParseFloat(strings.TrimSuffix(parts[11], "m"), 64) - answer = fmt.Sprintf("%s %s %s %s %s %s %s %s %.2fm %.2fm %.2fm %.2fm", - parts[0], parts[1], parts[2], parts[3], - parts[4], parts[5], parts[6], parts[7], - altitude, size, hp, vp) - case "SVCB": - answer = fmt.Sprintf("%d %s", rc.SvcPriority, rc.GetTargetField()) - if rc.SvcParams != "" { - answer += " " + rc.SvcParams - } - case "SSHFP": - answer = fmt.Sprintf(`%v %v %s`, rc.SshfpAlgorithm, rc.SshfpFingerprint, rc.GetTargetField()) - case "NAPTR": - answer = fmt.Sprintf(`%v %v "%v" "%v" "%v" %v`, rc.NaptrOrder, rc.NaptrPreference, rc.NaptrFlags, rc.NaptrService, rc.NaptrRegexp, rc.GetTargetField()) - case "TLSA": - answer = fmt.Sprintf(`%v %v %v %s`, rc.TlsaUsage, rc.TlsaSelector, rc.TlsaMatchingType, rc.GetTargetField()) - case "SMIMEA": - answer = fmt.Sprintf(`%v %v %v %s`, rc.SmimeaUsage, rc.SmimeaSelector, rc.SmimeaMatchingType, rc.GetTargetField()) - case "CAA": - answer = fmt.Sprintf(`%v %s "%s"`, rc.CaaFlag, rc.CaaTag, rc.GetTargetField()) - case "TXT": - answer = txtutil.EncodeQuoted(rc.GetTargetTXTJoined()) - case "SRV": - if rc.GetTargetField() == "." { - return "", errors.New("SRV records with empty targets are not supported") - } - // _service._proto.name. TTL Type Priority Weight Port Target. - // e.g. _sip._tcp.phone.example.org. 86400 IN SRV 5 6 7 sip.example.org. - answer = fmt.Sprintf("%d %d %d %v", uint32(rc.SrvPriority), rc.SrvWeight, rc.SrvPort, rc.GetTargetField()) - default: - panic(fmt.Sprintf("createRecordString rtype %v unimplemented", rc.Type)) - // We panic so that we quickly find any switch statements - // that have not been updated for a new RR type. - } +func (client *Client) createRecordString(rc *models.RecordConfig, domain string) (string, error) { - // Apex records need a trailing dot on the host to avoid ambiguity - if domain == host { + host := rc.GetLabel() + // Apex records are represented by domain+".". + if host == domain { host += "." } - str := host + " " + strconv.FormatUint(uint64(rc.TTL), 10) + " " - - if rc.Type != "NS" { // TODO - str += "IN " + var answer string + + switch rc.TypeNum { // #rtype_variations + case dnsv2.TypeLOC: + answer = rc.AsLOC().String() + case dnsv2.TypeSVCB, dnsv2.TypeHTTPS: + answer = rc.GetRDATA().String() + answer = strings.ReplaceAll(answer, `"`, ``) + case dnsv2.TypeSSHFP: + f := rc.AsSSHFP() + answer = fmt.Sprintf(`%v %v %s`, f.Algorithm, f.Type, f.FingerPrint) + case dnsv2.TypeNAPTR: + f := rc.AsNAPTR() + answer = fmt.Sprintf(`%v %v "%v" "%v" "%v" %v`, f.Order, f.Preference, f.Flags, f.Service, f.Regexp, f.Replacement) + case dnsv2.TypeTLSA: + f := rc.AsTLSA() + answer = fmt.Sprintf(`%v %v %v %s`, f.Usage, f.Selector, f.MatchingType, f.Certificate) + case dnsv2.TypeSMIMEA: + f := rc.AsSMIMEA() + answer = fmt.Sprintf(`%v %v %v %s`, f.Usage, f.Selector, f.MatchingType, f.Certificate) + case dnsv2.TypeCAA: + f := rc.AsCAA() + answer = fmt.Sprintf(`%v %s "%s"`, f.Flag, f.Tag, f.Value) + default: + answer = rc.GetRDATA().String() } - str += rc.Type + " " - // Handle MX records which have priority - if rc.Type == "MX" { - str += strconv.FormatUint(uint64(uint32(rc.MxPreference)), 10) + " " + + var ifIn string + if rc.Type != "NS" { + ifIn = " IN" } - str += answer - return str, nil + + return fmt.Sprintf("%s %d%s %s %s", host, rc.TTL, ifIn, rc.Type, answer), nil } // deleteRecordString constructs the record string based on the provided Record. -func (n *Client) deleteRecordString(record *Record) string { - // Initialize values slice - values := []string{ - record.Host, - strconv.FormatUint(uint64(record.TTL), 10), - "IN", - record.Type, +func deleteRecordString(rc *models.RecordConfig) string { + switch rc.TypeNum { + case dnsv2.TypeMX: + return fmt.Sprintf("%s %d IN MX %s", rc.GetLabel(), rc.TTL, rc.AsMX().Mx) + case dnsv2.TypeNS: + return fmt.Sprintf("%s %d NS %s", rc.GetLabel(), rc.TTL, rc.AsNS().Ns) + case dnsv2.TypeSVCB, dnsv2.TypeHTTPS: + d := rc.GetRDATA().String() + d = strings.ReplaceAll(d, `"`, ``) + return fmt.Sprintf("%s %d IN %s %s", rc.GetLabel(), rc.TTL, rc.Type, d) + case dnsv2.TypeTLSA: + d := rc.GetRDATA().String() + d = strings.ToLower(d) + return fmt.Sprintf("%s %d IN %s %s", rc.GetLabel(), rc.TTL, rc.Type, d) } - if record.Type == "SRV" { - values = append(values, strconv.FormatUint(uint64(record.Priority), 10)) - } - values = append(values, record.Answer) - - // Remove IN if the record type is "NS" TODO - if record.Type == "NS" { - values = append(values[:2], values[3:]...) // Skip over the "IN" - } - - // Return the final string by joining the elements with spaces - return strings.Join(values, " ") + return fmt.Sprintf("%s %d IN %s %s", rc.GetLabel(), rc.TTL, rc.Type, rc.GetRDATA().String()) } // Function to check the no-populate argument. @@ -458,7 +344,7 @@ func isNoPopulate() bool { } // Function to check if debug mode is enabled. -func (n *Client) isDebugOn() bool { - debugMode, exists := n.conf["debugmode"] +func (client *Client) isDebugOn() bool { + debugMode, exists := client.conf["debugmode"] return exists && (debugMode == "1" || debugMode == "2") } diff --git a/providers/cnr/records_test.go b/providers/cnr/records_test.go new file mode 100644 index 0000000000..703be9c28f --- /dev/null +++ b/providers/cnr/records_test.go @@ -0,0 +1,162 @@ +package cnr + +import ( + "testing" + + dnsv2 "codeberg.org/miekg/dns" + "github.com/DNSControl/dnscontrol/v5/models" + "github.com/DNSControl/dnscontrol/v5/pkg/privatetypes" + "github.com/DNSControl/dnscontrol/v5/pkg/txtutil" +) + +func TestCreateRecordString(t *testing.T) { + dc := models.MustNewDomainConfig("example.com") + + tests := []struct { + name string + typeAny any + data string + want string + }{ + {name: "A", typeAny: dnsv2.TypeA, data: "192.0.2.1", want: "www 300 IN A 192.0.2.1"}, + {name: "AAAA", typeAny: dnsv2.TypeAAAA, data: "2001:db8::1", want: "www 300 IN AAAA 2001:db8::1"}, + {name: "CNAME", typeAny: dnsv2.TypeCNAME, data: "target.example.com.", want: "www 300 IN CNAME target.example.com."}, + {name: "DHCID", typeAny: dnsv2.TypeDHCID, data: "dhcid.example.com.", want: "www 300 IN DHCID dhcid.example.com."}, + {name: "DNAME", typeAny: dnsv2.TypeDNAME, data: "example.net.", want: "www 300 IN DNAME example.net."}, + {name: "MX", typeAny: dnsv2.TypeMX, data: "10 mail.example.net.", want: "www 300 IN MX 10 mail.example.net."}, + {name: "NS", typeAny: dnsv2.TypeNS, data: "ns1.example.net.", want: "www 300 NS ns1.example.net."}, + {name: "PTR", typeAny: dnsv2.TypePTR, data: "192.0.2.1.", want: "www 300 IN PTR 192.0.2.1."}, + {name: "LOC", typeAny: dnsv2.TypeLOC, data: "52 14 5.000 N 000 08 50.000 E 10.00m 0.00m 0.00m 0.00m", want: "www 300 IN LOC 52 14 5.000 N 00 08 50.000 E 10m 0.00m 0.00m 0.00m"}, + {name: "SSHFP", typeAny: dnsv2.TypeSSHFP, data: "1 2 deadbeef", want: "www 300 IN SSHFP 1 2 DEADBEEF"}, + {name: "NAPTR", typeAny: dnsv2.TypeNAPTR, data: `10 20 "U" "E2U+sip" "!^.*$!sip:customer@example.com!" example.com.`, want: "www 300 IN NAPTR 10 20 \"U\" \"E2U+sip\" \"!^.*$!sip:customer@example.com!\" example.com."}, + {name: "TLSA", typeAny: dnsv2.TypeTLSA, data: "3 1 1 target", want: "www 300 IN TLSA 3 1 1 TARGET"}, + {name: "SMIMEA", typeAny: dnsv2.TypeSMIMEA, data: "3 1 1 target", want: "www 300 IN SMIMEA 3 1 1 target"}, + {name: "CAA", typeAny: dnsv2.TypeCAA, data: `0 issue "letsencrypt.org"`, want: "www 300 IN CAA 0 issue \"letsencrypt.org\""}, + {name: "TXT", typeAny: dnsv2.TypeTXT, data: "hello", want: "www 300 IN TXT " + txtutil.EncodeQuoted("hello")}, + {name: "SRV", typeAny: dnsv2.TypeSRV, data: "5 6 443 service.example.net.", want: "www 300 IN SRV 5 6 443 service.example.net."}, + {name: "SVCB", typeAny: dnsv2.TypeSVCB, data: "1 test.com. port=80", want: "www 300 IN SVCB 1 test.com. port=80"}, + {name: "HTTPS", typeAny: dnsv2.TypeHTTPS, data: "3 test.com. alpn=h2", want: "www 300 IN HTTPS 3 test.com. alpn=h2"}, + // pseudo + {name: "ANAME", typeAny: "ANAME", data: "example.com.", want: "www 300 IN ANAME example.com."}, + // private + {name: "ALIAS", typeAny: privatetypes.TypeALIAS, data: "alias.example.com.", want: "www 300 IN ALIAS alias.example.com."}, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + rc := func() *models.RecordConfig { + switch tt.typeAny { + case "ANAME": + rc := dc.MustNewRecordConfigParse("www", 300, "CNAME", tt.data) + rc.Type = "ANAME" + return rc + default: + return dc.MustNewRecordConfigParse("www", 300, tt.typeAny, tt.data) + } + }() + got, err := (&Client{}).createRecordString(rc, dc.Name) + if err != nil { + t.Fatalf("createRecordString(%s) error = %v", rc.Type, err) + } + if got != tt.want { + t.Fatalf("createRecordString(%s) = %q, want %q", rc.Type, got, tt.want) + } + }) + } +} + +func TestClient_deleteRecordString(t *testing.T) { + tests := []struct { + name string // description of this test case + host string + ttl uint32 + rtype string + value string + want string + }{ + // Test data generated by monitoring this function while integration + // tests ran. It's a lot of data, probably a lot of redundant test + // cases, but at least its complete. + {"A1", "decoy", 300, "A", "1.1.1.1", "decoy 300 IN A 1.1.1.1"}, + {"A2", "foo.bat", 300, "A", "1.2.3.4", "foo.bat 300 IN A 1.2.3.4"}, + {"AAAA", "foo", 300, "AAAA", "2003:dd:d7ff::fe71:aaaa", "foo 300 IN AAAA 2003:dd:d7ff::fe71:aaaa"}, + {"CAA1", "@", 300, "CAA", "0 issue \"letsencrypt.org; validationmethods=dns-01; accounturi=https://acme-v02.api.letsencrypt.org/acme/acct/1234\"", "@ 300 IN CAA 0 issue \"letsencrypt.org; validationmethods=dns-01; accounturi=https://acme-v02.api.letsencrypt.org/acme/acct/1234\""}, + {"CAA2", "@", 300, "CAA", "0 issue \"letsencrypt.org\"", "@ 300 IN CAA 0 issue \"letsencrypt.org\""}, + {"CAA3", "@", 300, "CAA", "0 issuewild \"letsencrypt.org\"", "@ 300 IN CAA 0 issuewild \"letsencrypt.org\""}, + {"CAA4", "@", 300, "CAA", "128 issuewild \";\"", "@ 300 IN CAA 128 issuewild \";\""}, + {"CNAME1", "foo", 300, "CNAME", "dnscontroltest-cnr.com.", "foo 300 IN CNAME dnscontroltest-cnr.com."}, + {"x", "testcname", 300, "CNAME", "foo.dnscontroltest-cnr.com.", "testcname 300 IN CNAME foo.dnscontroltest-cnr.com."}, + {"x", "foo", 300, "CNAME", "google.com.", "foo 300 IN CNAME google.com."}, + {"x", "test", 300, "DHCID", "AAIBY2/AuCccgoJbsaxcQc9TUapptP69lOjxfNuVAA2kjEA=", "test 300 IN DHCID AAIBY2/AuCccgoJbsaxcQc9TUapptP69lOjxfNuVAA2kjEA="}, + {"x", "a", 300, "DNAME", "b.dnscontroltest-cnr.com.", "a 300 IN DNAME b.dnscontroltest-cnr.com."}, + {"x", "c", 300, "LOC", "32 07 19.000 S 116 02 25.000 E 10.00m 0.00m 0.00m 0.00m", "c 300 IN LOC 32 07 19.000 S 116 02 25.000 E 10m 0.00m 0.00m 0.00m"}, + {"x", "d", 300, "LOC", "42 21 28.764 N 71 00 51.617 W -44.00m 2000.00m 0.00m 0.00m", "d 300 IN LOC 42 21 28.764 N 71 00 51.617 W -44m 2000m 0.00m 0.00m"}, + {"x", "a", 300, "LOC", "42 21 43.952 N 71 05 6.344 W -24.33m 1.00m 200.00m 10.00m", "a 300 IN LOC 42 21 43.952 N 71 05 6.344 W -24.33m 1m 200m 10m"}, + {"x", "@", 300, "LOC", "42 21 54.000 N 71 06 18.000 W -24.00m 30.00m 0.00m 0.00m", "@ 300 IN LOC 42 21 54.000 N 71 06 18.000 W -24m 30m 0.00m 0.00m"}, + {"x", "b", 300, "LOC", "52 14 5.000 N 00 08 50.000 E 10.22m 0.00m 0.00m 0.00m", "b 300 IN LOC 52 14 5.000 N 00 08 50.000 E 10.22m 0.00m 0.00m 0.00m"}, + {"x", "@", 300, "MX", ".", "@ 300 IN MX ."}, + {"x", "nmx", 300, "MX", ".", "nmx 300 IN MX ."}, + {"x", "foo", 300, "MX", "alt1.aspmx.l.google.com.", "foo 300 IN MX alt1.aspmx.l.google.com."}, + {"x", "@", 300, "MX", "www.dnscontroltest-cnr.com.", "@ 300 IN MX www.dnscontroltest-cnr.com."}, + {"x", "nmx", 300, "MX", "www.dnscontroltest-cnr.com.", "nmx 300 IN MX www.dnscontroltest-cnr.com."}, + {"x", "test", 300, "NAPTR", "100 10 \"U\" \"E2U+sip\" \"!^.*$!sip:customer-service@example.com!\" .", "test 300 IN NAPTR 100 10 \"U\" \"E2U+sip\" \"!^.*$!sip:customer-service@example.com!\" ."}, + {"x", "test", 300, "NAPTR", "103 20 \"A\" \"E2U+sip\" \"\" example2.foo.com.", "test 300 IN NAPTR 103 20 \"A\" \"E2U+sip\" \"\" example2.foo.com."}, + {"x", "test", 300, "NAPTR", "103 20 \"U\" \"E2U+email\" \"!^.*$!mailto:information@example.com!\" .", "test 300 IN NAPTR 103 20 \"U\" \"E2U+email\" \"!^.*$!mailto:information@example.com!\" ."}, + {"x", "@", 300, "NS", "ns2.foo.com.", "@ 300 NS ns2.foo.com."}, + {"x", "xyz", 300, "NS", "ns2.foo.com.", "xyz 300 NS ns2.foo.com."}, + {"x", "4", 300, "PTR", "bar.com.", "4 300 IN PTR bar.com."}, + {"x", "_443._tcp", 300, "SMIMEA", "2 0 1 0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef", "_443._tcp 300 IN SMIMEA 2 0 1 0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef"}, + {"x", "_sip._tcp", 300, "SRV", "15 65 75 .", "_sip._tcp 300 IN SRV 15 65 75 ."}, + {"x", "_sip._tcp", 300, "SRV", "15 65 75 foo3.com.", "_sip._tcp 300 IN SRV 15 65 75 foo3.com."}, + {"x", "@", 300, "SSHFP", "1 1 66C7D5540B7D75A1FB4C84FEBFA178AD99BDD67C", "@ 300 IN SSHFP 1 1 66C7D5540B7D75A1FB4C84FEBFA178AD99BDD67C"}, + {"x", "@", 300, "SVCB", "0 test.com.", "@ 300 IN SVCB 0 test.com."}, + {"x", "@", 300, "SVCB", "1 test.com. port=80", "@ 300 IN SVCB 1 test.com. port=80"}, + {"x", "_443._tcp", 300, "TLSA", "2 0 1 0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef", "_443._tcp 300 IN TLSA 2 0 1 0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef"}, + {"bs1", "fooosbs1", 300, "TXT", "\"1back\\\\slash\"", "fooosbs1 300 IN TXT \"1back\\\\slash\""}, + {"bs2", "fooosbs2", 300, "TXT", "\"2back\\\\\\\\slash\"", "fooosbs2 300 IN TXT \"2back\\\\\\\\slash\""}, + {"bs3", "fooosbs3", 300, "TXT", "\"3back\\\\\\\\\\\\slash\"", "fooosbs3 300 IN TXT \"3back\\\\\\\\\\\\slash\""}, + {"bs4", "fooosbs4", 300, "TXT", "\"4back\\\\\\\\\\\\\\\\slash\"", "fooosbs4 300 IN TXT \"4back\\\\\\\\\\\\\\\\slash\""}, + {"txt254", "foo254", 300, "TXT", "\"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\"", "foo254 300 IN TXT \"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\""}, + {"txt255", "foo255", 300, "TXT", "\"BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB\"", "foo255 300 IN TXT \"BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB\""}, + {"txt256", "foo256", 300, "TXT", "\"CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC\" \"C\"", "foo256 300 IN TXT \"CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC\" \"C\""}, + {"txt509", "foo509", 300, "TXT", "\"DDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDD\" \"DDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDD\"", "foo509 300 IN TXT \"DDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDD\" \"DDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDD\""}, + {"txt510", "foo510", 300, "TXT", "\"EEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE\" \"EEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE\"", "foo510 300 IN TXT \"EEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE\" \"EEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE\""}, + {"txt511", "foo511", 300, "TXT", "\"FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF\" \"FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF\" \"F\"", "foo511 300 IN TXT \"FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF\" \"FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF\" \"F\""}, + {"txt764", "foo764", 300, "TXT", "\"GGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGG\" \"GGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGG\" \"GGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGG\"", "foo764 300 IN TXT \"GGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGG\" \"GGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGG\" \"GGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGG\""}, + {"txt765", "foo765", 300, "TXT", "\"HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH\" \"HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH\" \"HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH\"", "foo765 300 IN TXT \"HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH\" \"HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH\" \"HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH\""}, + {"txt766", "foo766", 300, "TXT", "\"JJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJ\" \"JJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJ\" \"JJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJ\" \"J\"", "foo766 300 IN TXT \"JJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJ\" \"JJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJ\" \"JJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJ\" \"J\""}, + {"x", "@", 300, "TXT", "\"simple\"", "@ 300 IN TXT \"simple\""}, + {"x", "final", 300, "TXT", "\"TestDNSProviders was successful!\"", "final 300 IN TXT \"TestDNSProviders was successful!\""}, + {"x", "foo", 300, "TXT", "\"simple\"", "foo 300 IN TXT \"simple\""}, + {"x", "foo", 300, "TXT", "\"v=spf1 ip4:99.99.99.99 -all\"", "foo 300 IN TXT \"v=spf1 ip4:99.99.99.99 -all\""}, + {"x", "foo.bat", 300, "TXT", "\"simple\"", "foo.bat 300 IN TXT \"simple\""}, + {"x", "foobt", 300, "TXT", "\"blah`blah\"", "foobt 300 IN TXT \"blah`blah\""}, + {"x", "foosc1", 300, "TXT", "\"semi;colon\"", "foosc1 300 IN TXT \"semi;colon\""}, + {"x", "foosc2", 300, "TXT", "\"wssemi ; colon\"", "foosc2 300 IN TXT \"wssemi ; colon\""}, + {"x", "foosp", 300, "TXT", "\"with spaces\"", "foosp 300 IN TXT \"with spaces\""}, + {"x", "foosq", 300, "TXT", "\"quo'te\"", "foosq 300 IN TXT \"quo'te\""}, + {"x", "foows1", 300, "TXT", "\"trailingws \"", "foows1 300 IN TXT \"trailingws \""}, + {"x", "testtxt", 300, "TXT", "\"changed\"", "testtxt 300 IN TXT \"changed\""}, + {"x", "testtxt", 300, "TXT", "\"simple\"", "testtxt 300 IN TXT \"simple\""}, + } + + dc := models.MustNewDomainConfig("example.com") + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + conf := map[string]string{} + conf["apilogin"], conf["apipassword"], conf["apientity"] = "x", "y", "LIVE" + + var rc *models.RecordConfig + if tt.rtype == "MX" { + rc = dc.MustNewRecordConfig(dc.LabelFromShort(tt.host), tt.ttl, tt.rtype, 0, tt.value) + } else { + rc = dc.MustNewRecordConfigParse(dc.LabelFromShort(tt.host), tt.ttl, tt.rtype, tt.value) + } + + got := deleteRecordString(rc) + if got != tt.want { + t.Errorf("deleteRecordString() = %v, want %v", got, tt.want) + } + }) + } +} diff --git a/providers/cnr/test_data/expected_tonative_output_createRecordString_dnscontroltest-cnr.com.json b/providers/cnr/test_data/expected_tonative_output_createRecordString_dnscontroltest-cnr.com.json new file mode 100644 index 0000000000..993bd1f018 --- /dev/null +++ b/providers/cnr/test_data/expected_tonative_output_createRecordString_dnscontroltest-cnr.com.json @@ -0,0 +1,726 @@ +[ + { + "index": 1, + "value": "* 300 IN A 3.3.3.3" + }, + { + "index": 2, + "value": "4 300 IN PTR bar.com." + }, + { + "index": 3, + "value": "4 300 IN PTR foo.com." + }, + { + "index": 4, + "value": "@ 1000 IN A 8.8.8.8" + }, + { + "index": 5, + "value": "@ 300 IN A 1.2.3.2" + }, + { + "index": 6, + "value": "@ 300 IN A 1.2.3.4" + }, + { + "index": 7, + "value": "@ 300 IN A 2.2.2.2" + }, + { + "index": 8, + "value": "@ 300 IN A 2.3.4.5" + }, + { + "index": 9, + "value": "@ 300 IN A 4.4.4.4" + }, + { + "index": 10, + "value": "@ 300 IN CAA 0 issue \"letsencrypt.org\"" + }, + { + "index": 11, + "value": "@ 300 IN CAA 0 issue \"letsencrypt.org; validationmethods=dns-01; accounturi=https://acme-v02.api.letsencrypt.org/acme/acct/1234\"" + }, + { + "index": 12, + "value": "@ 300 IN CAA 0 issuewild \";\"" + }, + { + "index": 13, + "value": "@ 300 IN CAA 0 issuewild \"example.com\"" + }, + { + "index": 14, + "value": "@ 300 IN CAA 0 issuewild \"letsencrypt.org\"" + }, + { + "index": 15, + "value": "@ 300 IN CAA 128 issue \"letsencrypt.org\"" + }, + { + "index": 16, + "value": "@ 300 IN LOC 42 21 54.000 N 71 06 18.000 W -24.05m 30m 0.00m 0.00m" + }, + { + "index": 17, + "value": "@ 300 IN LOC 42 21 54.000 N 71 06 18.000 W -24.06m 30m 10m 0.00m" + }, + { + "index": 18, + "value": "@ 300 IN LOC 42 21 54.000 N 71 06 18.000 W -24m 30m 0.00m 0.00m" + }, + { + "index": 19, + "value": "@ 300 IN MX 0 ." + }, + { + "index": 20, + "value": "@ 300 IN MX 2 dnscontroltest-cnr.com." + }, + { + "index": 21, + "value": "@ 300 IN MX 5 bar.com." + }, + { + "index": 22, + "value": "@ 300 IN MX 5 foo.com." + }, + { + "index": 23, + "value": "@ 300 IN MX 8 www.dnscontroltest-cnr.com." + }, + { + "index": 24, + "value": "@ 300 NS ns1.example.com." + }, + { + "index": 25, + "value": "@ 300 NS ns1.foo.com." + }, + { + "index": 26, + "value": "@ 300 NS ns2.example.com." + }, + { + "index": 27, + "value": "@ 300 NS ns2.foo.com." + }, + { + "index": 28, + "value": "@ 300 IN SSHFP 1 1 66C7D5540B7D75A1FB4C84FEBFA178AD99BDD67C" + }, + { + "index": 29, + "value": "@ 300 IN SSHFP 2 1 66C7D5540B7D75A1FB4C84FEBFA178AD99BDD67C" + }, + { + "index": 30, + "value": "@ 300 IN SSHFP 2 2 745A635BC46A397A5C4F21D437483005BCC40D7511FF15FBFAFE913A081559BC" + }, + { + "index": 31, + "value": "@ 300 IN SVCB 0 test.com." + }, + { + "index": 32, + "value": "@ 300 IN SVCB 1 test.com. port=80" + }, + { + "index": 33, + "value": "@ 300 IN SVCB 1 test.com. port=99" + }, + { + "index": 34, + "value": "@ 300 IN TXT \"asimple\"" + }, + { + "index": 35, + "value": "@ 300 IN TXT \"simple\"" + }, + { + "index": 36, + "value": "@ 500 IN A 8.8.8.8" + }, + { + "index": 37, + "value": "@ 666 IN A 8.8.8.8" + }, + { + "index": 38, + "value": "_443._tcp 300 IN SMIMEA 2 0 1 0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef" + }, + { + "index": 39, + "value": "_443._tcp 300 IN SMIMEA 2 0 2 0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef" + }, + { + "index": 40, + "value": "_443._tcp 300 IN SMIMEA 2 0 2 fedcba9876543210fedcba9876543210fedcba9876543210fedcba9876543210fedcba9876543210fedcba9876543210fedcba9876543210fedcba9876543210" + }, + { + "index": 41, + "value": "_443._tcp 300 IN SMIMEA 2 1 1 0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef" + }, + { + "index": 42, + "value": "_443._tcp 300 IN SMIMEA 3 1 1 0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef" + }, + { + "index": 43, + "value": "_443._tcp 300 IN TLSA 2 0 1 0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF" + }, + { + "index": 44, + "value": "_443._tcp 300 IN TLSA 2 0 2 0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF" + }, + { + "index": 45, + "value": "_443._tcp 300 IN TLSA 2 0 2 FEDCBA9876543210FEDCBA9876543210FEDCBA9876543210FEDCBA9876543210FEDCBA9876543210FEDCBA9876543210FEDCBA9876543210FEDCBA9876543210" + }, + { + "index": 46, + "value": "_443._tcp 300 IN TLSA 2 1 1 0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF" + }, + { + "index": 47, + "value": "_443._tcp 300 IN TLSA 3 1 1 0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF" + }, + { + "index": 48, + "value": "_sip._tcp 300 IN SRV 15 65 75 ." + }, + { + "index": 49, + "value": "_sip._tcp 300 IN SRV 15 65 75 foo3.com." + }, + { + "index": 50, + "value": "_sip._tcp 300 IN SRV 15 65 75 foo4.com." + }, + { + "index": 51, + "value": "_sip._tcp 300 IN SRV 5 6 7 foo.com." + }, + { + "index": 52, + "value": "_sip._tcp 300 IN SRV 5 60 70 foo2.com." + }, + { + "index": 53, + "value": "_sip._tcp 300 IN SRV 52 6 7 foo.com." + }, + { + "index": 54, + "value": "_sip._tcp 300 IN SRV 52 62 7 foo.com." + }, + { + "index": 55, + "value": "_sip._tcp 300 IN SRV 52 62 72 foo.com." + }, + { + "index": 56, + "value": "_sip._tcp 333 IN SRV 5 6 7 foo.com." + }, + { + "index": 57, + "value": "_sip._tcp 4400 IN SRV 5 6 7 foo.com." + }, + { + "index": 58, + "value": "a 300 IN CNAME xn--ndaaa.com." + }, + { + "index": 59, + "value": "a 300 IN DNAME b.dnscontroltest-cnr.com." + }, + { + "index": 60, + "value": "a 300 IN LOC 42 21 43.950 N 71 05 6.340 W -24.33m 1m 200m 10m" + }, + { + "index": 61, + "value": "b 300 IN LOC 52 14 5.000 N 00 08 50.000 E 10.22m 0.00m 0.00m 0.00m" + }, + { + "index": 62, + "value": "bar 300 IN A 1.2.3.4" + }, + { + "index": 63, + "value": "bar 300 IN A 5.5.5.5" + }, + { + "index": 64, + "value": "bar 300 IN CNAME redact2.acm-validations.aws." + }, + { + "index": 65, + "value": "bar 300 IN MX 5 bar.com." + }, + { + "index": 66, + "value": "bar.bat 300 IN A 5.5.5.5" + }, + { + "index": 67, + "value": "c 300 IN LOC 32 07 19.000 S 116 02 25.000 E 10m 0.00m 0.00m 0.00m" + }, + { + "index": 68, + "value": "d 300 IN LOC 42 21 28.760 N 71 00 51.620 W -44m 2000m 0.00m 0.00m" + }, + { + "index": 69, + "value": "decoy 300 IN A 1.1.1.1" + }, + { + "index": 70, + "value": "decoy 300 IN A 2.2.2.2" + }, + { + "index": 71, + "value": "decoy 300 IN A 3.3.3.3" + }, + { + "index": 72, + "value": "dyndns-city1 300 IN A 91.42.1.1" + }, + { + "index": 73, + "value": "dyndns-city1 300 IN AAAA 2003:dd:d7ff::fe71:ce77" + }, + { + "index": 74, + "value": "dyndns-city2 300 IN A 91.42.1.2" + }, + { + "index": 75, + "value": "dyndns-city2 300 IN AAAA 2003:dd:d7ff::fe71:ce78" + }, + { + "index": 76, + "value": "final 300 IN TXT \"TestDNSProviders was successful!\"" + }, + { + "index": 77, + "value": "foo 300 IN A 1.1.1.1" + }, + { + "index": 78, + "value": "foo 300 IN A 1.2.3.4" + }, + { + "index": 79, + "value": "foo 300 IN A 10.10.10.10" + }, + { + "index": 80, + "value": "foo 300 IN A 11.11.11.11" + }, + { + "index": 81, + "value": "foo 300 IN A 12.12.12.12" + }, + { + "index": 82, + "value": "foo 300 IN A 13.13.13.13" + }, + { + "index": 83, + "value": "foo 300 IN A 14.14.14.14" + }, + { + "index": 84, + "value": "foo 300 IN A 2.3.4.5" + }, + { + "index": 85, + "value": "foo 300 IN A 3.4.5.6" + }, + { + "index": 86, + "value": "foo 300 IN A 4.5.6.7" + }, + { + "index": 87, + "value": "foo 300 IN A 8.8.8.8" + }, + { + "index": 88, + "value": "foo 300 IN AAAA 2003:dd:d7ff::fe71:aaaa" + }, + { + "index": 89, + "value": "foo 300 IN CNAME dnscontroltest-cnr.com." + }, + { + "index": 90, + "value": "foo 300 IN CNAME google.com." + }, + { + "index": 91, + "value": "foo 300 IN CNAME google2.com." + }, + { + "index": 92, + "value": "foo 300 IN CNAME redact1.acm-validations.aws." + }, + { + "index": 93, + "value": "foo 300 IN MX 10 aspmx.l.google.com." + }, + { + "index": 94, + "value": "foo 300 IN MX 10 foo.dnscontroltest-cnr.com." + }, + { + "index": 95, + "value": "foo 300 IN MX 20 alt1.aspmx.l.google.com." + }, + { + "index": 96, + "value": "foo 300 IN MX 20 bar.dnscontroltest-cnr.com." + }, + { + "index": 97, + "value": "foo 300 IN MX 5 mx.google.com." + }, + { + "index": 98, + "value": "foo 300 IN MX 8 dnscontroltest-cnr.com." + }, + { + "index": 99, + "value": "foo 300 NS dnscontroltest-cnr.com." + }, + { + "index": 100, + "value": "foo 300 IN TXT \"simple\"" + }, + { + "index": 101, + "value": "foo 300 IN TXT \"v=spf1 ip4:99.99.99.99 -all\"" + }, + { + "index": 102, + "value": "foo.bat 300 IN A 1.2.3.4" + }, + { + "index": 103, + "value": "foo.bat 300 IN A 2.3.4.5" + }, + { + "index": 104, + "value": "foo.bat 300 IN TXT \"simple\"" + }, + { + "index": 105, + "value": "foo254 300 IN TXT \"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\"" + }, + { + "index": 106, + "value": "foo255 300 IN TXT \"BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB\"" + }, + { + "index": 107, + "value": "foo256 300 IN TXT \"CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC\" \"C\"" + }, + { + "index": 108, + "value": "foo509 300 IN TXT \"DDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDD\" \"DDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDD\"" + }, + { + "index": 109, + "value": "foo510 300 IN TXT \"EEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE\" \"EEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE\"" + }, + { + "index": 110, + "value": "foo511 300 IN TXT \"FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF\" \"FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF\" \"F\"" + }, + { + "index": 111, + "value": "foo764 300 IN TXT \"GGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGG\" \"GGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGG\" \"GGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGG\"" + }, + { + "index": 112, + "value": "foo765 300 IN TXT \"HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH\" \"HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH\" \"HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH\"" + }, + { + "index": 113, + "value": "foo766 300 IN TXT \"JJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJ\" \"JJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJ\" \"JJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJ\" \"J\"" + }, + { + "index": 114, + "value": "foobt 300 IN TXT \"blah`blah\"" + }, + { + "index": 115, + "value": "fooosbs1 300 IN TXT \"1back\\\\slash\"" + }, + { + "index": 116, + "value": "fooosbs2 300 IN TXT \"2back\\\\\\\\slash\"" + }, + { + "index": 117, + "value": "fooosbs3 300 IN TXT \"3back\\\\\\\\\\\\slash\"" + }, + { + "index": 118, + "value": "fooosbs4 300 IN TXT \"4back\\\\\\\\\\\\\\\\slash\"" + }, + { + "index": 119, + "value": "foosc1 300 IN TXT \"semi;colon\"" + }, + { + "index": 120, + "value": "foosc2 300 IN TXT \"wssemi ; colon\"" + }, + { + "index": 121, + "value": "foosp 300 IN TXT \"with spaces\"" + }, + { + "index": 122, + "value": "foosq 300 IN TXT \"quo'te\"" + }, + { + "index": 123, + "value": "foows1 300 IN TXT \"trailingws \"" + }, + { + "index": 124, + "value": "mail 300 IN CNAME ghs.googlehosted.com." + }, + { + "index": 125, + "value": "mail.bat 300 IN CNAME ghs.googlehosted.com." + }, + { + "index": 126, + "value": "nmx 300 IN A 1.2.3.3" + }, + { + "index": 127, + "value": "nmx 300 IN MX 0 ." + }, + { + "index": 128, + "value": "nmx 300 IN MX 3 nmx.dnscontroltest-cnr.com." + }, + { + "index": 129, + "value": "nmx 300 IN MX 9 www.dnscontroltest-cnr.com." + }, + { + "index": 130, + "value": "test 300 IN DHCID AAAAAAAAuCccgoJbsaxcQc9TUapptP69lOjxfNuVAA2kjEA=" + }, + { + "index": 131, + "value": "test 300 IN DHCID AAIBY2/AuCccgoJbsaxcQc9TUapptP69lOjxfNuVAA2kjEA=" + }, + { + "index": 132, + "value": "test 300 IN DNAME example.com." + }, + { + "index": 133, + "value": "test 300 IN DNAME example.net." + }, + { + "index": 134, + "value": "test 300 IN NAPTR 100 10 \"U\" \"E2U+sip\" \"!^.*$!sip:customer-service@example.com!\" ." + }, + { + "index": 135, + "value": "test 300 IN NAPTR 102 10 \"U\" \"E2U+email\" \"!^.*$!mailto:information@example.com!\" ." + }, + { + "index": 136, + "value": "test 300 IN NAPTR 103 10 \"U\" \"E2U+email\" \"!^.*$!mailto:information@example.com!\" ." + }, + { + "index": 137, + "value": "test 300 IN NAPTR 103 20 \"A\" \"E2U+email\" \"!^.*$!mailto:information@example.com!\" ." + }, + { + "index": 138, + "value": "test 300 IN NAPTR 103 20 \"A\" \"E2U+sip\" \"!^.*$!mailto:information@example.com!\" ." + }, + { + "index": 139, + "value": "test 300 IN NAPTR 103 20 \"A\" \"E2U+sip\" \"!^.*$!sip:customer-service@example.com!\" ." + }, + { + "index": 140, + "value": "test 300 IN NAPTR 103 20 \"A\" \"E2U+sip\" \"\" example.foo.com." + }, + { + "index": 141, + "value": "test 300 IN NAPTR 103 20 \"A\" \"E2U+sip\" \"\" example2.foo.com." + }, + { + "index": 142, + "value": "test 300 IN NAPTR 103 20 \"U\" \"E2U+email\" \"!^.*$!mailto:information@example.com!\" ." + }, + { + "index": 143, + "value": "testa 300 IN A 1.1.1.1" + }, + { + "index": 144, + "value": "testa 300 IN A 3.3.3.3" + }, + { + "index": 145, + "value": "testa 333 IN A 1.1.1.1" + }, + { + "index": 146, + "value": "testa 999 IN A 1.1.1.1" + }, + { + "index": 147, + "value": "testaaaa 300 IN AAAA 2607:f8b0:4006:820::2006" + }, + { + "index": 148, + "value": "testaaaa 300 IN AAAA 2607:f8b0:4006:820::2013" + }, + { + "index": 149, + "value": "testcname 300 IN CNAME foo.dnscontroltest-cnr.com." + }, + { + "index": 150, + "value": "testcname 300 IN CNAME www.google.com." + }, + { + "index": 151, + "value": "testcname 300 IN CNAME www.yahoo.com." + }, + { + "index": 152, + "value": "testdefined 300 IN A 2.2.2.2" + }, + { + "index": 153, + "value": "testdefined 300 IN A 9.9.9.9" + }, + { + "index": 154, + "value": "testignore 300 IN A 8.8.8.8" + }, + { + "index": 155, + "value": "testmx 300 IN MX 100 bar.com." + }, + { + "index": 156, + "value": "testmx 300 IN MX 100 foo.com." + }, + { + "index": 157, + "value": "testmx 300 IN MX 5 bar.com." + }, + { + "index": 158, + "value": "testmx 300 IN MX 5 foo.com." + }, + { + "index": 159, + "value": "testtxt 300 IN TXT \"changed\"" + }, + { + "index": 160, + "value": "testtxt 300 IN TXT \"simple\"" + }, + { + "index": 161, + "value": "www 300 IN A 1.1.1.1" + }, + { + "index": 162, + "value": "www 300 IN A 1.2.3.4" + }, + { + "index": 163, + "value": "www 300 IN A 1.2.3.8" + }, + { + "index": 164, + "value": "www 300 IN A 1.2.3.9" + }, + { + "index": 165, + "value": "www 300 IN A 2.2.2.2" + }, + { + "index": 166, + "value": "www 300 IN A 3.3.3.3" + }, + { + "index": 167, + "value": "www 300 IN A 5.5.5.5" + }, + { + "index": 168, + "value": "www 300 IN A 5.6.7.8" + }, + { + "index": 169, + "value": "www 400 IN A 2.2.2.2" + }, + { + "index": 170, + "value": "www 400 IN A 5.6.7.8" + }, + { + "index": 171, + "value": "www 700 IN A 1.2.3.4" + }, + { + "index": 172, + "value": "www 700 IN A 5.6.7.8" + }, + { + "index": 173, + "value": "xn--fiq228c 300 IN A 1.2.3.4" + }, + { + "index": 174, + "value": "xn--ndaaa 300 IN A 1.2.3.4" + }, + { + "index": 175, + "value": "xn--ndaaa 300 IN A 2.2.2.2" + }, + { + "index": 176, + "value": "xn--o-0gab 300 IN CNAME xn--ndaaa.xn--vhquv." + }, + { + "index": 177, + "value": "xyz 300 NS ns1.foo.com." + }, + { + "index": 178, + "value": "xyz 300 NS ns2.foo.com." + }, + { + "index": 179, + "value": "zzz 300 IN A 3.3.3.3" + }, + { + "index": 180, + "value": "zzz 300 IN A 4.4.4.4" + }, + { + "index": 181, + "value": "zzz 300 IN AAAA 2003:dd:d7ff::fe71:cccc" + } +] diff --git a/providers/cnr/test_data/meta.json b/providers/cnr/test_data/meta.json new file mode 100644 index 0000000000..c1a2384532 --- /dev/null +++ b/providers/cnr/test_data/meta.json @@ -0,0 +1,11 @@ +{ + "version": 1, + "recordings": [ + { + "domain": "dnscontroltest-cnr.com", + "to_native": [ + "createRecordString" + ] + } + ] +} diff --git a/providers/cnr/test_data/recorded_tonative_input_createRecordString_dnscontroltest-cnr.com.records b/providers/cnr/test_data/recorded_tonative_input_createRecordString_dnscontroltest-cnr.com.records new file mode 100644 index 0000000000..9ebf2c872e --- /dev/null +++ b/providers/cnr/test_data/recorded_tonative_input_createRecordString_dnscontroltest-cnr.com.records @@ -0,0 +1,181 @@ +1 * 300 IN A 3.3.3.3 +2 4 300 IN PTR bar.com. +3 4 300 IN PTR foo.com. +4 @ 1000 IN A 8.8.8.8 +5 @ 300 IN A 1.2.3.2 +6 @ 300 IN A 1.2.3.4 +7 @ 300 IN A 2.2.2.2 +8 @ 300 IN A 2.3.4.5 +9 @ 300 IN A 4.4.4.4 +10 @ 300 IN CAA 0 issue "letsencrypt.org" +11 @ 300 IN CAA 0 issue "letsencrypt.org; validationmethods=dns-01; accounturi=https://acme-v02.api.letsencrypt.org/acme/acct/1234" +12 @ 300 IN CAA 0 issuewild ";" +13 @ 300 IN CAA 0 issuewild "example.com" +14 @ 300 IN CAA 0 issuewild "letsencrypt.org" +15 @ 300 IN CAA 128 issue "letsencrypt.org" +16 @ 300 IN LOC 42 21 54.000 N 71 06 18.000 W -24.05m 30m 0.00m 0.00m +17 @ 300 IN LOC 42 21 54.000 N 71 06 18.000 W -24.06m 30m 10m 0.00m +18 @ 300 IN LOC 42 21 54.000 N 71 06 18.000 W -24m 30m 0.00m 0.00m +19 @ 300 IN MX 0 . +20 @ 300 IN MX 2 dnscontroltest-cnr.com. +21 @ 300 IN MX 5 bar.com. +22 @ 300 IN MX 5 foo.com. +23 @ 300 IN MX 8 www.dnscontroltest-cnr.com. +24 @ 300 IN NS ns1.example.com. +25 @ 300 IN NS ns1.foo.com. +26 @ 300 IN NS ns2.example.com. +27 @ 300 IN NS ns2.foo.com. +28 @ 300 IN SSHFP 1 1 66C7D5540B7D75A1FB4C84FEBFA178AD99BDD67C +29 @ 300 IN SSHFP 2 1 66C7D5540B7D75A1FB4C84FEBFA178AD99BDD67C +30 @ 300 IN SSHFP 2 2 745A635BC46A397A5C4F21D437483005BCC40D7511FF15FBFAFE913A081559BC +31 @ 300 IN SVCB 0 test.com. +32 @ 300 IN SVCB 1 test.com. port="80" +33 @ 300 IN SVCB 1 test.com. port="99" +34 @ 300 IN TXT "asimple" +35 @ 300 IN TXT "simple" +36 @ 500 IN A 8.8.8.8 +37 @ 666 IN A 8.8.8.8 +38 _443._tcp 300 IN SMIMEA 2 0 1 0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef +39 _443._tcp 300 IN SMIMEA 2 0 2 0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef +40 _443._tcp 300 IN SMIMEA 2 0 2 fedcba9876543210fedcba9876543210fedcba9876543210fedcba9876543210fedcba9876543210fedcba9876543210fedcba9876543210fedcba9876543210 +41 _443._tcp 300 IN SMIMEA 2 1 1 0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef +42 _443._tcp 300 IN SMIMEA 3 1 1 0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef +43 _443._tcp 300 IN TLSA 2 0 1 0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF +44 _443._tcp 300 IN TLSA 2 0 2 0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF +45 _443._tcp 300 IN TLSA 2 0 2 FEDCBA9876543210FEDCBA9876543210FEDCBA9876543210FEDCBA9876543210FEDCBA9876543210FEDCBA9876543210FEDCBA9876543210FEDCBA9876543210 +46 _443._tcp 300 IN TLSA 2 1 1 0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF +47 _443._tcp 300 IN TLSA 3 1 1 0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF +48 _sip._tcp 300 IN SRV 15 65 75 . +49 _sip._tcp 300 IN SRV 15 65 75 foo3.com. +50 _sip._tcp 300 IN SRV 15 65 75 foo4.com. +51 _sip._tcp 300 IN SRV 5 6 7 foo.com. +52 _sip._tcp 300 IN SRV 5 60 70 foo2.com. +53 _sip._tcp 300 IN SRV 52 6 7 foo.com. +54 _sip._tcp 300 IN SRV 52 62 7 foo.com. +55 _sip._tcp 300 IN SRV 52 62 72 foo.com. +56 _sip._tcp 333 IN SRV 5 6 7 foo.com. +57 _sip._tcp 4400 IN SRV 5 6 7 foo.com. +58 a 300 IN CNAME xn--ndaaa.com. +59 a 300 IN DNAME b.dnscontroltest-cnr.com. +60 a 300 IN LOC 42 21 43.950 N 71 05 6.340 W -24.33m 1m 200m 10m +61 b 300 IN LOC 52 14 5.000 N 00 08 50.000 E 10.22m 0.00m 0.00m 0.00m +62 bar 300 IN A 1.2.3.4 +63 bar 300 IN A 5.5.5.5 +64 bar 300 IN CNAME redact2.acm-validations.aws. +65 bar 300 IN MX 5 bar.com. +66 bar.bat 300 IN A 5.5.5.5 +67 c 300 IN LOC 32 07 19.000 S 116 02 25.000 E 10m 0.00m 0.00m 0.00m +68 d 300 IN LOC 42 21 28.760 N 71 00 51.620 W -44m 2000m 0.00m 0.00m +69 decoy 300 IN A 1.1.1.1 +70 decoy 300 IN A 2.2.2.2 +71 decoy 300 IN A 3.3.3.3 +72 dyndns-city1 300 IN A 91.42.1.1 +73 dyndns-city1 300 IN AAAA 2003:dd:d7ff::fe71:ce77 +74 dyndns-city2 300 IN A 91.42.1.2 +75 dyndns-city2 300 IN AAAA 2003:dd:d7ff::fe71:ce78 +76 final 300 IN TXT "TestDNSProviders was successful!" +77 foo 300 IN A 1.1.1.1 +78 foo 300 IN A 1.2.3.4 +79 foo 300 IN A 10.10.10.10 +80 foo 300 IN A 11.11.11.11 +81 foo 300 IN A 12.12.12.12 +82 foo 300 IN A 13.13.13.13 +83 foo 300 IN A 14.14.14.14 +84 foo 300 IN A 2.3.4.5 +85 foo 300 IN A 3.4.5.6 +86 foo 300 IN A 4.5.6.7 +87 foo 300 IN A 8.8.8.8 +88 foo 300 IN AAAA 2003:dd:d7ff::fe71:aaaa +89 foo 300 IN CNAME dnscontroltest-cnr.com. +90 foo 300 IN CNAME google.com. +91 foo 300 IN CNAME google2.com. +92 foo 300 IN CNAME redact1.acm-validations.aws. +93 foo 300 IN MX 10 aspmx.l.google.com. +94 foo 300 IN MX 10 foo.dnscontroltest-cnr.com. +95 foo 300 IN MX 20 alt1.aspmx.l.google.com. +96 foo 300 IN MX 20 bar.dnscontroltest-cnr.com. +97 foo 300 IN MX 5 mx.google.com. +98 foo 300 IN MX 8 dnscontroltest-cnr.com. +99 foo 300 IN NS dnscontroltest-cnr.com. +100 foo 300 IN TXT "simple" +101 foo 300 IN TXT "v=spf1 ip4:99.99.99.99 -all" +102 foo.bat 300 IN A 1.2.3.4 +103 foo.bat 300 IN A 2.3.4.5 +104 foo.bat 300 IN TXT "simple" +105 foo254 300 IN TXT "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" +106 foo255 300 IN TXT "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" +107 foo256 300 IN TXT "CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC" "C" +108 foo509 300 IN TXT "DDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDD" "DDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDD" +109 foo510 300 IN TXT "EEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE" "EEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE" +110 foo511 300 IN TXT "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF" "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF" "F" +111 foo764 300 IN TXT "GGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGG" "GGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGG" "GGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGG" +112 foo765 300 IN TXT "HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH" "HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH" "HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH" +113 foo766 300 IN TXT "JJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJ" "JJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJ" "JJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJ" "J" +114 foobt 300 IN TXT "blah`blah" +115 fooosbs1 300 IN TXT "1back\\slash" +116 fooosbs2 300 IN TXT "2back\\\\slash" +117 fooosbs3 300 IN TXT "3back\\\\\\slash" +118 fooosbs4 300 IN TXT "4back\\\\\\\\slash" +119 foosc1 300 IN TXT "semi;colon" +120 foosc2 300 IN TXT "wssemi ; colon" +121 foosp 300 IN TXT "with spaces" +122 foosq 300 IN TXT "quo'te" +123 foows1 300 IN TXT "trailingws " +124 mail 300 IN CNAME ghs.googlehosted.com. +125 mail.bat 300 IN CNAME ghs.googlehosted.com. +126 nmx 300 IN A 1.2.3.3 +127 nmx 300 IN MX 0 . +128 nmx 300 IN MX 3 nmx.dnscontroltest-cnr.com. +129 nmx 300 IN MX 9 www.dnscontroltest-cnr.com. +130 test 300 IN DHCID AAAAAAAAuCccgoJbsaxcQc9TUapptP69lOjxfNuVAA2kjEA= +131 test 300 IN DHCID AAIBY2/AuCccgoJbsaxcQc9TUapptP69lOjxfNuVAA2kjEA= +132 test 300 IN DNAME example.com. +133 test 300 IN DNAME example.net. +134 test 300 IN NAPTR 100 10 "U" "E2U+sip" "!^.*$!sip:customer-service@example.com!" . +135 test 300 IN NAPTR 102 10 "U" "E2U+email" "!^.*$!mailto:information@example.com!" . +136 test 300 IN NAPTR 103 10 "U" "E2U+email" "!^.*$!mailto:information@example.com!" . +137 test 300 IN NAPTR 103 20 "A" "E2U+email" "!^.*$!mailto:information@example.com!" . +138 test 300 IN NAPTR 103 20 "A" "E2U+sip" "!^.*$!mailto:information@example.com!" . +139 test 300 IN NAPTR 103 20 "A" "E2U+sip" "!^.*$!sip:customer-service@example.com!" . +140 test 300 IN NAPTR 103 20 "A" "E2U+sip" "" example.foo.com. +141 test 300 IN NAPTR 103 20 "A" "E2U+sip" "" example2.foo.com. +142 test 300 IN NAPTR 103 20 "U" "E2U+email" "!^.*$!mailto:information@example.com!" . +143 testa 300 IN A 1.1.1.1 +144 testa 300 IN A 3.3.3.3 +145 testa 333 IN A 1.1.1.1 +146 testa 999 IN A 1.1.1.1 +147 testaaaa 300 IN AAAA 2607:f8b0:4006:820::2006 +148 testaaaa 300 IN AAAA 2607:f8b0:4006:820::2013 +149 testcname 300 IN CNAME foo.dnscontroltest-cnr.com. +150 testcname 300 IN CNAME www.google.com. +151 testcname 300 IN CNAME www.yahoo.com. +152 testdefined 300 IN A 2.2.2.2 +153 testdefined 300 IN A 9.9.9.9 +154 testignore 300 IN A 8.8.8.8 +155 testmx 300 IN MX 100 bar.com. +156 testmx 300 IN MX 100 foo.com. +157 testmx 300 IN MX 5 bar.com. +158 testmx 300 IN MX 5 foo.com. +159 testtxt 300 IN TXT "changed" +160 testtxt 300 IN TXT "simple" +161 www 300 IN A 1.1.1.1 +162 www 300 IN A 1.2.3.4 +163 www 300 IN A 1.2.3.8 +164 www 300 IN A 1.2.3.9 +165 www 300 IN A 2.2.2.2 +166 www 300 IN A 3.3.3.3 +167 www 300 IN A 5.5.5.5 +168 www 300 IN A 5.6.7.8 +169 www 400 IN A 2.2.2.2 +170 www 400 IN A 5.6.7.8 +171 www 700 IN A 1.2.3.4 +172 www 700 IN A 5.6.7.8 +173 xn--fiq228c 300 IN A 1.2.3.4 +174 xn--ndaaa 300 IN A 1.2.3.4 +175 xn--ndaaa 300 IN A 2.2.2.2 +176 xn--o-0gab 300 IN CNAME xn--ndaaa.xn--vhquv. +177 xyz 300 IN NS ns1.foo.com. +178 xyz 300 IN NS ns2.foo.com. +179 zzz 300 IN A 3.3.3.3 +180 zzz 300 IN A 4.4.4.4 +181 zzz 300 IN AAAA 2003:dd:d7ff::fe71:cccc diff --git a/providers/cscglobal/api.go b/providers/cscglobal/api.go index 8a4d5ea47f..d7d5c91fac 100644 --- a/providers/cscglobal/api.go +++ b/providers/cscglobal/api.go @@ -12,7 +12,7 @@ import ( "strings" "time" - "github.com/DNSControl/dnscontrol/v4/pkg/printer" + "github.com/DNSControl/dnscontrol/v5/pkg/printer" "github.com/mattn/go-isatty" ) diff --git a/providers/cscglobal/auditrecords.go b/providers/cscglobal/auditrecords.go index 1086d1e272..6a751d2819 100644 --- a/providers/cscglobal/auditrecords.go +++ b/providers/cscglobal/auditrecords.go @@ -1,14 +1,14 @@ package cscglobal import ( - "github.com/DNSControl/dnscontrol/v4/models" - "github.com/DNSControl/dnscontrol/v4/pkg/rejectif" + "github.com/DNSControl/dnscontrol/v5/models" + "github.com/DNSControl/dnscontrol/v5/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 { +func AuditRecords(records models.Records) []error { a := rejectif.Auditor{} a.Add("MX", rejectif.MxNull) // Last verified 2022-06-07 diff --git a/providers/cscglobal/convert.go b/providers/cscglobal/convert.go index 535ac14c04..1b6358369e 100644 --- a/providers/cscglobal/convert.go +++ b/providers/cscglobal/convert.go @@ -3,141 +3,53 @@ package cscglobal // Convert the provider's native record description to models.RecordConfig. import ( - "net/netip" - - "github.com/DNSControl/dnscontrol/v4/models" + dnsv2 "codeberg.org/miekg/dns" + "github.com/DNSControl/dnscontrol/v5/models" ) -// nativeToRecordA takes an A record from DNS and returns a native RecordConfig struct. -func nativeToRecordA(nr nativeRecordA, origin string, defaultTTL uint32) *models.RecordConfig { - ttl := nr.TTL +func recordTTL(ttl, defaultTTL uint32) uint32 { if ttl == 0 { - ttl = defaultTTL - } - rc := &models.RecordConfig{ - Type: "A", - TTL: ttl, + return defaultTTL } - rc.SetLabel(nr.Key, origin) - if err := rc.SetTargetIP(netip.MustParseAddr(nr.Value)); err != nil { - panic(err) // Should never happen. - } - return rc + return ttl +} + +// nativeToRecordA takes an A record from DNS and returns a native RecordConfig struct. +func nativeToRecordA(nr nativeRecordA, dc *models.DomainConfig, defaultTTL uint32) *models.RecordConfig { + return dc.MustNewRecordConfig(dc.LabelFromShort(nr.Key), recordTTL(nr.TTL, defaultTTL), dnsv2.TypeA, nr.Value) } // nativeToRecordCNAME takes a CNAME record from DNS and returns a native RecordConfig struct. -func nativeToRecordCNAME(nr nativeRecordCNAME, origin string, defaultTTL uint32) *models.RecordConfig { - ttl := nr.TTL - if ttl == 0 { - ttl = defaultTTL - } - rc := &models.RecordConfig{ - Type: "CNAME", - TTL: ttl, - } - rc.SetLabel(nr.Key, origin) - if err := rc.SetTarget(nr.Value); err != nil { - panic(err) // Should never happen. - } - return rc +func nativeToRecordCNAME(nr nativeRecordCNAME, dc *models.DomainConfig, defaultTTL uint32) *models.RecordConfig { + return dc.MustNewRecordConfig(dc.LabelFromShort(nr.Key), recordTTL(nr.TTL, defaultTTL), dnsv2.TypeCNAME, nr.Value) } // nativeToRecordAAAA takes an AAAA record from DNS and returns a native RecordConfig struct. -func nativeToRecordAAAA(nr nativeRecordAAAA, origin string, defaultTTL uint32) *models.RecordConfig { - ttl := nr.TTL - if ttl == 0 { - ttl = defaultTTL - } - rc := &models.RecordConfig{ - Type: "AAAA", - TTL: ttl, - } - rc.SetLabel(nr.Key, origin) - if err := rc.SetTargetIP(netip.MustParseAddr(nr.Value)); err != nil { - panic(err) // Should never happen. - } - return rc +func nativeToRecordAAAA(nr nativeRecordAAAA, dc *models.DomainConfig, defaultTTL uint32) *models.RecordConfig { + return dc.MustNewRecordConfig(dc.LabelFromShort(nr.Key), recordTTL(nr.TTL, defaultTTL), dnsv2.TypeAAAA, nr.Value) } // nativeToRecordTXT takes a TXT record from DNS and returns a native RecordConfig struct. -func nativeToRecordTXT(nr nativeRecordTXT, origin string, defaultTTL uint32) *models.RecordConfig { - ttl := nr.TTL - if ttl == 0 { - ttl = defaultTTL - } - rc := &models.RecordConfig{ - Type: "TXT", - TTL: ttl, - } - rc.SetLabel(nr.Key, origin) - if err := rc.SetTargetTXT(nr.Value); err != nil { - panic(err) // Should never happen. - } - return rc +func nativeToRecordTXT(nr nativeRecordTXT, dc *models.DomainConfig, defaultTTL uint32) *models.RecordConfig { + return dc.MustNewRecordConfig(dc.LabelFromShort(nr.Key), recordTTL(nr.TTL, defaultTTL), dnsv2.TypeTXT, nr.Value) } -// nativeToRecordMX takes a MX record from DNS and returns a native RecordConfig struct. -func nativeToRecordMX(nr nativeRecordMX, origin string, defaultTTL uint32) *models.RecordConfig { - ttl := nr.TTL - if ttl == 0 { - ttl = defaultTTL - } - rc := &models.RecordConfig{ - Type: "MX", - TTL: ttl, - } - rc.SetLabel(nr.Key, origin) - if err := rc.SetTargetMX(nr.Priority, nr.Value); err != nil { - panic(err) // Should never happen. - } - return rc +// nativeToRecordMX takes an MX record from DNS and returns a native RecordConfig struct. +func nativeToRecordMX(nr nativeRecordMX, dc *models.DomainConfig, defaultTTL uint32) *models.RecordConfig { + return dc.MustNewRecordConfig(dc.LabelFromShort(nr.Key), recordTTL(nr.TTL, defaultTTL), dnsv2.TypeMX, nr.Priority, nr.Value) } // nativeToRecordNS takes a NS record from DNS and returns a native RecordConfig struct. -func nativeToRecordNS(nr nativeRecordNS, origin string, defaultTTL uint32) *models.RecordConfig { - ttl := nr.TTL - if ttl == 0 { - ttl = defaultTTL - } - rc := &models.RecordConfig{ - Type: "NS", - TTL: ttl, - } - rc.SetLabel(nr.Key, origin) - rc.MustSetTarget(nr.Value) - return rc +func nativeToRecordNS(nr nativeRecordNS, dc *models.DomainConfig, defaultTTL uint32) *models.RecordConfig { + return dc.MustNewRecordConfig(dc.LabelFromShort(nr.Key), recordTTL(nr.TTL, defaultTTL), dnsv2.TypeNS, nr.Value) } // nativeToRecordSRV takes a SRV record from DNS and returns a native RecordConfig struct. -func nativeToRecordSRV(nr nativeRecordSRV, origin string, defaultTTL uint32) *models.RecordConfig { - ttl := nr.TTL - if ttl == 0 { - ttl = defaultTTL - } - rc := &models.RecordConfig{ - Type: "SRV", - TTL: ttl, - } - rc.SetLabel(nr.Key, origin) - if err := rc.SetTargetSRV(nr.Priority, nr.Weight, nr.Port, nr.Value); err != nil { - panic(err) // Should never happen. - } - return rc +func nativeToRecordSRV(nr nativeRecordSRV, dc *models.DomainConfig, defaultTTL uint32) *models.RecordConfig { + return dc.MustNewRecordConfig(dc.LabelFromShort(nr.Key), recordTTL(nr.TTL, defaultTTL), dnsv2.TypeSRV, nr.Priority, nr.Weight, nr.Port, nr.Value) } // nativeToRecordCAA takes a CAA record from DNS and returns a native RecordConfig struct. -func nativeToRecordCAA(nr nativeRecordCAA, origin string, defaultTTL uint32) *models.RecordConfig { - ttl := nr.TTL - if ttl == 0 { - ttl = defaultTTL - } - rc := &models.RecordConfig{ - Type: "CAA", - TTL: ttl, - } - rc.SetLabel(nr.Key, origin) - if err := rc.SetTargetCAA(nr.Flag, nr.Tag, nr.Value); err != nil { - panic(err) // Should never happen. - } - return rc +func nativeToRecordCAA(nr nativeRecordCAA, dc *models.DomainConfig, defaultTTL uint32) *models.RecordConfig { + return dc.MustNewRecordConfig(dc.LabelFromShort(nr.Key), recordTTL(nr.TTL, defaultTTL), dnsv2.TypeCAA, nr.Flag, nr.Tag, nr.Value) } diff --git a/providers/cscglobal/convert_test.go b/providers/cscglobal/convert_test.go new file mode 100644 index 0000000000..4f7beb5eb0 --- /dev/null +++ b/providers/cscglobal/convert_test.go @@ -0,0 +1,25 @@ +package cscglobal + +import ( + "testing" + + "github.com/DNSControl/dnscontrol/v5/models" +) + +func TestNativeRecordConversion(t *testing.T) { + t.Parallel() + + dc := models.MustNewDomainConfig("example.com") + a := nativeToRecordA(nativeRecordA{Key: "www", Value: "192.0.2.1"}, dc, 600) + if a.TTL != 600 || a.GetRDATA().String() != "192.0.2.1" { + t.Errorf("unexpected A conversion: TTL=%d RDATA=%q", a.TTL, a.GetRDATA().String()) + } + + srv := nativeToRecordSRV(nativeRecordSRV{ + Key: "_sip._tcp", Value: "service.example.net.", TTL: 300, + Priority: 1, Weight: 2, Port: 443, + }, dc, 600) + if got := srv.GetRDATA().String(); got != "1 2 443 service.example.net." { + t.Errorf("unexpected SRV conversion: %q", got) + } +} diff --git a/providers/cscglobal/cscglobalProvider.go b/providers/cscglobal/cscglobalProvider.go index c870c5ad1a..7328e1ef1a 100644 --- a/providers/cscglobal/cscglobalProvider.go +++ b/providers/cscglobal/cscglobalProvider.go @@ -5,7 +5,7 @@ import ( "errors" "strings" - "github.com/DNSControl/dnscontrol/v4/pkg/providers" + "github.com/DNSControl/dnscontrol/v5/pkg/providers" ) /* diff --git a/providers/cscglobal/dns.go b/providers/cscglobal/dns.go index 670dd9be4b..3703c6d006 100644 --- a/providers/cscglobal/dns.go +++ b/providers/cscglobal/dns.go @@ -1,10 +1,12 @@ package cscglobal import ( + "fmt" "strings" - "github.com/DNSControl/dnscontrol/v4/models" - "github.com/DNSControl/dnscontrol/v4/pkg/diff" + dnsv2 "codeberg.org/miekg/dns" + "github.com/DNSControl/dnscontrol/v5/models" + "github.com/DNSControl/dnscontrol/v5/pkg/diff2" ) // GetZoneRecords gets the records of a zone and returns them in RecordConfig format. @@ -18,51 +20,32 @@ func (client *providerClient) GetZoneRecords(dc *models.DomainConfig) (models.Re // Convert them to DNScontrol's native format: - existingRecords := []*models.RecordConfig{} - - // Option 1: One long list. If your provider returns one long list, - // convert each one to RecordType like this: - // for _, rr := range records { - // existingRecords = append(existingRecords, nativeToRecord(rr, domain)) - //} - - // Option 2: Grouped records. Sometimes the provider returns one item per - // label. Each item contains a list of all the records at that label. - // You'll need to split them out into one RecordConfig for each record. An - // example of this is the ROUTE53 provider. - // for _, rg := range records { - // for _, rr := range rg { - // existingRecords = append(existingRecords, nativeToRecords(rg, rr, domain)...) - // } - // } - - // Option 3: Something else. In this case, we get a big massive structure - // which needs to be broken up. Still, we're generating a list of - // RecordConfig structures. + existingRecords := models.Records{} + defaultTTL := records.Soa.TTL for _, rr := range records.A { - existingRecords = append(existingRecords, nativeToRecordA(rr, domain, defaultTTL)) + existingRecords = append(existingRecords, nativeToRecordA(rr, dc, defaultTTL)) } for _, rr := range records.Cname { - existingRecords = append(existingRecords, nativeToRecordCNAME(rr, domain, defaultTTL)) + existingRecords = append(existingRecords, nativeToRecordCNAME(rr, dc, defaultTTL)) } for _, rr := range records.Aaaa { - existingRecords = append(existingRecords, nativeToRecordAAAA(rr, domain, defaultTTL)) + existingRecords = append(existingRecords, nativeToRecordAAAA(rr, dc, defaultTTL)) } for _, rr := range records.Txt { - existingRecords = append(existingRecords, nativeToRecordTXT(rr, domain, defaultTTL)) + existingRecords = append(existingRecords, nativeToRecordTXT(rr, dc, defaultTTL)) } for _, rr := range records.Mx { - existingRecords = append(existingRecords, nativeToRecordMX(rr, domain, defaultTTL)) + existingRecords = append(existingRecords, nativeToRecordMX(rr, dc, defaultTTL)) } for _, rr := range records.Ns { - existingRecords = append(existingRecords, nativeToRecordNS(rr, domain, defaultTTL)) + existingRecords = append(existingRecords, nativeToRecordNS(rr, dc, defaultTTL)) } for _, rr := range records.Srv { - existingRecords = append(existingRecords, nativeToRecordSRV(rr, domain, defaultTTL)) + existingRecords = append(existingRecords, nativeToRecordSRV(rr, dc, defaultTTL)) } for _, rr := range records.Caa { - existingRecords = append(existingRecords, nativeToRecordCAA(rr, domain, defaultTTL)) + existingRecords = append(existingRecords, nativeToRecordCAA(rr, dc, defaultTTL)) } return existingRecords, nil @@ -78,12 +61,27 @@ func (client *providerClient) GetNameservers(domain string) ([]*models.Nameserve // GetZoneRecordsCorrections returns a list of corrections that will turn existing records into dc.Records. func (client *providerClient) GetZoneRecordsCorrections(dc *models.DomainConfig, foundRecords models.Records) ([]*models.Correction, int, error) { - toReport, creates, dels, modifications, actualChangeCount, err := diff.NewCompat(dc).IncrementalDiff(foundRecords) + changes, actualChangeCount, err := diff2.ByRecord(foundRecords, dc, nil) if err != nil { return nil, 0, err } - // Start corrections with the reports - corrections := diff.GenerateMessageCorrections(toReport) + + var corrections []*models.Correction + var creates, dels, modifications diff2.ChangeList + for _, change := range changes { + switch change.Type { + case diff2.REPORT: + corrections = append(corrections, &models.Correction{Msg: change.MsgsJoined}) + case diff2.CREATE: + creates = append(creates, change) + case diff2.DELETE: + dels = append(dels, change) + case diff2.CHANGE: + modifications = append(modifications, change) + default: + panic(fmt.Sprintf("unhandled change.Type %s", change.Type)) + } + } // CSCGlobal has a unique API. A list of edits is sent in one API // call. Edits aren't permitted if an existing edit is being @@ -93,16 +91,16 @@ func (client *providerClient) GetZoneRecordsCorrections(dc *models.DomainConfig, var edits []zoneResourceRecordEdit var descriptions []string for _, del := range dels { - edits = append(edits, makePurge(del)) - descriptions = append(descriptions, del.String()) + edits = append(edits, makePurge(del.Old[0])) + descriptions = append(descriptions, del.MsgsJoined) } for _, cre := range creates { - edits = append(edits, makeAdd(cre)) - descriptions = append(descriptions, cre.String()) + edits = append(edits, makeAdd(cre.New[0])) + descriptions = append(descriptions, cre.MsgsJoined) } for _, m := range modifications { - edits = append(edits, makeEdit(m)) - descriptions = append(descriptions, m.String()) + edits = append(edits, makeEdit(m.Old[0], m.New[0])) + descriptions = append(descriptions, m.MsgsJoined) } if len(edits) > 0 { c := &models.Correction{ @@ -127,25 +125,25 @@ func (client *providerClient) GetZoneRecordsCorrections(dc *models.DomainConfig, return corrections, actualChangeCount, nil } -func makePurge(cor diff.Correlation) zoneResourceRecordEdit { +func makePurge(existing *models.RecordConfig) zoneResourceRecordEdit { var existingTarget string - switch cor.Existing.Type { - case "TXT": - existingTarget = cor.Existing.GetTargetTXTJoined() + switch existing.TypeNum { + case dnsv2.TypeTXT: + existingTarget = existing.GetTargetTXTJoined() default: - existingTarget = cor.Existing.GetTargetField() + existingTarget = existing.GetRDATA().String() } zer := zoneResourceRecordEdit{ Action: "PURGE", - RecordType: cor.Existing.Type, - CurrentKey: cor.Existing.Name, + RecordType: existing.Type, + CurrentKey: existing.Name, CurrentValue: existingTarget, } - if cor.Existing.Type == "CAA" { - tagValue := cor.Existing.CaaTag + if existing.Type == "CAA" { + tagValue := existing.AsCAA().Tag // printer.Printf("DEBUG: CAA TAG = %q\n", tagValue) zer.CurrentTag = &tagValue } @@ -153,59 +151,58 @@ func makePurge(cor diff.Correlation) zoneResourceRecordEdit { return zer } -func makeAdd(cre diff.Correlation) zoneResourceRecordEdit { - rec := cre.Desired - - var recTarget string - switch rec.Type { - case "TXT": - recTarget = rec.GetTargetTXTJoined() - default: - recTarget = rec.GetTargetField() - } +func makeAdd(rec *models.RecordConfig) zoneResourceRecordEdit { zer := zoneResourceRecordEdit{ Action: "ADD", RecordType: rec.Type, NewKey: rec.Name, - NewValue: recTarget, NewTTL: rec.TTL, } - switch rec.Type { - case "CAA": - tagValue := rec.CaaTag - flagValue := rec.CaaFlag + switch rec.TypeNum { + case dnsv2.TypeCAA: + f := rec.AsCAA() + tagValue := f.Tag + flagValue := f.Flag zer.NewTag = &tagValue zer.NewFlag = &flagValue - case "MX": - zer.NewPriority = rec.MxPreference - case "SRV": - zer.NewPriority = rec.SrvPriority - zer.NewWeight = rec.SrvWeight - zer.NewPort = rec.SrvPort - case "TXT": + zer.NewValue = f.Value + case dnsv2.TypeMX: + f := rec.AsMX() + zer.NewPriority = f.Preference + zer.NewValue = f.Mx + case dnsv2.TypeSRV: + f := rec.AsSRV() + zer.NewPriority = f.Priority + zer.NewWeight = f.Weight + zer.NewPort = f.Port + zer.NewValue = f.Target + case dnsv2.TypeTXT: zer.NewValue = rec.GetTargetTXTJoined() - default: // "A", "CNAME", "NS" - // Nothing to do. + default: + zer.NewValue = rec.GetRDATA().String() } return zer } -func makeEdit(m diff.Correlation) zoneResourceRecordEdit { - old, rec := m.Existing, m.Desired - // TODO: Assert that old.Type == rec.Type - // TODO: Assert that old.Name == rec.Name +func makeEdit(old, rec *models.RecordConfig) zoneResourceRecordEdit { + if old.Type != rec.Type { + panic(fmt.Sprintf("record type mismatch: %q != %q", old.Type, rec.Type)) + } + if old.Name != rec.Name { + panic(fmt.Sprintf("record name mismatch: %q != %q", old.Name, rec.Name)) + } var oldTarget, recTarget string - switch old.Type { - case "TXT": + switch old.TypeNum { + case dnsv2.TypeTXT: oldTarget = old.GetTargetTXTJoined() recTarget = rec.GetTargetTXTJoined() default: - oldTarget = old.GetTargetField() - recTarget = rec.GetTargetField() + oldTarget = old.GetRDATA().String() + recTarget = rec.GetRDATA().String() } zer := zoneResourceRecordEdit{ @@ -221,24 +218,27 @@ func makeEdit(m diff.Correlation) zoneResourceRecordEdit { zer.NewTTL = rec.TTL } - switch old.Type { - case "CAA": - tagValue := old.CaaTag + switch old.TypeNum { + case dnsv2.TypeCAA: + of := old.AsCAA() + tagValue := of.Tag zer.CurrentTag = &tagValue - if old.CaaTag != rec.CaaTag || old.CaaFlag != rec.CaaFlag || old.TTL != rec.TTL { + if old.AsCAA().Tag != rec.AsCAA().Tag || old.AsCAA().Flag != rec.AsCAA().Flag || old.TTL != rec.TTL { // If anything changed, we need to update both tag and flag. - zer.NewTag = &(rec.CaaTag) - zer.NewFlag = &(rec.CaaFlag) + zer.NewFlag = new(rec.AsCAA().Flag) + zer.NewTag = new(rec.AsCAA().Tag) + zer.NewFlag = new(rec.AsCAA().Flag) } - case "MX": - if old.MxPreference != rec.MxPreference { - zer.NewPriority = rec.MxPreference + case dnsv2.TypeMX: + if old.AsMX().Preference != rec.AsMX().Preference { + zer.NewPriority = rec.AsMX().Preference } - case "SRV": - zer.NewWeight = rec.SrvWeight - zer.NewPort = rec.SrvPort - zer.NewPriority = rec.SrvPriority - default: // "A", "CNAME", "NS", "TXT" + case dnsv2.TypeSRV: + f := rec.AsSRV() + zer.NewWeight = f.Weight + zer.NewPort = f.Port + zer.NewPriority = f.Priority + default: // Nothing to do. } diff --git a/providers/cscglobal/registrar.go b/providers/cscglobal/registrar.go index 8760938efb..a6908af12d 100644 --- a/providers/cscglobal/registrar.go +++ b/providers/cscglobal/registrar.go @@ -6,7 +6,7 @@ import ( "sort" "strings" - "github.com/DNSControl/dnscontrol/v4/models" + "github.com/DNSControl/dnscontrol/v5/models" ) // GetRegistrarCorrections gathers corrections that would bring n to match dc. diff --git a/providers/desec/auditrecords.go b/providers/desec/auditrecords.go index a707189a1e..474d3a164a 100644 --- a/providers/desec/auditrecords.go +++ b/providers/desec/auditrecords.go @@ -1,10 +1,17 @@ package desec -import "github.com/DNSControl/dnscontrol/v4/models" +import ( + "github.com/DNSControl/dnscontrol/v5/models" + "github.com/DNSControl/dnscontrol/v5/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 +func AuditRecords(records models.Records) []error { + a := rejectif.Auditor{} + + a.Add("DNSKEY", rejectif.DnskeyNotAtApex) // Last verified 2026-08-04 + + return a.Audit(records) } diff --git a/providers/desec/convert.go b/providers/desec/convert.go index 59549f7f5e..b28ab14f27 100644 --- a/providers/desec/convert.go +++ b/providers/desec/convert.go @@ -5,37 +5,33 @@ package desec import ( "fmt" - "github.com/DNSControl/dnscontrol/v4/models" - "github.com/DNSControl/dnscontrol/v4/pkg/printer" - dnsutilv1 "github.com/miekg/dns/dnsutil" + "github.com/DNSControl/dnscontrol/v5/models" + "github.com/DNSControl/dnscontrol/v5/pkg/printer" ) // nativeToRecord takes a DNS record from deSEC and returns a native RecordConfig struct. -func nativeToRecords(n resourceRecord, origin string) (rcs []*models.RecordConfig) { +func nativeToRecords(n resourceRecord, dc *models.DomainConfig) (rcs models.Records) { // deSEC returns all the values for a given label/rtype pair in each // resourceRecord. In other words, if there are multiple A // records for a label, all the IP addresses are listed in // n.Records rather than having many resourceRecord's. // We must split them out into individual records, one for each value. for _, value := range n.Records { - rc := &models.RecordConfig{ - TTL: n.TTL, - Original: n, - } - rc.SetLabel(n.Subname, origin) - switch rtype := n.Type; rtype { - default: // "A", "AAAA", "CAA", "NS", "CNAME", "MX", "PTR", "SRV", "TXT" - if err := rc.PopulateFromString(rtype, value, origin); err != nil { - panic(fmt.Errorf("unparsable record received from deSEC: %w", err)) - } + label := dc.LabelFromShort(n.Subname) + ttl := n.TTL + + rc, err := dc.NewRecordConfigParse(label, ttl, n.Type, value) + if err != nil { + panic(fmt.Errorf("unparsable record received from deSEC: %w", err)) } + rc.Original = n rcs = append(rcs, rc) } return rcs } -func recordsToNative(rcs []*models.RecordConfig, origin string) []resourceRecord { +func recordsToNative(rcs models.Records) []resourceRecord { // Take a list of RecordConfig and return an equivalent list of resourceRecord. // deSEC requires one resourceRecord for each label:key tuple, therefore we // might collapse many RecordConfig into one resourceRecord. @@ -43,7 +39,8 @@ func recordsToNative(rcs []*models.RecordConfig, origin string) []resourceRecord keys := map[models.RecordKey]*resourceRecord{} var zrs []resourceRecord for _, r := range rcs { - label := dnsutilv1.TrimDomainName(r.GetLabel(), origin) + // label := dnsutilv1.Trim DomainName(r.GetLabel(), origin) + label := r.Name if label == "@" { label = "" } @@ -55,11 +52,11 @@ func recordsToNative(rcs []*models.RecordConfig, origin string) []resourceRecord Type: r.Type, TTL: r.TTL, Subname: label, - Records: []string{r.GetTargetCombined()}, + Records: []string{r.GetRDATA().String()}, } keys[key] = &zr } else { - zr.Records = append(zr.Records, r.GetTargetCombined()) + zr.Records = append(zr.Records, r.GetRDATA().String()) if r.TTL != zr.TTL { printer.Warnf("All TTLs for a rrset (%v) must be the same. Using smaller of %v and %v.\n", key, r.TTL, zr.TTL) diff --git a/providers/desec/convert_test.go b/providers/desec/convert_test.go new file mode 100644 index 0000000000..6b39141c7f --- /dev/null +++ b/providers/desec/convert_test.go @@ -0,0 +1,71 @@ +package desec + +import ( + "reflect" + "testing" + + dnsrdatav2 "codeberg.org/miekg/dns/rdata" + "github.com/DNSControl/dnscontrol/v5/models" +) + +func TestNativeToRecords(t *testing.T) { + dc, err := models.NewDomainConfig("example.com") + if err != nil { + t.Fatal(err) + } + + native := resourceRecord{ + Subname: "www", + Records: []string{"192.0.2.1", "192.0.2.2"}, + TTL: 300, + Type: "A", + } + records := nativeToRecords(native, dc) + if len(records) != 2 { + t.Fatalf("got %d records, want 2", len(records)) + } + for i, want := range native.Records { + if got := records[i].GetRDATA().String(); got != want { + t.Errorf("record %d target = %q, want %q", i, got, want) + } + if got := records[i].GetLabel(); got != "www" { + t.Errorf("record %d label = %q, want %q", i, got, "www") + } + if !reflect.DeepEqual(records[i].Original, native) { + t.Errorf("record %d did not retain its original value", i) + } + } +} + +func TestNativeToRecordsPreservesRawTXT(t *testing.T) { + dc, err := models.NewDomainConfig("example.com") + if err != nil { + t.Fatal(err) + } + + records := nativeToRecords(resourceRecord{ + Subname: "@", + Records: []string{`\"quoted\" text`}, + TTL: 300, + Type: "TXT", + }, dc) + if got, want := models.TXTJoined(records[0].GetRDATA().(dnsrdatav2.TXT)), `"quoted" text`; got != want { + t.Errorf("TXT target = %q, want %q", got, want) + } +} + +func TestRecordsToNativeUsesShortLabel(t *testing.T) { + dc, err := models.NewDomainConfig("example.com") + if err != nil { + t.Fatal(err) + } + record := dc.MustNewRecordConfigParse("www", 300, "A", "192.0.2.1") + + native := recordsToNative(models.Records{record}) + if len(native) != 1 { + t.Fatalf("got %d records, want 1", len(native)) + } + if got, want := native[0].Subname, "www"; got != want { + t.Errorf("subname = %q, want %q", got, want) + } +} diff --git a/providers/desec/desecProvider.go b/providers/desec/desecProvider.go index 00eb7bbda6..c8c8c65c8f 100644 --- a/providers/desec/desecProvider.go +++ b/providers/desec/desecProvider.go @@ -7,12 +7,10 @@ import ( "fmt" "strings" - "github.com/DNSControl/dnscontrol/v4/models" - "github.com/DNSControl/dnscontrol/v4/pkg/diff" - "github.com/DNSControl/dnscontrol/v4/pkg/printer" - "github.com/DNSControl/dnscontrol/v4/pkg/providers" - dnsutilv1 "github.com/miekg/dns/dnsutil" - "golang.org/x/net/idna" + "github.com/DNSControl/dnscontrol/v5/models" + "github.com/DNSControl/dnscontrol/v5/pkg/diff2" + "github.com/DNSControl/dnscontrol/v5/pkg/printer" + "github.com/DNSControl/dnscontrol/v5/pkg/providers" ) /* @@ -41,7 +39,8 @@ var features = providers.DocumentationNotes{ providers.CanUseAlias: providers.Unimplemented("Apex aliasing is supported via new SVCB and HTTPS record types. For details, check the deSEC docs."), providers.CanUseCAA: providers.Can(), providers.CanUseDNSKEY: providers.Can(), - providers.CanUseDS: providers.Can(), + providers.CanUseDS: providers.Cannot(), + providers.CanUseDSForChildren: providers.Can(), providers.CanUseHTTPS: providers.Can(), providers.CanUseLOC: providers.Can(), providers.CanUseNAPTR: providers.Can(), @@ -95,23 +94,16 @@ func (c *desecProvider) GetNameservers(domain string) ([]*models.Nameserver, err // GetZoneRecords gets the records of a zone and returns them in RecordConfig format. func (c *desecProvider) GetZoneRecords(dc *models.DomainConfig) (models.Records, error) { - domain := dc.Name - - punycodeDomain, err := idna.ToASCII(domain) - if err != nil { - return nil, err - } - - records, err := c.getRecords(punycodeDomain) + records, err := c.getRecords(dc.Name) if err != nil { return nil, err } // Convert them to DNScontrol's native format: - existingRecords := []*models.RecordConfig{} + existingRecords := models.Records{} // spew.Dump(records) for _, rr := range records { - existingRecords = append(existingRecords, nativeToRecords(rr, punycodeDomain)...) + existingRecords = append(existingRecords, nativeToRecords(rr, dc)...) } return existingRecords, nil @@ -139,8 +131,16 @@ func PrepDesiredRecords(dc *models.DomainConfig, minTTL uint32) { // provider. We try to do minimal changes otherwise it gets // confusing. - // dc.Punycode() - recordsToKeep := make([]*models.RecordConfig, 0, len(dc.Records)) + // TODO(tlim): We shouldn't modify rec's because if the same rec is used + // for another provider, there will be confusion. Right now we use a + // little memory by making a copy of every record for each provider, but + // we'd like to not do that in the future. + // If possible, it would be better to eliminate this function + // and instead: + // * ALIAS: Skip them in recordsToNative() + // * minTTL: recordsToNative() should return records with fixed TTLs. + + recordsToKeep := make(models.Records, 0, len(dc.Records)) for _, rec := range dc.Records { if rec.Type == "ALIAS" { // deSEC does not permit ALIAS records, just ignore it @@ -160,12 +160,7 @@ 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, int, error) { - punycodeName, err := idna.ToASCII(dc.Name) - if err != nil { - return nil, 0, err - } - - minTTL, ok, err := c.searchDomainIndex(punycodeName) + minTTL, ok, err := c.searchDomainIndex(dc.Name) if err != nil { return nil, 0, err } @@ -175,58 +170,51 @@ func (c *desecProvider) GetZoneRecordsCorrections(dc *models.DomainConfig, exist PrepDesiredRecords(dc, minTTL) - keysToUpdate, toReport, actualChangeCount, err := diff.NewCompat(dc).ChangedGroups(existing) + changes, actualChangeCount, err := diff2.ByRecordSet(existing, dc, nil) if err != nil { return nil, 0, err } - // Start corrections with the reports - corrections := diff.GenerateMessageCorrections(toReport) - - if len(corrections) == 0 && len(keysToUpdate) == 0 { - return nil, 0, nil - } - desiredRecords := dc.Records.GroupedByKey() + var corrections []*models.Correction var rrs []resourceRecord buf := &bytes.Buffer{} - // For any key with an update, delete or replace those records. - for label := range keysToUpdate { - if _, ok := desiredRecords[label]; !ok { - // we could not find this RecordKey in the desiredRecords - // this means it must be deleted - for i, msg := range keysToUpdate[label] { - if i == 0 { - rc := resourceRecord{} - rc.Type = label.Type - rc.Records = make([]string, 0) // empty array of records should delete this rrset - rc.TTL = 3600 - shortname := dnsutilv1.TrimDomainName(label.NameFQDN, punycodeName) - if shortname == "@" { - shortname = "" - } - rc.Subname = shortname - fmt.Fprintln(buf, msg) - rrs = append(rrs, rc) - } else { - // just add the message - fmt.Fprintln(buf, msg) - } + // For any rrset with an update, delete or replace those records. deSEC's + // API is rrset-oriented: a single upsert call replaces the whole rrset (an + // empty record list deletes it). + for _, change := range changes { + switch change.Type { + case diff2.REPORT: + corrections = append(corrections, &models.Correction{Msg: change.MsgsJoined}) + + case diff2.DELETE: + // An empty array of records deletes this rrset. + rc := resourceRecord{ + Type: change.Key.Type, + Records: make([]string, 0), + TTL: 3600} + shortname := dc.ToShort(change.Key.NameFQDN) + if shortname == "@" { + shortname = "" + } + rc.Subname = shortname + rrs = append(rrs, rc) + for _, msg := range change.Msgs { + fmt.Fprintln(buf, msg) } - } else { - // it must be an update or create, both can be done with the same api call. - ns := recordsToNative(desiredRecords[label], punycodeName) + + case diff2.CREATE, diff2.CHANGE: + // A create or update are both done with the same api call. + ns := recordsToNative(change.New) if len(ns) > 1 { panic("we got more than one resource record to create / modify") } - for i, msg := range keysToUpdate[label] { - if i == 0 { - rrs = append(rrs, ns[0]) - fmt.Fprintln(buf, msg) - } else { - // noop just for printing the additional messages - fmt.Fprintln(buf, msg) - } + rrs = append(rrs, ns[0]) + for _, msg := range change.Msgs { + fmt.Fprintln(buf, msg) } + + default: + panic(fmt.Sprintf("unhandled change.Type %s", change.Type)) } } @@ -238,7 +226,7 @@ func (c *desecProvider) GetZoneRecordsCorrections(dc *models.DomainConfig, exist Msg: msg, F: func() error { rc := rrs - err := c.upsertRR(rc, punycodeName) + err := c.upsertRR(rc, dc.Name) if err != nil { return err } diff --git a/providers/desec/protocol.go b/providers/desec/protocol.go index ede39c2862..90b7db00ea 100644 --- a/providers/desec/protocol.go +++ b/providers/desec/protocol.go @@ -13,7 +13,7 @@ import ( "sync" "time" - "github.com/DNSControl/dnscontrol/v4/pkg/printer" + "github.com/DNSControl/dnscontrol/v5/pkg/printer" ) const apiBase = "https://desec.io/api/v1" @@ -160,6 +160,9 @@ func appendDomainIndexFromResponse(domainIndex map[string]uint32, bodyString []b } // Parses the Link Header into a map (https://github.com/desec-io/desec-tools/blob/main/fetch_zone.py#L13) +// linkRelRe extracts the rel="..." parameter from an HTTP Link header. +var linkRelRe = regexp.MustCompile(`rel="(.*)"`) + func convertLinks(links string) map[string]string { mapping := make(map[string]string) printer.Debugf("Header: %s\n", links) @@ -169,8 +172,7 @@ func convertLinks(links string) map[string]string { printer.Printf("unexpected link header %s", link) continue } - r := regexp.MustCompile(`rel="(.*)"`) - matches := r.FindStringSubmatch(tmpurl[1]) + matches := linkRelRe.FindStringSubmatch(tmpurl[1]) if len(matches) != 2 { printer.Printf("unexpected label %s", tmpurl[1]) continue diff --git a/providers/digitalocean/auditrecords.go b/providers/digitalocean/auditrecords.go index 79c1aafbaa..40b975b282 100644 --- a/providers/digitalocean/auditrecords.go +++ b/providers/digitalocean/auditrecords.go @@ -3,14 +3,14 @@ package digitalocean import ( "errors" - "github.com/DNSControl/dnscontrol/v4/models" - "github.com/DNSControl/dnscontrol/v4/pkg/rejectif" + "github.com/DNSControl/dnscontrol/v5/models" + "github.com/DNSControl/dnscontrol/v5/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 { +func AuditRecords(records models.Records) []error { a := rejectif.Auditor{} a.Add("CAA", rejectif.CaaTargetContainsWhitespace) // Last verified xxxx-xx-xx @@ -44,7 +44,7 @@ func MaxLengthDO(rc *models.RecordConfig) error { // In other words, they're doing the checking on the API protocol // encoded data instead of on the resulting TXT record. Sigh. - if len(rc.GetTargetRFC1035Quoted()) > 509 { + if len(rc.GetRDATA().String()) > 509 { return errors.New("encoded txt too long") } diff --git a/providers/digitalocean/convert_golden_test.go b/providers/digitalocean/convert_golden_test.go new file mode 100644 index 0000000000..b1f7c922be --- /dev/null +++ b/providers/digitalocean/convert_golden_test.go @@ -0,0 +1,24 @@ +package digitalocean + +import ( + "testing" + + "github.com/DNSControl/dnscontrol/v5/models" + "github.com/DNSControl/dnscontrol/v5/pkg/providergolden" + "github.com/digitalocean/godo" +) + +func TestToRcGolden(t *testing.T) { + providergolden.CheckToRC(t, "toRc", + func(dc *models.DomainConfig, native godo.DomainRecord) (models.Records, error) { + rc, err := toRc(dc, &native) + return models.Records{rc}, err + }) +} + +func TestToReqGolden(t *testing.T) { + providergolden.CheckToNative(t, "toReq", + func(_ *models.DomainConfig, records models.Records) (*godo.DomainRecordEditRequest, error) { + return toReq(records[0]), nil + }) +} diff --git a/providers/digitalocean/digitaloceanProvider.go b/providers/digitalocean/digitaloceanProvider.go index a6791f2394..13d4f9137a 100644 --- a/providers/digitalocean/digitaloceanProvider.go +++ b/providers/digitalocean/digitaloceanProvider.go @@ -9,11 +9,13 @@ import ( "net/http" "time" - "github.com/DNSControl/dnscontrol/v4/models" - "github.com/DNSControl/dnscontrol/v4/pkg/diff2" - "github.com/DNSControl/dnscontrol/v4/pkg/providers" + dnsv2 "codeberg.org/miekg/dns" + dnsrdatav2 "codeberg.org/miekg/dns/rdata" + "github.com/DNSControl/dnscontrol/v5/models" + "github.com/DNSControl/dnscontrol/v5/pkg/diff2" + "github.com/DNSControl/dnscontrol/v5/pkg/nrc" + "github.com/DNSControl/dnscontrol/v5/pkg/providers" "github.com/digitalocean/godo" - dnsutilv1 "github.com/miekg/dns/dnsutil" "golang.org/x/oauth2" ) @@ -28,7 +30,12 @@ Info required in `creds.json`: // digitaloceanProvider is the handle for operations. type digitaloceanProvider struct { - client *godo.Client + observer providers.ConversionObserver + client *godo.Client +} + +func (api *digitaloceanProvider) SetConversionObserver(observer providers.ConversionObserver) { + api.observer = observer } var defaultNameServerNames = []string{ @@ -193,15 +200,17 @@ func (api *digitaloceanProvider) GetZoneRecords(dc *models.DomainConfig) (models return nil, err } - var existingRecords []*models.RecordConfig + var existingRecords models.Records for i := range records { - r, err := toRc(domain, &records[i]) + if records[i].Type == "SOA" { + continue + } + before := providers.BeginToRC(api.observer, "toRc", &records[i]) + r, err := toRc(dc, &records[i]) + providers.EndToRC(api.observer, "toRc", before, &records[i], models.Records{r}, err) if err != nil { return nil, err } - if r.Type == "SOA" { - continue - } existingRecords = append(existingRecords, r) } @@ -246,7 +255,10 @@ func (api *digitaloceanProvider) GetZoneRecordsCorrections(dc *models.DomainConf continue case diff2.CREATE: + input := models.Records{inst.New[0]} + before := providers.BeginToNative(api.observer, "toReq", input) req := toReq(inst.New[0]) + providers.EndToNative(api.observer, "toReq", before, input, req, nil) addCorrection(inst.MsgsJoined, func() (*godo.Response, error) { _, resp, err := api.client.Domains.CreateRecord(ctx, dc.Name, req) return resp, err @@ -254,7 +266,10 @@ func (api *digitaloceanProvider) GetZoneRecordsCorrections(dc *models.DomainConf case diff2.CHANGE: id := inst.Old[0].Original.(*godo.DomainRecord).ID + input := models.Records{inst.New[0]} + before := providers.BeginToNative(api.observer, "toReq", input) req := toReq(inst.New[0]) + providers.EndToNative(api.observer, "toReq", before, input, req, nil) addCorrection(inst.MsgsJoined, func() (*godo.Response, error) { _, resp, err := api.client.Domains.EditRecord(ctx, dc.Name, id, req) return resp, err @@ -307,86 +322,76 @@ retry: return records, nil } -func toRc(domain string, r *godo.DomainRecord) (*models.RecordConfig, error) { - // This handles "@" etc. - name := dnsutilv1.AddOrigin(r.Name, domain) - - target := r.Data - // Make target FQDN (#rtype_variations) - if r.Type == "CNAME" || r.Type == "MX" || r.Type == "NS" || r.Type == "SRV" { - // If target is the domainname, e.g. cname foo.example.com -> example.com, - // DO returns "@" on read even if fqdn was written. - switch target { - case "@": - target = domain - case ".": - target = "" - } - target = target + "." - } +func toRc(dc *models.DomainConfig, r *godo.DomainRecord) (*models.RecordConfig, error) { - t := &models.RecordConfig{ - Type: r.Type, - TTL: uint32(r.TTL), - MxPreference: uint16(r.Priority), - SrvPriority: uint16(r.Priority), - SrvWeight: uint16(r.Weight), - SrvPort: uint16(r.Port), - Original: r, - CaaTag: r.Tag, - CaaFlag: uint8(r.Flags), - } - t.SetLabelFromFQDN(name, domain) + label := dc.LabelFromShort(r.Name) + ttl := uint32(r.TTL) + + var rc *models.RecordConfig + var err error switch rtype := r.Type; rtype { - case "TXT": - if err := t.SetTargetTXT(target); err != nil { - return nil, err - } + case "MX": + rc, err = dc.NewRecordConfig(label, ttl, dnsv2.TypeMX, uint16(r.Priority), r.Data, + nrc.Flags{TargetIsFqdnNoDot: true}) + case "SRV": + rc, err = dc.NewRecordConfig(label, ttl, dnsv2.TypeSRV, uint16(r.Priority), uint16(r.Weight), uint16(r.Port), r.Data, + nrc.Flags{TargetIsFqdnNoDot: true}) + case "CAA": + rc, err = dc.NewRecordConfig(label, ttl, dnsv2.TypeCAA, uint8(r.Flags), r.Tag, r.Data, + nrc.Flags{TargetIsFqdnNoDot: true}) default: - if err := t.SetTarget(target); err != nil { - return nil, err - } + rc, err = dc.NewRecordConfig(label, ttl, r.Type, r.Data, + nrc.Flags{TargetIsFqdnNoDot: true}) } - return t, nil + if err != nil { + return nil, err + } + + rc.Original = r + + return rc, nil } func toReq(rc *models.RecordConfig) *godo.DomainRecordEditRequest { - name := rc.GetLabel() // DO wants the short name or "@" for apex. - target := rc.GetTargetField() // DO uses the target field only for a single value - priority := 0 // DO uses the same property for MX and SRV priority + name := rc.GetLabel() // DO wants the short name or "@" for apex. - switch rc.Type { // #rtype_variations - case "CAA": + r := &godo.DomainRecordEditRequest{ + Type: rc.Type, + Name: name, + TTL: int(rc.TTL), + } + + switch f := rc.GetRDATA().(type) { + case dnsrdatav2.CAA: // DO API requires that a CAA target ends in dot. // Interestingly enough, the value returned from API doesn't // contain a trailing dot. - target = target + "." - case "MX": - priority = int(rc.MxPreference) - case "SRV": - priority = int(rc.SrvPriority) - case "TXT": + // r.Data = target + "." + r.Tag = f.Tag + r.Flags = int(f.Flag) + r.Data = f.Value + "." + case dnsrdatav2.MX: + // DO uses the same field for MX and SRV priority + r.Priority = int(f.Preference) + r.Data = f.Mx + case dnsrdatav2.SRV: + // DO uses the same field for MX and SRV priority + r.Priority = int(f.Priority) + r.Weight = int(f.Weight) + r.Port = int(f.Port) + r.Data = f.Target + case dnsrdatav2.TXT: // TXT records are the one place where DO combines many items into one field. - target = rc.GetTargetTXTJoined() + r.Data = rc.GetTargetTXTJoined() default: - // no action required + r.Data = rc.GetRDATA().String() // DO uses the target field only for a single value } - return &godo.DomainRecordEditRequest{ - Type: rc.Type, - Name: name, - Data: target, - TTL: int(rc.TTL), - Priority: priority, - Port: int(rc.SrvPort), - Weight: int(rc.SrvWeight), - Tag: rc.CaaTag, - Flags: int(rc.CaaFlag), - } + return r } // backoff is the amount of time to sleep if a 429 or 504 is received. -// It is doubled after each use. +// It is increased by 1.5x after each use. var backoff = time.Second * 5 const maxBackoff = time.Minute * 3 diff --git a/providers/digitalocean/digitaloceanProvider_test.go b/providers/digitalocean/digitaloceanProvider_test.go new file mode 100644 index 0000000000..f3609310f4 --- /dev/null +++ b/providers/digitalocean/digitaloceanProvider_test.go @@ -0,0 +1,38 @@ +package digitalocean + +import ( + "testing" + + dnsv2 "codeberg.org/miekg/dns" + "github.com/DNSControl/dnscontrol/v5/models" + "github.com/digitalocean/godo" +) + +func TestToRcUsesV3RecordConfig(t *testing.T) { + dc := models.MustNewDomainConfig("example.com") + tests := []struct { + name string + in godo.DomainRecord + want *models.RecordConfig + }{ + {"TXT", godo.DomainRecord{Name: "www", Type: "TXT", Data: "hello world", TTL: 300}, dc.MustNewRecordConfig("www", 300, dnsv2.TypeTXT, "hello world")}, + {"MX", godo.DomainRecord{Name: "www", Type: "MX", Data: "mail.example.net", TTL: 300, Priority: 10}, dc.MustNewRecordConfig("www", 300, dnsv2.TypeMX, uint16(10), "mail.example.net.")}, + {"SRV", godo.DomainRecord{Name: "www", Type: "SRV", Data: "service.example.net", TTL: 300, Priority: 1, Weight: 2, Port: 443}, dc.MustNewRecordConfig("www", 300, dnsv2.TypeSRV, uint16(1), uint16(2), uint16(443), "service.example.net.")}, + {"CAA", godo.DomainRecord{Name: "www", Type: "CAA", Data: "letsencrypt.org", TTL: 300, Flags: 0, Tag: "issue"}, dc.MustNewRecordConfig("www", 300, dnsv2.TypeCAA, uint8(0), "issue", "letsencrypt.org")}, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + got, err := toRc(dc, &tt.in) + if err != nil { + t.Fatal(err) + } + if got.NameFQDN != tt.want.NameFQDN || got.TTL != tt.want.TTL || got.TypeNum != tt.want.TypeNum || got.GetRDATA().String() != tt.want.GetRDATA().String() { + t.Errorf("toRc() = %s %d IN %s %s, want %s %d IN %s %s", got.NameFQDN, got.TTL, got.Type, got.GetRDATA(), tt.want.NameFQDN, tt.want.TTL, tt.want.Type, tt.want.GetRDATA()) + } + if got.Original != &tt.in { + t.Error("toRc() did not preserve the original DigitalOcean record") + } + }) + } +} diff --git a/providers/digitalocean/test_data/expected_tonative_output_toReq_dnscontroltest-digitalocean.com.json b/providers/digitalocean/test_data/expected_tonative_output_toReq_dnscontroltest-digitalocean.com.json new file mode 100644 index 0000000000..16bff9b505 --- /dev/null +++ b/providers/digitalocean/test_data/expected_tonative_output_toReq_dnscontroltest-digitalocean.com.json @@ -0,0 +1,1736 @@ +[ + { + "index": 1, + "value": { + "type": "A", + "name": "*", + "data": "3.3.3.3", + "priority": 0, + "port": 0, + "ttl": 300, + "weight": 0, + "flags": 0 + } + }, + { + "index": 2, + "value": { + "type": "A", + "name": "@", + "data": "8.8.8.8", + "priority": 0, + "port": 0, + "ttl": 1000, + "weight": 0, + "flags": 0 + } + }, + { + "index": 3, + "value": { + "type": "A", + "name": "@", + "data": "1.2.3.2", + "priority": 0, + "port": 0, + "ttl": 300, + "weight": 0, + "flags": 0 + } + }, + { + "index": 4, + "value": { + "type": "A", + "name": "@", + "data": "1.2.3.4", + "priority": 0, + "port": 0, + "ttl": 300, + "weight": 0, + "flags": 0 + } + }, + { + "index": 5, + "value": { + "type": "A", + "name": "@", + "data": "2.2.2.2", + "priority": 0, + "port": 0, + "ttl": 300, + "weight": 0, + "flags": 0 + } + }, + { + "index": 6, + "value": { + "type": "A", + "name": "@", + "data": "2.3.4.5", + "priority": 0, + "port": 0, + "ttl": 300, + "weight": 0, + "flags": 0 + } + }, + { + "index": 7, + "value": { + "type": "A", + "name": "@", + "data": "4.4.4.4", + "priority": 0, + "port": 0, + "ttl": 300, + "weight": 0, + "flags": 0 + } + }, + { + "index": 8, + "value": { + "type": "CAA", + "name": "@", + "data": "letsencrypt.org.", + "priority": 0, + "port": 0, + "ttl": 300, + "weight": 0, + "flags": 0, + "tag": "issue" + } + }, + { + "index": 9, + "value": { + "type": "CAA", + "name": "@", + "data": ";.", + "priority": 0, + "port": 0, + "ttl": 300, + "weight": 0, + "flags": 0, + "tag": "issuewild" + } + }, + { + "index": 10, + "value": { + "type": "CAA", + "name": "@", + "data": "example.com.", + "priority": 0, + "port": 0, + "ttl": 300, + "weight": 0, + "flags": 0, + "tag": "issuewild" + } + }, + { + "index": 11, + "value": { + "type": "CAA", + "name": "@", + "data": "letsencrypt.org.", + "priority": 0, + "port": 0, + "ttl": 300, + "weight": 0, + "flags": 0, + "tag": "issuewild" + } + }, + { + "index": 12, + "value": { + "type": "CAA", + "name": "@", + "data": "letsencrypt.org.", + "priority": 0, + "port": 0, + "ttl": 300, + "weight": 0, + "flags": 128, + "tag": "issue" + } + }, + { + "index": 13, + "value": { + "type": "MX", + "name": "@", + "data": "dnscontroltest-digitalocean.com.", + "priority": 2, + "port": 0, + "ttl": 300, + "weight": 0, + "flags": 0 + } + }, + { + "index": 14, + "value": { + "type": "MX", + "name": "@", + "data": "bar.com.", + "priority": 5, + "port": 0, + "ttl": 300, + "weight": 0, + "flags": 0 + } + }, + { + "index": 15, + "value": { + "type": "MX", + "name": "@", + "data": "foo.com.", + "priority": 5, + "port": 0, + "ttl": 300, + "weight": 0, + "flags": 0 + } + }, + { + "index": 16, + "value": { + "type": "MX", + "name": "@", + "data": "www.dnscontroltest-digitalocean.com.", + "priority": 8, + "port": 0, + "ttl": 300, + "weight": 0, + "flags": 0 + } + }, + { + "index": 17, + "value": { + "type": "NS", + "name": "@", + "data": "ns1.example.com.", + "priority": 0, + "port": 0, + "ttl": 300, + "weight": 0, + "flags": 0 + } + }, + { + "index": 18, + "value": { + "type": "NS", + "name": "@", + "data": "ns1.foo.com.", + "priority": 0, + "port": 0, + "ttl": 300, + "weight": 0, + "flags": 0 + } + }, + { + "index": 19, + "value": { + "type": "NS", + "name": "@", + "data": "ns2.example.com.", + "priority": 0, + "port": 0, + "ttl": 300, + "weight": 0, + "flags": 0 + } + }, + { + "index": 20, + "value": { + "type": "NS", + "name": "@", + "data": "ns2.foo.com.", + "priority": 0, + "port": 0, + "ttl": 300, + "weight": 0, + "flags": 0 + } + }, + { + "index": 21, + "value": { + "type": "TXT", + "name": "@", + "data": "asimple", + "priority": 0, + "port": 0, + "ttl": 300, + "weight": 0, + "flags": 0 + } + }, + { + "index": 22, + "value": { + "type": "TXT", + "name": "@", + "data": "simple", + "priority": 0, + "port": 0, + "ttl": 300, + "weight": 0, + "flags": 0 + } + }, + { + "index": 23, + "value": { + "type": "A", + "name": "@", + "data": "8.8.8.8", + "priority": 0, + "port": 0, + "ttl": 500, + "weight": 0, + "flags": 0 + } + }, + { + "index": 24, + "value": { + "type": "A", + "name": "@", + "data": "8.8.8.8", + "priority": 0, + "port": 0, + "ttl": 666, + "weight": 0, + "flags": 0 + } + }, + { + "index": 25, + "value": { + "type": "SRV", + "name": "_sip._tcp", + "data": ".", + "priority": 15, + "port": 75, + "ttl": 300, + "weight": 65, + "flags": 0 + } + }, + { + "index": 26, + "value": { + "type": "SRV", + "name": "_sip._tcp", + "data": "foo3.com.", + "priority": 15, + "port": 75, + "ttl": 300, + "weight": 65, + "flags": 0 + } + }, + { + "index": 27, + "value": { + "type": "SRV", + "name": "_sip._tcp", + "data": "foo4.com.", + "priority": 15, + "port": 75, + "ttl": 300, + "weight": 65, + "flags": 0 + } + }, + { + "index": 28, + "value": { + "type": "SRV", + "name": "_sip._tcp", + "data": "foo.com.", + "priority": 5, + "port": 7, + "ttl": 300, + "weight": 6, + "flags": 0 + } + }, + { + "index": 29, + "value": { + "type": "SRV", + "name": "_sip._tcp", + "data": "foo2.com.", + "priority": 5, + "port": 70, + "ttl": 300, + "weight": 60, + "flags": 0 + } + }, + { + "index": 30, + "value": { + "type": "SRV", + "name": "_sip._tcp", + "data": "foo.com.", + "priority": 52, + "port": 7, + "ttl": 300, + "weight": 6, + "flags": 0 + } + }, + { + "index": 31, + "value": { + "type": "SRV", + "name": "_sip._tcp", + "data": "foo.com.", + "priority": 52, + "port": 7, + "ttl": 300, + "weight": 62, + "flags": 0 + } + }, + { + "index": 32, + "value": { + "type": "SRV", + "name": "_sip._tcp", + "data": "foo.com.", + "priority": 52, + "port": 72, + "ttl": 300, + "weight": 62, + "flags": 0 + } + }, + { + "index": 33, + "value": { + "type": "SRV", + "name": "_sip._tcp", + "data": "foo.com.", + "priority": 5, + "port": 7, + "ttl": 333, + "weight": 6, + "flags": 0 + } + }, + { + "index": 34, + "value": { + "type": "SRV", + "name": "_sip._tcp", + "data": "foo.com.", + "priority": 5, + "port": 7, + "ttl": 4400, + "weight": 6, + "flags": 0 + } + }, + { + "index": 35, + "value": { + "type": "CNAME", + "name": "a", + "data": "xn--ndaaa.com.", + "priority": 0, + "port": 0, + "ttl": 300, + "weight": 0, + "flags": 0 + } + }, + { + "index": 36, + "value": { + "type": "A", + "name": "bar", + "data": "1.2.3.4", + "priority": 0, + "port": 0, + "ttl": 300, + "weight": 0, + "flags": 0 + } + }, + { + "index": 37, + "value": { + "type": "A", + "name": "bar", + "data": "5.5.5.5", + "priority": 0, + "port": 0, + "ttl": 300, + "weight": 0, + "flags": 0 + } + }, + { + "index": 38, + "value": { + "type": "CNAME", + "name": "bar", + "data": "redact2.acm-validations.aws.", + "priority": 0, + "port": 0, + "ttl": 300, + "weight": 0, + "flags": 0 + } + }, + { + "index": 39, + "value": { + "type": "MX", + "name": "bar", + "data": "bar.com.", + "priority": 5, + "port": 0, + "ttl": 300, + "weight": 0, + "flags": 0 + } + }, + { + "index": 40, + "value": { + "type": "A", + "name": "bar.bat", + "data": "5.5.5.5", + "priority": 0, + "port": 0, + "ttl": 300, + "weight": 0, + "flags": 0 + } + }, + { + "index": 41, + "value": { + "type": "A", + "name": "decoy", + "data": "1.1.1.1", + "priority": 0, + "port": 0, + "ttl": 300, + "weight": 0, + "flags": 0 + } + }, + { + "index": 42, + "value": { + "type": "A", + "name": "decoy", + "data": "2.2.2.2", + "priority": 0, + "port": 0, + "ttl": 300, + "weight": 0, + "flags": 0 + } + }, + { + "index": 43, + "value": { + "type": "A", + "name": "decoy", + "data": "3.3.3.3", + "priority": 0, + "port": 0, + "ttl": 300, + "weight": 0, + "flags": 0 + } + }, + { + "index": 44, + "value": { + "type": "A", + "name": "dyndns-city1", + "data": "91.42.1.1", + "priority": 0, + "port": 0, + "ttl": 300, + "weight": 0, + "flags": 0 + } + }, + { + "index": 45, + "value": { + "type": "AAAA", + "name": "dyndns-city1", + "data": "2003:dd:d7ff::fe71:ce77", + "priority": 0, + "port": 0, + "ttl": 300, + "weight": 0, + "flags": 0 + } + }, + { + "index": 46, + "value": { + "type": "A", + "name": "dyndns-city2", + "data": "91.42.1.2", + "priority": 0, + "port": 0, + "ttl": 300, + "weight": 0, + "flags": 0 + } + }, + { + "index": 47, + "value": { + "type": "AAAA", + "name": "dyndns-city2", + "data": "2003:dd:d7ff::fe71:ce78", + "priority": 0, + "port": 0, + "ttl": 300, + "weight": 0, + "flags": 0 + } + }, + { + "index": 48, + "value": { + "type": "TXT", + "name": "final", + "data": "TestDNSProviders was successful!", + "priority": 0, + "port": 0, + "ttl": 300, + "weight": 0, + "flags": 0 + } + }, + { + "index": 49, + "value": { + "type": "A", + "name": "foo", + "data": "1.1.1.1", + "priority": 0, + "port": 0, + "ttl": 300, + "weight": 0, + "flags": 0 + } + }, + { + "index": 50, + "value": { + "type": "A", + "name": "foo", + "data": "1.2.3.4", + "priority": 0, + "port": 0, + "ttl": 300, + "weight": 0, + "flags": 0 + } + }, + { + "index": 51, + "value": { + "type": "A", + "name": "foo", + "data": "10.10.10.10", + "priority": 0, + "port": 0, + "ttl": 300, + "weight": 0, + "flags": 0 + } + }, + { + "index": 52, + "value": { + "type": "A", + "name": "foo", + "data": "11.11.11.11", + "priority": 0, + "port": 0, + "ttl": 300, + "weight": 0, + "flags": 0 + } + }, + { + "index": 53, + "value": { + "type": "A", + "name": "foo", + "data": "12.12.12.12", + "priority": 0, + "port": 0, + "ttl": 300, + "weight": 0, + "flags": 0 + } + }, + { + "index": 54, + "value": { + "type": "A", + "name": "foo", + "data": "13.13.13.13", + "priority": 0, + "port": 0, + "ttl": 300, + "weight": 0, + "flags": 0 + } + }, + { + "index": 55, + "value": { + "type": "A", + "name": "foo", + "data": "14.14.14.14", + "priority": 0, + "port": 0, + "ttl": 300, + "weight": 0, + "flags": 0 + } + }, + { + "index": 56, + "value": { + "type": "A", + "name": "foo", + "data": "2.3.4.5", + "priority": 0, + "port": 0, + "ttl": 300, + "weight": 0, + "flags": 0 + } + }, + { + "index": 57, + "value": { + "type": "A", + "name": "foo", + "data": "3.4.5.6", + "priority": 0, + "port": 0, + "ttl": 300, + "weight": 0, + "flags": 0 + } + }, + { + "index": 58, + "value": { + "type": "A", + "name": "foo", + "data": "4.5.6.7", + "priority": 0, + "port": 0, + "ttl": 300, + "weight": 0, + "flags": 0 + } + }, + { + "index": 59, + "value": { + "type": "A", + "name": "foo", + "data": "8.8.8.8", + "priority": 0, + "port": 0, + "ttl": 300, + "weight": 0, + "flags": 0 + } + }, + { + "index": 60, + "value": { + "type": "AAAA", + "name": "foo", + "data": "2003:dd:d7ff::fe71:aaaa", + "priority": 0, + "port": 0, + "ttl": 300, + "weight": 0, + "flags": 0 + } + }, + { + "index": 61, + "value": { + "type": "CNAME", + "name": "foo", + "data": "dnscontroltest-digitalocean.com.", + "priority": 0, + "port": 0, + "ttl": 300, + "weight": 0, + "flags": 0 + } + }, + { + "index": 62, + "value": { + "type": "CNAME", + "name": "foo", + "data": "google.com.", + "priority": 0, + "port": 0, + "ttl": 300, + "weight": 0, + "flags": 0 + } + }, + { + "index": 63, + "value": { + "type": "CNAME", + "name": "foo", + "data": "google2.com.", + "priority": 0, + "port": 0, + "ttl": 300, + "weight": 0, + "flags": 0 + } + }, + { + "index": 64, + "value": { + "type": "CNAME", + "name": "foo", + "data": "redact1.acm-validations.aws.", + "priority": 0, + "port": 0, + "ttl": 300, + "weight": 0, + "flags": 0 + } + }, + { + "index": 65, + "value": { + "type": "MX", + "name": "foo", + "data": "aspmx.l.google.com.", + "priority": 10, + "port": 0, + "ttl": 300, + "weight": 0, + "flags": 0 + } + }, + { + "index": 66, + "value": { + "type": "MX", + "name": "foo", + "data": "foo.dnscontroltest-digitalocean.com.", + "priority": 10, + "port": 0, + "ttl": 300, + "weight": 0, + "flags": 0 + } + }, + { + "index": 67, + "value": { + "type": "MX", + "name": "foo", + "data": "alt1.aspmx.l.google.com.", + "priority": 20, + "port": 0, + "ttl": 300, + "weight": 0, + "flags": 0 + } + }, + { + "index": 68, + "value": { + "type": "MX", + "name": "foo", + "data": "bar.dnscontroltest-digitalocean.com.", + "priority": 20, + "port": 0, + "ttl": 300, + "weight": 0, + "flags": 0 + } + }, + { + "index": 69, + "value": { + "type": "MX", + "name": "foo", + "data": "mx.google.com.", + "priority": 5, + "port": 0, + "ttl": 300, + "weight": 0, + "flags": 0 + } + }, + { + "index": 70, + "value": { + "type": "MX", + "name": "foo", + "data": "dnscontroltest-digitalocean.com.", + "priority": 8, + "port": 0, + "ttl": 300, + "weight": 0, + "flags": 0 + } + }, + { + "index": 71, + "value": { + "type": "NS", + "name": "foo", + "data": "dnscontroltest-digitalocean.com.", + "priority": 0, + "port": 0, + "ttl": 300, + "weight": 0, + "flags": 0 + } + }, + { + "index": 72, + "value": { + "type": "TXT", + "name": "foo", + "data": "simple", + "priority": 0, + "port": 0, + "ttl": 300, + "weight": 0, + "flags": 0 + } + }, + { + "index": 73, + "value": { + "type": "TXT", + "name": "foo", + "data": "v=spf1 ip4:99.99.99.99 -all", + "priority": 0, + "port": 0, + "ttl": 300, + "weight": 0, + "flags": 0 + } + }, + { + "index": 74, + "value": { + "type": "A", + "name": "foo.bat", + "data": "1.2.3.4", + "priority": 0, + "port": 0, + "ttl": 300, + "weight": 0, + "flags": 0 + } + }, + { + "index": 75, + "value": { + "type": "A", + "name": "foo.bat", + "data": "2.3.4.5", + "priority": 0, + "port": 0, + "ttl": 300, + "weight": 0, + "flags": 0 + } + }, + { + "index": 76, + "value": { + "type": "TXT", + "name": "foo.bat", + "data": "simple", + "priority": 0, + "port": 0, + "ttl": 300, + "weight": 0, + "flags": 0 + } + }, + { + "index": 77, + "value": { + "type": "TXT", + "name": "foo254", + "data": "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", + "priority": 0, + "port": 0, + "ttl": 300, + "weight": 0, + "flags": 0 + } + }, + { + "index": 78, + "value": { + "type": "TXT", + "name": "foo255", + "data": "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB", + "priority": 0, + "port": 0, + "ttl": 300, + "weight": 0, + "flags": 0 + } + }, + { + "index": 79, + "value": { + "type": "TXT", + "name": "foo256", + "data": "CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC", + "priority": 0, + "port": 0, + "ttl": 300, + "weight": 0, + "flags": 0 + } + }, + { + "index": 80, + "value": { + "type": "TXT", + "name": "foobt", + "data": "blah`blah", + "priority": 0, + "port": 0, + "ttl": 300, + "weight": 0, + "flags": 0 + } + }, + { + "index": 81, + "value": { + "type": "TXT", + "name": "foodq", + "data": "in\"side", + "priority": 0, + "port": 0, + "ttl": 300, + "weight": 0, + "flags": 0 + } + }, + { + "index": 82, + "value": { + "type": "TXT", + "name": "foodqs", + "data": "\"left", + "priority": 0, + "port": 0, + "ttl": 300, + "weight": 0, + "flags": 0 + } + }, + { + "index": 83, + "value": { + "type": "TXT", + "name": "foodqs", + "data": "in\"ter\"ior", + "priority": 0, + "port": 0, + "ttl": 300, + "weight": 0, + "flags": 0 + } + }, + { + "index": 84, + "value": { + "type": "TXT", + "name": "foodqs", + "data": "right\"", + "priority": 0, + "port": 0, + "ttl": 300, + "weight": 0, + "flags": 0 + } + }, + { + "index": 85, + "value": { + "type": "TXT", + "name": "foosc1", + "data": "semi;colon", + "priority": 0, + "port": 0, + "ttl": 300, + "weight": 0, + "flags": 0 + } + }, + { + "index": 86, + "value": { + "type": "TXT", + "name": "foosc2", + "data": "wssemi ; colon", + "priority": 0, + "port": 0, + "ttl": 300, + "weight": 0, + "flags": 0 + } + }, + { + "index": 87, + "value": { + "type": "TXT", + "name": "foosp", + "data": "with spaces", + "priority": 0, + "port": 0, + "ttl": 300, + "weight": 0, + "flags": 0 + } + }, + { + "index": 88, + "value": { + "type": "TXT", + "name": "foosq", + "data": "quo'te", + "priority": 0, + "port": 0, + "ttl": 300, + "weight": 0, + "flags": 0 + } + }, + { + "index": 89, + "value": { + "type": "TXT", + "name": "foows1", + "data": "trailingws ", + "priority": 0, + "port": 0, + "ttl": 300, + "weight": 0, + "flags": 0 + } + }, + { + "index": 90, + "value": { + "type": "CNAME", + "name": "mail", + "data": "ghs.googlehosted.com.", + "priority": 0, + "port": 0, + "ttl": 300, + "weight": 0, + "flags": 0 + } + }, + { + "index": 91, + "value": { + "type": "CNAME", + "name": "mail.bat", + "data": "ghs.googlehosted.com.", + "priority": 0, + "port": 0, + "ttl": 300, + "weight": 0, + "flags": 0 + } + }, + { + "index": 92, + "value": { + "type": "A", + "name": "nmx", + "data": "1.2.3.3", + "priority": 0, + "port": 0, + "ttl": 300, + "weight": 0, + "flags": 0 + } + }, + { + "index": 93, + "value": { + "type": "MX", + "name": "nmx", + "data": "nmx.dnscontroltest-digitalocean.com.", + "priority": 3, + "port": 0, + "ttl": 300, + "weight": 0, + "flags": 0 + } + }, + { + "index": 94, + "value": { + "type": "MX", + "name": "nmx", + "data": "www.dnscontroltest-digitalocean.com.", + "priority": 9, + "port": 0, + "ttl": 300, + "weight": 0, + "flags": 0 + } + }, + { + "index": 95, + "value": { + "type": "A", + "name": "testa", + "data": "1.1.1.1", + "priority": 0, + "port": 0, + "ttl": 300, + "weight": 0, + "flags": 0 + } + }, + { + "index": 96, + "value": { + "type": "A", + "name": "testa", + "data": "3.3.3.3", + "priority": 0, + "port": 0, + "ttl": 300, + "weight": 0, + "flags": 0 + } + }, + { + "index": 97, + "value": { + "type": "A", + "name": "testa", + "data": "1.1.1.1", + "priority": 0, + "port": 0, + "ttl": 333, + "weight": 0, + "flags": 0 + } + }, + { + "index": 98, + "value": { + "type": "A", + "name": "testa", + "data": "1.1.1.1", + "priority": 0, + "port": 0, + "ttl": 999, + "weight": 0, + "flags": 0 + } + }, + { + "index": 99, + "value": { + "type": "AAAA", + "name": "testaaaa", + "data": "2607:f8b0:4006:820::2006", + "priority": 0, + "port": 0, + "ttl": 300, + "weight": 0, + "flags": 0 + } + }, + { + "index": 100, + "value": { + "type": "AAAA", + "name": "testaaaa", + "data": "2607:f8b0:4006:820::2013", + "priority": 0, + "port": 0, + "ttl": 300, + "weight": 0, + "flags": 0 + } + }, + { + "index": 101, + "value": { + "type": "CNAME", + "name": "testcname", + "data": "foo.dnscontroltest-digitalocean.com.", + "priority": 0, + "port": 0, + "ttl": 300, + "weight": 0, + "flags": 0 + } + }, + { + "index": 102, + "value": { + "type": "CNAME", + "name": "testcname", + "data": "www.google.com.", + "priority": 0, + "port": 0, + "ttl": 300, + "weight": 0, + "flags": 0 + } + }, + { + "index": 103, + "value": { + "type": "CNAME", + "name": "testcname", + "data": "www.yahoo.com.", + "priority": 0, + "port": 0, + "ttl": 300, + "weight": 0, + "flags": 0 + } + }, + { + "index": 104, + "value": { + "type": "A", + "name": "testdefined", + "data": "2.2.2.2", + "priority": 0, + "port": 0, + "ttl": 300, + "weight": 0, + "flags": 0 + } + }, + { + "index": 105, + "value": { + "type": "A", + "name": "testdefined", + "data": "9.9.9.9", + "priority": 0, + "port": 0, + "ttl": 300, + "weight": 0, + "flags": 0 + } + }, + { + "index": 106, + "value": { + "type": "A", + "name": "testignore", + "data": "8.8.8.8", + "priority": 0, + "port": 0, + "ttl": 300, + "weight": 0, + "flags": 0 + } + }, + { + "index": 107, + "value": { + "type": "MX", + "name": "testmx", + "data": "bar.com.", + "priority": 100, + "port": 0, + "ttl": 300, + "weight": 0, + "flags": 0 + } + }, + { + "index": 108, + "value": { + "type": "MX", + "name": "testmx", + "data": "foo.com.", + "priority": 100, + "port": 0, + "ttl": 300, + "weight": 0, + "flags": 0 + } + }, + { + "index": 109, + "value": { + "type": "MX", + "name": "testmx", + "data": "bar.com.", + "priority": 5, + "port": 0, + "ttl": 300, + "weight": 0, + "flags": 0 + } + }, + { + "index": 110, + "value": { + "type": "MX", + "name": "testmx", + "data": "foo.com.", + "priority": 5, + "port": 0, + "ttl": 300, + "weight": 0, + "flags": 0 + } + }, + { + "index": 111, + "value": { + "type": "TXT", + "name": "testtxt", + "data": "changed", + "priority": 0, + "port": 0, + "ttl": 300, + "weight": 0, + "flags": 0 + } + }, + { + "index": 112, + "value": { + "type": "TXT", + "name": "testtxt", + "data": "simple", + "priority": 0, + "port": 0, + "ttl": 300, + "weight": 0, + "flags": 0 + } + }, + { + "index": 113, + "value": { + "type": "A", + "name": "www", + "data": "1.1.1.1", + "priority": 0, + "port": 0, + "ttl": 300, + "weight": 0, + "flags": 0 + } + }, + { + "index": 114, + "value": { + "type": "A", + "name": "www", + "data": "1.2.3.4", + "priority": 0, + "port": 0, + "ttl": 300, + "weight": 0, + "flags": 0 + } + }, + { + "index": 115, + "value": { + "type": "A", + "name": "www", + "data": "1.2.3.8", + "priority": 0, + "port": 0, + "ttl": 300, + "weight": 0, + "flags": 0 + } + }, + { + "index": 116, + "value": { + "type": "A", + "name": "www", + "data": "1.2.3.9", + "priority": 0, + "port": 0, + "ttl": 300, + "weight": 0, + "flags": 0 + } + }, + { + "index": 117, + "value": { + "type": "A", + "name": "www", + "data": "2.2.2.2", + "priority": 0, + "port": 0, + "ttl": 300, + "weight": 0, + "flags": 0 + } + }, + { + "index": 118, + "value": { + "type": "A", + "name": "www", + "data": "3.3.3.3", + "priority": 0, + "port": 0, + "ttl": 300, + "weight": 0, + "flags": 0 + } + }, + { + "index": 119, + "value": { + "type": "A", + "name": "www", + "data": "5.5.5.5", + "priority": 0, + "port": 0, + "ttl": 300, + "weight": 0, + "flags": 0 + } + }, + { + "index": 120, + "value": { + "type": "A", + "name": "www", + "data": "5.6.7.8", + "priority": 0, + "port": 0, + "ttl": 300, + "weight": 0, + "flags": 0 + } + }, + { + "index": 121, + "value": { + "type": "A", + "name": "www", + "data": "2.2.2.2", + "priority": 0, + "port": 0, + "ttl": 400, + "weight": 0, + "flags": 0 + } + }, + { + "index": 122, + "value": { + "type": "A", + "name": "www", + "data": "5.6.7.8", + "priority": 0, + "port": 0, + "ttl": 400, + "weight": 0, + "flags": 0 + } + }, + { + "index": 123, + "value": { + "type": "A", + "name": "www", + "data": "1.2.3.4", + "priority": 0, + "port": 0, + "ttl": 700, + "weight": 0, + "flags": 0 + } + }, + { + "index": 124, + "value": { + "type": "A", + "name": "www", + "data": "5.6.7.8", + "priority": 0, + "port": 0, + "ttl": 700, + "weight": 0, + "flags": 0 + } + }, + { + "index": 125, + "value": { + "type": "A", + "name": "xn--fiq228c", + "data": "1.2.3.4", + "priority": 0, + "port": 0, + "ttl": 300, + "weight": 0, + "flags": 0 + } + }, + { + "index": 126, + "value": { + "type": "A", + "name": "xn--ndaaa", + "data": "1.2.3.4", + "priority": 0, + "port": 0, + "ttl": 300, + "weight": 0, + "flags": 0 + } + }, + { + "index": 127, + "value": { + "type": "A", + "name": "xn--ndaaa", + "data": "2.2.2.2", + "priority": 0, + "port": 0, + "ttl": 300, + "weight": 0, + "flags": 0 + } + }, + { + "index": 128, + "value": { + "type": "CNAME", + "name": "xn--o-0gab", + "data": "xn--ndaaa.xn--vhquv.", + "priority": 0, + "port": 0, + "ttl": 300, + "weight": 0, + "flags": 0 + } + }, + { + "index": 129, + "value": { + "type": "NS", + "name": "xyz", + "data": "ns1.foo.com.", + "priority": 0, + "port": 0, + "ttl": 300, + "weight": 0, + "flags": 0 + } + }, + { + "index": 130, + "value": { + "type": "NS", + "name": "xyz", + "data": "ns2.foo.com.", + "priority": 0, + "port": 0, + "ttl": 300, + "weight": 0, + "flags": 0 + } + }, + { + "index": 131, + "value": { + "type": "A", + "name": "zzz", + "data": "3.3.3.3", + "priority": 0, + "port": 0, + "ttl": 300, + "weight": 0, + "flags": 0 + } + }, + { + "index": 132, + "value": { + "type": "A", + "name": "zzz", + "data": "4.4.4.4", + "priority": 0, + "port": 0, + "ttl": 300, + "weight": 0, + "flags": 0 + } + }, + { + "index": 133, + "value": { + "type": "AAAA", + "name": "zzz", + "data": "2003:dd:d7ff::fe71:cccc", + "priority": 0, + "port": 0, + "ttl": 300, + "weight": 0, + "flags": 0 + } + } +] diff --git a/providers/digitalocean/test_data/expected_torc_output_toRc_dnscontroltest-digitalocean.com.records b/providers/digitalocean/test_data/expected_torc_output_toRc_dnscontroltest-digitalocean.com.records new file mode 100644 index 0000000000..830301c44f --- /dev/null +++ b/providers/digitalocean/test_data/expected_torc_output_toRc_dnscontroltest-digitalocean.com.records @@ -0,0 +1,166 @@ +1 @ 300 IN NS ns1.digitalocean.com. +2 @ 300 IN NS ns2.digitalocean.com. +3 @ 300 IN NS ns3.digitalocean.com. +4 testa 300 IN A 1.1.1.1 +5 testa 300 IN A 3.3.3.3 +6 @ 300 IN A 2.2.2.2 +7 @ 300 IN A 4.4.4.4 +8 * 300 IN A 3.3.3.3 +9 www 300 IN A 5.5.5.5 +10 testaaaa 300 IN AAAA 2607:f8b0:4006:820::2006 +11 testaaaa 300 IN AAAA 2607:f8b0:4006:820::2013 +12 testcname 300 IN CNAME www.google.com. +13 testcname 300 IN CNAME www.yahoo.com. +14 foo 300 IN A 1.2.3.4 +15 testcname 300 IN CNAME foo.dnscontroltest-digitalocean.com. +16 @ 300 IN MX 5 bar.com. +17 @ 300 IN MX 5 foo.com. +18 testmx 300 IN MX 5 bar.com. +19 testmx 300 IN MX 5 foo.com. +20 testmx 300 IN MX 100 foo.com. +21 testmx 300 IN MX 5 foo.com. +22 testtxt 300 IN TXT "changed" +23 testtxt 300 IN TXT "simple" +24 www 300 IN A 1.1.1.1 +25 www 300 IN A 2.2.2.2 +26 www 300 IN A 3.3.3.3 +27 www 300 IN A 1.1.1.1 +28 www 300 IN A 2.2.2.2 +29 www 300 IN A 3.3.3.3 +30 testmx 300 IN MX 100 bar.com. +31 testmx 300 IN MX 5 foo.com. +32 www 300 IN A 1.1.1.1 +33 www 300 IN A 1.1.1.1 +34 testmx 300 IN MX 5 foo.com. +35 testmx 300 IN MX 100 bar.com. +36 testa 333 IN A 1.1.1.1 +37 testa 999 IN A 1.1.1.1 +38 @ 1000 IN A 8.8.8.8 +39 @ 500 IN A 8.8.8.8 +40 @ 666 IN A 8.8.8.8 +41 www 300 IN A 1.2.3.4 +42 www 300 IN A 2.2.2.2 +43 www 400 IN A 2.2.2.2 +44 www 300 IN A 5.6.7.8 +45 www 400 IN A 5.6.7.8 +46 www 400 IN A 5.6.7.8 +47 www 700 IN A 5.6.7.8 +48 www 700 IN A 1.2.3.4 +49 foo 300 IN A 1.2.3.4 +50 foo 300 IN MX 5 mx.google.com. +51 foo 300 IN A 4.5.6.7 +52 foo 300 IN CNAME google.com. +53 foo 300 IN A 1.2.3.4 +54 foo 300 IN CNAME google2.com. +55 @ 300 IN A 1.2.3.4 +56 foo 300 IN CNAME dnscontroltest-digitalocean.com. +57 @ 300 IN A 1.2.3.4 +58 foo 300 IN MX 8 dnscontroltest-digitalocean.com. +59 nmx 300 IN A 1.2.3.3 +60 www 300 IN A 1.2.3.9 +61 nmx 300 IN MX 9 www.dnscontroltest-digitalocean.com. +62 nmx 300 IN MX 3 nmx.dnscontroltest-digitalocean.com. +63 @ 300 IN A 1.2.3.2 +64 www 300 IN A 1.2.3.8 +65 @ 300 IN MX 8 www.dnscontroltest-digitalocean.com. +66 @ 300 IN MX 2 dnscontroltest-digitalocean.com. +67 xyz 300 IN NS ns2.foo.com. +68 xyz 300 IN NS ns1.foo.com. +69 @ 300 IN A 1.2.3.4 +70 foo 300 IN NS dnscontroltest-digitalocean.com. +71 @ 300 IN NS ns1.foo.com. +72 @ 300 IN NS ns2.foo.com. +73 foo254 300 IN TXT "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" +74 foo255 300 IN TXT "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" +75 foo256 300 IN TXT "CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC" "C" +76 foosq 300 IN TXT "quo'te" +77 foobt 300 IN TXT "blah`blah" +78 foodq 300 IN TXT "in\"side" +79 foodqs 300 IN TXT "\"left" +80 foodqs 300 IN TXT "in\"ter\"ior" +81 foodqs 300 IN TXT "right\"" +82 foosc1 300 IN TXT "semi;colon" +83 foosc2 300 IN TXT "wssemi ; colon" +84 foosp 300 IN TXT "with spaces" +85 foows1 300 IN TXT "trailingws " +86 foo 300 IN TXT "v=spf1 ip4:99.99.99.99 -all" +87 bar 300 IN MX 5 bar.com. +88 decoy 300 IN A 1.1.1.1 +89 decoy 300 IN A 2.2.2.2 +90 decoy 300 IN A 3.3.3.3 +91 foo 300 IN A 1.2.3.4 +92 foo 300 IN A 2.3.4.5 +93 foo 300 IN A 3.4.5.6 +94 foo 300 IN A 3.4.5.6 +95 bar 300 IN A 1.2.3.4 +96 foo 300 IN A 2.3.4.5 +97 foo 300 IN A 3.4.5.6 +98 foo 300 IN A 8.8.8.8 +99 foo 300 IN MX 20 bar.dnscontroltest-digitalocean.com. +100 foo 300 IN MX 10 foo.dnscontroltest-digitalocean.com. +101 foo 300 IN A 8.8.8.8 +102 xn--ndaaa 300 IN A 1.2.3.4 +103 xn--ndaaa 300 IN A 2.2.2.2 +104 xn--fiq228c 300 IN A 1.2.3.4 +105 a 300 IN CNAME xn--ndaaa.com. +106 xn--o-0gab 300 IN CNAME xn--ndaaa.xn--vhquv. +107 @ 300 IN CAA 0 issuewild ";" +108 @ 300 IN CAA 0 issuewild "example.com" +109 @ 300 IN CAA 0 issue "letsencrypt.org" +110 @ 300 IN CAA 0 issuewild "letsencrypt.org" +111 @ 300 IN CAA 0 issue "letsencrypt.org" +112 @ 300 IN CAA 128 issue "letsencrypt.org" +113 _sip._tcp 300 IN SRV 5 6 7 foo.com. +114 _sip._tcp 300 IN SRV 52 6 7 foo.com. +115 _sip._tcp 300 IN SRV 52 62 7 foo.com. +116 _sip._tcp 300 IN SRV 52 62 72 foo.com. +117 _sip._tcp 300 IN SRV 5 60 70 foo2.com. +118 _sip._tcp 300 IN SRV 15 65 75 foo3.com. +119 _sip._tcp 300 IN SRV 15 65 75 foo4.com. +120 _sip._tcp 300 IN SRV 15 65 75 . +121 _sip._tcp 333 IN SRV 5 6 7 foo.com. +122 _sip._tcp 4400 IN SRV 5 6 7 foo.com. +123 bar 300 IN A 5.5.5.5 +124 foo 300 IN A 1.2.3.4 +125 foo 300 IN A 2.3.4.5 +126 foo 300 IN TXT "simple" +127 mail 300 IN CNAME ghs.googlehosted.com. +128 @ 300 IN A 1.2.3.4 +129 @ 300 IN A 2.3.4.5 +130 @ 300 IN TXT "simple" +131 bar 300 IN A 5.5.5.5 +132 mail 300 IN CNAME ghs.googlehosted.com. +133 @ 300 IN A 2.2.2.2 +134 @ 300 IN TXT "asimple" +135 foo 300 IN A 1.2.3.4 +136 foo 300 IN TXT "simple" +137 bar.bat 300 IN A 5.5.5.5 +138 foo.bat 300 IN A 1.2.3.4 +139 foo.bat 300 IN A 2.3.4.5 +140 foo.bat 300 IN TXT "simple" +141 mail.bat 300 IN CNAME ghs.googlehosted.com. +142 foo 300 IN A 1.1.1.1 +143 foo 300 IN A 10.10.10.10 +144 foo 300 IN A 11.11.11.11 +145 foo 300 IN A 12.12.12.12 +146 foo 300 IN A 13.13.13.13 +147 foo 300 IN A 14.14.14.14 +148 foo 300 IN AAAA 2003:dd:d7ff::fe71:aaaa +149 foo 300 IN MX 10 aspmx.l.google.com. +150 foo 300 IN MX 20 alt1.aspmx.l.google.com. +151 zzz 300 IN A 3.3.3.3 +152 zzz 300 IN A 4.4.4.4 +153 zzz 300 IN AAAA 2003:dd:d7ff::fe71:cccc +154 bar 300 IN CNAME redact2.acm-validations.aws. +155 foo 300 IN CNAME redact1.acm-validations.aws. +156 dyndns-city1 300 IN A 91.42.1.1 +157 dyndns-city1 300 IN AAAA 2003:dd:d7ff::fe71:ce77 +158 dyndns-city2 300 IN A 91.42.1.2 +159 dyndns-city2 300 IN AAAA 2003:dd:d7ff::fe71:ce78 +160 testdefined 300 IN A 2.2.2.2 +161 testdefined 300 IN A 9.9.9.9 +162 testignore 300 IN A 8.8.8.8 +163 final 300 IN TXT "TestDNSProviders was successful!" +164 final 300 IN TXT "TestDNSProviders was successful!" +165 @ 300 IN NS ns1.example.com. +166 @ 300 IN NS ns2.example.com. diff --git a/providers/digitalocean/test_data/meta.json b/providers/digitalocean/test_data/meta.json new file mode 100644 index 0000000000..979da23050 --- /dev/null +++ b/providers/digitalocean/test_data/meta.json @@ -0,0 +1,14 @@ +{ + "version": 1, + "recordings": [ + { + "domain": "dnscontroltest-digitalocean.com", + "to_rc": [ + "toRc" + ], + "to_native": [ + "toReq" + ] + } + ] +} diff --git a/providers/digitalocean/test_data/recorded_tonative_input_toReq_dnscontroltest-digitalocean.com.records b/providers/digitalocean/test_data/recorded_tonative_input_toReq_dnscontroltest-digitalocean.com.records new file mode 100644 index 0000000000..10904b15c2 --- /dev/null +++ b/providers/digitalocean/test_data/recorded_tonative_input_toReq_dnscontroltest-digitalocean.com.records @@ -0,0 +1,133 @@ +1 * 300 IN A 3.3.3.3 +2 @ 1000 IN A 8.8.8.8 +3 @ 300 IN A 1.2.3.2 +4 @ 300 IN A 1.2.3.4 +5 @ 300 IN A 2.2.2.2 +6 @ 300 IN A 2.3.4.5 +7 @ 300 IN A 4.4.4.4 +8 @ 300 IN CAA 0 issue "letsencrypt.org" +9 @ 300 IN CAA 0 issuewild ";" +10 @ 300 IN CAA 0 issuewild "example.com" +11 @ 300 IN CAA 0 issuewild "letsencrypt.org" +12 @ 300 IN CAA 128 issue "letsencrypt.org" +13 @ 300 IN MX 2 dnscontroltest-digitalocean.com. +14 @ 300 IN MX 5 bar.com. +15 @ 300 IN MX 5 foo.com. +16 @ 300 IN MX 8 www.dnscontroltest-digitalocean.com. +17 @ 300 IN NS ns1.example.com. +18 @ 300 IN NS ns1.foo.com. +19 @ 300 IN NS ns2.example.com. +20 @ 300 IN NS ns2.foo.com. +21 @ 300 IN TXT "asimple" +22 @ 300 IN TXT "simple" +23 @ 500 IN A 8.8.8.8 +24 @ 666 IN A 8.8.8.8 +25 _sip._tcp 300 IN SRV 15 65 75 . +26 _sip._tcp 300 IN SRV 15 65 75 foo3.com. +27 _sip._tcp 300 IN SRV 15 65 75 foo4.com. +28 _sip._tcp 300 IN SRV 5 6 7 foo.com. +29 _sip._tcp 300 IN SRV 5 60 70 foo2.com. +30 _sip._tcp 300 IN SRV 52 6 7 foo.com. +31 _sip._tcp 300 IN SRV 52 62 7 foo.com. +32 _sip._tcp 300 IN SRV 52 62 72 foo.com. +33 _sip._tcp 333 IN SRV 5 6 7 foo.com. +34 _sip._tcp 4400 IN SRV 5 6 7 foo.com. +35 a 300 IN CNAME xn--ndaaa.com. +36 bar 300 IN A 1.2.3.4 +37 bar 300 IN A 5.5.5.5 +38 bar 300 IN CNAME redact2.acm-validations.aws. +39 bar 300 IN MX 5 bar.com. +40 bar.bat 300 IN A 5.5.5.5 +41 decoy 300 IN A 1.1.1.1 +42 decoy 300 IN A 2.2.2.2 +43 decoy 300 IN A 3.3.3.3 +44 dyndns-city1 300 IN A 91.42.1.1 +45 dyndns-city1 300 IN AAAA 2003:dd:d7ff::fe71:ce77 +46 dyndns-city2 300 IN A 91.42.1.2 +47 dyndns-city2 300 IN AAAA 2003:dd:d7ff::fe71:ce78 +48 final 300 IN TXT "TestDNSProviders was successful!" +49 foo 300 IN A 1.1.1.1 +50 foo 300 IN A 1.2.3.4 +51 foo 300 IN A 10.10.10.10 +52 foo 300 IN A 11.11.11.11 +53 foo 300 IN A 12.12.12.12 +54 foo 300 IN A 13.13.13.13 +55 foo 300 IN A 14.14.14.14 +56 foo 300 IN A 2.3.4.5 +57 foo 300 IN A 3.4.5.6 +58 foo 300 IN A 4.5.6.7 +59 foo 300 IN A 8.8.8.8 +60 foo 300 IN AAAA 2003:dd:d7ff::fe71:aaaa +61 foo 300 IN CNAME dnscontroltest-digitalocean.com. +62 foo 300 IN CNAME google.com. +63 foo 300 IN CNAME google2.com. +64 foo 300 IN CNAME redact1.acm-validations.aws. +65 foo 300 IN MX 10 aspmx.l.google.com. +66 foo 300 IN MX 10 foo.dnscontroltest-digitalocean.com. +67 foo 300 IN MX 20 alt1.aspmx.l.google.com. +68 foo 300 IN MX 20 bar.dnscontroltest-digitalocean.com. +69 foo 300 IN MX 5 mx.google.com. +70 foo 300 IN MX 8 dnscontroltest-digitalocean.com. +71 foo 300 IN NS dnscontroltest-digitalocean.com. +72 foo 300 IN TXT "simple" +73 foo 300 IN TXT "v=spf1 ip4:99.99.99.99 -all" +74 foo.bat 300 IN A 1.2.3.4 +75 foo.bat 300 IN A 2.3.4.5 +76 foo.bat 300 IN TXT "simple" +77 foo254 300 IN TXT "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" +78 foo255 300 IN TXT "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" +79 foo256 300 IN TXT "CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC" "C" +80 foobt 300 IN TXT "blah`blah" +81 foodq 300 IN TXT "in\"side" +82 foodqs 300 IN TXT "\"left" +83 foodqs 300 IN TXT "in\"ter\"ior" +84 foodqs 300 IN TXT "right\"" +85 foosc1 300 IN TXT "semi;colon" +86 foosc2 300 IN TXT "wssemi ; colon" +87 foosp 300 IN TXT "with spaces" +88 foosq 300 IN TXT "quo'te" +89 foows1 300 IN TXT "trailingws " +90 mail 300 IN CNAME ghs.googlehosted.com. +91 mail.bat 300 IN CNAME ghs.googlehosted.com. +92 nmx 300 IN A 1.2.3.3 +93 nmx 300 IN MX 3 nmx.dnscontroltest-digitalocean.com. +94 nmx 300 IN MX 9 www.dnscontroltest-digitalocean.com. +95 testa 300 IN A 1.1.1.1 +96 testa 300 IN A 3.3.3.3 +97 testa 333 IN A 1.1.1.1 +98 testa 999 IN A 1.1.1.1 +99 testaaaa 300 IN AAAA 2607:f8b0:4006:820::2006 +100 testaaaa 300 IN AAAA 2607:f8b0:4006:820::2013 +101 testcname 300 IN CNAME foo.dnscontroltest-digitalocean.com. +102 testcname 300 IN CNAME www.google.com. +103 testcname 300 IN CNAME www.yahoo.com. +104 testdefined 300 IN A 2.2.2.2 +105 testdefined 300 IN A 9.9.9.9 +106 testignore 300 IN A 8.8.8.8 +107 testmx 300 IN MX 100 bar.com. +108 testmx 300 IN MX 100 foo.com. +109 testmx 300 IN MX 5 bar.com. +110 testmx 300 IN MX 5 foo.com. +111 testtxt 300 IN TXT "changed" +112 testtxt 300 IN TXT "simple" +113 www 300 IN A 1.1.1.1 +114 www 300 IN A 1.2.3.4 +115 www 300 IN A 1.2.3.8 +116 www 300 IN A 1.2.3.9 +117 www 300 IN A 2.2.2.2 +118 www 300 IN A 3.3.3.3 +119 www 300 IN A 5.5.5.5 +120 www 300 IN A 5.6.7.8 +121 www 400 IN A 2.2.2.2 +122 www 400 IN A 5.6.7.8 +123 www 700 IN A 1.2.3.4 +124 www 700 IN A 5.6.7.8 +125 xn--fiq228c 300 IN A 1.2.3.4 +126 xn--ndaaa 300 IN A 1.2.3.4 +127 xn--ndaaa 300 IN A 2.2.2.2 +128 xn--o-0gab 300 IN CNAME xn--ndaaa.xn--vhquv. +129 xyz 300 IN NS ns1.foo.com. +130 xyz 300 IN NS ns2.foo.com. +131 zzz 300 IN A 3.3.3.3 +132 zzz 300 IN A 4.4.4.4 +133 zzz 300 IN AAAA 2003:dd:d7ff::fe71:cccc diff --git a/providers/digitalocean/test_data/recorded_torc_input_toRc_dnscontroltest-digitalocean.com.json b/providers/digitalocean/test_data/recorded_torc_input_toRc_dnscontroltest-digitalocean.com.json new file mode 100644 index 0000000000..21aeb3657b --- /dev/null +++ b/providers/digitalocean/test_data/recorded_torc_input_toRc_dnscontroltest-digitalocean.com.json @@ -0,0 +1,2332 @@ +[ + { + "index": 1, + "value": { + "id": 1819995064, + "type": "NS", + "name": "@", + "data": "ns1.digitalocean.com", + "priority": 0, + "port": 0, + "ttl": 300, + "weight": 0, + "flags": 0 + } + }, + { + "index": 2, + "value": { + "id": 1827732904, + "type": "NS", + "name": "@", + "data": "ns2.digitalocean.com", + "priority": 0, + "port": 0, + "ttl": 300, + "weight": 0, + "flags": 0 + } + }, + { + "index": 3, + "value": { + "id": 1827759143, + "type": "NS", + "name": "@", + "data": "ns3.digitalocean.com", + "priority": 0, + "port": 0, + "ttl": 300, + "weight": 0, + "flags": 0 + } + }, + { + "index": 4, + "value": { + "id": 1828352356, + "type": "A", + "name": "testa", + "data": "1.1.1.1", + "priority": 0, + "port": 0, + "ttl": 300, + "weight": 0, + "flags": 0 + } + }, + { + "index": 5, + "value": { + "id": 1828352356, + "type": "A", + "name": "testa", + "data": "3.3.3.3", + "priority": 0, + "port": 0, + "ttl": 300, + "weight": 0, + "flags": 0 + } + }, + { + "index": 6, + "value": { + "id": 1828352359, + "type": "A", + "name": "@", + "data": "2.2.2.2", + "priority": 0, + "port": 0, + "ttl": 300, + "weight": 0, + "flags": 0 + } + }, + { + "index": 7, + "value": { + "id": 1828352359, + "type": "A", + "name": "@", + "data": "4.4.4.4", + "priority": 0, + "port": 0, + "ttl": 300, + "weight": 0, + "flags": 0 + } + }, + { + "index": 8, + "value": { + "id": 1828352362, + "type": "A", + "name": "*", + "data": "3.3.3.3", + "priority": 0, + "port": 0, + "ttl": 300, + "weight": 0, + "flags": 0 + } + }, + { + "index": 9, + "value": { + "id": 1828352363, + "type": "A", + "name": "www", + "data": "5.5.5.5", + "priority": 0, + "port": 0, + "ttl": 300, + "weight": 0, + "flags": 0 + } + }, + { + "index": 10, + "value": { + "id": 1828352364, + "type": "AAAA", + "name": "testaaaa", + "data": "2607:f8b0:4006:820::2006", + "priority": 0, + "port": 0, + "ttl": 300, + "weight": 0, + "flags": 0 + } + }, + { + "index": 11, + "value": { + "id": 1828352364, + "type": "AAAA", + "name": "testaaaa", + "data": "2607:f8b0:4006:820::2013", + "priority": 0, + "port": 0, + "ttl": 300, + "weight": 0, + "flags": 0 + } + }, + { + "index": 12, + "value": { + "id": 1828352365, + "type": "CNAME", + "name": "testcname", + "data": "www.google.com", + "priority": 0, + "port": 0, + "ttl": 300, + "weight": 0, + "flags": 0 + } + }, + { + "index": 13, + "value": { + "id": 1828352365, + "type": "CNAME", + "name": "testcname", + "data": "www.yahoo.com", + "priority": 0, + "port": 0, + "ttl": 300, + "weight": 0, + "flags": 0 + } + }, + { + "index": 14, + "value": { + "id": 1828352366, + "type": "A", + "name": "foo", + "data": "1.2.3.4", + "priority": 0, + "port": 0, + "ttl": 300, + "weight": 0, + "flags": 0 + } + }, + { + "index": 15, + "value": { + "id": 1828352367, + "type": "CNAME", + "name": "testcname", + "data": "foo.dnscontroltest-digitalocean.com", + "priority": 0, + "port": 0, + "ttl": 300, + "weight": 0, + "flags": 0 + } + }, + { + "index": 16, + "value": { + "id": 1828352368, + "type": "MX", + "name": "@", + "data": "bar.com", + "priority": 5, + "port": 0, + "ttl": 300, + "weight": 0, + "flags": 0 + } + }, + { + "index": 17, + "value": { + "id": 1828352368, + "type": "MX", + "name": "@", + "data": "foo.com", + "priority": 5, + "port": 0, + "ttl": 300, + "weight": 0, + "flags": 0 + } + }, + { + "index": 18, + "value": { + "id": 1828352369, + "type": "MX", + "name": "testmx", + "data": "bar.com", + "priority": 5, + "port": 0, + "ttl": 300, + "weight": 0, + "flags": 0 + } + }, + { + "index": 19, + "value": { + "id": 1828352369, + "type": "MX", + "name": "testmx", + "data": "foo.com", + "priority": 5, + "port": 0, + "ttl": 300, + "weight": 0, + "flags": 0 + } + }, + { + "index": 20, + "value": { + "id": 1828352373, + "type": "MX", + "name": "testmx", + "data": "foo.com", + "priority": 100, + "port": 0, + "ttl": 300, + "weight": 0, + "flags": 0 + } + }, + { + "index": 21, + "value": { + "id": 1828352373, + "type": "MX", + "name": "testmx", + "data": "foo.com", + "priority": 5, + "port": 0, + "ttl": 300, + "weight": 0, + "flags": 0 + } + }, + { + "index": 22, + "value": { + "id": 1828352374, + "type": "TXT", + "name": "testtxt", + "data": "changed", + "priority": 0, + "port": 0, + "ttl": 300, + "weight": 0, + "flags": 0 + } + }, + { + "index": 23, + "value": { + "id": 1828352374, + "type": "TXT", + "name": "testtxt", + "data": "simple", + "priority": 0, + "port": 0, + "ttl": 300, + "weight": 0, + "flags": 0 + } + }, + { + "index": 24, + "value": { + "id": 1828352375, + "type": "A", + "name": "www", + "data": "1.1.1.1", + "priority": 0, + "port": 0, + "ttl": 300, + "weight": 0, + "flags": 0 + } + }, + { + "index": 25, + "value": { + "id": 1828352376, + "type": "A", + "name": "www", + "data": "2.2.2.2", + "priority": 0, + "port": 0, + "ttl": 300, + "weight": 0, + "flags": 0 + } + }, + { + "index": 26, + "value": { + "id": 1828352377, + "type": "A", + "name": "www", + "data": "3.3.3.3", + "priority": 0, + "port": 0, + "ttl": 300, + "weight": 0, + "flags": 0 + } + }, + { + "index": 27, + "value": { + "id": 1828352378, + "type": "A", + "name": "www", + "data": "1.1.1.1", + "priority": 0, + "port": 0, + "ttl": 300, + "weight": 0, + "flags": 0 + } + }, + { + "index": 28, + "value": { + "id": 1828352379, + "type": "A", + "name": "www", + "data": "2.2.2.2", + "priority": 0, + "port": 0, + "ttl": 300, + "weight": 0, + "flags": 0 + } + }, + { + "index": 29, + "value": { + "id": 1828352380, + "type": "A", + "name": "www", + "data": "3.3.3.3", + "priority": 0, + "port": 0, + "ttl": 300, + "weight": 0, + "flags": 0 + } + }, + { + "index": 30, + "value": { + "id": 1828352381, + "type": "MX", + "name": "testmx", + "data": "bar.com", + "priority": 100, + "port": 0, + "ttl": 300, + "weight": 0, + "flags": 0 + } + }, + { + "index": 31, + "value": { + "id": 1828352382, + "type": "MX", + "name": "testmx", + "data": "foo.com", + "priority": 5, + "port": 0, + "ttl": 300, + "weight": 0, + "flags": 0 + } + }, + { + "index": 32, + "value": { + "id": 1828352383, + "type": "A", + "name": "www", + "data": "1.1.1.1", + "priority": 0, + "port": 0, + "ttl": 300, + "weight": 0, + "flags": 0 + } + }, + { + "index": 33, + "value": { + "id": 1828352384, + "type": "A", + "name": "www", + "data": "1.1.1.1", + "priority": 0, + "port": 0, + "ttl": 300, + "weight": 0, + "flags": 0 + } + }, + { + "index": 34, + "value": { + "id": 1828352385, + "type": "MX", + "name": "testmx", + "data": "foo.com", + "priority": 5, + "port": 0, + "ttl": 300, + "weight": 0, + "flags": 0 + } + }, + { + "index": 35, + "value": { + "id": 1828352387, + "type": "MX", + "name": "testmx", + "data": "bar.com", + "priority": 100, + "port": 0, + "ttl": 300, + "weight": 0, + "flags": 0 + } + }, + { + "index": 36, + "value": { + "id": 1828352388, + "type": "A", + "name": "testa", + "data": "1.1.1.1", + "priority": 0, + "port": 0, + "ttl": 333, + "weight": 0, + "flags": 0 + } + }, + { + "index": 37, + "value": { + "id": 1828352388, + "type": "A", + "name": "testa", + "data": "1.1.1.1", + "priority": 0, + "port": 0, + "ttl": 999, + "weight": 0, + "flags": 0 + } + }, + { + "index": 38, + "value": { + "id": 1828352389, + "type": "A", + "name": "@", + "data": "8.8.8.8", + "priority": 0, + "port": 0, + "ttl": 1000, + "weight": 0, + "flags": 0 + } + }, + { + "index": 39, + "value": { + "id": 1828352389, + "type": "A", + "name": "@", + "data": "8.8.8.8", + "priority": 0, + "port": 0, + "ttl": 500, + "weight": 0, + "flags": 0 + } + }, + { + "index": 40, + "value": { + "id": 1828352389, + "type": "A", + "name": "@", + "data": "8.8.8.8", + "priority": 0, + "port": 0, + "ttl": 666, + "weight": 0, + "flags": 0 + } + }, + { + "index": 41, + "value": { + "id": 1828352390, + "type": "A", + "name": "www", + "data": "1.2.3.4", + "priority": 0, + "port": 0, + "ttl": 300, + "weight": 0, + "flags": 0 + } + }, + { + "index": 42, + "value": { + "id": 1828352390, + "type": "A", + "name": "www", + "data": "2.2.2.2", + "priority": 0, + "port": 0, + "ttl": 300, + "weight": 0, + "flags": 0 + } + }, + { + "index": 43, + "value": { + "id": 1828352390, + "type": "A", + "name": "www", + "data": "2.2.2.2", + "priority": 0, + "port": 0, + "ttl": 400, + "weight": 0, + "flags": 0 + } + }, + { + "index": 44, + "value": { + "id": 1828352391, + "type": "A", + "name": "www", + "data": "5.6.7.8", + "priority": 0, + "port": 0, + "ttl": 300, + "weight": 0, + "flags": 0 + } + }, + { + "index": 45, + "value": { + "id": 1828352391, + "type": "A", + "name": "www", + "data": "5.6.7.8", + "priority": 0, + "port": 0, + "ttl": 400, + "weight": 0, + "flags": 0 + } + }, + { + "index": 46, + "value": { + "id": 1828352400, + "type": "A", + "name": "www", + "data": "5.6.7.8", + "priority": 0, + "port": 0, + "ttl": 400, + "weight": 0, + "flags": 0 + } + }, + { + "index": 47, + "value": { + "id": 1828352400, + "type": "A", + "name": "www", + "data": "5.6.7.8", + "priority": 0, + "port": 0, + "ttl": 700, + "weight": 0, + "flags": 0 + } + }, + { + "index": 48, + "value": { + "id": 1828352403, + "type": "A", + "name": "www", + "data": "1.2.3.4", + "priority": 0, + "port": 0, + "ttl": 700, + "weight": 0, + "flags": 0 + } + }, + { + "index": 49, + "value": { + "id": 1828352404, + "type": "A", + "name": "foo", + "data": "1.2.3.4", + "priority": 0, + "port": 0, + "ttl": 300, + "weight": 0, + "flags": 0 + } + }, + { + "index": 50, + "value": { + "id": 1828352407, + "type": "MX", + "name": "foo", + "data": "mx.google.com", + "priority": 5, + "port": 0, + "ttl": 300, + "weight": 0, + "flags": 0 + } + }, + { + "index": 51, + "value": { + "id": 1828352410, + "type": "A", + "name": "foo", + "data": "4.5.6.7", + "priority": 0, + "port": 0, + "ttl": 300, + "weight": 0, + "flags": 0 + } + }, + { + "index": 52, + "value": { + "id": 1828352414, + "type": "CNAME", + "name": "foo", + "data": "google.com", + "priority": 0, + "port": 0, + "ttl": 300, + "weight": 0, + "flags": 0 + } + }, + { + "index": 53, + "value": { + "id": 1828352419, + "type": "A", + "name": "foo", + "data": "1.2.3.4", + "priority": 0, + "port": 0, + "ttl": 300, + "weight": 0, + "flags": 0 + } + }, + { + "index": 54, + "value": { + "id": 1828352421, + "type": "CNAME", + "name": "foo", + "data": "google2.com", + "priority": 0, + "port": 0, + "ttl": 300, + "weight": 0, + "flags": 0 + } + }, + { + "index": 55, + "value": { + "id": 1828352422, + "type": "A", + "name": "@", + "data": "1.2.3.4", + "priority": 0, + "port": 0, + "ttl": 300, + "weight": 0, + "flags": 0 + } + }, + { + "index": 56, + "value": { + "id": 1828352423, + "type": "CNAME", + "name": "foo", + "data": "@", + "priority": 0, + "port": 0, + "ttl": 300, + "weight": 0, + "flags": 0 + } + }, + { + "index": 57, + "value": { + "id": 1828352424, + "type": "A", + "name": "@", + "data": "1.2.3.4", + "priority": 0, + "port": 0, + "ttl": 300, + "weight": 0, + "flags": 0 + } + }, + { + "index": 58, + "value": { + "id": 1828352426, + "type": "MX", + "name": "foo", + "data": "@", + "priority": 8, + "port": 0, + "ttl": 300, + "weight": 0, + "flags": 0 + } + }, + { + "index": 59, + "value": { + "id": 1828352430, + "type": "A", + "name": "nmx", + "data": "1.2.3.3", + "priority": 0, + "port": 0, + "ttl": 300, + "weight": 0, + "flags": 0 + } + }, + { + "index": 60, + "value": { + "id": 1828352432, + "type": "A", + "name": "www", + "data": "1.2.3.9", + "priority": 0, + "port": 0, + "ttl": 300, + "weight": 0, + "flags": 0 + } + }, + { + "index": 61, + "value": { + "id": 1828352434, + "type": "MX", + "name": "nmx", + "data": "www.dnscontroltest-digitalocean.com", + "priority": 9, + "port": 0, + "ttl": 300, + "weight": 0, + "flags": 0 + } + }, + { + "index": 62, + "value": { + "id": 1828352435, + "type": "MX", + "name": "nmx", + "data": "nmx.dnscontroltest-digitalocean.com", + "priority": 3, + "port": 0, + "ttl": 300, + "weight": 0, + "flags": 0 + } + }, + { + "index": 63, + "value": { + "id": 1828352437, + "type": "A", + "name": "@", + "data": "1.2.3.2", + "priority": 0, + "port": 0, + "ttl": 300, + "weight": 0, + "flags": 0 + } + }, + { + "index": 64, + "value": { + "id": 1828352438, + "type": "A", + "name": "www", + "data": "1.2.3.8", + "priority": 0, + "port": 0, + "ttl": 300, + "weight": 0, + "flags": 0 + } + }, + { + "index": 65, + "value": { + "id": 1828352440, + "type": "MX", + "name": "@", + "data": "www.dnscontroltest-digitalocean.com", + "priority": 8, + "port": 0, + "ttl": 300, + "weight": 0, + "flags": 0 + } + }, + { + "index": 66, + "value": { + "id": 1828352441, + "type": "MX", + "name": "@", + "data": "@", + "priority": 2, + "port": 0, + "ttl": 300, + "weight": 0, + "flags": 0 + } + }, + { + "index": 67, + "value": { + "id": 1828352442, + "type": "NS", + "name": "xyz", + "data": "ns2.foo.com", + "priority": 0, + "port": 0, + "ttl": 300, + "weight": 0, + "flags": 0 + } + }, + { + "index": 68, + "value": { + "id": 1828352443, + "type": "NS", + "name": "xyz", + "data": "ns1.foo.com", + "priority": 0, + "port": 0, + "ttl": 300, + "weight": 0, + "flags": 0 + } + }, + { + "index": 69, + "value": { + "id": 1828352444, + "type": "A", + "name": "@", + "data": "1.2.3.4", + "priority": 0, + "port": 0, + "ttl": 300, + "weight": 0, + "flags": 0 + } + }, + { + "index": 70, + "value": { + "id": 1828352445, + "type": "NS", + "name": "foo", + "data": "@", + "priority": 0, + "port": 0, + "ttl": 300, + "weight": 0, + "flags": 0 + } + }, + { + "index": 71, + "value": { + "id": 1828352446, + "type": "NS", + "name": "@", + "data": "ns1.foo.com", + "priority": 0, + "port": 0, + "ttl": 300, + "weight": 0, + "flags": 0 + } + }, + { + "index": 72, + "value": { + "id": 1828352447, + "type": "NS", + "name": "@", + "data": "ns2.foo.com", + "priority": 0, + "port": 0, + "ttl": 300, + "weight": 0, + "flags": 0 + } + }, + { + "index": 73, + "value": { + "id": 1828352468, + "type": "TXT", + "name": "foo254", + "data": "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", + "priority": 0, + "port": 0, + "ttl": 300, + "weight": 0, + "flags": 0 + } + }, + { + "index": 74, + "value": { + "id": 1828352469, + "type": "TXT", + "name": "foo255", + "data": "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB", + "priority": 0, + "port": 0, + "ttl": 300, + "weight": 0, + "flags": 0 + } + }, + { + "index": 75, + "value": { + "id": 1828352470, + "type": "TXT", + "name": "foo256", + "data": "CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC", + "priority": 0, + "port": 0, + "ttl": 300, + "weight": 0, + "flags": 0 + } + }, + { + "index": 76, + "value": { + "id": 1828352471, + "type": "TXT", + "name": "foosq", + "data": "quo'te", + "priority": 0, + "port": 0, + "ttl": 300, + "weight": 0, + "flags": 0 + } + }, + { + "index": 77, + "value": { + "id": 1828352472, + "type": "TXT", + "name": "foobt", + "data": "blah`blah", + "priority": 0, + "port": 0, + "ttl": 300, + "weight": 0, + "flags": 0 + } + }, + { + "index": 78, + "value": { + "id": 1828352475, + "type": "TXT", + "name": "foodq", + "data": "in\"side", + "priority": 0, + "port": 0, + "ttl": 300, + "weight": 0, + "flags": 0 + } + }, + { + "index": 79, + "value": { + "id": 1828352476, + "type": "TXT", + "name": "foodqs", + "data": "\"left", + "priority": 0, + "port": 0, + "ttl": 300, + "weight": 0, + "flags": 0 + } + }, + { + "index": 80, + "value": { + "id": 1828352476, + "type": "TXT", + "name": "foodqs", + "data": "in\"ter\"ior", + "priority": 0, + "port": 0, + "ttl": 300, + "weight": 0, + "flags": 0 + } + }, + { + "index": 81, + "value": { + "id": 1828352476, + "type": "TXT", + "name": "foodqs", + "data": "right\"", + "priority": 0, + "port": 0, + "ttl": 300, + "weight": 0, + "flags": 0 + } + }, + { + "index": 82, + "value": { + "id": 1828352479, + "type": "TXT", + "name": "foosc1", + "data": "semi;colon", + "priority": 0, + "port": 0, + "ttl": 300, + "weight": 0, + "flags": 0 + } + }, + { + "index": 83, + "value": { + "id": 1828352480, + "type": "TXT", + "name": "foosc2", + "data": "wssemi ; colon", + "priority": 0, + "port": 0, + "ttl": 300, + "weight": 0, + "flags": 0 + } + }, + { + "index": 84, + "value": { + "id": 1828352481, + "type": "TXT", + "name": "foosp", + "data": "with spaces", + "priority": 0, + "port": 0, + "ttl": 300, + "weight": 0, + "flags": 0 + } + }, + { + "index": 85, + "value": { + "id": 1828352483, + "type": "TXT", + "name": "foows1", + "data": "trailingws ", + "priority": 0, + "port": 0, + "ttl": 300, + "weight": 0, + "flags": 0 + } + }, + { + "index": 86, + "value": { + "id": 1828352484, + "type": "TXT", + "name": "foo", + "data": "v=spf1 ip4:99.99.99.99 -all", + "priority": 0, + "port": 0, + "ttl": 300, + "weight": 0, + "flags": 0 + } + }, + { + "index": 87, + "value": { + "id": 1828352485, + "type": "MX", + "name": "bar", + "data": "bar.com", + "priority": 5, + "port": 0, + "ttl": 300, + "weight": 0, + "flags": 0 + } + }, + { + "index": 88, + "value": { + "id": 1828352486, + "type": "A", + "name": "decoy", + "data": "1.1.1.1", + "priority": 0, + "port": 0, + "ttl": 300, + "weight": 0, + "flags": 0 + } + }, + { + "index": 89, + "value": { + "id": 1828352486, + "type": "A", + "name": "decoy", + "data": "2.2.2.2", + "priority": 0, + "port": 0, + "ttl": 300, + "weight": 0, + "flags": 0 + } + }, + { + "index": 90, + "value": { + "id": 1828352486, + "type": "A", + "name": "decoy", + "data": "3.3.3.3", + "priority": 0, + "port": 0, + "ttl": 300, + "weight": 0, + "flags": 0 + } + }, + { + "index": 91, + "value": { + "id": 1828352488, + "type": "A", + "name": "foo", + "data": "1.2.3.4", + "priority": 0, + "port": 0, + "ttl": 300, + "weight": 0, + "flags": 0 + } + }, + { + "index": 92, + "value": { + "id": 1828352489, + "type": "A", + "name": "foo", + "data": "2.3.4.5", + "priority": 0, + "port": 0, + "ttl": 300, + "weight": 0, + "flags": 0 + } + }, + { + "index": 93, + "value": { + "id": 1828352489, + "type": "A", + "name": "foo", + "data": "3.4.5.6", + "priority": 0, + "port": 0, + "ttl": 300, + "weight": 0, + "flags": 0 + } + }, + { + "index": 94, + "value": { + "id": 1828352490, + "type": "A", + "name": "foo", + "data": "3.4.5.6", + "priority": 0, + "port": 0, + "ttl": 300, + "weight": 0, + "flags": 0 + } + }, + { + "index": 95, + "value": { + "id": 1828352491, + "type": "A", + "name": "bar", + "data": "1.2.3.4", + "priority": 0, + "port": 0, + "ttl": 300, + "weight": 0, + "flags": 0 + } + }, + { + "index": 96, + "value": { + "id": 1828352492, + "type": "A", + "name": "foo", + "data": "2.3.4.5", + "priority": 0, + "port": 0, + "ttl": 300, + "weight": 0, + "flags": 0 + } + }, + { + "index": 97, + "value": { + "id": 1828352493, + "type": "A", + "name": "foo", + "data": "3.4.5.6", + "priority": 0, + "port": 0, + "ttl": 300, + "weight": 0, + "flags": 0 + } + }, + { + "index": 98, + "value": { + "id": 1828352493, + "type": "A", + "name": "foo", + "data": "8.8.8.8", + "priority": 0, + "port": 0, + "ttl": 300, + "weight": 0, + "flags": 0 + } + }, + { + "index": 99, + "value": { + "id": 1828352494, + "type": "MX", + "name": "foo", + "data": "bar.dnscontroltest-digitalocean.com", + "priority": 20, + "port": 0, + "ttl": 300, + "weight": 0, + "flags": 0 + } + }, + { + "index": 100, + "value": { + "id": 1828352495, + "type": "MX", + "name": "foo", + "data": "foo.dnscontroltest-digitalocean.com", + "priority": 10, + "port": 0, + "ttl": 300, + "weight": 0, + "flags": 0 + } + }, + { + "index": 101, + "value": { + "id": 1828352496, + "type": "A", + "name": "foo", + "data": "8.8.8.8", + "priority": 0, + "port": 0, + "ttl": 300, + "weight": 0, + "flags": 0 + } + }, + { + "index": 102, + "value": { + "id": 1828352499, + "type": "A", + "name": "xn--ndaaa", + "data": "1.2.3.4", + "priority": 0, + "port": 0, + "ttl": 300, + "weight": 0, + "flags": 0 + } + }, + { + "index": 103, + "value": { + "id": 1828352499, + "type": "A", + "name": "xn--ndaaa", + "data": "2.2.2.2", + "priority": 0, + "port": 0, + "ttl": 300, + "weight": 0, + "flags": 0 + } + }, + { + "index": 104, + "value": { + "id": 1828352500, + "type": "A", + "name": "xn--fiq228c", + "data": "1.2.3.4", + "priority": 0, + "port": 0, + "ttl": 300, + "weight": 0, + "flags": 0 + } + }, + { + "index": 105, + "value": { + "id": 1828352501, + "type": "CNAME", + "name": "a", + "data": "xn--ndaaa.com", + "priority": 0, + "port": 0, + "ttl": 300, + "weight": 0, + "flags": 0 + } + }, + { + "index": 106, + "value": { + "id": 1828352503, + "type": "CNAME", + "name": "xn--o-0gab", + "data": "xn--ndaaa.xn--vhquv", + "priority": 0, + "port": 0, + "ttl": 300, + "weight": 0, + "flags": 0 + } + }, + { + "index": 107, + "value": { + "id": 1828352504, + "type": "CAA", + "name": "@", + "data": ";", + "priority": 0, + "port": 0, + "ttl": 300, + "weight": 0, + "flags": 0, + "tag": "issuewild" + } + }, + { + "index": 108, + "value": { + "id": 1828352504, + "type": "CAA", + "name": "@", + "data": "example.com", + "priority": 0, + "port": 0, + "ttl": 300, + "weight": 0, + "flags": 0, + "tag": "issuewild" + } + }, + { + "index": 109, + "value": { + "id": 1828352504, + "type": "CAA", + "name": "@", + "data": "letsencrypt.org", + "priority": 0, + "port": 0, + "ttl": 300, + "weight": 0, + "flags": 0, + "tag": "issue" + } + }, + { + "index": 110, + "value": { + "id": 1828352504, + "type": "CAA", + "name": "@", + "data": "letsencrypt.org", + "priority": 0, + "port": 0, + "ttl": 300, + "weight": 0, + "flags": 0, + "tag": "issuewild" + } + }, + { + "index": 111, + "value": { + "id": 1828352506, + "type": "CAA", + "name": "@", + "data": "letsencrypt.org", + "priority": 0, + "port": 0, + "ttl": 300, + "weight": 0, + "flags": 0, + "tag": "issue" + } + }, + { + "index": 112, + "value": { + "id": 1828352506, + "type": "CAA", + "name": "@", + "data": "letsencrypt.org", + "priority": 0, + "port": 0, + "ttl": 300, + "weight": 0, + "flags": 128, + "tag": "issue" + } + }, + { + "index": 113, + "value": { + "id": 1828352513, + "type": "SRV", + "name": "_sip._tcp", + "data": "foo.com", + "priority": 5, + "port": 7, + "ttl": 300, + "weight": 6, + "flags": 0 + } + }, + { + "index": 114, + "value": { + "id": 1828352513, + "type": "SRV", + "name": "_sip._tcp", + "data": "foo.com", + "priority": 52, + "port": 7, + "ttl": 300, + "weight": 6, + "flags": 0 + } + }, + { + "index": 115, + "value": { + "id": 1828352513, + "type": "SRV", + "name": "_sip._tcp", + "data": "foo.com", + "priority": 52, + "port": 7, + "ttl": 300, + "weight": 62, + "flags": 0 + } + }, + { + "index": 116, + "value": { + "id": 1828352513, + "type": "SRV", + "name": "_sip._tcp", + "data": "foo.com", + "priority": 52, + "port": 72, + "ttl": 300, + "weight": 62, + "flags": 0 + } + }, + { + "index": 117, + "value": { + "id": 1828352515, + "type": "SRV", + "name": "_sip._tcp", + "data": "foo2.com", + "priority": 5, + "port": 70, + "ttl": 300, + "weight": 60, + "flags": 0 + } + }, + { + "index": 118, + "value": { + "id": 1828352518, + "type": "SRV", + "name": "_sip._tcp", + "data": "foo3.com", + "priority": 15, + "port": 75, + "ttl": 300, + "weight": 65, + "flags": 0 + } + }, + { + "index": 119, + "value": { + "id": 1828352518, + "type": "SRV", + "name": "_sip._tcp", + "data": "foo4.com", + "priority": 15, + "port": 75, + "ttl": 300, + "weight": 65, + "flags": 0 + } + }, + { + "index": 120, + "value": { + "id": 1828352523, + "type": "SRV", + "name": "_sip._tcp", + "data": ".", + "priority": 15, + "port": 75, + "ttl": 300, + "weight": 65, + "flags": 0 + } + }, + { + "index": 121, + "value": { + "id": 1828352524, + "type": "SRV", + "name": "_sip._tcp", + "data": "foo.com", + "priority": 5, + "port": 7, + "ttl": 333, + "weight": 6, + "flags": 0 + } + }, + { + "index": 122, + "value": { + "id": 1828352524, + "type": "SRV", + "name": "_sip._tcp", + "data": "foo.com", + "priority": 5, + "port": 7, + "ttl": 4400, + "weight": 6, + "flags": 0 + } + }, + { + "index": 123, + "value": { + "id": 1828352528, + "type": "A", + "name": "bar", + "data": "5.5.5.5", + "priority": 0, + "port": 0, + "ttl": 300, + "weight": 0, + "flags": 0 + } + }, + { + "index": 124, + "value": { + "id": 1828352529, + "type": "A", + "name": "foo", + "data": "1.2.3.4", + "priority": 0, + "port": 0, + "ttl": 300, + "weight": 0, + "flags": 0 + } + }, + { + "index": 125, + "value": { + "id": 1828352530, + "type": "A", + "name": "foo", + "data": "2.3.4.5", + "priority": 0, + "port": 0, + "ttl": 300, + "weight": 0, + "flags": 0 + } + }, + { + "index": 126, + "value": { + "id": 1828352531, + "type": "TXT", + "name": "foo", + "data": "simple", + "priority": 0, + "port": 0, + "ttl": 300, + "weight": 0, + "flags": 0 + } + }, + { + "index": 127, + "value": { + "id": 1828352532, + "type": "CNAME", + "name": "mail", + "data": "ghs.googlehosted.com", + "priority": 0, + "port": 0, + "ttl": 300, + "weight": 0, + "flags": 0 + } + }, + { + "index": 128, + "value": { + "id": 1828352535, + "type": "A", + "name": "@", + "data": "1.2.3.4", + "priority": 0, + "port": 0, + "ttl": 300, + "weight": 0, + "flags": 0 + } + }, + { + "index": 129, + "value": { + "id": 1828352536, + "type": "A", + "name": "@", + "data": "2.3.4.5", + "priority": 0, + "port": 0, + "ttl": 300, + "weight": 0, + "flags": 0 + } + }, + { + "index": 130, + "value": { + "id": 1828352537, + "type": "TXT", + "name": "@", + "data": "simple", + "priority": 0, + "port": 0, + "ttl": 300, + "weight": 0, + "flags": 0 + } + }, + { + "index": 131, + "value": { + "id": 1828352538, + "type": "A", + "name": "bar", + "data": "5.5.5.5", + "priority": 0, + "port": 0, + "ttl": 300, + "weight": 0, + "flags": 0 + } + }, + { + "index": 132, + "value": { + "id": 1828352539, + "type": "CNAME", + "name": "mail", + "data": "ghs.googlehosted.com", + "priority": 0, + "port": 0, + "ttl": 300, + "weight": 0, + "flags": 0 + } + }, + { + "index": 133, + "value": { + "id": 1828352581, + "type": "A", + "name": "@", + "data": "2.2.2.2", + "priority": 0, + "port": 0, + "ttl": 300, + "weight": 0, + "flags": 0 + } + }, + { + "index": 134, + "value": { + "id": 1828352582, + "type": "TXT", + "name": "@", + "data": "asimple", + "priority": 0, + "port": 0, + "ttl": 300, + "weight": 0, + "flags": 0 + } + }, + { + "index": 135, + "value": { + "id": 1828352583, + "type": "A", + "name": "foo", + "data": "1.2.3.4", + "priority": 0, + "port": 0, + "ttl": 300, + "weight": 0, + "flags": 0 + } + }, + { + "index": 136, + "value": { + "id": 1828352584, + "type": "TXT", + "name": "foo", + "data": "simple", + "priority": 0, + "port": 0, + "ttl": 300, + "weight": 0, + "flags": 0 + } + }, + { + "index": 137, + "value": { + "id": 1828352586, + "type": "A", + "name": "bar.bat", + "data": "5.5.5.5", + "priority": 0, + "port": 0, + "ttl": 300, + "weight": 0, + "flags": 0 + } + }, + { + "index": 138, + "value": { + "id": 1828352587, + "type": "A", + "name": "foo.bat", + "data": "1.2.3.4", + "priority": 0, + "port": 0, + "ttl": 300, + "weight": 0, + "flags": 0 + } + }, + { + "index": 139, + "value": { + "id": 1828352588, + "type": "A", + "name": "foo.bat", + "data": "2.3.4.5", + "priority": 0, + "port": 0, + "ttl": 300, + "weight": 0, + "flags": 0 + } + }, + { + "index": 140, + "value": { + "id": 1828352589, + "type": "TXT", + "name": "foo.bat", + "data": "simple", + "priority": 0, + "port": 0, + "ttl": 300, + "weight": 0, + "flags": 0 + } + }, + { + "index": 141, + "value": { + "id": 1828352591, + "type": "CNAME", + "name": "mail.bat", + "data": "ghs.googlehosted.com", + "priority": 0, + "port": 0, + "ttl": 300, + "weight": 0, + "flags": 0 + } + }, + { + "index": 142, + "value": { + "id": 1828352595, + "type": "A", + "name": "foo", + "data": "1.1.1.1", + "priority": 0, + "port": 0, + "ttl": 300, + "weight": 0, + "flags": 0 + } + }, + { + "index": 143, + "value": { + "id": 1828352596, + "type": "A", + "name": "foo", + "data": "10.10.10.10", + "priority": 0, + "port": 0, + "ttl": 300, + "weight": 0, + "flags": 0 + } + }, + { + "index": 144, + "value": { + "id": 1828352596, + "type": "A", + "name": "foo", + "data": "11.11.11.11", + "priority": 0, + "port": 0, + "ttl": 300, + "weight": 0, + "flags": 0 + } + }, + { + "index": 145, + "value": { + "id": 1828352596, + "type": "A", + "name": "foo", + "data": "12.12.12.12", + "priority": 0, + "port": 0, + "ttl": 300, + "weight": 0, + "flags": 0 + } + }, + { + "index": 146, + "value": { + "id": 1828352596, + "type": "A", + "name": "foo", + "data": "13.13.13.13", + "priority": 0, + "port": 0, + "ttl": 300, + "weight": 0, + "flags": 0 + } + }, + { + "index": 147, + "value": { + "id": 1828352596, + "type": "A", + "name": "foo", + "data": "14.14.14.14", + "priority": 0, + "port": 0, + "ttl": 300, + "weight": 0, + "flags": 0 + } + }, + { + "index": 148, + "value": { + "id": 1828352597, + "type": "AAAA", + "name": "foo", + "data": "2003:dd:d7ff::fe71:aaaa", + "priority": 0, + "port": 0, + "ttl": 300, + "weight": 0, + "flags": 0 + } + }, + { + "index": 149, + "value": { + "id": 1828352598, + "type": "MX", + "name": "foo", + "data": "aspmx.l.google.com", + "priority": 10, + "port": 0, + "ttl": 300, + "weight": 0, + "flags": 0 + } + }, + { + "index": 150, + "value": { + "id": 1828352599, + "type": "MX", + "name": "foo", + "data": "alt1.aspmx.l.google.com", + "priority": 20, + "port": 0, + "ttl": 300, + "weight": 0, + "flags": 0 + } + }, + { + "index": 151, + "value": { + "id": 1828352600, + "type": "A", + "name": "zzz", + "data": "3.3.3.3", + "priority": 0, + "port": 0, + "ttl": 300, + "weight": 0, + "flags": 0 + } + }, + { + "index": 152, + "value": { + "id": 1828352601, + "type": "A", + "name": "zzz", + "data": "4.4.4.4", + "priority": 0, + "port": 0, + "ttl": 300, + "weight": 0, + "flags": 0 + } + }, + { + "index": 153, + "value": { + "id": 1828352602, + "type": "AAAA", + "name": "zzz", + "data": "2003:dd:d7ff::fe71:cccc", + "priority": 0, + "port": 0, + "ttl": 300, + "weight": 0, + "flags": 0 + } + }, + { + "index": 154, + "value": { + "id": 1828352608, + "type": "CNAME", + "name": "bar", + "data": "redact2.acm-validations.aws", + "priority": 0, + "port": 0, + "ttl": 300, + "weight": 0, + "flags": 0 + } + }, + { + "index": 155, + "value": { + "id": 1828352609, + "type": "CNAME", + "name": "foo", + "data": "redact1.acm-validations.aws", + "priority": 0, + "port": 0, + "ttl": 300, + "weight": 0, + "flags": 0 + } + }, + { + "index": 156, + "value": { + "id": 1828352610, + "type": "A", + "name": "dyndns-city1", + "data": "91.42.1.1", + "priority": 0, + "port": 0, + "ttl": 300, + "weight": 0, + "flags": 0 + } + }, + { + "index": 157, + "value": { + "id": 1828352611, + "type": "AAAA", + "name": "dyndns-city1", + "data": "2003:dd:d7ff::fe71:ce77", + "priority": 0, + "port": 0, + "ttl": 300, + "weight": 0, + "flags": 0 + } + }, + { + "index": 158, + "value": { + "id": 1828352612, + "type": "A", + "name": "dyndns-city2", + "data": "91.42.1.2", + "priority": 0, + "port": 0, + "ttl": 300, + "weight": 0, + "flags": 0 + } + }, + { + "index": 159, + "value": { + "id": 1828352613, + "type": "AAAA", + "name": "dyndns-city2", + "data": "2003:dd:d7ff::fe71:ce78", + "priority": 0, + "port": 0, + "ttl": 300, + "weight": 0, + "flags": 0 + } + }, + { + "index": 160, + "value": { + "id": 1828352614, + "type": "A", + "name": "testdefined", + "data": "2.2.2.2", + "priority": 0, + "port": 0, + "ttl": 300, + "weight": 0, + "flags": 0 + } + }, + { + "index": 161, + "value": { + "id": 1828352614, + "type": "A", + "name": "testdefined", + "data": "9.9.9.9", + "priority": 0, + "port": 0, + "ttl": 300, + "weight": 0, + "flags": 0 + } + }, + { + "index": 162, + "value": { + "id": 1828352615, + "type": "A", + "name": "testignore", + "data": "8.8.8.8", + "priority": 0, + "port": 0, + "ttl": 300, + "weight": 0, + "flags": 0 + } + }, + { + "index": 163, + "value": { + "id": 1828352618, + "type": "TXT", + "name": "final", + "data": "TestDNSProviders was successful!", + "priority": 0, + "port": 0, + "ttl": 300, + "weight": 0, + "flags": 0 + } + }, + { + "index": 164, + "value": { + "id": 1828352620, + "type": "TXT", + "name": "final", + "data": "TestDNSProviders was successful!", + "priority": 0, + "port": 0, + "ttl": 300, + "weight": 0, + "flags": 0 + } + }, + { + "index": 165, + "value": { + "id": 1828352621, + "type": "NS", + "name": "@", + "data": "ns1.example.com", + "priority": 0, + "port": 0, + "ttl": 300, + "weight": 0, + "flags": 0 + } + }, + { + "index": 166, + "value": { + "id": 1828352622, + "type": "NS", + "name": "@", + "data": "ns2.example.com", + "priority": 0, + "port": 0, + "ttl": 300, + "weight": 0, + "flags": 0 + } + } +] diff --git a/providers/dnscale/auditrecords.go b/providers/dnscale/auditrecords.go index 4ea641e91f..4d77683d3e 100644 --- a/providers/dnscale/auditrecords.go +++ b/providers/dnscale/auditrecords.go @@ -1,14 +1,14 @@ package dnscale import ( - "github.com/DNSControl/dnscontrol/v4/models" - "github.com/DNSControl/dnscontrol/v4/pkg/rejectif" + "github.com/DNSControl/dnscontrol/v5/models" + "github.com/DNSControl/dnscontrol/v5/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 { +func AuditRecords(records models.Records) []error { a := rejectif.Auditor{} a.Add("MX", rejectif.MxNull) // MX records must have a target diff --git a/providers/dnscale/dnscaleProvider.go b/providers/dnscale/dnscaleProvider.go index be4c2a2a70..7825063961 100644 --- a/providers/dnscale/dnscaleProvider.go +++ b/providers/dnscale/dnscaleProvider.go @@ -12,9 +12,11 @@ import ( "strings" "time" - "github.com/DNSControl/dnscontrol/v4/models" - "github.com/DNSControl/dnscontrol/v4/pkg/diff2" - "github.com/DNSControl/dnscontrol/v4/pkg/providers" + dnsv2 "codeberg.org/miekg/dns" + "github.com/DNSControl/dnscontrol/v5/models" + "github.com/DNSControl/dnscontrol/v5/pkg/diff2" + privatetypes "github.com/DNSControl/dnscontrol/v5/pkg/privatetypes" + "github.com/DNSControl/dnscontrol/v5/pkg/providers" ) /* @@ -174,7 +176,7 @@ func (p *dnscaleProvider) GetZoneRecords(dc *models.DomainConfig) (models.Record continue } - rc, err := toRecordConfig(domain, rec) + rc, err := toRecordConfig(dc, rec) if err != nil { return nil, fmt.Errorf("failed to convert record: %w", err) } @@ -204,7 +206,7 @@ func (p *dnscaleProvider) GetZoneRecordsCorrections(dc *models.DomainConfig, cur case diff2.REPORT: corrections = append(corrections, &models.Correction{Msg: change.MsgsJoined}) case diff2.CREATE: - rec := fromRecordConfig(change.New[0], dc.Name) + rec := fromRecordConfig(change.New[0]) corrections = append(corrections, &models.Correction{ Msg: change.Msgs[0], F: func() error { @@ -213,7 +215,7 @@ func (p *dnscaleProvider) GetZoneRecordsCorrections(dc *models.DomainConfig, cur }) case diff2.CHANGE: oldRec := change.Old[0].Original.(Record) - rec := fromRecordConfig(change.New[0], dc.Name) + rec := fromRecordConfig(change.New[0]) corrections = append(corrections, &models.Correction{ Msg: fmt.Sprintf("%s; DNScale RecordID: %v", change.Msgs[0], oldRec.ID), F: func() error { @@ -416,13 +418,10 @@ func (p *dnscaleProvider) deleteRecord(zoneID, recordID string) error { // Record conversion functions // toRecordConfig converts a DNScale Record to a RecordConfig. -func toRecordConfig(domain string, r Record) (*models.RecordConfig, error) { - rc := &models.RecordConfig{ - TTL: uint32(r.TTL), - Original: r, - } - +func toRecordConfig(dc *models.DomainConfig, r Record) (*models.RecordConfig, error) { // Extract label from full record name + domain := dc.Name + name := strings.TrimSuffix(r.Name, ".") domainWithDot := domain + "." if before, ok := strings.CutSuffix(r.Name, domainWithDot); ok { @@ -434,22 +433,33 @@ func toRecordConfig(domain string, r Record) (*models.RecordConfig, error) { if name == "" { name = "@" } - rc.SetLabel(name, domain) + label := dc.LabelFromShort(name) + + // TODO(tom): The above code can probably be replaced with the following line, but I haven't tested it yet. + //label := dc.LabelFromFQDNWithDot(r.Name) + // And if that doesn't work... try this: + //label := dc.LabelFromFQDNNoDot(r.Name) content := r.Content + ttl := uint32(r.TTL) + var rc *models.RecordConfig + var err error switch r.Type { case "A", "AAAA": - rc.Type = r.Type - return rc, rc.SetTarget(content) + rc, err = dc.NewRecordConfig(label, ttl, r.Type, content) case "CNAME", "NS", "PTR", "ALIAS": - rc.Type = r.Type + // TODO(tlim): Test without this "if". It may no longer be needed. + // Ensure FQDN if !strings.HasSuffix(content, ".") { content = content + "." } - return rc, rc.SetTarget(content) + rc, err = dc.NewRecordConfig(label, ttl, r.Type, content) case "MX": + // TODO(tlim): Test replacing this with simply: + // rc, err = dc.NewRecordConfigParse(label, ttl, r.Type, content) + // DNScale API returns MX as "priority target" in content field // If priority field is 0, parse it from content priority := uint16(r.Priority) @@ -466,96 +476,111 @@ func toRecordConfig(domain string, r Record) (*models.RecordConfig, error) { if !strings.HasSuffix(target, ".") { target = target + "." } - return rc, rc.SetTargetMX(priority, target) + rc, err = dc.NewRecordConfig(label, ttl, r.Type, priority, target) case "TXT": // DNScale returns TXT content without surrounding quotes - return rc, rc.SetTargetTXT(content) + rc, err = dc.NewRecordConfig(label, ttl, r.Type, content) case "SRV": // DNScale API returns SRV as "priority weight port target" - // SetTargetSRV expects priority, weight, port, target separately - parts := strings.Fields(content) - if len(parts) != 4 { - return nil, fmt.Errorf("SRV value does not contain 4 fields: (%q)", content) - } - priority, err := strconv.ParseUint(parts[0], 10, 16) - if err != nil { - return nil, fmt.Errorf("SRV priority parse error: %w", err) - } - weight, err := strconv.ParseUint(parts[1], 10, 16) - if err != nil { - return nil, fmt.Errorf("SRV weight parse error: %w", err) - } - port, err := strconv.ParseUint(parts[2], 10, 16) - if err != nil { - return nil, fmt.Errorf("SRV port parse error: %w", err) - } - target := parts[3] - if !strings.HasSuffix(target, ".") { - target = target + "." + + // TODO(tlim): If the NEW version works, please remove the commented out "OLD" version. + + // OLD: + + // // Set|TargetSRV expects priority, weight, port, target separately + // parts := strings.Fields(content) + // if len(parts) != 4 { + // return nil, fmt.Errorf("SRV value does not contain 4 fields: (%q)", content) + // } + // priority, parseErr := strconv.ParseUint(parts[0], 10, 16) + // if parseErr != nil { + // return nil, fmt.Errorf("SRV priority parse error: %w", parseErr) + // } + // weight, parseErr := strconv.ParseUint(parts[1], 10, 16) + // if parseErr != nil { + // return nil, fmt.Errorf("SRV weight parse error: %w", parseErr) + // } + // port, parseErr := strconv.ParseUint(parts[2], 10, 16) + // if parseErr != nil { + // return nil, fmt.Errorf("SRV port parse error: %w", parseErr) + // } + // target := parts[3] + // if !strings.HasSuffix(target, ".") { + // target = target + "." + // } + // rc, err = dc.NewRecordConfig(label, ttl, r.Type, uint16(priority), uint16(weight), uint16(port), target) + + // NEW: + if !strings.HasSuffix(content, ".") { + content = content + "." } - return rc, rc.SetTargetSRV(uint16(priority), uint16(weight), uint16(port), target) - case "CAA": - // DNScale returns CAA as "flag tag value" - return rc, rc.SetTargetCAAString(content) - case "TLSA": - // DNScale returns TLSA as "usage selector matchingType certificate" - return rc, rc.SetTargetTLSAString(content) - case "SSHFP": - // DNScale returns SSHFP as "algorithm fpType fingerprint" - return rc, rc.SetTargetSSHFPString(content) - case "HTTPS": - // DNScale returns HTTPS as "priority target params" - // Must set Type before calling SetTargetSVCBString (it defaults to SVCB if empty) - rc.Type = "HTTPS" - return rc, rc.SetTargetSVCBString(domain, content) - case "SVCB": - // DNScale returns SVCB as "priority target params" - rc.Type = "SVCB" - return rc, rc.SetTargetSVCBString(domain, content) + rc, err = dc.NewRecordConfigParse(label, ttl, r.Type, content) + default: - return rc, rc.PopulateFromString(r.Type, content, domain) + rc, err = dc.NewRecordConfigParse(label, ttl, r.Type, content) + } + if err != nil { + return nil, err } + rc.Original = r + return rc, nil } // fromRecordConfig converts a RecordConfig to a DNScale Record. -func fromRecordConfig(rc *models.RecordConfig, domain string) Record { +func fromRecordConfig(rc *models.RecordConfig) Record { name := rc.GetLabel() + + // TODO(tlim): Is this needed? Seems like a no-op. // DNScale uses "@" for apex if name == "@" { name = "@" } - content := rc.GetTargetField() + var content string priority := 0 - switch rc.Type { - case "CNAME", "NS", "PTR", "ALIAS": + switch rc.TypeNum { + case dnsv2.TypeCNAME, dnsv2.TypeNS, dnsv2. // Remove trailing dot for DNScale API - content = strings.TrimSuffix(content, ".") - case "MX": - priority = int(rc.MxPreference) - content = strings.TrimSuffix(content, ".") - case "SRV": - // DNScale API expects full content: "priority weight port target" - target := rc.GetTargetField() - if !strings.HasSuffix(target, ".") { - target = target + "." - } - content = fmt.Sprintf("%d %d %d %s", rc.SrvPriority, rc.SrvWeight, rc.SrvPort, target) - case "CAA": - content = fmt.Sprintf("%d %s \"%s\"", rc.CaaFlag, rc.CaaTag, rc.GetTargetField()) - case "TLSA": - content = fmt.Sprintf("%d %d %d %s", rc.TlsaUsage, rc.TlsaSelector, rc.TlsaMatchingType, rc.GetTargetField()) - case "SSHFP": - content = fmt.Sprintf("%d %d %s", rc.SshfpAlgorithm, rc.SshfpFingerprint, rc.GetTargetField()) - case "HTTPS", "SVCB": - // Use GetTargetCombined() which formats SVCB/HTTPS records correctly via miekg/dns + TypePTR, privatetypes.TypeALIAS: + content = strings.TrimSuffix(rc.GetRDATA().String(), ".") + case dnsv2.TypeMX: + f := rc.AsMX() + priority = int(f.Preference) + content = strings.TrimSuffix(f.Mx, ".") + // case "SRV": + // // TODO(tlim): Remove commented out code if new code works. + // // DNScale API expects full content: "priority weight port target" + // // target := rc.Get|TargetField() + // // if !strings.HasSuffix(target, ".") { + // // target = target + "." + // // } + // // content = fmt.Sprintf("%d %d %d %s", rc.SrvPriority, rc.SrvWeight, rc.SrvPort, target) + // content = rc.GetRDATA().String() + + // case "CAA": + // // TODO(tlim): Remove commented out code if new code works. + // //content = fmt.Sprintf("%d %s \"%s\"", rc.CaaFlag, rc.CaaTag, rc.Get|TargetField()) + // content = rc.GetRDATA().String() + // case "TLSA": + // // TODO(tlim): Remove commented out code if new code works. + // //content = fmt.Sprintf("%d %d %d %s", rc.TlsaUsage, rc.TlsaSelector, rc.TlsaMatchingType, rc.Get|TargetField()) + // content = rc.GetRDATA().String() + // case "SSHFP": + // // TODO(tlim): Remove commented out code if new code works. + // //content = fmt.Sprintf("%d %d %s", rc.SshfpAlgorithm, rc.SshfpFingerprint, rc.Get|TargetField()) + // content = rc.GetRDATA().String() + case dnsv2.TypeHTTPS, dnsv2.TypeSVCB: + // Use GetRDATA().String() which formats SVCB/HTTPS records correctly via miekg/dns // DNScale API requires selective quote handling for SVCB params: // - alpn="h2,h3" must become alpn=h2,h3 (quotes stripped) // - ech="base64..." must keep quotes (required for base64 values) - content = stripSvcbQuotesExceptEch(rc.GetTargetCombined()) - case "TXT": - content = strings.Join(rc.GetTargetTXTSegmented(), "") + + content = stripSvcbQuotesExceptEch(rc.GetRDATA().String()) + case dnsv2.TypeTXT: + content = rc.GetTargetTXTJoined() + default: + content = rc.GetRDATA().String() } return Record{ diff --git a/providers/dnscale/dnscaleProvider_test.go b/providers/dnscale/dnscaleProvider_test.go new file mode 100644 index 0000000000..9afddfc8a5 --- /dev/null +++ b/providers/dnscale/dnscaleProvider_test.go @@ -0,0 +1,46 @@ +package dnscale + +import ( + "reflect" + "testing" + + "github.com/DNSControl/dnscontrol/v5/models" +) + +func TestToRecordConfig(t *testing.T) { + dc, err := models.NewDomainConfig("example.com") + if err != nil { + t.Fatal(err) + } + + tests := []struct { + name string + record Record + wantLabel string + wantTarget string + }{ + {"A", Record{Name: "www.example.com.", Type: "A", Content: "192.0.2.1", TTL: 300}, "www", "192.0.2.1"}, + {"apex TXT", Record{Name: "example.com.", Type: "TXT", Content: "raw text", TTL: 300}, "@", `"raw text"`}, + {"MX priority field", Record{Name: "example.com.", Type: "MX", Content: "mail.example.net", TTL: 300, Priority: 10}, "@", "10 mail.example.net."}, + {"MX content priority", Record{Name: "example.com.", Type: "MX", Content: "20 mail.example.net", TTL: 300}, "@", "20 mail.example.net."}, + {"SRV", Record{Name: "_sip._tcp.example.com.", Type: "SRV", Content: "1 2 5060 sip.example.net", TTL: 300}, "_sip._tcp", "1 2 5060 sip.example.net."}, + } + + for _, tc := range tests { + t.Run(tc.name, func(t *testing.T) { + rc, err := toRecordConfig(dc, tc.record) + if err != nil { + t.Fatal(err) + } + if got := rc.GetLabel(); got != tc.wantLabel { + t.Errorf("label = %q, want %q", got, tc.wantLabel) + } + if got := rc.GetRDATA().String(); got != tc.wantTarget { + t.Errorf("target = %q, want %q", got, tc.wantTarget) + } + if !reflect.DeepEqual(rc.Original, tc.record) { + t.Error("original provider record was not retained") + } + }) + } +} diff --git a/providers/dnsimple/auditrecords.go b/providers/dnsimple/auditrecords.go index 5b99817659..ffcf57d12c 100644 --- a/providers/dnsimple/auditrecords.go +++ b/providers/dnsimple/auditrecords.go @@ -1,14 +1,14 @@ package dnsimple import ( - "github.com/DNSControl/dnscontrol/v4/models" - "github.com/DNSControl/dnscontrol/v4/pkg/rejectif" + "github.com/DNSControl/dnscontrol/v5/models" + "github.com/DNSControl/dnscontrol/v5/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 { +func AuditRecords(records models.Records) []error { a := rejectif.Auditor{} a.Add("TXT", rejectif.TxtLongerThan(1000)) // Last verified 2023-12 diff --git a/providers/dnsimple/dnsimpleProvider.go b/providers/dnsimple/dnsimpleProvider.go index da139c9a77..89a8cf6dd4 100644 --- a/providers/dnsimple/dnsimpleProvider.go +++ b/providers/dnsimple/dnsimpleProvider.go @@ -11,11 +11,12 @@ import ( "strings" "sync" - "github.com/DNSControl/dnscontrol/v4/models" - "github.com/DNSControl/dnscontrol/v4/pkg/diff2" - "github.com/DNSControl/dnscontrol/v4/pkg/printer" - "github.com/DNSControl/dnscontrol/v4/pkg/providers" - "github.com/DNSControl/dnscontrol/v4/pkg/txtutil" + dnsv2 "codeberg.org/miekg/dns" + "github.com/DNSControl/dnscontrol/v5/models" + "github.com/DNSControl/dnscontrol/v5/pkg/diff2" + "github.com/DNSControl/dnscontrol/v5/pkg/nrc" + "github.com/DNSControl/dnscontrol/v5/pkg/printer" + "github.com/DNSControl/dnscontrol/v5/pkg/providers" dnsimpleapi "github.com/dnsimple/dnsimple-go/v8/dnsimple" "golang.org/x/oauth2" ) @@ -123,45 +124,12 @@ func (c *dnsimpleProvider) GetZoneRecords(dc *models.DomainConfig) (models.Recor var cleanedRecords models.Records for _, r := range records { - if r.Type == "SOA" { + switch r.Type { + case "SOA", "DNSKEY", "CDNSKEY", "CDS": continue } - if r.Name == "" { - r.Name = "@" - } - - if r.Type == "CNAME" || r.Type == "ALIAS" || r.Type == "NS" { - r.Content += "." - } else if r.Type == "MX" && r.Content != "." { - r.Content += "." - } - - rec := &models.RecordConfig{ - TTL: uint32(r.TTL), - Original: r, - } - rec.SetLabel(r.Name, domain) - - var err error - switch rtype := r.Type; rtype { - case "DNSKEY", "CDNSKEY", "CDS": - continue - case "ALIAS", "URL": - rec.Type = r.Type - err = rec.SetTarget(r.Content) - case "DS": - err = rec.SetTargetDSString(r.Content) - case "MX": - err = rec.SetTargetMX(uint16(r.Priority), r.Content) - case "SRV": - err = rec.SetTargetSRVPriorityString(uint16(r.Priority), r.Content) - case "TXT": - err = rec.PopulateFromStringFunc(r.Type, r.Content, domain, txtutil.ParseQuoted) - default: - err = rec.PopulateFromString(r.Type, r.Content, domain) - } - + rec, err := toRecordConfig(dc, r) if err != nil { return nil, fmt.Errorf("unparsable record received from dnsimple: %w", err) } @@ -175,6 +143,51 @@ func (c *dnsimpleProvider) GetZoneRecords(dc *models.DomainConfig) (models.Recor return cleanedRecords, nil } +func qualifySVCBTarget(content string) string { + fields := strings.SplitN(content, " ", 3) + if len(fields) < 2 { + return content + } + if target := fields[1]; !strings.HasSuffix(target, ".") { + fields[1] = target + "." + } + return strings.Join(fields, " ") +} + +func toRecordConfig(dc *models.DomainConfig, r dnsimpleapi.ZoneRecord) (*models.RecordConfig, error) { + label := dc.LabelFromShort(r.Name) + ttl := uint32(r.TTL) + + var rec *models.RecordConfig + var err error + + switch r.Type { + case "ALIAS", "URL": + rec, err = dc.NewRecordConfig(label, ttl, r.Type, r.Content, + nrc.Flags{TargetIsFqdnNoDot: true}) + case "MX": + rec, err = dc.NewRecordConfig(label, ttl, dnsv2.TypeMX, r.Priority, r.Content, + nrc.Flags{TargetIsFqdnNoDot: true}) + case "SRV": + rec, err = dc.NewRecordConfig(label, ttl, dnsv2.TypeSRV, r.Priority, r.Content, + nrc.Flags{SrvWeirdSplit: true}) + case "SVCB", "HTTPS": + rec, err = dc.NewRecordConfigParse(label, ttl, r.Type, qualifySVCBTarget(r.Content), + nrc.Flags{TargetIsFqdnNoDot: true}) + default: + rec, err = dc.NewRecordConfigParse(label, ttl, r.Type, r.Content, + nrc.Flags{TargetIsFqdnNoDot: true}) + + } + if err != nil { + return nil, err + } + + rec.Original = r + + return rec, nil +} + func (c *dnsimpleProvider) GetZoneRecordsCorrections(dc *models.DomainConfig, actual models.Records) ([]*models.Correction, int, error) { removeOtherApexNS(dc) @@ -517,7 +530,7 @@ func (c *dnsimpleProvider) recordUpdate(old *dnsimpleapi.ZoneRecord, rc *models. // priority:0 from the PATCH payload. Without an explicit priority, // the API keeps the old (non-zero) priority and rejects the update. // Work around this by deleting and recreating the record. - if rc.Type == "MX" && rc.GetTargetField() == "." { + if rc.TypeNum == dnsv2.TypeMX && rc.AsMX().Mx == "." { if err := c.recordDelete(old.ID, domainName); err != nil { return err } @@ -601,15 +614,15 @@ func newProvider(m map[string]string, _ json.RawMessage) (*dnsimpleProvider, err // Removes all non-dnsimple NS records from our desired state. // If any are found, print a warning. func removeOtherApexNS(dc *models.DomainConfig) { - newList := make([]*models.RecordConfig, 0, len(dc.Records)) + newList := make(models.Records, 0, len(dc.Records)) for _, rec := range dc.Records { - if rec.Type == "NS" { + if rec.TypeNum == dnsv2.TypeNS { // apex NS inside dnsimple are expected. // We ignore them, warning as needed. // Child delegations are supported so we allow non-apex NS records. if rec.GetLabelFQDN() == dc.Name { - if !isDnsimpleNameServerDomain(rec.GetTargetField()) { - printer.Printf("Warning: dnsimple.com does not allow NS records to be modified. %s will not be added.\n", rec.GetTargetField()) + if !isDnsimpleNameServerDomain(rec.AsNS().Ns) { + printer.Printf("Warning: dnsimple.com does not allow NS records to be modified. %s will not be added.\n", rec.AsNS().Ns) } continue } @@ -620,53 +633,57 @@ func removeOtherApexNS(dc *models.DomainConfig) { } // Returns the correct combined content for all special record types, Target for everything else -// Using RecordConfig.GetTargetCombined returns priority in the string, which we do not allow. +// Using RecordConfig.GetRDATA().String() returns priority in the string, which we do not allow. +// NB(tlim): For SRV this returns the fields in the order weight, port, target. +// The priority is not included in the string, but is returned separately by +// getTargetRecordPriority. func getTargetRecordContent(rc *models.RecordConfig) string { - switch rtype := rc.Type; rtype { - case "CAA": - return rc.GetTargetCombined() - case "DS": - return fmt.Sprintf("%d %d %d %s", rc.DsKeyTag, rc.DsAlgorithm, rc.DsDigestType, rc.DsDigest) - case "HTTPS", "SVCB": + switch rc.TypeNum { + case dnsv2.TypeHTTPS: // DNSimple API does not accept FQDN trailing dots in SVCB/HTTPS targets. // Preserve "." for AliasMode (priority 0) self-referencing records. - target := rc.GetTargetField() + f := rc.AsHTTPS() + target := f.Target if target != "." { target = strings.TrimSuffix(target, ".") } - if rc.SvcParams != "" { - return fmt.Sprintf("%d %s %s", rc.SvcPriority, target, rc.SvcParams) + if len(f.Value) != 0 { + return fmt.Sprintf("%d %s %s", f.Priority, target, models.Svcbv2ValueToString(f.Value)) } - return fmt.Sprintf("%d %s", rc.SvcPriority, target) - case "MX": - return rc.GetTargetField() - case "NAPTR": - return fmt.Sprintf(`%d %d "%s" "%s" "%s" %s`, - rc.NaptrOrder, rc.NaptrPreference, rc.NaptrFlags, rc.NaptrService, rc.NaptrRegexp, - rc.GetTargetField()) - case "SSHFP": - return fmt.Sprintf("%d %d %s", rc.SshfpAlgorithm, rc.SshfpFingerprint, rc.GetTargetField()) - case "SRV": - return fmt.Sprintf("%d %d %s", rc.SrvWeight, rc.SrvPort, rc.GetTargetField()) - case "TLSA": - return fmt.Sprintf("%d %d %d %s", rc.TlsaUsage, rc.TlsaSelector, rc.TlsaMatchingType, rc.GetTargetField()) - case "TXT": - return rc.GetTargetCombinedFunc(txtutil.EncodeQuoted) - default: - return rc.GetTargetField() + return fmt.Sprintf("%d %s", f.Priority, target) + case dnsv2.TypeSVCB: + // DNSimple API does not accept FQDN trailing dots in SVCB/HTTPS targets. + // Preserve "." for AliasMode (priority 0) self-referencing records. + f := rc.AsSVCB() + target := f.Target + if target != "." { + target = strings.TrimSuffix(target, ".") + } + if len(f.Value) != 0 { + return fmt.Sprintf("%d %s %s", f.Priority, target, models.Svcbv2ValueToString(f.Value)) + } + return fmt.Sprintf("%d %s", f.Priority, target) + case dnsv2.TypeMX: + return rc.AsMX().Mx + case dnsv2.TypeSRV: + f := rc.AsSRV() + return fmt.Sprintf("%d %d %s", f.Weight, f.Port, f.Target) + case dnsv2.TypeTXT: + return rc.AsTXT().String() } + return rc.GetRDATA().String() } // Returns the correct priority for the record type, 0 for records without priority. func getTargetRecordPriority(rc *models.RecordConfig) int { - switch rtype := rc.Type; rtype { - case "MX": - return int(rc.MxPreference) - case "SRV": - return int(rc.SrvPriority) - case "NAPTR": - // Neither order nor preference - return 0 + switch rc.TypeNum { + case dnsv2.TypeMX: + return int(rc.AsMX().Preference) + case dnsv2.TypeSRV: + return int(rc.AsSRV().Priority) + // case dnsv2.TypeNAPTR: + // // Neither order nor preference + // return 0 default: return 0 } @@ -675,8 +692,7 @@ func getTargetRecordPriority(rc *models.RecordConfig) int { // wrapError converts a DNSimple API ErrorResponse into a compiled error message, // or returns the original error if it is not an ErrorResponse. func wrapError(err error) error { - var errorResponse *dnsimpleapi.ErrorResponse - if errors.As(err, &errorResponse) { + if errorResponse, ok := errors.AsType[*dnsimpleapi.ErrorResponse](err); ok { return compileAttributeErrors(errorResponse) } return err diff --git a/providers/dnsimple/dnsimpleProvider_test.go b/providers/dnsimple/dnsimpleProvider_test.go new file mode 100644 index 0000000000..7dfef4f894 --- /dev/null +++ b/providers/dnsimple/dnsimpleProvider_test.go @@ -0,0 +1,50 @@ +package dnsimple + +import ( + "testing" + + "github.com/DNSControl/dnscontrol/v5/models" + dnsimpleapi "github.com/dnsimple/dnsimple-go/v8/dnsimple" +) + +func TestToRecordConfig(t *testing.T) { + dc, err := models.NewDomainConfig("example.com") + if err != nil { + t.Fatal(err) + } + + tests := []struct { + name string + record dnsimpleapi.ZoneRecord + wantLabel string + wantTarget string + }{ + {"A", dnsimpleapi.ZoneRecord{Name: "www", Type: "A", Content: "192.0.2.1", TTL: 300}, "www", "192.0.2.1"}, + {"apex TXT", dnsimpleapi.ZoneRecord{Name: "", Type: "TXT", Content: `"quoted text"`, TTL: 300}, "@", `"quoted text"`}, + {"MX", dnsimpleapi.ZoneRecord{Name: "", Type: "MX", Content: "mail.example.net", TTL: 300, Priority: 10}, "@", "10 mail.example.net."}, + {"SRV", dnsimpleapi.ZoneRecord{Name: "_sip._tcp", Type: "SRV", Content: "2 5060 sip.example.net.", TTL: 300, Priority: 1}, "_sip._tcp", "1 2 5060 sip.example.net."}, + {"HTTPS alias mode", dnsimpleapi.ZoneRecord{Name: "", Type: "HTTPS", Content: "0 target.example.net", TTL: 300}, "@", "0 target.example.net."}, + {"HTTPS with params", dnsimpleapi.ZoneRecord{Name: "", Type: "HTTPS", Content: `3 target.example.net alpn="h2,h3" port="999"`, TTL: 300}, "@", `3 target.example.net. alpn="h2,h3" port="999"`}, + {"SVCB alias mode", dnsimpleapi.ZoneRecord{Name: "", Type: "SVCB", Content: "0 target.example.net", TTL: 300}, "@", "0 target.example.net."}, + {"SVCB already qualified", dnsimpleapi.ZoneRecord{Name: "", Type: "SVCB", Content: "0 target.example.net.", TTL: 300}, "@", "0 target.example.net."}, + } + + for _, tc := range tests { + t.Run(tc.name, func(t *testing.T) { + rc, err := toRecordConfig(dc, tc.record) + if err != nil { + t.Fatal(err) + } + if got := rc.GetLabel(); got != tc.wantLabel { + t.Errorf("label = %q, want %q", got, tc.wantLabel) + } + if got := rc.GetRDATA().String(); got != tc.wantTarget { + t.Errorf("target = %q, want %q", got, tc.wantTarget) + } + original, ok := rc.Original.(dnsimpleapi.ZoneRecord) + if !ok || original.Type != tc.record.Type { + t.Error("original provider record was not retained") + } + }) + } +} diff --git a/providers/dnsimple/test_data/meta.json b/providers/dnsimple/test_data/meta.json new file mode 100644 index 0000000000..bbf8c84542 --- /dev/null +++ b/providers/dnsimple/test_data/meta.json @@ -0,0 +1,8 @@ +{ + "version": 1, + "recordings": [ + { + "domain": "dnsimple.test.dnscontrol.org" + } + ] +} diff --git a/providers/dnsmadeeasy/api.go b/providers/dnsmadeeasy/api.go index 6fd9706e9c..db23f7fbb3 100644 --- a/providers/dnsmadeeasy/api.go +++ b/providers/dnsmadeeasy/api.go @@ -6,7 +6,7 @@ import ( "net/http" "time" - "github.com/DNSControl/dnscontrol/v4/pkg/printer" + "github.com/DNSControl/dnscontrol/v5/pkg/printer" ) type dnsMadeEasyProvider struct { diff --git a/providers/dnsmadeeasy/auditrecords.go b/providers/dnsmadeeasy/auditrecords.go index 1a688cd5d3..fae5f9f73f 100644 --- a/providers/dnsmadeeasy/auditrecords.go +++ b/providers/dnsmadeeasy/auditrecords.go @@ -1,14 +1,14 @@ package dnsmadeeasy import ( - "github.com/DNSControl/dnscontrol/v4/models" - "github.com/DNSControl/dnscontrol/v4/pkg/rejectif" + "github.com/DNSControl/dnscontrol/v5/models" + "github.com/DNSControl/dnscontrol/v5/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 { +func AuditRecords(records models.Records) []error { a := rejectif.Auditor{} a.Add("TXT", rejectif.TxtHasDoubleQuotes) // Last verified 2021-03-11 diff --git a/providers/dnsmadeeasy/dnsMadeEasyProvider.go b/providers/dnsmadeeasy/dnsMadeEasyProvider.go index 443fd16f81..6e54a92ce8 100644 --- a/providers/dnsmadeeasy/dnsMadeEasyProvider.go +++ b/providers/dnsmadeeasy/dnsMadeEasyProvider.go @@ -3,12 +3,13 @@ package dnsmadeeasy import ( "encoding/json" "errors" + "fmt" "os" "strings" - "github.com/DNSControl/dnscontrol/v4/models" - "github.com/DNSControl/dnscontrol/v4/pkg/diff" - "github.com/DNSControl/dnscontrol/v4/pkg/providers" + "github.com/DNSControl/dnscontrol/v5/models" + "github.com/DNSControl/dnscontrol/v5/pkg/diff2" + "github.com/DNSControl/dnscontrol/v5/pkg/providers" ) var features = providers.DocumentationNotes{ @@ -97,29 +98,56 @@ func (api *dnsMadeEasyProvider) GetZoneRecordsCorrections(dc *models.DomainConfi } for _, rec := range dc.Records { - switch rec.Type { - case "ALIAS": - // ALIAS is called ANAME on DNS Made Easy - rec.ChangeType("ANAME", dc.Name) - case "NS": - // NS records have fixed TTL on DNS Made Easy and it cannot be changed + // NS records have a fixed TTL on DNS Made Easy that cannot be changed. + if rec.Type == "NS" { rec.TTL = fixedNameServerRecordTTL } } - toReport, create, del, modify, actualChangeCount, err := diff.NewCompat(dc).IncrementalDiff(existingRecords) + changes, actualChangeCount, err := diff2.ByRecord(existingRecords, dc, nil) if err != nil { return nil, 0, err } - // Start corrections with the reports - corrections := diff.GenerateMessageCorrections(toReport) + var corrections []*models.Correction + + // DNS Made Easy applies creates, deletes and modifications in three + // separate batch API calls, so collect each category before emitting. var deleteRecordIds []int deleteDescription := []string{"Batch deletion of records:"} - for _, m := range del { - originalRecordID := m.Existing.Original.(*recordResponseDataEntry).ID - deleteRecordIds = append(deleteRecordIds, originalRecordID) - deleteDescription = append(deleteDescription, m.String()) + var createRecords []recordRequestData + createDescription := []string{"Batch creation of records:"} + var modifyRecords []recordRequestData + modifyDescription := []string{"Batch modification of records:"} + + for _, change := range changes { + switch change.Type { + case diff2.REPORT: + corrections = append(corrections, &models.Correction{Msg: change.MsgsJoined}) + + case diff2.DELETE: + originalRecordID := change.Old[0].Original.(*recordResponseDataEntry).ID + deleteRecordIds = append(deleteRecordIds, originalRecordID) + deleteDescription = append(deleteDescription, change.Msgs[0]) + + case diff2.CREATE: + record := fromRecordConfig(change.New[0]) + createRecords = append(createRecords, *record) + createDescription = append(createDescription, change.Msgs[0]) + + case diff2.CHANGE: + originalRecord := change.Old[0].Original.(*recordResponseDataEntry) + + record := fromRecordConfig(change.New[0]) + record.ID = originalRecord.ID + record.GtdLocation = originalRecord.GtdLocation + + modifyRecords = append(modifyRecords, *record) + modifyDescription = append(modifyDescription, change.Msgs[0]) + + default: + panic(fmt.Sprintf("unhandled change.Type %s", change.Type)) + } } if len(deleteRecordIds) > 0 { @@ -132,14 +160,6 @@ func (api *dnsMadeEasyProvider) GetZoneRecordsCorrections(dc *models.DomainConfi corrections = append(corrections, corr) } - var createRecords []recordRequestData - createDescription := []string{"Batch creation of records:"} - for _, m := range create { - record := fromRecordConfig(m.Desired) - createRecords = append(createRecords, *record) - createDescription = append(createDescription, m.String()) - } - if len(createRecords) > 0 { corr := &models.Correction{ Msg: strings.Join(createDescription, "\n\t"), @@ -150,19 +170,6 @@ func (api *dnsMadeEasyProvider) GetZoneRecordsCorrections(dc *models.DomainConfi corrections = append(corrections, corr) } - var modifyRecords []recordRequestData - modifyDescription := []string{"Batch modification of records:"} - for _, m := range modify { - originalRecord := m.Existing.Original.(*recordResponseDataEntry) - - record := fromRecordConfig(m.Desired) - record.ID = originalRecord.ID - record.GtdLocation = originalRecord.GtdLocation - - modifyRecords = append(modifyRecords, *record) - modifyDescription = append(modifyDescription, m.String()) - } - if len(modifyRecords) > 0 { corr := &models.Correction{ Msg: strings.Join(modifyDescription, "\n\t"), @@ -217,17 +224,17 @@ func (api *dnsMadeEasyProvider) GetZoneRecords(dc *models.DomainConfig) (models. return nil, err } - existingRecords := make([]*models.RecordConfig, 0, len(records)) + existingRecords := make(models.Records, 0, len(records)) for i := range records { // Ignore HTTPRED and SPF records if records[i].Type == "HTTPRED" || records[i].Type == "SPF" { continue } - existingRecords = append(existingRecords, toRecordConfig(domain, &records[i])) + existingRecords = append(existingRecords, toRecordConfig(dc, &records[i])) } for i := range nameServers { - existingRecords = append(existingRecords, systemNameServerToRecordConfig(domain, nameServers[i])) + existingRecords = append(existingRecords, systemNameServerToRecordConfig(dc, nameServers[i])) } return existingRecords, nil diff --git a/providers/dnsmadeeasy/restApi.go b/providers/dnsmadeeasy/restApi.go index a486eb2a0d..32c9f7e616 100644 --- a/providers/dnsmadeeasy/restApi.go +++ b/providers/dnsmadeeasy/restApi.go @@ -12,7 +12,7 @@ import ( "strings" "time" - "github.com/DNSControl/dnscontrol/v4/pkg/printer" + "github.com/DNSControl/dnscontrol/v5/pkg/printer" ) const ( diff --git a/providers/dnsmadeeasy/types.go b/providers/dnsmadeeasy/types.go index fec9154fb9..5f3954934f 100644 --- a/providers/dnsmadeeasy/types.go +++ b/providers/dnsmadeeasy/types.go @@ -3,7 +3,8 @@ package dnsmadeeasy import ( "strconv" - "github.com/DNSControl/dnscontrol/v4/models" + "github.com/DNSControl/dnscontrol/v5/models" + "github.com/DNSControl/dnscontrol/v5/pkg/txtutil" ) // DNS Made Easy does not allow the system name servers to be edited, and said records appear to always have a fixed TTL of 86400. @@ -123,34 +124,40 @@ type recordRequestData struct { IssuerCritical int `json:"issuerCritical"` } -func toRecordConfig(domain string, record *recordResponseDataEntry) *models.RecordConfig { - rc := &models.RecordConfig{ - Type: record.Type, - TTL: uint32(record.TTL), - Original: record, +func toRecordConfig(dc *models.DomainConfig, record *recordResponseDataEntry) *models.RecordConfig { + recordType := record.Type + if recordType == "ANAME" { + // ANAME is DNS Made Easy's name for ALIAS (inverse of the ALIAS->ANAME + // conversion in GetZoneRecordsCorrections). + recordType = "ALIAS" } - rc.SetLabel(record.Name, domain) + label := dc.LabelFromShort(record.Name) + ttl := uint32(record.TTL) + var rc *models.RecordConfig var err error - switch record.Type { + switch recordType { case "MX": - err = rc.SetTargetMX(uint16(record.MxLevel), record.Value) + rc, err = dc.NewRecordConfig(label, ttl, recordType, record.MxLevel, record.Value) case "SRV": - err = rc.SetTargetSRV(uint16(record.Priority), uint16(record.Weight), uint16(record.Port), record.Value) + rc, err = dc.NewRecordConfig(label, ttl, recordType, record.Priority, record.Weight, record.Port, record.Value) case "CAA": value, unquoteErr := strconv.Unquote(record.Value) if unquoteErr != nil { panic(unquoteErr) } - err = rc.SetTargetCAA(uint8(record.IssuerCritical), record.CaaType, value) + rc, err = dc.NewRecordConfig(label, ttl, recordType, record.IssuerCritical, record.CaaType, value) + case "ALIAS": + rc, err = dc.NewRecordConfig(label, ttl, recordType, record.Value) default: - err = rc.PopulateFromString(record.Type, record.Value, domain) + rc, err = dc.NewRecordConfigParse(label, ttl, recordType, record.Value) } if err != nil { panic(err) } + rc.Original = record return rc } @@ -161,38 +168,53 @@ func fromRecordConfig(rc *models.RecordConfig) *recordRequestData { label = "" } + recordType := rc.Type + if recordType == "ALIAS" { + // ALIAS is called ANAME on DNS Made Easy. Converting on write only + // keeps the diff comparing ALIAS against ALIAS. + recordType = "ANAME" + } + record := &recordRequestData{ - Type: rc.Type, + Type: recordType, TTL: int(rc.TTL), GtdLocation: "DEFAULT", Name: label, - Value: rc.GetTargetCombined(), + // DNS Made Easy stores TXT as opaque text and mangles multi-chunk + // values, so send the whole value as one quoted string. + } + if recordType == "TXT" { + record.Value = txtutil.EncodeSingle(rc.GetTargetTXTJoined()) + } else { + record.Value = rc.GetRDATA().String() } switch record.Type { case "MX": - record.MxLevel = int(rc.MxPreference) - record.Value = rc.GetTargetField() + f := rc.AsMX() + record.MxLevel = int(f.Preference) + record.Value = f.Mx case "SRV": - target := rc.GetTargetField() + f := rc.AsSRV() + target := f.Target if target == "." { target += "." } - - record.Priority = int(rc.SrvPriority) - record.Weight = int(rc.SrvWeight) - record.Port = int(rc.SrvPort) + record.Priority = int(f.Priority) + record.Weight = int(f.Weight) + record.Port = int(f.Port) record.Value = target case "CAA": - record.IssuerCritical = int(rc.CaaFlag) - record.CaaType = rc.CaaTag - record.Value = rc.GetTargetField() + f := rc.AsCAA() + record.IssuerCritical = int(f.Flag) + record.CaaType = f.Tag + record.Value = f.Value } return record } -func systemNameServerToRecordConfig(domain string, nameServer string) *models.RecordConfig { +func systemNameServerToRecordConfig(dc *models.DomainConfig, nameServer string) *models.RecordConfig { target := nameServer + "." - return toRecordConfig(domain, &recordResponseDataEntry{Type: "NS", Value: target, TTL: fixedNameServerRecordTTL}) + return toRecordConfig(dc, &recordResponseDataEntry{Type: "NS", Value: target, TTL: fixedNameServerRecordTTL}) } diff --git a/providers/dnsmadeeasy/types_test.go b/providers/dnsmadeeasy/types_test.go new file mode 100644 index 0000000000..c8714d9b20 --- /dev/null +++ b/providers/dnsmadeeasy/types_test.go @@ -0,0 +1,85 @@ +package dnsmadeeasy + +import ( + "testing" + + "github.com/DNSControl/dnscontrol/v5/models" +) + +func TestToRecordConfig(t *testing.T) { + dc := models.MustNewDomainConfig("example.com") + + tests := []struct { + name string + record recordResponseDataEntry + wantType string + wantLabel string + wantTarget string + }{ + {"MX", recordResponseDataEntry{Name: "@", Type: "MX", Value: "mail.example.net.", TTL: 300, MxLevel: 10}, "MX", "@", "10 mail.example.net."}, + {"SRV", recordResponseDataEntry{Name: "_sip._tcp", Type: "SRV", Value: "sip.example.net.", TTL: 300, Priority: 1, Weight: 2, Port: 5060}, "SRV", "_sip._tcp", "1 2 5060 sip.example.net."}, + {"CAA", recordResponseDataEntry{Name: "@", Type: "CAA", Value: `"letsencrypt.org"`, TTL: 300, CaaType: "issue", IssuerCritical: 1}, "CAA", "@", `1 issue "letsencrypt.org"`}, + {"TXT", recordResponseDataEntry{Name: "@", Type: "TXT", Value: `"quoted text"`, TTL: 300}, "TXT", "@", `"quoted text"`}, + {"ANAME", recordResponseDataEntry{Name: "@", Type: "ANAME", Value: "target.example.net.", TTL: 300}, "ALIAS", "@", "target.example.net."}, + // The API returns an empty name for records at the zone apex. + {"apex empty name", recordResponseDataEntry{Name: "", Type: "A", Value: "1.2.3.4", TTL: 300}, "A", "@", "1.2.3.4"}, + {"mixed case name", recordResponseDataEntry{Name: "WWW", Type: "A", Value: "1.2.3.4", TTL: 300}, "A", "www", "1.2.3.4"}, + } + + for _, tc := range tests { + t.Run(tc.name, func(t *testing.T) { + record := tc.record + rc := toRecordConfig(dc, &record) + if got := rc.Type; got != tc.wantType { + t.Errorf("type = %q, want %q", got, tc.wantType) + } + if got := rc.GetLabel(); got != tc.wantLabel { + t.Errorf("label = %q, want %q", got, tc.wantLabel) + } + if got := rc.GetRDATA().String(); got != tc.wantTarget { + t.Errorf("target = %q, want %q", got, tc.wantTarget) + } + if got := rc.TTL; got != uint32(tc.record.TTL) { + t.Errorf("ttl = %d, want %d", got, tc.record.TTL) + } + if rc.Original != &record { + t.Error("original provider record was not retained") + } + }) + } +} + +// TestApexRoundTrip checks both halves of the apex label mapping: the API sends +// an empty name for apex records, and expects one back. +func TestApexRoundTrip(t *testing.T) { + dc := models.MustNewDomainConfig("example.com") + + rc := toRecordConfig(dc, &recordResponseDataEntry{Name: "", Type: "A", Value: "1.2.3.4", TTL: 300}) + if got := rc.GetLabelFQDN(); got != "example.com" { + t.Errorf("fqdn = %q, want %q", got, "example.com") + } + if got := fromRecordConfig(rc).Name; got != "" { + t.Errorf("name = %q, want %q", got, "") + } +} + +func TestSystemNameServerToRecordConfig(t *testing.T) { + dc := models.MustNewDomainConfig("example.com") + + rc := systemNameServerToRecordConfig(dc, "ns1.example.net") + if got := rc.Type; got != "NS" { + t.Errorf("type = %q, want %q", got, "NS") + } + if got := rc.GetLabel(); got != "@" { + t.Errorf("label = %q, want %q", got, "@") + } + if got := rc.GetLabelFQDN(); got != "example.com" { + t.Errorf("fqdn = %q, want %q", got, "example.com") + } + if got := rc.GetRDATA().String(); got != "ns1.example.net." { + t.Errorf("target = %q, want %q", got, "ns1.example.net.") + } + if got := rc.TTL; got != fixedNameServerRecordTTL { + t.Errorf("ttl = %d, want %d", got, fixedNameServerRecordTTL) + } +} diff --git a/providers/doh/dohProvider.go b/providers/doh/dohProvider.go index e3f0c8d9ab..57f8fdf9ec 100644 --- a/providers/doh/dohProvider.go +++ b/providers/doh/dohProvider.go @@ -5,8 +5,8 @@ import ( "slices" "strings" - "github.com/DNSControl/dnscontrol/v4/models" - "github.com/DNSControl/dnscontrol/v4/pkg/providers" + "github.com/DNSControl/dnscontrol/v5/models" + "github.com/DNSControl/dnscontrol/v5/pkg/providers" ) /* diff --git a/providers/domainnameshop/api.go b/providers/domainnameshop/api.go index 05abf8fb46..5fc39855a8 100644 --- a/providers/domainnameshop/api.go +++ b/providers/domainnameshop/api.go @@ -207,10 +207,10 @@ func (api *domainNameShopProvider) sendChangeRequest(method string, uri string, switch resp.StatusCode { case http.StatusCreated: - // Record is deleted + // Created successfully return nil case http.StatusNoContent: - // Update successful + // Updated successful return nil case http.StatusBadRequest: return errors.New("DNS record failed validation") diff --git a/providers/domainnameshop/auditrecords.go b/providers/domainnameshop/auditrecords.go index 6857294154..9bde09388a 100644 --- a/providers/domainnameshop/auditrecords.go +++ b/providers/domainnameshop/auditrecords.go @@ -1,10 +1,23 @@ package domainnameshop -import "github.com/DNSControl/dnscontrol/v4/models" +import ( + "github.com/DNSControl/dnscontrol/v5/models" + "github.com/DNSControl/dnscontrol/v5/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 +func AuditRecords(records models.Records) []error { + a := rejectif.Auditor{} + + // last verified 2026-08-05 + // DomainNameShop does not allow NS records at the apex: the apex nameservers + // are managed at the delegation level and are synthesized read-only from + // the /domains endpoint (see api.go). POSTing an apex NS record returns + // "400 - DNS record failed validation". + // NS records at subdomains work fine and are left untouched. + a.Add("NS", rejectif.NsAtApex) + + return a.Audit(records) } diff --git a/providers/domainnameshop/convert.go b/providers/domainnameshop/convert.go index 08fa780d2a..c7dcd8ba30 100644 --- a/providers/domainnameshop/convert.go +++ b/providers/domainnameshop/convert.go @@ -3,50 +3,43 @@ package domainnameshop import ( "strconv" - "github.com/DNSControl/dnscontrol/v4/models" - dnsutilv1 "github.com/miekg/dns/dnsutil" + dnsrdatav2 "codeberg.org/miekg/dns/rdata" + "github.com/DNSControl/dnscontrol/v5/models" ) -func toRecordConfig(domain string, currentRecord *domainNameShopRecord) (*models.RecordConfig, error) { - name := dnsutilv1.AddOrigin(currentRecord.Host, domain) - +func toRecordConfig(dc *models.DomainConfig, currentRecord *domainNameShopRecord) (*models.RecordConfig, error) { + label := dc.LabelFromShort(currentRecord.Host) + ttl := fixTTL(uint32(currentRecord.TTL)) target := currentRecord.Data - t := &models.RecordConfig{ - Type: currentRecord.Type, - TTL: fixTTL(uint32(currentRecord.TTL)), - MxPreference: uint16(currentRecord.ActualPriority), - SrvPriority: uint16(currentRecord.ActualPriority), - SrvWeight: uint16(currentRecord.ActualWeight), - SrvPort: uint16(currentRecord.ActualPort), - Original: currentRecord, - CaaTag: currentRecord.CAATag, - CaaFlag: uint8(currentRecord.CAAFlag), - } - - if err := t.SetTarget(target); err != nil { - return nil, err - } - t.SetLabelFromFQDN(name, domain) - - switch rtype := currentRecord.Type; rtype { - case "TXT": - if err := t.SetTargetTXT(target); err != nil { - return nil, err - } + var rc *models.RecordConfig + var err error + switch currentRecord.Type { + // case "TXT": + // rc, err = dc.NewRecordConfig(label, ttl, currentRecord.Type, target) + case "MX": + rc, err = dc.NewRecordConfig(label, ttl, currentRecord.Type, currentRecord.ActualPriority, target) + case "SRV": + rc, err = dc.NewRecordConfig(label, ttl, currentRecord.Type, currentRecord.ActualPriority, currentRecord.ActualWeight, currentRecord.ActualPort, target) case "CAA": + tag := "iodef" switch currentRecord.CAATag { case "0": - t.CaaTag = "issue" + tag = "issue" case "1": - t.CaaTag = "issuewild" - default: - t.CaaTag = "iodef" + tag = "issuewild" } + rc, err = dc.NewRecordConfig(label, ttl, currentRecord.Type, uint8(currentRecord.CAAFlag), tag, target) default: - // nothing additional required + rc, err = dc.NewRecordConfig(label, ttl, currentRecord.Type, target) } - return t, nil + if err != nil { + return nil, err + } + + rc.Original = currentRecord + + return rc, nil } func (api *domainNameShopProvider) fromRecordConfig(domainName string, rc *models.RecordConfig) (*domainNameShopRecord, error) { @@ -55,32 +48,18 @@ func (api *domainNameShopProvider) fromRecordConfig(domainName string, rc *model return nil, err } - data := "" - if rc.Type == "TXT" { - data = rc.GetTargetTXTJoined() - } else { - data = rc.GetTargetField() - } - dnsR := &domainNameShopRecord{ - ID: 0, - Host: rc.GetLabel(), - TTL: uint16(fixTTL(rc.TTL)), - Type: rc.Type, - Data: data, - Weight: strconv.Itoa(int(rc.SrvWeight)), - Port: strconv.Itoa(int(rc.SrvPort)), - ActualWeight: rc.SrvWeight, - ActualPort: rc.SrvPort, - CAAFlag: uint64(int(rc.CaaFlag)), - ActualCAAFlag: strconv.Itoa(int(rc.CaaFlag)), - DomainID: domainID, + ID: 0, + Host: rc.GetLabel(), + TTL: uint16(fixTTL(rc.TTL)), + Type: rc.Type, + DomainID: domainID, } - switch rc.Type { - case "CAA": + switch f := rc.GetRDATA().(type) { + case dnsrdatav2.CAA: // Actual CAA FLAG - switch rc.CaaTag { + switch f.Tag { case "issue": dnsR.CAATag = "0" case "issuewild": @@ -88,12 +67,23 @@ func (api *domainNameShopProvider) fromRecordConfig(domainName string, rc *model case "iodef": dnsR.CAATag = "2" } - case "MX": - dnsR.Priority = strconv.Itoa(int(rc.MxPreference)) - case "SRV": - dnsR.Priority = strconv.Itoa(int(rc.SrvPriority)) + dnsR.CAAFlag = uint64(int(f.Flag)) + dnsR.ActualCAAFlag = strconv.Itoa(int(f.Flag)) + dnsR.Data = f.Value + case dnsrdatav2.MX: + dnsR.Priority = strconv.Itoa(int(f.Preference)) + dnsR.Data = f.Mx + case dnsrdatav2.SRV: + dnsR.Priority = strconv.Itoa(int(f.Priority)) + dnsR.Weight = strconv.Itoa(int(f.Weight)) + dnsR.Port = strconv.Itoa(int(f.Port)) + dnsR.ActualWeight = f.Weight + dnsR.ActualPort = f.Port + dnsR.Data = f.Target + case dnsrdatav2.TXT: + dnsR.Data = rc.GetTargetTXTJoined() default: - // pass through + dnsR.Data = rc.GetRDATA().String() } return dnsR, nil diff --git a/providers/domainnameshop/dns.go b/providers/domainnameshop/dns.go index 574246229a..01b5f0680e 100644 --- a/providers/domainnameshop/dns.go +++ b/providers/domainnameshop/dns.go @@ -5,8 +5,8 @@ import ( "strconv" "strings" - "github.com/DNSControl/dnscontrol/v4/models" - "github.com/DNSControl/dnscontrol/v4/pkg/diff" + "github.com/DNSControl/dnscontrol/v5/models" + "github.com/DNSControl/dnscontrol/v5/pkg/diff2" ) func (api *domainNameShopProvider) GetZoneRecords(dc *models.DomainConfig) (models.Records, error) { @@ -17,9 +17,9 @@ func (api *domainNameShopProvider) GetZoneRecords(dc *models.DomainConfig) (mode return nil, err } - var existingRecords []*models.RecordConfig + var existingRecords models.Records for i := range records { - rC, err := toRecordConfig(domain, &records[i]) + rC, err := toRecordConfig(dc, &records[i]) if err != nil { return nil, err } @@ -31,73 +31,72 @@ func (api *domainNameShopProvider) GetZoneRecords(dc *models.DomainConfig) (mode // GetZoneRecordsCorrections returns a list of corrections that will turn existing records into dc.Records. func (api *domainNameShopProvider) GetZoneRecordsCorrections(dc *models.DomainConfig, existingRecords models.Records) ([]*models.Correction, int, error) { + // NB(tlim): Commenting this out. GetTargetTXTJoined() should be sufficient. // Merge TXT strings to one string - for _, rc := range dc.Records { - if rc.HasFormatIdenticalToTXT() { - if err := rc.SetTargetTXT(rc.GetTargetTXTJoined()); err != nil { - return nil, 0, err - } - } - } + // for _, rc := range dc.Records { + // if rc.HasFormatIdenticalToTXT() { + // if err := rc.Set|TargetTXT(rc.GetTargetTXTJoined()); err != nil { + // return nil, 0, err + // } + // } + // } // Domainnameshop doesn't allow arbitrary TTLs they must be a multiple of 60. for _, record := range dc.Records { record.TTL = fixTTL(record.TTL) } - toReport, toCreate, toDelete, toModify, actualChangeCount, err := diff.NewCompat(dc).IncrementalDiff(existingRecords) + changes, actualChangeCount, err := diff2.ByRecord(existingRecords, dc, nil) if err != nil { return nil, 0, err } - // Start corrections with the reports - corrections := diff.GenerateMessageCorrections(toReport) - - // Delete record - for _, r := range toDelete { - domainID := r.Existing.Original.(*domainNameShopRecord).DomainID - recordID := strconv.Itoa(r.Existing.Original.(*domainNameShopRecord).ID) - - corr := &models.Correction{ - Msg: fmt.Sprintf("%s, record id: %s", r.String(), recordID), - F: func() error { return api.deleteRecord(domainID, recordID) }, - } - corrections = append(corrections, corr) - } - - // Create records - for _, r := range toCreate { - // Retrieve the domain name that is targeted. I.e. example.com instead of sub.example.com - domainName := strings.ReplaceAll(r.Desired.GetLabelFQDN(), r.Desired.GetLabel()+".", "") - - dnsR, err := api.fromRecordConfig(domainName, r.Desired) - if err != nil { - return nil, 0, err - } - - corr := &models.Correction{ - Msg: r.String(), - F: func() error { return api.CreateRecord(domainName, dnsR) }, - } - corrections = append(corrections, corr) - } + var corrections []*models.Correction + for _, change := range changes { + switch change.Type { + case diff2.REPORT: + corrections = append(corrections, &models.Correction{Msg: change.MsgsJoined}) - for _, r := range toModify { - domainName := strings.ReplaceAll(r.Desired.GetLabelFQDN(), r.Desired.GetLabel()+".", "") + case diff2.CREATE: + // Retrieve the domain name that is targeted. I.e. example.com instead of sub.example.com + des := change.New[0] + domainName := strings.ReplaceAll(des.GetLabelFQDN(), des.GetLabel()+".", "") - dnsR, err := api.fromRecordConfig(domainName, r.Desired) - if err != nil { - return nil, 0, err - } + dnsR, err := api.fromRecordConfig(domainName, des) + if err != nil { + return nil, 0, err + } + corrections = append(corrections, &models.Correction{ + Msg: change.Msgs[0], + F: func() error { return api.CreateRecord(domainName, dnsR) }, + }) - dnsR.ID = r.Existing.Original.(*domainNameShopRecord).ID + case diff2.CHANGE: + des := change.New[0] + domainName := strings.ReplaceAll(des.GetLabelFQDN(), des.GetLabel()+".", "") - corr := &models.Correction{ - Msg: r.String(), - F: func() error { return api.UpdateRecord(dnsR) }, + dnsR, err := api.fromRecordConfig(domainName, des) + if err != nil { + return nil, 0, err + } + dnsR.ID = change.Old[0].Original.(*domainNameShopRecord).ID + corrections = append(corrections, &models.Correction{ + Msg: change.Msgs[0], + F: func() error { return api.UpdateRecord(dnsR) }, + }) + + case diff2.DELETE: + original := change.Old[0].Original.(*domainNameShopRecord) + domainID := original.DomainID + recordID := strconv.Itoa(original.ID) + corrections = append(corrections, &models.Correction{ + Msg: fmt.Sprintf("%s, record id: %s", change.Msgs[0], recordID), + F: func() error { return api.deleteRecord(domainID, recordID) }, + }) + + default: + panic(fmt.Sprintf("unhandled change.Type %s", change.Type)) } - - corrections = append(corrections, corr) } return corrections, actualChangeCount, nil diff --git a/providers/domainnameshop/dns_test.go b/providers/domainnameshop/dns_test.go index 7f483ff2c5..5a7922a710 100644 --- a/providers/domainnameshop/dns_test.go +++ b/providers/domainnameshop/dns_test.go @@ -1,6 +1,10 @@ package domainnameshop -import "testing" +import ( + "testing" + + "github.com/DNSControl/dnscontrol/v5/models" +) func TestFixTTL(t *testing.T) { for i, test := range []struct { @@ -23,3 +27,37 @@ func TestFixTTL(t *testing.T) { } } } + +func TestToRecordConfig(t *testing.T) { + dc, err := models.NewDomainConfig("example.com") + if err != nil { + t.Fatal(err) + } + + tests := []struct { + name string + record domainNameShopRecord + wantTarget string + }{ + {"MX", domainNameShopRecord{Host: "@", Type: "MX", Data: "mail.example.net.", TTL: 300, ActualPriority: 10}, "10 mail.example.net."}, + {"SRV", domainNameShopRecord{Host: "_sip._tcp", Type: "SRV", Data: "sip.example.net.", TTL: 300, ActualPriority: 1, ActualWeight: 2, ActualPort: 5060}, "1 2 5060 sip.example.net."}, + {"CAA", domainNameShopRecord{Host: "@", Type: "CAA", Data: "letsencrypt.org", TTL: 300, CAATag: "0", CAAFlag: 1}, `1 issue "letsencrypt.org"`}, + {"TXT", domainNameShopRecord{Host: "@", Type: "TXT", Data: "raw text", TTL: 300}, `"raw text"`}, + } + + for _, tc := range tests { + t.Run(tc.name, func(t *testing.T) { + record := tc.record + rc, err := toRecordConfig(dc, &record) + if err != nil { + t.Fatal(err) + } + if got := rc.GetRDATA().String(); got != tc.wantTarget { + t.Errorf("target = %q, want %q", got, tc.wantTarget) + } + if rc.Original != &record { + t.Error("original provider record was not retained") + } + }) + } +} diff --git a/providers/domainnameshop/domainnameshopProvider.go b/providers/domainnameshop/domainnameshopProvider.go index d68c75e25a..95e04715b1 100644 --- a/providers/domainnameshop/domainnameshopProvider.go +++ b/providers/domainnameshop/domainnameshopProvider.go @@ -4,7 +4,7 @@ import ( "encoding/json" "errors" - "github.com/DNSControl/dnscontrol/v4/pkg/providers" + "github.com/DNSControl/dnscontrol/v5/pkg/providers" ) /** diff --git a/providers/dynadot/dynadotProvider.go b/providers/dynadot/dynadotProvider.go index 11ae6487c5..dbe02b69b0 100644 --- a/providers/dynadot/dynadotProvider.go +++ b/providers/dynadot/dynadotProvider.go @@ -6,8 +6,8 @@ import ( "sort" "strings" - "github.com/DNSControl/dnscontrol/v4/models" - "github.com/DNSControl/dnscontrol/v4/pkg/providers" + "github.com/DNSControl/dnscontrol/v5/models" + "github.com/DNSControl/dnscontrol/v5/pkg/providers" ) /* diff --git a/providers/dynu/api.go b/providers/dynu/api.go index 455c75967a..e9ac7dde2f 100644 --- a/providers/dynu/api.go +++ b/providers/dynu/api.go @@ -60,11 +60,11 @@ type dynuRecord struct { IPv6Address string `json:"ipv6Address,omitempty"` // CNAME / DNAME / MX / NS / PTR / SRV / NAPTR (replacement) / AFSDB Host string `json:"host,omitempty"` - // MX / SRV / URI / NAPTR (order) / CERT (certificateType stored here by Dynu) + // MX / SRV / URI Priority *int `json:"priority,omitempty"` - // SRV / SSHFP (fingerprint type) / NAPTR / URI + // SRV / SSHFP (fingerprint type) / URI Weight *int `json:"weight,omitempty"` - // SRV / TLSA (matchingType) / SMIMEA + // SRV Port *int `json:"port,omitempty"` // CAA / KEY Flags *int `json:"flags,omitempty"` diff --git a/providers/dynu/auditrecords.go b/providers/dynu/auditrecords.go index 499c9a6282..b1b3904ea8 100644 --- a/providers/dynu/auditrecords.go +++ b/providers/dynu/auditrecords.go @@ -1,14 +1,14 @@ package dynu import ( - "github.com/DNSControl/dnscontrol/v4/models" - "github.com/DNSControl/dnscontrol/v4/pkg/rejectif" + "github.com/DNSControl/dnscontrol/v5/models" + "github.com/DNSControl/dnscontrol/v5/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 { +func AuditRecords(records models.Records) []error { a := rejectif.Auditor{} a.TypesSupported([]string{ diff --git a/providers/dynu/dynuProvider.go b/providers/dynu/dynuProvider.go index 2914b3507f..6b749cdd72 100644 --- a/providers/dynu/dynuProvider.go +++ b/providers/dynu/dynuProvider.go @@ -1,21 +1,22 @@ // Package dynu implements a DNSControl provider for Dynu (https://www.dynu.com). // API docs: https://www.dynu.com/en-US/Resources/API // Auth: set api_key in creds.json. -// Module: github.com/DNSControl/dnscontrol/v4 +// Module: github.com/DNSControl/dnscontrol/v5 package dynu import ( "encoding/base64" "encoding/hex" "encoding/json" + "errors" "fmt" "strconv" "strings" - "github.com/DNSControl/dnscontrol/v4/models" - "github.com/DNSControl/dnscontrol/v4/pkg/diff2" - "github.com/DNSControl/dnscontrol/v4/pkg/providers" - dnsv1 "github.com/miekg/dns" + dnsv2 "codeberg.org/miekg/dns" + "github.com/DNSControl/dnscontrol/v5/models" + "github.com/DNSControl/dnscontrol/v5/pkg/diff2" + "github.com/DNSControl/dnscontrol/v5/pkg/providers" ) var features = providers.DocumentationNotes{ @@ -60,7 +61,7 @@ func init() { func New(m map[string]string, metadata json.RawMessage) (providers.DNSServiceProvider, error) { apiKey := m["api_key"] if apiKey == "" { - return nil, fmt.Errorf("missing Dynu API key") + return nil, errors.New("missing Dynu API key") } return &dynuProvider{ apiKey: apiKey, @@ -92,7 +93,7 @@ func (d *dynuProvider) GetZoneRecords(dc *models.DomainConfig) (models.Records, } var existing models.Records for _, r := range records { - rc, err := toRc(r, dc.Name) + rc, err := toRc(r, dc) if err != nil { return nil, err } @@ -183,40 +184,36 @@ func (d *dynuProvider) GetZones() ([]string, error) { // NOTE: r.Content from the Dynu API is the full zone-file line (hostname TTL class // type rdata), not just the rdata. We therefore always use the individual structured // fields returned by Dynu rather than r.Content. -func toRc(r *dynuRecord, domain string) (*models.RecordConfig, error) { +func toRc(r *dynuRecord, dc *models.DomainConfig) (*models.RecordConfig, error) { switch r.RecordType { case "SOA", "WCA": return nil, nil } - rc := &models.RecordConfig{ - Type: r.RecordType, - TTL: uint32(r.TTL), - Original: r, - } - rc.SetLabel(r.NodeName, domain) - + domain := dc.Name + var rc *models.RecordConfig var err error + label := dc.LabelFromShort(r.NodeName) + ttl := uint32(r.TTL) switch r.RecordType { case "A": - err = rc.SetTarget(r.IPv4Address) + rc, err = dc.NewRecordConfig(label, ttl, dnsv2.TypeA, r.IPv4Address) case "AAAA": - err = rc.SetTarget(r.IPv6Address) + rc, err = dc.NewRecordConfig(label, ttl, dnsv2.TypeAAAA, r.IPv6Address) case "AFSDB": - err = rc.SetTarget(fmt.Sprintf("%d %s", intOrZero(r.SubType), ensureTrailingDot(r.Host))) + rc, err = dc.NewRecordConfigParse(label, ttl, dnsv2.TypeAFSDB, fmt.Sprintf("%d %s", intOrZero(r.SubType), ensureTrailingDot(r.Host))) case "CAA": - err = rc.SetTargetCAA(uint8(intOrZero(r.Flags)), r.Tag, r.Value) + rc, err = dc.NewRecordConfig(label, ttl, dnsv2.TypeCAA, intOrZero(r.Flags), r.Tag, r.Value) case "CERT": - err = rc.SetTarget(fmt.Sprintf("%d %d %d %s", - intOrZero(r.CertificateType), intOrZero(r.KeyTag), intOrZero(r.Algorithm), r.Certificate)) + rc, err = dc.NewRecordConfigParse(label, ttl, dnsv2.TypeCERT, fmt.Sprintf("%d %d %d %s", intOrZero(r.CertificateType), intOrZero(r.KeyTag), intOrZero(r.Algorithm), r.Certificate)) case "CNAME": - err = rc.SetTarget(ensureTrailingDot(r.Host)) + rc, err = dc.NewRecordConfig(label, ttl, dnsv2.TypeCNAME, ensureTrailingDot(r.Host)) case "DHCID": - err = rc.SetTarget(r.RecordData) + rc, err = dc.NewRecordConfigParse(label, ttl, dnsv2.TypeDHCID, r.RecordData) case "DNAME": - err = rc.SetTarget(ensureTrailingDot(r.Host)) + rc, err = dc.NewRecordConfig(label, ttl, dnsv2.TypeDNAME, ensureTrailingDot(r.Host)) case "HINFO": - err = rc.SetTarget(fmt.Sprintf("%q %q", r.CPU, r.OperatingSystem)) + rc, err = dc.NewRecordConfigParse(label, ttl, dnsv2.TypeHINFO, fmt.Sprintf("%q %q", r.CPU, r.OperatingSystem)) case "HTTPS", "SVCB": // Build rdata from individual structured Dynu fields. // targetName is returned by Dynu with a trailing dot already. @@ -224,14 +221,13 @@ func toRc(r *dynuRecord, domain string) (*models.RecordConfig, error) { if target == "" { target = "." } - rdata := fmt.Sprintf("%d %s", intOrZero(r.SvcPriority), target) - if ps := svcParamsToString(r.SvcParams); ps != "" { + rdata := fmt.Sprintf("%d %s", intOrZero(r.SvcPriority), target) // ignore:legacyfield + if ps := svcParamsToString(r.SvcParams); ps != "" { // ignore:legacyfield rdata += " " + ps } - err = rc.SetTargetSVCBString(domain, rdata) + rc, err = dc.NewRecordConfigParse(label, ttl, r.RecordType, rdata) case "KEY": - err = rc.SetTarget(fmt.Sprintf("%d %d %d %s", - intOrZero(r.Flags), intOrZero(r.KeyProtocol), intOrZero(r.Algorithm), r.PublicKey)) + rc, err = dc.NewRecordConfigParse(label, ttl, dnsv2.TypeKEY, fmt.Sprintf("%d %d %d %s", intOrZero(r.Flags), intOrZero(r.KeyProtocol), intOrZero(r.Algorithm), r.PublicKey)) case "LOC": // Parse DMS components from the content string (avoids miekg precision issues). // Use Dynu's individual metric fields (r.Altitude, r.Size, r.Horizontal/ @@ -259,70 +255,61 @@ func toRc(r *dynuRecord, domain string) (*models.RecordConfig, error) { if r.VerticalPrecision != nil { vp = float32(*r.VerticalPrecision) } - err = rc.SetLOCParams(d1, m1, s1, ns, d2, m2, s2, ew, al, sz, hp, vp) + rc, err = dc.NewRecordConfig(label, ttl, dnsv2.TypeLOC, d1, m1, s1, ns, d2, m2, s2, ew, float64(al), sz, hp, vp) case "MX": host := r.Host // Dynu stores null MX (priority 0, target ".") by returning the zone name as host. if intOrZero(r.Priority) == 0 && (host == "" || strings.TrimSuffix(host, ".") == domain) { host = "." } - err = rc.SetTargetMX(uint16(intOrZero(r.Priority)), ensureTrailingDot(host)) + rc, err = dc.NewRecordConfig(label, ttl, dnsv2.TypeMX, intOrZero(r.Priority), ensureTrailingDot(host)) case "NAPTR": // Dynu stores the null replacement (".") as an empty string. naptrReplacement := r.Replacement if naptrReplacement == "" { naptrReplacement = "." } - err = rc.SetTargetNAPTR(uint16(intOrZero(r.Order)), uint16(intOrZero(r.Preference)), - r.NaptrFlags, r.Services, r.RegExp, ensureTrailingDot(naptrReplacement)) + rc, err = dc.NewRecordConfig(label, ttl, dnsv2.TypeNAPTR, + intOrZero(r.Order), intOrZero(r.Preference), r.NaptrFlags, r.Services, r.RegExp, ensureTrailingDot(naptrReplacement)) // ignore:legacyfield case "NS": - err = rc.SetTarget(ensureTrailingDot(r.Host)) + rc, err = dc.NewRecordConfig(label, ttl, dnsv2.TypeNS, ensureTrailingDot(r.Host)) case "OPENPGPKEY": - err = rc.SetTarget(r.PublicKey) + rc, err = dc.NewRecordConfigParse(label, ttl, dnsv2.TypeOPENPGPKEY, r.PublicKey) case "PTR": - err = rc.SetTarget(ensureTrailingDot(r.Host)) + rc, err = dc.NewRecordConfig(label, ttl, dnsv2.TypePTR, ensureTrailingDot(r.Host)) case "RP": - // RP uses the modern rc.F-based system. We also set ZonefilePartial and - // Comparable directly so comparison works even if CopyFromLegacyFields - // cannot derive them (e.g. when the rtype package init has not run). mbox := ensureTrailingDot(r.MailBox) txt := ensureTrailingDot(r.TxtDomainName) - rc.F = &dnsv1.RP{ - Mbox: mbox, - Txt: txt, - } - rc.ZonefilePartial = mbox + " " + txt - rc.Comparable = rc.ZonefilePartial + rc, err = dc.NewRecordConfig(label, ttl, dnsv2.TypeRP, mbox, txt) case "SMIMEA": certHex, convErr := base64ToHex(r.CertificateAssociatedData) if convErr != nil { return nil, fmt.Errorf("SMIMEA certAssocData base64 decode for %s: %w", r.Hostname, convErr) } - err = rc.SetTargetSMIMEA(uint8(intOrZero(r.CertificateUsage)), uint8(intOrZero(r.Selector)), uint8(intOrZero(r.MatchingType)), certHex) + rc, err = dc.NewRecordConfig(label, ttl, dnsv2.TypeSMIMEA, intOrZero(r.CertificateUsage), intOrZero(r.Selector), intOrZero(r.MatchingType), certHex) case "SPF", "TXT": - rc.Type = "TXT" - err = rc.SetTargetTXT(r.TextData) + rc, err = dc.NewRecordConfig(label, ttl, dnsv2.TypeTXT, r.TextData) case "SRV": // Dynu stores the null SRV target (".") as an empty host string. srvHost := r.Host if srvHost == "" { srvHost = "." } - err = rc.SetTargetSRV(uint16(intOrZero(r.Priority)), uint16(intOrZero(r.Weight)), uint16(intOrZero(r.Port)), ensureTrailingDot(srvHost)) + rc, err = dc.NewRecordConfig(label, ttl, dnsv2.TypeSRV, intOrZero(r.Priority), intOrZero(r.Weight), intOrZero(r.Port), ensureTrailingDot(srvHost)) case "SSHFP": fpHex, convErr := base64ToHex(r.FingerPrint) if convErr != nil { return nil, fmt.Errorf("SSHFP fingerprint base64 decode for %s: %w", r.Hostname, convErr) } - err = rc.SetTargetSSHFP(uint8(intOrZero(r.Algorithm)), uint8(intOrZero(r.FingerPrintType)), fpHex) + rc, err = dc.NewRecordConfig(label, ttl, dnsv2.TypeSSHFP, intOrZero(r.Algorithm), intOrZero(r.FingerPrintType), fpHex) case "TLSA": certHex, convErr := base64ToHex(r.CertificateAssociatedData) if convErr != nil { return nil, fmt.Errorf("TLSA certAssocData base64 decode for %s: %w", r.Hostname, convErr) } - err = rc.SetTargetTLSA(uint8(intOrZero(r.CertificateUsage)), uint8(intOrZero(r.Selector)), uint8(intOrZero(r.MatchingType)), certHex) + rc, err = dc.NewRecordConfig(label, ttl, dnsv2.TypeTLSA, intOrZero(r.CertificateUsage), intOrZero(r.Selector), intOrZero(r.MatchingType), certHex) case "URI": - err = rc.SetTarget(fmt.Sprintf("%d %d %q", intOrZero(r.Priority), intOrZero(r.Weight), r.TargetURI)) + rc, err = dc.NewRecordConfigParse(label, ttl, dnsv2.TypeURI, fmt.Sprintf("%d %d %q", intOrZero(r.Priority), intOrZero(r.Weight), r.TargetURI)) default: return nil, nil } @@ -330,6 +317,7 @@ func toRc(r *dynuRecord, domain string) (*models.RecordConfig, error) { if err != nil { return nil, fmt.Errorf("record %s %s: %w", r.RecordType, r.Hostname, err) } + rc.Original = r return rc, nil } @@ -345,69 +333,57 @@ func toReq(rc *models.RecordConfig) *dynuRecord { TTL: int(rc.TTL), State: true, } - switch rc.Type { - case "A": - req.IPv4Address = rc.GetTargetField() - case "AAAA": - req.IPv6Address = rc.GetTargetField() - case "AFSDB": + switch rc.TypeNum { + case dnsv2.TypeA: + req.IPv4Address = rc.AsA().String() + case dnsv2.TypeAAAA: + req.IPv6Address = rc.AsAAAA().String() + case dnsv2.TypeAFSDB: // Target: " ." - parts := strings.Fields(rc.GetTargetField()) - if len(parts) >= 2 { - st, _ := strconv.Atoi(parts[0]) - req.SubType = &st - req.Host = strings.TrimSuffix(parts[1], ".") - } - case "CAA": - flags := int(rc.CaaFlag) + f := rc.AsAFSDB() + req.SubType = new(int(f.Subtype)) + req.Host = strings.TrimSuffix(f.Hostname, ".") + case dnsv2.TypeCAA: + f := rc.AsCAA() + flags := int(f.Flag) req.Flags = &flags - req.Tag = rc.CaaTag - req.Value = rc.GetTargetField() - case "CERT": - // Target: " " - parts := strings.Fields(rc.GetTargetField()) - if len(parts) >= 4 { - ct := parseCERTType(parts[0]) - kt, _ := strconv.Atoi(parts[1]) - algo, _ := strconv.Atoi(parts[2]) - req.CertificateType = &ct - req.KeyTag = &kt - req.Algorithm = &algo - req.Certificate = parts[3] - } - case "CNAME", "NS", "PTR", "DNAME": - req.Host = strings.TrimSuffix(rc.GetTargetField(), ".") - case "DHCID": + req.Tag = f.Tag + req.Value = f.Value + case dnsv2.TypeCERT: + f := rc.AsCERT() + req.CertificateType = new(int(f.Type)) + req.KeyTag = new(int(f.KeyTag)) + req.Algorithm = new(int(f.Algorithm)) + req.Certificate = f.Certificate + + case dnsv2.TypeCNAME, dnsv2.TypeNS, dnsv2.TypePTR, dnsv2.TypeDNAME: + req.Host = strings.TrimSuffix(rc.GetRDATA().String(), ".") + case dnsv2.TypeDHCID: // Target is the base64-encoded DHCID data (zone-file format == API format). - req.RecordData = rc.GetTargetField() - case "HINFO": + req.RecordData = rc.AsDHCID().Digest + case dnsv2.TypeHINFO: // Target: "<"cpu"> <"os">" — parse the two quoted character-strings. - cpu, os := parseCharStrings(rc.GetTargetField()) - req.CPU = cpu - req.OperatingSystem = os - case "HTTPS": - svcPrio := int(rc.SvcPriority) - req.SvcPriority = &svcPrio + req.CPU = rc.AsHINFO().Cpu + req.OperatingSystem = rc.AsHINFO().Os + case dnsv2.TypeHTTPS: + f := rc.AsHTTPS() + req.SvcPriority = new(int(f.Priority)) // ignore:legacyfield // Preserve "." for the null target; strip trailing dot from real hostnames. - target := strings.TrimSuffix(rc.GetTargetField(), ".") + target := strings.TrimSuffix(f.Target, ".") if target == "" { target = "." } req.TargetName = target - req.SvcParams = parseSvcParams(rc.SvcParams) - case "KEY": + req.SvcParams = parseSvcParams(models.Svcbv2ValueToString(f.Value)) // ignore:legacyfield + case dnsv2.TypeKEY: // Target: " " - parts := strings.Fields(rc.GetTargetField()) - if len(parts) >= 4 { - f, _ := strconv.Atoi(parts[0]) - proto, _ := strconv.Atoi(parts[1]) - algo, _ := strconv.Atoi(parts[2]) - req.Flags = &f - req.KeyProtocol = &proto - req.Algorithm = &algo - req.PublicKey = parts[3] - } - case "LOC": + f := rc.AsKEY() + req.Flags = new(int(f.Flags)) + req.KeyProtocol = new(int(f.Protocol)) + req.Algorithm = new(int(f.Algorithm)) + req.PublicKey = f.PublicKey + + case dnsv2.TypeLOC: // Convert DNSControl's packed binary LOC fields to Dynu's decimal-degree format. // The packed values are integer arc-milliseconds. We compute total ms first // (avoiding intermediate fractional divisions), then add a +0.5 ms bias before @@ -415,112 +391,122 @@ func toReq(rc *models.RecordConfig) *dynuRecord { // rounds to the correct integer millisecond (e.g. 71°06'18.000" rather than // 71°06'17.999" when the float64 representation of 71.105 is slightly below exact). const locMsPerDegree = 3600000.0 - latHemi, latDeg, latMin, latSec := models.ReverseLatitude(rc.LocLatitude) + f := rc.AsLOC() + latHemi, latDeg, latMin, latSec := models.ReverseLatitude(f.Latitude) latMs := float64(latDeg)*locMsPerDegree + float64(latMin)*60000 + latSec*1000 lat := (latMs + 0.5) / locMsPerDegree if latHemi == "S" { lat = -lat } - lonHemi, lonDeg, lonMin, lonSec := models.ReverseLongitude(rc.LocLongitude) + lonHemi, lonDeg, lonMin, lonSec := models.ReverseLongitude(f.Longitude) lonMs := float64(lonDeg)*locMsPerDegree + float64(lonMin)*60000 + lonSec*1000 lon := (lonMs + 0.5) / locMsPerDegree if lonHemi == "W" { lon = -lon } - alt := models.ReverseAltitude(rc.LocAltitude) - size := models.ReverseENotationInt(rc.LocSize) - horizPre := models.ReverseENotationInt(rc.LocHorizPre) - vertPre := models.ReverseENotationInt(rc.LocVertPre) + alt := models.ReverseAltitude(f.Altitude) + size := models.ReverseENotationInt(f.Size) + horizPre := models.ReverseENotationInt(f.HorizPre) + vertPre := models.ReverseENotationInt(f.VertPre) req.Latitude = &lat req.Longitude = &lon req.Altitude = &alt req.Size = &size req.HorizontalPrecision = &horizPre req.VerticalPrecision = &vertPre - case "MX": - req.Host = strings.TrimSuffix(rc.GetTargetField(), ".") - pref := int(rc.MxPreference) + case dnsv2.TypeMX: + f := rc.AsMX() + req.Host = strings.TrimSuffix(f.Mx, ".") + pref := int(f.Preference) req.Priority = &pref - case "NAPTR": - order := int(rc.NaptrOrder) - pref := int(rc.NaptrPreference) + case dnsv2.TypeNAPTR: + f := rc.AsNAPTR() + order := int(f.Order) + pref := int(f.Preference) req.Order = &order req.Preference = &pref - req.NaptrFlags = rc.NaptrFlags - req.Services = rc.NaptrService - req.RegExp = rc.NaptrRegexp + req.NaptrFlags = f.Flags // ignore:legacyfield + req.Services = f.Service + req.RegExp = f.Regexp // Preserve "." as-is (null replacement); strip trailing dot from real FQDNs. - naptrTarget := rc.GetTargetField() + naptrTarget := f.Replacement if naptrTarget != "." { naptrTarget = strings.TrimSuffix(naptrTarget, ".") } req.Replacement = naptrTarget - case "OPENPGPKEY": + case dnsv2.TypeOPENPGPKEY: // Target is the base64-encoded public key (zone-file format == API format). - req.PublicKey = rc.GetTargetField() - case "RP": - // rc.ZonefilePartial contains "mailbox. txtdomain." set by FromStruct/CopyFromLegacyFields. - parts := strings.Fields(rc.ZonefilePartial) - if len(parts) >= 2 { - req.MailBox = strings.TrimSuffix(parts[0], ".") - req.TxtDomainName = strings.TrimSuffix(parts[1], ".") - } - case "SMIMEA": - usage := int(rc.SmimeaUsage) - selector := int(rc.SmimeaSelector) - mtype := int(rc.SmimeaMatchingType) + req.PublicKey = rc.AsOPENPGPKEY().PublicKey + case dnsv2.TypeRP: + // Preserve "." as-is (null name); strip trailing dot from real FQDNs. + rd := rc.AsRP() + mbox := rd.Mbox + if mbox != "." { + mbox = strings.TrimSuffix(mbox, ".") + } + txt := rd.Txt + if txt != "." { + txt = strings.TrimSuffix(txt, ".") + } + req.MailBox = mbox + req.TxtDomainName = txt + case dnsv2.TypeSMIMEA: + f := rc.AsSMIMEA() + usage := int(f.Usage) + selector := int(f.Selector) + mtype := int(f.MatchingType) req.CertificateUsage = &usage req.Selector = &selector req.MatchingType = &mtype - req.CertificateAssociatedData = hexToBase64(rc.GetTargetField()) - case "SRV": + req.CertificateAssociatedData = hexToBase64(f.Certificate) + case dnsv2.TypeSRV: // Preserve "." for the null target; strip trailing dot from real hostnames. - srvTarget := strings.TrimSuffix(rc.GetTargetField(), ".") + f := rc.AsSRV() + srvTarget := strings.TrimSuffix(f.Target, ".") if srvTarget == "" { srvTarget = "." } req.Host = srvTarget - prio := int(rc.SrvPriority) - weight := int(rc.SrvWeight) - port := int(rc.SrvPort) + prio := int(f.Priority) + weight := int(f.Weight) + port := int(f.Port) req.Priority = &prio req.Weight = &weight req.Port = &port - case "SSHFP": - algo := int(rc.SshfpAlgorithm) - fptype := int(rc.SshfpFingerprint) + case dnsv2.TypeSSHFP: + f := rc.AsSSHFP() + algo := int(f.Algorithm) + fptype := int(f.Type) req.Algorithm = &algo req.FingerPrintType = &fptype - req.FingerPrint = hexToBase64(rc.GetTargetField()) - case "SVCB": - svcPrio := int(rc.SvcPriority) - req.SvcPriority = &svcPrio - target := strings.TrimSuffix(rc.GetTargetField(), ".") + req.FingerPrint = hexToBase64(f.FingerPrint) + case dnsv2.TypeSVCB: + f := rc.AsSVCB() + req.SvcPriority = new(int(f.Priority)) // ignore:legacyfield + target := strings.TrimSuffix(f.Target, ".") if target == "" { target = "." } req.TargetName = target - req.SvcParams = parseSvcParams(rc.SvcParams) - case "TLSA": - usage := int(rc.TlsaUsage) - selector := int(rc.TlsaSelector) - mtype := int(rc.TlsaMatchingType) + req.SvcParams = parseSvcParams(models.Svcbv2ValueToString(f.Value)) // ignore:legacyfield + case dnsv2.TypeTLSA: + f := rc.AsTLSA() + usage := int(f.Usage) + selector := int(f.Selector) + mtype := int(f.MatchingType) req.CertificateUsage = &usage req.Selector = &selector req.MatchingType = &mtype - req.CertificateAssociatedData = hexToBase64(rc.GetTargetField()) - case "TXT": + req.CertificateAssociatedData = hexToBase64(f.Certificate) + case dnsv2.TypeTXT: req.TextData = rc.GetTargetTXTJoined() - case "URI": + case dnsv2.TypeURI: // Target: " """ - parts := strings.SplitN(strings.TrimSpace(rc.GetTargetField()), " ", 3) - if len(parts) >= 3 { - prio, _ := strconv.Atoi(parts[0]) - wgt, _ := strconv.Atoi(parts[1]) - req.Priority = &prio - req.Weight = &wgt - req.TargetURI = strings.Trim(parts[2], "\"") - } + f := rc.AsURI() + req.Priority = new(int(f.Priority)) + req.Weight = new(int(f.Weight)) + req.TargetURI = strings.Trim(f.Target, "\"") + } return req } @@ -590,39 +576,6 @@ func svcParamsToString(params []svcParam) string { return strings.Join(parts, " ") } -// // locRdata builds the LOC rdata string (rdata-only, no owner/TTL) from Dynu's -// // decimal-degree and metre fields so it can be passed to SetTargetLOCString. -// func locRdata(lat, lon, alt, size, horizPre, vertPre float64) string { -// latD, latM, latS, latHemi := ddToDMS(lat, "N", "S") -// lonD, lonM, lonS, lonHemi := ddToDMS(lon, "E", "W") -// return fmt.Sprintf("%d %d %.3f %s %d %d %.3f %s %.2fm %.2fm %.2fm %.2fm", -// latD, latM, latS, latHemi, lonD, lonM, lonS, lonHemi, -// alt, size, horizPre, vertPre) -// } - -// // ddToDMS converts a signed decimal-degrees value to unsigned degrees, minutes, -// // seconds, and hemisphere strings (pos/neg for the two possible hemispheres). -// func ddToDMS(dd float64, pos, neg string) (d uint8, m uint8, s float32, hemi string) { -// hemi = pos -// if dd < 0 { -// hemi = neg -// dd = -dd -// } -// d = uint8(dd) -// minutesTotal := (dd - float64(d)) * 60.0 -// m = uint8(minutesTotal) -// s = float32((minutesTotal - float64(m)) * 60.0) -// return -// } - -// // floatOrDefault returns *f if non-nil, otherwise the supplied default. -// func floatOrDefault(f *float64, def float64) float64 { -// if f == nil { -// return def -// } -// return *f -// } - // extractRdata strips the owner name, TTL, optional class, and type from a full // DNS zone-file line ("hostname. TTL [IN] TYPE rdata") and returns just the rdata. // Returns "" if rtype is not found. @@ -636,58 +589,6 @@ func extractRdata(content, rtype string) string { return "" } -// parseCharStrings splits a string containing one or two DNS character-strings -// (optionally quoted) and returns the first two values. -// Used for HINFO: "X86-64" "Linux" → ("X86-64", "Linux"). -func parseCharStrings(s string) (first, second string) { - s = strings.TrimSpace(s) - var parts []string - for len(s) > 0 { - s = strings.TrimLeft(s, " \t") - if len(s) == 0 { - break - } - if s[0] == '"' { - end := strings.Index(s[1:], "\"") - if end < 0 { - parts = append(parts, s[1:]) - break - } - parts = append(parts, s[1:end+1]) - s = s[end+2:] - } else { - idx := strings.IndexAny(s, " \t") - if idx < 0 { - parts = append(parts, s) - break - } - parts = append(parts, s[:idx]) - s = s[idx:] - } - } - if len(parts) >= 1 { - first = parts[0] - } - if len(parts) >= 2 { - second = parts[1] - } - return -} - -// parseCERTType converts a CERT type name or number string to its integer value. -func parseCERTType(s string) int { - named := map[string]int{ - "PKIX": 1, "SPKI": 2, "PGP": 3, "IPKIX": 4, - "ISPKI": 5, "IPGP": 6, "ACPKIX": 7, "IACPKIX": 8, - "URI": 253, "OID": 254, - } - if v, ok := named[strings.ToUpper(s)]; ok { - return v - } - v, _ := strconv.Atoi(s) - return v -} - // parseLOCRdata parses a LOC record rdata string (the part after the type label) // into the 12 parameters required by models.RecordConfig.SetLOCParams. // It uses strings.Fields so it is robust to Dynu's variable-precision output diff --git a/providers/dynu/dynuProvider_test.go b/providers/dynu/dynuProvider_test.go new file mode 100644 index 0000000000..7d2613ed34 --- /dev/null +++ b/providers/dynu/dynuProvider_test.go @@ -0,0 +1,137 @@ +package dynu + +import ( + "testing" + + dnsv2 "codeberg.org/miekg/dns" + "github.com/DNSControl/dnscontrol/v5/models" +) + +func TestToRc(t *testing.T) { + dc, err := models.NewDomainConfig("example.com") + if err != nil { + t.Fatal(err) + } + + priority := 10 + zero := 0 + weight := 2 + port := 5060 + order := 100 + preference := 10 + tests := []struct { + name string + record dynuRecord + wantTarget string + }{ + {"A", dynuRecord{NodeName: "www", RecordType: "A", IPv4Address: "192.0.2.1", TTL: 300}, "192.0.2.1"}, + {"MX", dynuRecord{NodeName: "@", RecordType: "MX", Host: "mail.example.net", Priority: &priority, TTL: 300}, "10 mail.example.net."}, + {"null MX", dynuRecord{NodeName: "@", RecordType: "MX", Host: "example.com", Priority: &zero, TTL: 300}, "0 ."}, + {"TXT", dynuRecord{NodeName: "@", RecordType: "TXT", TextData: "raw text", TTL: 300}, `"raw text"`}, + {"SRV", dynuRecord{NodeName: "_sip._tcp", RecordType: "SRV", Host: "sip.example.net", Priority: &priority, Weight: &weight, Port: &port, TTL: 300}, "10 2 5060 sip.example.net."}, + {"NAPTR", dynuRecord{NodeName: "@", RecordType: "NAPTR", Order: &order, Preference: &preference, NaptrFlags: "U", Services: "E2U+sip", RegExp: `!^.*$!sip:info@example.com!`, Replacement: "sip.example.net", TTL: 300}, `100 10 "U" "E2U+sip" "!^.*$!sip:info@example.com!" sip.example.net.`}, + {"NAPTR null replacement", dynuRecord{NodeName: "@", RecordType: "NAPTR", Order: &order, Preference: &preference, NaptrFlags: "S", Services: "SIP+D2U", Replacement: "", TTL: 300}, `100 10 "S" "SIP+D2U" "" .`}, + } + + for _, tc := range tests { + t.Run(tc.name, func(t *testing.T) { + record := tc.record + rc, err := toRc(&record, dc) + if err != nil { + t.Fatal(err) + } + if got := rc.GetRDATA().String(); got != tc.wantTarget { + t.Errorf("target = %q, want %q", got, tc.wantTarget) + } + if rc.Original != &record { + t.Error("original provider record was not retained") + } + }) + } +} + +// TestToReqNAPTR verifies that toReq puts each NAPTR field in the matching Dynu +// API field. In particular, replacement must come from the record's replacement +// and not from its service. +func TestToReqNAPTR(t *testing.T) { + dc, err := models.NewDomainConfig("example.com") + if err != nil { + t.Fatal(err) + } + + tests := []struct { + name string + replacement string + wantReplacement string + }{ + {"fqdn replacement", "sip.example.net.", "sip.example.net"}, + {"null replacement", ".", "."}, + } + + for _, tc := range tests { + t.Run(tc.name, func(t *testing.T) { + rc, err := dc.NewRecordConfig("@", 300, dnsv2.TypeNAPTR, + 100, 10, "U", "E2U+sip", `!^.*$!sip:info@example.com!`, tc.replacement) // ignore:legacyfield + if err != nil { + t.Fatal(err) + } + + req := toReq(rc) + if req.Replacement != tc.wantReplacement { + t.Errorf("Replacement = %q, want %q", req.Replacement, tc.wantReplacement) + } + if req.Services != "E2U+sip" { + t.Errorf("Services = %q, want %q", req.Services, "E2U+sip") + } + if req.NaptrFlags != "U" { + t.Errorf("NaptrFlags = %q, want %q", req.NaptrFlags, "U") + } + if req.RegExp != `!^.*$!sip:info@example.com!` { + t.Errorf("RegExp = %q, want %q", req.RegExp, `!^.*$!sip:info@example.com!`) + } + if intOrZero(req.Order) != 100 { + t.Errorf("Order = %d, want 100", intOrZero(req.Order)) + } + if intOrZero(req.Preference) != 10 { + t.Errorf("Preference = %d, want 10", intOrZero(req.Preference)) + } + }) + } +} + +// TestToReqRP verifies that toReq strips the trailing dot from the RP mailbox +// and TXT domain name. The Dynu API validates both as hostnames and rejects a +// trailing dot with "Invalid content.". DNSControl fully qualifies relative +// names, so both fields always arrive here with a trailing dot. +func TestToReqRP(t *testing.T) { + dc, err := models.NewDomainConfig("example.com") + if err != nil { + t.Fatal(err) + } + + tests := []struct { + name string + mbox, txt string + wantMbox, wantTxt string + }{ + {"absolute names", "user.example.com.", "bar.com.", "user.example.com", "bar.com"}, + {"relative names get qualified", "user", "server", "user.example.com", "server.example.com"}, + } + + for _, tc := range tests { + t.Run(tc.name, func(t *testing.T) { + rc, err := dc.NewRecordConfig("foo", 300, dnsv2.TypeRP, tc.mbox, tc.txt) + if err != nil { + t.Fatal(err) + } + + req := toReq(rc) + if req.MailBox != tc.wantMbox { + t.Errorf("MailBox = %q, want %q", req.MailBox, tc.wantMbox) + } + if req.TxtDomainName != tc.wantTxt { + t.Errorf("TxtDomainName = %q, want %q", req.TxtDomainName, tc.wantTxt) + } + }) + } +} diff --git a/providers/easyname/easynameProvider.go b/providers/easyname/easynameProvider.go index 104c338bfa..d969e726d6 100644 --- a/providers/easyname/easynameProvider.go +++ b/providers/easyname/easynameProvider.go @@ -6,8 +6,8 @@ import ( "sort" "strings" - "github.com/DNSControl/dnscontrol/v4/models" - "github.com/DNSControl/dnscontrol/v4/pkg/providers" + "github.com/DNSControl/dnscontrol/v5/models" + "github.com/DNSControl/dnscontrol/v5/pkg/providers" ) type easynameProvider struct { diff --git a/providers/exoscale/auditrecords.go b/providers/exoscale/auditrecords.go index 0583762f81..c68f7b910f 100644 --- a/providers/exoscale/auditrecords.go +++ b/providers/exoscale/auditrecords.go @@ -1,15 +1,15 @@ package exoscale import ( - "fmt" + "errors" - "github.com/DNSControl/dnscontrol/v4/models" - "github.com/DNSControl/dnscontrol/v4/pkg/rejectif" + "github.com/DNSControl/dnscontrol/v5/models" + "github.com/DNSControl/dnscontrol/v5/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 { +func AuditRecords(records models.Records) []error { auditor := rejectif.Auditor{} auditor.Add("CAA", rejectif.CaaTargetContainsWhitespace) // Last verified 2022-07-11 @@ -17,7 +17,7 @@ func AuditRecords(records []*models.RecordConfig) []error { auditor.Add("MX", rejectif.MxNull) // Last verified 2022-07-11 auditor.Add("PTR", func(rc *models.RecordConfig) error { - return fmt.Errorf("PTR records are not supported by the Exoscale provider") + return errors.New("PTR records are not supported by the Exoscale provider") }) auditor.Add("SRV", rejectif.SrvHasNullTarget) // Last verified 2020-12-28 diff --git a/providers/exoscale/exoscaleProvider.go b/providers/exoscale/exoscaleProvider.go index d9e9a983c4..17519cbcf3 100644 --- a/providers/exoscale/exoscaleProvider.go +++ b/providers/exoscale/exoscaleProvider.go @@ -6,16 +6,16 @@ import ( "errors" "fmt" "os" - "strconv" "strings" + dnsv2 "codeberg.org/miekg/dns" + dnsrdatav2 "codeberg.org/miekg/dns/rdata" + "github.com/DNSControl/dnscontrol/v5/models" + "github.com/DNSControl/dnscontrol/v5/pkg/diff2" + "github.com/DNSControl/dnscontrol/v5/pkg/printer" + "github.com/DNSControl/dnscontrol/v5/pkg/providers" egoscale "github.com/exoscale/egoscale/v3" "github.com/exoscale/egoscale/v3/credentials" - - "github.com/DNSControl/dnscontrol/v4/models" - "github.com/DNSControl/dnscontrol/v4/pkg/diff" - "github.com/DNSControl/dnscontrol/v4/pkg/printer" - "github.com/DNSControl/dnscontrol/v4/pkg/providers" ) type exoscaleProvider struct { @@ -60,7 +60,7 @@ var features = providers.DocumentationNotes{ providers.CanUseAlias: providers.Can(), providers.CanUseCAA: providers.Can(), providers.CanUseLOC: providers.Cannot(), - providers.CanUsePTR: providers.Can(), + providers.CanUsePTR: providers.Cannot(), providers.CanUseSRV: providers.Can("SRV records with empty targets are not supported"), providers.CanUseTLSA: providers.Cannot(), providers.DocCreateDomains: providers.Cannot(), @@ -113,9 +113,9 @@ func (provider *exoscaleProvider) GetZoneRecords(domainConfig *models.DomainConf return nil, err } - existingRecords := make([]*models.RecordConfig, 0, len(records.DNSDomainRecords)) + existingRecords := make(models.Records, 0, len(records.DNSDomainRecords)) for i := range records.DNSDomainRecords { - recordConfig, err := nativeToRecord(&records.DNSDomainRecords[i], domainName) + recordConfig, err := nativeToRecord(&records.DNSDomainRecords[i], domainConfig) if err != nil { return nil, err } @@ -129,7 +129,7 @@ func (provider *exoscaleProvider) GetZoneRecords(domainConfig *models.DomainConf // nativeToRecord converts an Exoscale DNS record to a RecordConfig. // Returns nil, nil for record types that should be silently skipped (SOA, NS, TXT ALIAS mirrors). -func nativeToRecord(record *egoscale.DNSDomainRecord, domainName string) (*models.RecordConfig, error) { +func nativeToRecord(record *egoscale.DNSDomainRecord, dc *models.DomainConfig) (*models.RecordConfig, error) { recordContent := record.Content if record.Type == "SOA" || record.Type == "NS" { @@ -152,31 +152,25 @@ func nativeToRecord(record *egoscale.DNSDomainRecord, domainName string) (*model return nil, nil } - recordConfig := &models.RecordConfig{ - Original: record, - } - if record.Ttl != 0 { - recordConfig.TTL = uint32(record.Ttl) - } - recordConfig.SetLabel(record.Name, domainName) + label := dc.LabelFromShort(record.Name) + ttl := uint32(record.Ttl) + var recordConfig *models.RecordConfig var err error switch record.Type { case "ALIAS", "URL": - recordConfig.Type = string(record.Type) - _ = recordConfig.SetTarget(recordContent) + recordConfig, err = dc.NewRecordConfig(label, ttl, string(record.Type), recordContent) case "MX": - var priority uint16 - if record.Priority != 0 { - priority = uint16(record.Priority) - } - err = recordConfig.SetTargetMX(priority, recordContent) + recordConfig, err = dc.NewRecordConfig(label, ttl, string(record.Type), record.Priority, recordContent) + case "TXT": + recordConfig, err = dc.NewRecordConfig(label, ttl, string(record.Type), recordContent) default: - err = recordConfig.PopulateFromString(string(record.Type), recordContent, domainName) + recordConfig, err = dc.NewRecordConfigParse(label, ttl, string(record.Type), recordContent) } if err != nil { return nil, fmt.Errorf("unparsable record received from exoscale: %w", err) } + recordConfig.Original = record return recordConfig, nil } @@ -191,36 +185,41 @@ func (provider *exoscaleProvider) GetZoneRecordsCorrections( return nil, 0, err } - toReport, toCreate, toDelete, toUpdate, actualChangeCount, err := diff.NewCompat(domainConfig).IncrementalDiff(existingRecords) + changes, actualChangeCount, err := diff2.ByRecord(existingRecords, domainConfig, nil) if err != nil { return nil, 0, err } - // Start corrections with the reports - corrections := diff.GenerateMessageCorrections(toReport) - - for _, deletionCorrelation := range toDelete { - record := deletionCorrelation.Existing.Original.(*egoscale.DNSDomainRecord) - corrections = append(corrections, &models.Correction{ - Msg: deletionCorrelation.String(), - F: provider.deleteRecordFunc(record.ID, domain.ID), - }) - } - - for _, creationCorrelation := range toCreate { - recordConfig := creationCorrelation.Desired - corrections = append(corrections, &models.Correction{ - Msg: creationCorrelation.String(), - F: provider.createRecordFunc(recordConfig, domain.ID), - }) - } - for _, updateCorrelation := range toUpdate { - oldc := updateCorrelation.Existing.Original.(*egoscale.DNSDomainRecord) - newc := updateCorrelation.Desired - corrections = append(corrections, &models.Correction{ - Msg: updateCorrelation.String(), - F: provider.updateRecordFunc(oldc, newc, domain.ID), - }) + var corrections []*models.Correction + for _, change := range changes { + switch change.Type { + case diff2.REPORT: + corrections = append(corrections, &models.Correction{Msg: change.MsgsJoined}) + + case diff2.CREATE: + corrections = append(corrections, &models.Correction{ + Msg: change.Msgs[0], + F: provider.createRecordFunc(change.New[0], domain.ID), + }) + + case diff2.DELETE: + record := change.Old[0].Original.(*egoscale.DNSDomainRecord) + corrections = append(corrections, &models.Correction{ + Msg: change.Msgs[0], + F: provider.deleteRecordFunc(record.ID, domain.ID), + }) + + case diff2.CHANGE: + oldc := change.Old[0].Original.(*egoscale.DNSDomainRecord) + newc := change.New[0] + corrections = append(corrections, &models.Correction{ + Msg: change.Msgs[0], + F: provider.updateRecordFunc(oldc, newc, domain.ID), + }) + + default: + panic(fmt.Sprintf("unhandled change.Type %s", change.Type)) + } } return corrections, actualChangeCount, nil @@ -231,27 +230,21 @@ func (provider *exoscaleProvider) createRecordFunc( recordConfig *models.RecordConfig, domainID egoscale.UUID) func() error { return func() error { - target := recordConfig.GetTargetCombined() name := recordConfig.GetLabel() var prio int64 - if recordConfig.Type == "MX" { - target = recordConfig.GetTargetField() - - if recordConfig.MxPreference != 0 { - prio = int64(recordConfig.MxPreference) - } - } - - if recordConfig.Type == "SRV" { - // API wants priority as a separate argument, here we will strip it from combined target. - sp := strings.Split(target, " ") - target = strings.Join(sp[1:], " ") - p, err := strconv.ParseInt(sp[0], 10, 64) - if err != nil { - return err - } - prio = p + var target string + switch recordConfig.TypeNum { + case dnsv2.TypeMX: + f := recordConfig.AsMX() + target = f.Mx + prio = int64(f.Preference) + case dnsv2.TypeSRV: + f := recordConfig.AsSRV() + prio = int64(f.Priority) + target = fmt.Sprintf("%d %d %s", f.Weight, f.Port, f.Target) + default: + target = recordConfig.GetRDATA().String() } if recordConfig.Type == "NS" && (name == "@" || name == "") { @@ -263,11 +256,8 @@ func (provider *exoscaleProvider) createRecordFunc( Type: egoscale.CreateDNSDomainRecordRequestType(recordConfig.Type), Content: target, Priority: prio, - } - if recordConfig.TTL != 0 { - record.Ttl = int64(recordConfig.TTL) - } + Ttl: int64(recordConfig.TTL)} ctx := context.Background() op, err := provider.client.CreateDNSDomainRecord(ctx, domainID, record) @@ -298,41 +288,34 @@ func (provider *exoscaleProvider) deleteRecordFunc(recordID, domainID egoscale.U // Returns a function that can be invoked to update a record in a zone. func (provider *exoscaleProvider) updateRecordFunc( record *egoscale.DNSDomainRecord, - recordConfig *models.RecordConfig, + rc *models.RecordConfig, domainID egoscale.UUID) func() error { return func() error { - target := recordConfig.GetTargetCombined() - name := recordConfig.GetLabel() - - if recordConfig.Type == "MX" { - target = recordConfig.GetTargetField() - - if recordConfig.MxPreference != 0 { - record.Priority = int64(recordConfig.MxPreference) - } + name := rc.GetLabel() + + var target string + switch rc.TypeNum { + case dnsv2.TypeMX: + mx := rc.GetRDATA().(dnsrdatav2.MX) + target = mx.Mx + record.Priority = int64(mx.Preference) + case dnsv2.TypeSRV: + // API wants priority as separate argument. The target contains the weight, port, target. + srv := rc.GetRDATA().(dnsrdatav2.SRV) + target = fmt.Sprintf("%d %d %s", srv.Weight, srv.Port, srv.Target) + record.Priority = int64(srv.Priority) + default: + target = rc.GetRDATA().String() } - if recordConfig.Type == "SRV" { - // API wants priority as separate argument, here we will strip it from combined target. - sp := strings.Split(target, " ") - target = strings.Join(sp[1:], " ") - p, err := strconv.ParseInt(sp[0], 10, 64) - if err != nil { - return err - } - record.Priority = p - } - - if recordConfig.Type == "NS" && (name == "@" || name == "") { + if rc.Type == "NS" && (name == "@" || name == "") { name = "*" } record.Name = name - record.Type = egoscale.DNSDomainRecordType(recordConfig.Type) + record.Type = egoscale.DNSDomainRecordType(rc.Type) record.Content = target - if recordConfig.TTL != 0 { - record.Ttl = int64(recordConfig.TTL) - } + record.Ttl = int64(rc.TTL) ctx := context.Background() op, err := provider.client.UpdateDNSDomainRecord(ctx, domainID, record.ID, egoscale.UpdateDNSDomainRecordRequest{ @@ -368,14 +351,14 @@ func defaultNSSUffix(defNS string) bool { // remove all non-exoscale NS records from our desired state. // if any are found, print a warning. func removeOtherNS(domainConfig *models.DomainConfig) { - recordConfigs := make([]*models.RecordConfig, 0, len(domainConfig.Records)) + recordConfigs := make(models.Records, 0, len(domainConfig.Records)) for _, recordConfig := range domainConfig.Records { if recordConfig.Type == "NS" { // apex NS inside exoscale are expected. - if recordConfig.GetLabelFQDN() == domainConfig.Name && defaultNSSUffix(recordConfig.GetTargetField()) { + if recordConfig.GetLabelFQDN() == domainConfig.Name && defaultNSSUffix(recordConfig.AsNS().Ns) { continue } - printer.Printf("Warning: exoscale.com(.io, .ch, .net) does not allow NS records to be modified. %s will not be added.\n", recordConfig.GetTargetField()) + printer.Printf("Warning: exoscale.com(.io, .ch, .net) does not allow NS records to be modified. %s will not be added.\n", recordConfig.AsNS().Ns) continue } recordConfigs = append(recordConfigs, recordConfig) diff --git a/providers/exoscale/exoscaleProvider_test.go b/providers/exoscale/exoscaleProvider_test.go index e51fe2dfe8..328499fdd1 100644 --- a/providers/exoscale/exoscaleProvider_test.go +++ b/providers/exoscale/exoscaleProvider_test.go @@ -5,7 +5,7 @@ import ( egoscale "github.com/exoscale/egoscale/v3" - "github.com/DNSControl/dnscontrol/v4/models" + "github.com/DNSControl/dnscontrol/v5/models" ) func makeNativeRecord(rtype, name, content string, priority int64, ttl int64) *egoscale.DNSDomainRecord { @@ -21,6 +21,7 @@ func makeNativeRecord(rtype, name, content string, priority int64, ttl int64) *e // TestNativeToRecord_ContentPopulated regression: rcontent was declared as "" and never // assigned from record.Content, so all records got empty content. func TestNativeToRecord_ContentPopulated(t *testing.T) { + dc := models.MustNewDomainConfig("example.com") tests := []struct { name string record *egoscale.DNSDomainRecord @@ -42,14 +43,14 @@ func TestNativeToRecord_ContentPopulated(t *testing.T) { { name: "TXT", record: makeNativeRecord("TXT", "foo", "hello world", 0, 300), - wantTarget: "hello world", + wantTarget: `"hello world"`, wantType: "TXT", }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { - rc, err := nativeToRecord(tt.record, "example.com") + rc, err := nativeToRecord(tt.record, dc) if err != nil { t.Fatalf("unexpected error: %v", err) } @@ -59,8 +60,8 @@ func TestNativeToRecord_ContentPopulated(t *testing.T) { if rc.Type != tt.wantType { t.Errorf("type: got %q, want %q", rc.Type, tt.wantType) } - if rc.GetTargetField() != tt.wantTarget { - t.Errorf("target: got %q, want %q", rc.GetTargetField(), tt.wantTarget) + if rc.GetRDATA().String() != tt.wantTarget { + t.Errorf("target: got %q, want %q", rc.GetRDATA().String(), tt.wantTarget) } }) } @@ -69,6 +70,7 @@ func TestNativeToRecord_ContentPopulated(t *testing.T) { // TestNativeToRecord_SRVNoDoubleDot: API returns content as "weight port target"; we appended // a trailing dot unconditionally, causing double-dot when the API already returned one. func TestNativeToRecord_SRVNoDoubleDot(t *testing.T) { + dc := models.MustNewDomainConfig("example.com") tests := []struct { name string content string // as returned by the API: "weight port target" @@ -80,7 +82,7 @@ func TestNativeToRecord_SRVNoDoubleDot(t *testing.T) { for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { record := makeNativeRecord("SRV", "_sip._tcp", tt.content, 10, 300) - rc, err := nativeToRecord(record, "example.com") + rc, err := nativeToRecord(record, dc) if err != nil { t.Fatalf("unexpected error: %v", err) } @@ -88,7 +90,7 @@ func TestNativeToRecord_SRVNoDoubleDot(t *testing.T) { t.Fatal("expected record, got nil") } // target should end with exactly one dot - target := rc.GetTargetField() + target := rc.AsSRV().Target if len(target) >= 2 && target[len(target)-1] == '.' && target[len(target)-2] == '.' { t.Errorf("double trailing dot in SRV target: %q", target) } @@ -98,13 +100,14 @@ func TestNativeToRecord_SRVNoDoubleDot(t *testing.T) { // TestNativeToRecord_CNAMENoDoubleDot: same trailing-dot guard for CNAME. func TestNativeToRecord_CNAMENoDoubleDot(t *testing.T) { + dc := models.MustNewDomainConfig("example.com") for _, content := range []string{"target.example.com", "target.example.com."} { record := makeNativeRecord("CNAME", "foo", content, 0, 300) - rc, err := nativeToRecord(record, "example.com") + rc, err := nativeToRecord(record, dc) if err != nil { t.Fatalf("unexpected error for content %q: %v", content, err) } - target := rc.GetTargetField() + target := rc.AsCNAME().Target if len(target) >= 2 && target[len(target)-1] == '.' && target[len(target)-2] == '.' { t.Errorf("double trailing dot in CNAME target for input %q: got %q", content, target) } @@ -113,6 +116,7 @@ func TestNativeToRecord_CNAMENoDoubleDot(t *testing.T) { // TestNativeToRecord_SkippedTypes: SOA, NS, and TXT ALIAS mirrors should return nil. func TestNativeToRecord_SkippedTypes(t *testing.T) { + dc := models.MustNewDomainConfig("example.com") skipped := []*egoscale.DNSDomainRecord{ makeNativeRecord("SOA", "@", "ns1.example.com", 0, 3600), makeNativeRecord("NS", "@", "ns1.example.com.", 0, 3600), @@ -120,7 +124,7 @@ func TestNativeToRecord_SkippedTypes(t *testing.T) { } for _, r := range skipped { - rc, err := nativeToRecord(r, "example.com") + rc, err := nativeToRecord(r, dc) if err != nil { t.Errorf("type %s: unexpected error: %v", r.Type, err) } @@ -132,11 +136,10 @@ func TestNativeToRecord_SkippedTypes(t *testing.T) { // TestAuditRecords_PTRRejected: API does not support PTR; provider must reject it. func TestAuditRecords_PTRRejected(t *testing.T) { - rc := &models.RecordConfig{Type: "PTR"} - rc.SetLabel("4", "example.com") - rc.MustSetTarget("foo.example.com.") + dc := models.MustNewDomainConfig("example.com") + rc := dc.MustNewRecordConfig("4", 300, "PTR", "foo.example.com.") - errs := AuditRecords([]*models.RecordConfig{rc}) + errs := AuditRecords(models.Records{rc}) if len(errs) == 0 { t.Error("expected PTR to be rejected, got no errors") } @@ -144,11 +147,10 @@ func TestAuditRecords_PTRRejected(t *testing.T) { // TestAuditRecords_EmptyTXTRejected: API rejects empty TXT values. func TestAuditRecords_EmptyTXTRejected(t *testing.T) { - rc := &models.RecordConfig{Type: "TXT"} - rc.SetLabel("foo", "example.com") - _ = rc.SetTargetTXT("") + dc := models.MustNewDomainConfig("example.com") + rc := dc.MustNewRecordConfig("foo", 300, "TXT", "") - errs := AuditRecords([]*models.RecordConfig{rc}) + errs := AuditRecords(models.Records{rc}) if len(errs) == 0 { t.Error("expected empty TXT to be rejected, got no errors") } @@ -156,17 +158,11 @@ func TestAuditRecords_EmptyTXTRejected(t *testing.T) { // TestAuditRecords_ValidRecordsPass: common record types should pass without errors. func TestAuditRecords_ValidRecordsPass(t *testing.T) { - var records []*models.RecordConfig - - a := &models.RecordConfig{Type: "A"} - a.SetLabel("foo", "example.com") - a.MustSetTarget("1.2.3.4") - records = append(records, a) - - txt := &models.RecordConfig{Type: "TXT"} - txt.SetLabel("foo", "example.com") - _ = txt.SetTargetTXT("v=spf1 -all") - records = append(records, txt) + dc := models.MustNewDomainConfig("example.com") + records := models.Records{ + dc.MustNewRecordConfig("foo", 300, "A", "1.2.3.4"), + dc.MustNewRecordConfig("foo", 300, "TXT", "v=spf1 -all"), + } errs := AuditRecords(records) if len(errs) != 0 { diff --git a/providers/fortigate/auditrecords.go b/providers/fortigate/auditrecords.go index 68b76cf129..9de4fcd061 100644 --- a/providers/fortigate/auditrecords.go +++ b/providers/fortigate/auditrecords.go @@ -4,21 +4,24 @@ import ( "fmt" "strings" - "github.com/DNSControl/dnscontrol/v4/models" + dnsv2 "codeberg.org/miekg/dns" + "github.com/DNSControl/dnscontrol/v5/models" ) // AuditRecords performs basic validation and returns warnings for known limitations. -func AuditRecords(records []*models.RecordConfig) []error { +func AuditRecords(records models.Records) []error { var problems []error for _, rc := range records { - switch rc.Type { - case "A", "AAAA", "CNAME", "NS", "MX": + switch rc.TypeNum { + case dnsv2.TypeA, dnsv2.TypeAAAA, // Supported - case "PTR": - // FortiGate limitations: these record types are not fully supported. - problems = append(problems, - fmt.Errorf("record type %s is not supported by FortiGate provider (name: %s)", rc.Type, rc.GetLabelFQDN())) + // case "PTR": + // // FortiGate limitations: these record types are not fully supported. + // problems = append(problems, + // fmt.Errorf("record type %s is not supported by FortiGate provider (name: %s)", rc.Type, rc.GetLabelFQDN())) + dnsv2.TypeCNAME: + default: problems = append(problems, fmt.Errorf("record type %s is not supported by FortiGate provider (name: %s)", rc.Type, rc.GetLabelFQDN())) @@ -30,28 +33,28 @@ func AuditRecords(records []*models.RecordConfig) []error { fmt.Errorf("CNAME at apex (@) is not allowed (name: %s)", rc.GetLabelFQDN())) } - //Handle NS Records limitations - if rc.Type == "NS" && rc.GetLabel() != "@" && rc.GetLabel() != "" { - problems = append(problems, - fmt.Errorf("NS records are only supported at the zone apex (@): %s", rc.GetLabelFQDN())) - } + // //Handle NS Records limitations + // if rc.Type == "NS" && rc.GetLabel() != "@" && rc.GetLabel() != "" { + // problems = append(problems, + // fmt.Errorf("NS records are only supported at the zone apex (@): %s", rc.GetLabelFQDN())) + // } - //Handle MX Records limitations - if rc.Type == "MX" { + // //Handle MX Records limitations + // if rc.Type == "MX" { - // MX only supported at zone apex - if rc.GetLabel() != "@" && rc.GetLabel() != "" { - problems = append(problems, - fmt.Errorf("MX records are only supported at the zone apex (@): %s", rc.GetLabelFQDN())) - } + // // MX only supported at zone apex + // if rc.GetLabel() != "@" && rc.GetLabel() != "" { + // problems = append(problems, + // fmt.Errorf("MX records are only supported at the zone apex (@): %s", rc.GetLabelFQDN())) + // } - // FortiGate does not accept "." as target (it's not a valid DNS name) - target := rc.GetTargetField() - if target == "." { - problems = append(problems, - fmt.Errorf("FortiGate does not accept '.' as an MX target: %s", rc.GetLabelFQDN())) - } - } + // // FortiGate does not accept "." as target (it's not a valid DNS name) + // target := rc.Get|TargetField() + // if target == "." { + // problems = append(problems, + // fmt.Errorf("FortiGate does not accept '.' as an MX target: %s", rc.GetLabelFQDN())) + // } + // } // Wildcard support if strings.Contains(rc.GetLabelFQDN(), "*") { diff --git a/providers/fortigate/converter.go b/providers/fortigate/converter.go index e208f6df66..843bc4a580 100644 --- a/providers/fortigate/converter.go +++ b/providers/fortigate/converter.go @@ -4,48 +4,36 @@ import ( "fmt" "strings" - "github.com/DNSControl/dnscontrol/v4/models" - "golang.org/x/net/idna" + "github.com/DNSControl/dnscontrol/v5/models" ) // nativeToRecord – convert an fgDNSRecord coming from FortiGate into a *models.RecordConfig that dnscontrol understands. -func nativeToRecord(domain string, n fgDNSRecord) (*models.RecordConfig, error) { - rc := &models.RecordConfig{} - rc.Type = strings.ToUpper(n.Type) - rc.Original = n - - // Label / Name - label := strings.TrimSuffix(n.Hostname, ".") - if label == "@" { - label = "" - } - rc.SetLabel(label, domain) - - // TTL - if n.TTL == 0 { - rc.TTL = 0 // inherit +func nativeToRecord(dc *models.DomainConfig, n fgDNSRecord) (*models.RecordConfig, error) { + rtype := strings.ToUpper(n.Type) + + var label string + hostname := n.Hostname + if hostname == "@" || hostname == "" { + label = "@" + } else if hostname[len(hostname)-1] == '.' { + label = dc.LabelFromFQDNWithDot(n.Hostname) } else { - rc.TTL = n.TTL - } - - // Status → Metadata - if strings.ToLower(n.Status) != "enable" { - if rc.Metadata == nil { - rc.Metadata = map[string]string{} - } - rc.Metadata["fortigate_status"] = "disable" + label = dc.LabelFromShort(n.Hostname) } + ttl := n.TTL // Type-specific fields - switch rc.Type { + var rc *models.RecordConfig + var err error + switch rtype { case "A": - err := rc.SetTarget(n.IP) + rc, err = dc.NewRecordConfig(label, ttl, rtype, n.IP) if err != nil { return nil, fmt.Errorf("[FORTIGATE] Invalid IPv4 address %q in %+v", n.IP, n) } case "AAAA": - err := rc.SetTarget(n.IPv6) + rc, err = dc.NewRecordConfig(label, ttl, rtype, n.IPv6) if err != nil { return nil, fmt.Errorf("[FORTIGATE] Invalid IPv6 address %q in %+v", n.IPv6, n) } @@ -54,35 +42,33 @@ func nativeToRecord(domain string, n fgDNSRecord) (*models.RecordConfig, error) if n.CanonicalName == "" { return nil, fmt.Errorf("[FORTIGATE] CNAME record without canonical-name (id=%d)", n.ID) } - if err := rc.SetTarget(n.CanonicalName); err != nil { - return nil, err - } + rc, err = dc.NewRecordConfig(label, ttl, rtype, n.CanonicalName) case "NS": if n.Hostname == "" { return nil, fmt.Errorf("[FORTIGATE] NS record missing hostname (id=%d)", n.ID) } - - rc.SetLabel("@", domain) - if err := rc.SetTarget(n.Hostname); err != nil { - return nil, err - } + rc, err = dc.NewRecordConfig("@", ttl, rtype, n.Hostname) case "MX": if n.Hostname == "" { return nil, fmt.Errorf("[FORTIGATE] MX record missing hostname (id=%d)", n.ID) } - - rc.SetLabel("@", domain) - rc.MxPreference = n.Preference - - if err := rc.SetTarget(n.Hostname); err != nil { - return nil, err - } + rc, err = dc.NewRecordConfig("@", ttl, rtype, n.Preference, n.Hostname) default: // Not supported due to FortiGate limitations - return nil, fmt.Errorf("[FORTIGATE] Record type %q is not supported by fortigate provider", rc.Type) + return nil, fmt.Errorf("[FORTIGATE] Record type %q is not supported by fortigate provider", rtype) + } + if err != nil { + return nil, err + } + + rc.Original = n + + // Status → Metadata + if strings.ToLower(n.Status) != "enable" { + rc.Metadata["fortigate_status"] = "disable" } return rc, nil @@ -143,27 +129,18 @@ func recordsToNative(recs models.Records) ([]*fgDNSRecord, []error) { n.IPv6 = ip.String() case "CNAME": - target := record.GetTargetField() - if ascii, err := idna.ToASCII(target); err == nil { - target = ascii - } + target := record.AsCNAME().String() n.CanonicalName = target case "NS": - target := record.GetTargetField() - if ascii, err := idna.ToASCII(target); err == nil { - target = ascii - } + target := record.AsNS().String() n.Hostname = target n.CanonicalName = "" case "MX": - target := record.GetTargetField() - if ascii, err := idna.ToASCII(target); err == nil { - target = ascii - } - n.Hostname = target - n.Preference = record.MxPreference + mx := record.AsMX() + n.Preference = mx.Preference + n.Hostname = mx.Mx n.CanonicalName = "" default: diff --git a/providers/fortigate/converter_test.go b/providers/fortigate/converter_test.go new file mode 100644 index 0000000000..212eadeb42 --- /dev/null +++ b/providers/fortigate/converter_test.go @@ -0,0 +1,83 @@ +package fortigate + +import ( + "testing" + + "github.com/DNSControl/dnscontrol/v5/models" +) + +func TestNativeToRecord(t *testing.T) { + dc, err := models.NewDomainConfig("example.com") + if err != nil { + t.Fatal(err) + } + tests := []struct { + name string + record fgDNSRecord + wantLabel string + wantTarget string + }{ + {"A", fgDNSRecord{Type: "A", Hostname: "www", IP: "192.0.2.1", TTL: 300, Status: "enable"}, "www", "192.0.2.1"}, + {"A", fgDNSRecord{Type: "A", Hostname: "@", IP: "192.0.2.1", TTL: 300, Status: "enable"}, "@", "192.0.2.1"}, + {"A", fgDNSRecord{Type: "A", Hostname: "example.com.", IP: "192.0.2.1", TTL: 300, Status: "enable"}, "@", "192.0.2.1"}, + {"CNAME", fgDNSRecord{Type: "CNAME", Hostname: "www", CanonicalName: "target.example.net.", TTL: 300, Status: "enable"}, "www", "target.example.net."}, + {"MX", fgDNSRecord{Type: "MX", Hostname: "mail.example.com.", Preference: 10, TTL: 300, Status: "disable"}, "@", "10 mail.example.com."}, + } + for _, tc := range tests { + t.Run(tc.name, func(t *testing.T) { + rc, err := nativeToRecord(dc, tc.record) + if err != nil { + t.Fatal(err) + } + if got := rc.GetRDATA().String(); got != tc.wantTarget { + t.Errorf("target = %q, want %q", got, tc.wantTarget) + } + if got := rc.GetLabel(); got != tc.wantLabel { + t.Errorf("label = %q, want %q", got, tc.wantLabel) + } + }) + } +} + +func TestNativeToRecord_Gen(t *testing.T) { + dc, err := models.NewDomainConfig("example.com") + if err != nil { + t.Fatal(err) + } + tests := []struct { + name string + record fgDNSRecord + wantTarget string + }{ + // These were taken from the API directly while running integration tests. + {"a1", fgDNSRecord{ID: 1, Status: "enable", Type: "A", TTL: 300, Preference: 10, IP: "1.1.1.1", IPv6: "::", Hostname: "foo"}, "1.1.1.1"}, + {"a2", fgDNSRecord{ID: 2, Status: "enable", Type: "A", TTL: 300, Preference: 10, IP: "12.12.12.12", IPv6: "::", Hostname: "foo"}, "12.12.12.12"}, + {"a3", fgDNSRecord{ID: 3, Status: "enable", Type: "AAAA", TTL: 300, Preference: 10, IP: "0.0.0.0", IPv6: "2003:dd:d7ff::fe71:aaaa", Hostname: "foo"}, "2003:dd:d7ff::fe71:aaaa"}, + {"a4", fgDNSRecord{ID: 4, Status: "enable", Type: "A", TTL: 300, Preference: 10, IP: "3.3.3.3", IPv6: "::", Hostname: "zzz"}, "3.3.3.3"}, + {"a5", fgDNSRecord{ID: 5, Status: "enable", Type: "A", TTL: 300, Preference: 10, IP: "4.4.4.4", IPv6: "::", Hostname: "zzz"}, "4.4.4.4"}, + {"a6", fgDNSRecord{ID: 6, Status: "enable", Type: "AAAA", TTL: 300, Preference: 10, IP: "0.0.0.0", IPv6: "2003:dd:d7ff::fe71:cccc", Hostname: "zzz"}, "2003:dd:d7ff::fe71:cccc"}, + {"b1", fgDNSRecord{ID: 1, Status: "enable", Type: "A", TTL: 300, Preference: 10, IP: "1.1.1.1", IPv6: "::", Hostname: "foo"}, "1.1.1.1"}, + {"b2", fgDNSRecord{ID: 2, Status: "enable", Type: "A", TTL: 300, Preference: 10, IP: "12.12.12.12", IPv6: "::", Hostname: "foo"}, "12.12.12.12"}, + {"b3", fgDNSRecord{ID: 3, Status: "enable", Type: "AAAA", TTL: 300, Preference: 10, IP: "0.0.0.0", IPv6: "2003:dd:d7ff::fe71:aaaa", Hostname: "foo"}, "2003:dd:d7ff::fe71:aaaa"}, + {"b4", fgDNSRecord{ID: 4, Status: "enable", Type: "A", TTL: 300, Preference: 10, IP: "3.3.3.3", IPv6: "::", Hostname: "zzz"}, "3.3.3.3"}, + {"b5", fgDNSRecord{ID: 5, Status: "enable", Type: "A", TTL: 300, Preference: 10, IP: "4.4.4.4", IPv6: "::", Hostname: "zzz"}, "4.4.4.4"}, + {"b6", fgDNSRecord{ID: 6, Status: "enable", Type: "AAAA", TTL: 300, Preference: 10, IP: "0.0.0.0", IPv6: "2003:dd:d7ff::fe71:cccc", Hostname: "zzz"}, "2003:dd:d7ff::fe71:cccc"}, + {"c1", fgDNSRecord{ID: 1, Status: "enable", Type: "A", TTL: 300, Preference: 10, IP: "1.1.1.1", IPv6: "::", Hostname: "foo"}, "1.1.1.1"}, + {"c2", fgDNSRecord{ID: 2, Status: "enable", Type: "A", TTL: 300, Preference: 10, IP: "13.13.13.13", IPv6: "::", Hostname: "foo"}, "13.13.13.13"}, + {"c3", fgDNSRecord{ID: 3, Status: "enable", Type: "A", TTL: 300, Preference: 10, IP: "3.3.3.3", IPv6: "2003:dd:d7ff::fe71:aaaa", Hostname: "zzz"}, "3.3.3.3"}, + {"c4", fgDNSRecord{ID: 4, Status: "enable", Type: "A", TTL: 300, Preference: 10, IP: "4.4.4.4", IPv6: "::", Hostname: "zzz"}, "4.4.4.4"}, + {"c5", fgDNSRecord{ID: 5, Status: "enable", Type: "AAAA", TTL: 300, Preference: 10, IP: "4.4.4.4", IPv6: "2003:dd:d7ff::fe71:cccc", Hostname: "zzz"}, "2003:dd:d7ff::fe71:cccc"}, + {"c6", fgDNSRecord{ID: 6, Status: "enable", Type: "AAAA", TTL: 300, Preference: 10, IP: "0.0.0.0", IPv6: "2003:dd:d7ff::fe71:aaaa", Hostname: "foo"}, "2003:dd:d7ff::fe71:aaaa"}, + } + for _, tc := range tests { + t.Run(tc.name, func(t *testing.T) { + rc, err := nativeToRecord(dc, tc.record) + if err != nil { + t.Fatal(err) + } + if got := rc.GetRDATA().String(); got != tc.wantTarget { + t.Errorf("target = %q, want %q", got, tc.wantTarget) + } + }) + } +} diff --git a/providers/fortigate/fortigateProvider.go b/providers/fortigate/fortigateProvider.go index 3c00e44425..af5ea199f1 100644 --- a/providers/fortigate/fortigateProvider.go +++ b/providers/fortigate/fortigateProvider.go @@ -7,9 +7,9 @@ import ( "net/netip" "strings" - "github.com/DNSControl/dnscontrol/v4/models" - "github.com/DNSControl/dnscontrol/v4/pkg/diff2" - "github.com/DNSControl/dnscontrol/v4/pkg/providers" + "github.com/DNSControl/dnscontrol/v5/models" + "github.com/DNSControl/dnscontrol/v5/pkg/diff2" + "github.com/DNSControl/dnscontrol/v5/pkg/providers" ) // Feature Declaration @@ -146,7 +146,7 @@ func (p *fortigateProvider) GetZoneRecords(dc *models.DomainConfig) (models.Reco // Convert native records to dnscontrol Records for _, n := range resp.Results[0].DNSEntry { - rc, err := nativeToRecord(domain, n) + rc, err := nativeToRecord(dc, n) if err != nil { return nil, err } diff --git a/providers/gandiv5/auditrecords.go b/providers/gandiv5/auditrecords.go index 2f8deacc9f..638abb4bd9 100644 --- a/providers/gandiv5/auditrecords.go +++ b/providers/gandiv5/auditrecords.go @@ -1,12 +1,12 @@ package gandiv5 import ( - "github.com/DNSControl/dnscontrol/v4/models" + "github.com/DNSControl/dnscontrol/v5/models" ) // AuditRecords returns a list of errors corresponding to the records // that aren't supported by this provider. If all records are // supported, an empty list is returned. -func AuditRecords(records []*models.RecordConfig) []error { +func AuditRecords(records models.Records) []error { return nil } diff --git a/providers/gandiv5/convert.go b/providers/gandiv5/convert.go index 6b737a746f..0b1da3a0ba 100644 --- a/providers/gandiv5/convert.go +++ b/providers/gandiv5/convert.go @@ -5,63 +5,34 @@ package gandiv5 import ( "fmt" - "github.com/DNSControl/dnscontrol/v4/models" - "github.com/DNSControl/dnscontrol/v4/pkg/domaintags" - "github.com/DNSControl/dnscontrol/v4/pkg/printer" - "github.com/DNSControl/dnscontrol/v4/pkg/rtypecontrol" - "github.com/DNSControl/dnscontrol/v4/pkg/rtypeinfo" - "github.com/DNSControl/dnscontrol/v4/pkg/txtutil" + "github.com/DNSControl/dnscontrol/v5/models" + "github.com/DNSControl/dnscontrol/v5/pkg/printer" "github.com/go-gandi/go-gandi/livedns" ) // nativeToRecord takes a DNS record from Gandi and returns a native RecordConfig struct. -func nativeToRecords(n livedns.DomainRecord, origin string) (rcs []*models.RecordConfig, err error) { +func nativeToRecords(dc *models.DomainConfig, n livedns.DomainRecord) (rcs models.Records, err error) { // Gandi returns all the values for a given label/rtype pair in each // livedns.DomainRecord. In other words, if there are multiple A // records for a label, all the IP addresses are listed in // n.RrsetValues rather than having many livedns.DomainRecord's. // We must split them out into individual records, one for each value. - dcn := domaintags.MakeDomainNameVarieties(origin) - for _, value := range n.RrsetValues { - var rc *models.RecordConfig - var err error - - rtype := n.RrsetType + rc, err := dc.NewRecordConfigParse(dc.LabelFromShort(n.RrsetName), uint32(n.RrsetTTL), n.RrsetType, value) + if err != nil { + return nil, fmt.Errorf("unparsable record received from gandi (%s): %w", n.RrsetType, err) + } - if rtypeinfo.IsModernType(rtype) { - rc, err = rtypecontrol.NewRecordConfigFromString(n.RrsetName, uint32(n.RrsetTTL), rtype, value, dcn) - if err != nil { - return nil, fmt.Errorf("unparsable record received from gandi: %w", err) - } - rc.Original = n - } else { - rc = &models.RecordConfig{ - TTL: uint32(n.RrsetTTL), - Original: n, - } - rc.SetLabel(n.RrsetName, origin) + rc.Original = n - switch rtype := n.RrsetType; rtype { - case "ALIAS": - rc.Type = "ALIAS" - err = rc.SetTarget(value) - default: - err = rc.PopulateFromStringFunc(rtype, value, origin, txtutil.ParseQuoted) - } - if err != nil { - return nil, fmt.Errorf("unparsable record received from gandi: %w", err) - } - } rcs = append(rcs, rc) - } return rcs, nil } -func recordsToNative(rcs []*models.RecordConfig, origin string) []livedns.DomainRecord { +func recordsToNative(rcs models.Records, origin string) []livedns.DomainRecord { // Take a list of RecordConfig and return an equivalent list of ZoneRecords. // Gandi requires one ZoneRecord for each label:key tuple, therefore we // might collapse many RecordConfig into one ZoneRecord. @@ -82,11 +53,11 @@ func recordsToNative(rcs []*models.RecordConfig, origin string) []livedns.Domain RrsetType: r.Type, RrsetTTL: int(r.TTL), RrsetName: label, - RrsetValues: []string{r.GetTargetCombinedFunc(txtutil.EncodeQuoted)}, + RrsetValues: []string{r.GetRDATA().String()}, } keys[key] = &zr } else { - zr.RrsetValues = append(zr.RrsetValues, r.GetTargetCombinedFunc(txtutil.EncodeQuoted)) + zr.RrsetValues = append(zr.RrsetValues, r.GetRDATA().String()) 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/convert_golden_test.go b/providers/gandiv5/convert_golden_test.go new file mode 100644 index 0000000000..216f3dc3ac --- /dev/null +++ b/providers/gandiv5/convert_golden_test.go @@ -0,0 +1,11 @@ +package gandiv5 + +import ( + "testing" + + "github.com/DNSControl/dnscontrol/v5/pkg/providergolden" +) + +func TestNativeToRecordsGolden(t *testing.T) { + providergolden.CheckToRC(t, "nativeToRecords", nativeToRecords) +} diff --git a/providers/gandiv5/convert_test.go b/providers/gandiv5/convert_test.go index 0c6c7f0d71..f694895295 100644 --- a/providers/gandiv5/convert_test.go +++ b/providers/gandiv5/convert_test.go @@ -3,16 +3,15 @@ package gandiv5 import ( "testing" - "github.com/DNSControl/dnscontrol/v4/models" + dnsv2 "codeberg.org/miekg/dns" + "github.com/DNSControl/dnscontrol/v5/models" ) func TestRecordsToNative_1(t *testing.T) { - rcs := []*models.RecordConfig{{}} - rcs[0].SetLabelFromFQDN("foo.example.com", "example.com") - rcs[0].Type = "A" - rcs[0].MustSetTarget("1.2.3.4") + dc := models.MustNewDomainConfig("example.com") + dc.AddTestRC(t, dc.LabelFromShort("foo"), 0, dnsv2.TypeA, "1.2.3.4") - ns := recordsToNative(rcs, "example.com") + ns := recordsToNative(dc.Records, "example.com") if len(ns) != 1 { t.Errorf("len(ns) != 1; got=%v", len(ns)) @@ -23,15 +22,11 @@ func TestRecordsToNative_1(t *testing.T) { } func TestRecordsToNative_2(t *testing.T) { - rcs := []*models.RecordConfig{{}, {}} - rcs[0].SetLabelFromFQDN("foo.example.com", "example.com") - rcs[0].Type = "A" - rcs[0].MustSetTarget("1.2.3.4") - rcs[1].SetLabelFromFQDN("foo.example.com", "example.com") - rcs[1].Type = "A" - rcs[1].MustSetTarget("5.6.7.8") + dc := models.MustNewDomainConfig("example.com") + dc.AddTestRC(t, dc.LabelFromShort("foo"), 0, dnsv2.TypeA, "1.2.3.4") + dc.AddTestRC(t, dc.LabelFromShort("foo"), 0, dnsv2.TypeA, "5.6.7.8") - ns := recordsToNative(rcs, "example.com") + ns := recordsToNative(dc.Records, "example.com") if len(ns) != 1 { t.Errorf("len(ns) != 1; got=%v", len(ns)) @@ -40,3 +35,23 @@ func TestRecordsToNative_2(t *testing.T) { t.Errorf("len(ns[0].RrsetValues) != 2; got=%v", ns[0].RrsetValues) } } + +func TestTXTRecordRoundTripUsesV3RDATA(t *testing.T) { + dc := models.MustNewDomainConfig("example.com") + want := dc.MustNewRecordConfig("txt", 300, dnsv2.TypeTXT, `hello "gandi" \\ world`) + + native := recordsToNative(models.Records{want}, dc.Name) + if len(native) != 1 || len(native[0].RrsetValues) != 1 { + t.Fatalf("recordsToNative() returned %#v", native) + } + got, err := nativeToRecords(dc, native[0]) + if err != nil { + t.Fatal(err) + } + if len(got) != 1 { + t.Fatalf("nativeToRecords() returned %d records, want 1", len(got)) + } + if got[0].GetRDATA().String() != want.GetRDATA().String() { + t.Errorf("TXT round trip = %q, want %q", got[0].GetRDATA(), want.GetRDATA()) + } +} diff --git a/providers/gandiv5/gandiv5Provider.go b/providers/gandiv5/gandiv5Provider.go index ad4d1c7070..5a2d9fc19b 100644 --- a/providers/gandiv5/gandiv5Provider.go +++ b/providers/gandiv5/gandiv5Provider.go @@ -23,14 +23,14 @@ import ( "strings" "time" - "github.com/DNSControl/dnscontrol/v4/models" - "github.com/DNSControl/dnscontrol/v4/pkg/diff2" - "github.com/DNSControl/dnscontrol/v4/pkg/printer" - "github.com/DNSControl/dnscontrol/v4/pkg/providers" + dnsv2 "codeberg.org/miekg/dns" + "github.com/DNSControl/dnscontrol/v5/models" + "github.com/DNSControl/dnscontrol/v5/pkg/diff2" + "github.com/DNSControl/dnscontrol/v5/pkg/printer" + "github.com/DNSControl/dnscontrol/v5/pkg/providers" "github.com/go-gandi/go-gandi" "github.com/go-gandi/go-gandi/config" "github.com/go-gandi/go-gandi/livedns" - dnsutilv1 "github.com/miekg/dns/dnsutil" ) // Section 1: Register this provider in the system. @@ -112,6 +112,7 @@ var features = providers.DocumentationNotes{ // gandiv5Provider is the gandiv5Provider handle used to store any client-related state. type gandiv5Provider struct { + observer providers.ConversionObserver apikey string token string sharingid string @@ -119,6 +120,10 @@ type gandiv5Provider struct { apiurl string } +func (client *gandiv5Provider) SetConversionObserver(observer providers.ConversionObserver) { + client.observer = observer +} + // newDsp generates a DNS Service Provider client handle. func newDsp(conf map[string]string, metadata json.RawMessage) (providers.DNSServiceProvider, error) { return newHelper(conf, metadata) @@ -193,9 +198,11 @@ func (client *gandiv5Provider) GetZoneRecords(dc *models.DomainConfig) (models.R } // Convert them to DNScontrol's native format: - existingRecords := []*models.RecordConfig{} + var existingRecords models.Records for _, rr := range records { - rrs, err := nativeToRecords(rr, domain) + before := providers.BeginToRC(client.observer, "nativeToRecords", rr) + rrs, err := nativeToRecords(dc, rr) + providers.EndToRC(client.observer, "nativeToRecords", before, rr, rrs, err) if err != nil { return nil, err } @@ -212,12 +219,17 @@ func PrepDesiredRecords(dc *models.DomainConfig) { // provider. We try to do minimal changes otherwise it gets // confusing. - recordsToKeep := make([]*models.RecordConfig, 0, len(dc.Records)) + recordsToKeep := make(models.Records, 0, len(dc.Records)) + var err error for _, rec := range dc.Records { if rec.Type == "ALIAS" && rec.Name != "@" { // GANDI only permits aliases on a naked domain. // Therefore, we change this to a CNAME. - rec.ChangeType("CNAME", dc.Name) + + rec, err = dc.NewRecordConfig(dc.LabelFromShort(rec.Name), rec.TTL, dnsv2.TypeCNAME, rec.AsALIAS().Target) + if err != nil { + panic("should not happen PrepDesiredRecords") + } } if rec.TTL < 300 { printer.Warnf("Gandi does not support ttls < 300. Setting %s from %d to 300\n", rec.GetLabelFQDN(), rec.TTL) @@ -228,8 +240,8 @@ func PrepDesiredRecords(dc *models.DomainConfig) { rec.TTL = 2592000 } 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()) + if !strings.HasSuffix(rec.AsNS().Ns, ".gandi.net.") { + printer.Warnf("Gandi does not support changing apex NS records. Ignoring %s\n", rec.AsNS().Ns) } continue } @@ -269,7 +281,7 @@ func (client *gandiv5Provider) GetZoneRecordsCorrections(dc *models.DomainConfig label := inst.Key.NameFQDN rtype := n.RrsetType domain := dc.Name - shortname := dnsutilv1.TrimDomainName(label, dc.Name) + shortname := dc.ToShort(label) ttl := n.RrsetTTL values := n.RrsetValues key := models.RecordKey{NameFQDN: label, Type: rtype} @@ -320,7 +332,7 @@ func (client *gandiv5Provider) GetZoneRecordsCorrections(dc *models.DomainConfig msgs := strings.Join(inst.Msgs, "\n") domain := dc.Name label := inst.Key.NameFQDN - shortname := dnsutilv1.TrimDomainName(label, dc.Name) + shortname := dc.ToShort(label) corrections = append(corrections, &models.Correction{ Msg: msgs, @@ -342,10 +354,10 @@ func (client *gandiv5Provider) GetZoneRecordsCorrections(dc *models.DomainConfig } // debugRecords prints a list of RecordConfig. -func debugRecords(note string, recs []*models.RecordConfig) { +func debugRecords(note string, recs models.Records) { printer.Debugf("%s", note) for k, v := range recs { - printer.Printf(" %v: %v %v %v %v\n", k, v.GetLabel(), v.Type, v.TTL, v.GetTargetDebug()) + printer.Printf(" %v: %s %s %d %s\n", k, v.GetLabel(), v.Type, v.TTL, v.GetRDATA().String()) } } diff --git a/providers/gandiv5/test_data/expected_torc_output_nativeToRecords_tomontime.com.records b/providers/gandiv5/test_data/expected_torc_output_nativeToRecords_tomontime.com.records new file mode 100644 index 0000000000..fe645c97cb --- /dev/null +++ b/providers/gandiv5/test_data/expected_torc_output_nativeToRecords_tomontime.com.records @@ -0,0 +1,231 @@ +1 @ 1000 IN A 8.8.8.8 +2 * 300 IN A 3.3.3.3 +3 @ 300 IN A 1.2.3.2 +4 @ 300 IN A 1.2.3.4 +4 @ 300 IN A 2.3.4.5 +5 @ 300 IN A 1.2.3.4 +6 @ 300 IN A 2.2.2.2 +7 @ 300 IN A 4.4.4.4 +8 bar 300 IN A 1.2.3.4 +9 bar 300 IN A 5.5.5.5 +10 bar.bat 300 IN A 5.5.5.5 +11 decoy 300 IN A 1.1.1.1 +12 decoy 300 IN A 2.2.2.2 +13 decoy 300 IN A 3.3.3.3 +14 dyndns-city1 300 IN A 91.42.1.1 +15 dyndns-city2 300 IN A 91.42.1.2 +16 foo 300 IN A 1.1.1.1 +16 foo 300 IN A 10.10.10.10 +17 foo 300 IN A 1.1.1.1 +17 foo 300 IN A 11.11.11.11 +18 foo 300 IN A 1.1.1.1 +18 foo 300 IN A 12.12.12.12 +19 foo 300 IN A 1.1.1.1 +19 foo 300 IN A 13.13.13.13 +20 foo 300 IN A 1.1.1.1 +20 foo 300 IN A 14.14.14.14 +21 foo 300 IN A 1.2.3.4 +21 foo 300 IN A 2.3.4.5 +22 foo 300 IN A 1.2.3.4 +22 foo 300 IN A 3.4.5.6 +23 foo 300 IN A 1.2.3.4 +24 foo 300 IN A 2.3.4.5 +24 foo 300 IN A 3.4.5.6 +25 foo 300 IN A 2.3.4.5 +25 foo 300 IN A 8.8.8.8 +26 foo 300 IN A 2.3.4.5 +27 foo 300 IN A 4.5.6.7 +28 foo.bat 300 IN A 1.2.3.4 +28 foo.bat 300 IN A 2.3.4.5 +29 nmx 300 IN A 1.2.3.3 +30 testa 300 IN A 1.1.1.1 +31 testa 300 IN A 3.3.3.3 +32 testdefined 300 IN A 2.2.2.2 +33 testdefined 300 IN A 9.9.9.9 +34 testignore 300 IN A 8.8.8.8 +35 www 300 IN A 1.1.1.1 +35 www 300 IN A 2.2.2.2 +35 www 300 IN A 3.3.3.3 +36 www 300 IN A 1.1.1.1 +36 www 300 IN A 2.2.2.2 +37 www 300 IN A 1.1.1.1 +38 www 300 IN A 1.2.3.4 +38 www 300 IN A 5.6.7.8 +39 www 300 IN A 1.2.3.8 +40 www 300 IN A 1.2.3.9 +41 www 300 IN A 2.2.2.2 +41 www 300 IN A 5.6.7.8 +42 www 300 IN A 5.5.5.5 +43 xn--fiq228c 300 IN A 1.2.3.4 +44 xn--ndaaa 300 IN A 1.2.3.4 +45 xn--ndaaa 300 IN A 2.2.2.2 +46 zzz 300 IN A 3.3.3.3 +46 zzz 300 IN A 4.4.4.4 +47 testa 333 IN A 1.1.1.1 +48 www 400 IN A 2.2.2.2 +48 www 400 IN A 5.6.7.8 +49 www 400 IN A 5.6.7.8 +50 @ 500 IN A 8.8.8.8 +51 @ 666 IN A 8.8.8.8 +52 www 700 IN A 1.2.3.4 +52 www 700 IN A 5.6.7.8 +53 testa 999 IN A 1.1.1.1 +54 dyndns-city1 300 IN AAAA 2003:dd:d7ff::fe71:ce77 +55 dyndns-city2 300 IN AAAA 2003:dd:d7ff::fe71:ce78 +56 foo 300 IN AAAA 2003:dd:d7ff::fe71:aaaa +57 testaaaa 300 IN AAAA 2607:f8b0:4006:820::2006 +58 testaaaa 300 IN AAAA 2607:f8b0:4006:820::2013 +59 zzz 300 IN AAAA 2003:dd:d7ff::fe71:cccc +60 @ 300 IN ALIAS foo.com. +61 @ 300 IN ALIAS foo.tomontime.com. +62 @ 300 IN ALIAS foo2.com. +63 @ 300 IN CAA 0 issue "letsencrypt.org; validationmethods=dns-01; accounturi=https://acme-v02.api.letsencrypt.org/acme/acct/1234" +64 @ 300 IN CAA 0 issue "letsencrypt.org" +65 @ 300 IN CAA 0 issuewild ";" +66 @ 300 IN CAA 0 issuewild "example.com" +67 @ 300 IN CAA 0 issuewild "letsencrypt.org" +68 @ 300 IN CAA 128 issue "letsencrypt.org" +69 a 300 IN CNAME xn--ndaaa.com. +70 bar 300 IN CNAME redact2.acm-validations.aws. +71 foo 300 IN CNAME google.com. +72 foo 300 IN CNAME google2.com. +73 foo 300 IN CNAME redact1.acm-validations.aws. +74 foo 300 IN CNAME tomontime.com. +75 mail 300 IN CNAME ghs.googlehosted.com. +76 mail.bat 300 IN CNAME ghs.googlehosted.com. +77 test 300 IN CNAME foo.com. +78 test 300 IN CNAME foo2.com. +79 testcname 300 IN CNAME foo.tomontime.com. +80 testcname 300 IN CNAME www.google.com. +81 testcname 300 IN CNAME www.yahoo.com. +82 xn--o-0gab 300 IN CNAME xn--ndaaa.xn--vhquv. +83 another-child 300 IN DS 44 13 2 4B9B6B073EDD97FEB5BC12DC4E1B32D2C6AF7AE23A293936CEB87BB10494EC44 +83 another-child 300 IN DS 1501 14 4 109BB6B5B6D5547C1CE03C7A8BD7D8F80C1CB0957F50C4F7FDA04692079917E4F9CAD52B878F3D8234E1A170B154B72D +83 another-child 300 IN DS 1502 8 2 2FA14F53E6B15CAC9AC77846C7BE87862C2A7E9EC0C6CEA319DB939317F126ED +83 another-child 300 IN DS 65535 13 2 2FA14F53E6B15CAC9AC77846C7BE87862C2A7E9EC0C6CEA319DB939317F126ED +84 another-child 300 IN DS 44 13 2 4B9B6B073EDD97FEB5BC12DC4E1B32D2C6AF7AE23A293936CEB87BB10494EC44 +85 child 300 IN DS 1 14 4 417212FD1C8BC5896FEFD8DB58AF824545E85B0D0546409366A30AEF7269FAE258173BD185FB262C86F3BB86FBA04368 +86 child 300 IN DS 3 13 2 4B9B6B073EDD97FEB5BC12DC4E1B32D2C6AF7AE23A293936CEB87BB10494EC44 +87 child 300 IN DS 3 14 4 3115238F89E0BF5252D9718113B1B9FFF854608D84BE94EEFB9210DC1CC0B4F3557342A27465CFACC42EF137AE9A5489 +88 child 300 IN DS 3 8 2 4B9B6B073EDD97FEB5BC12DC4E1B32D2C6AF7AE23A293936CEB87BB10494EC44 +89 child 300 IN DS 8857 8 2 4B9B6B073EDD97FEB5BC12DC4E1B32D2C6AF7AE23A293936CEB87BB10494EC44 +90 @ 300 IN HTTPS 0 test.com. +91 @ 300 IN HTTPS 1 test.com. alpn="h2" port="99" +92 @ 300 IN HTTPS 1 test.com. port="80" +93 @ 300 IN HTTPS 1 test.com. port="99" +94 @ 300 IN HTTPS 3 example.com. alpn="h2,h3" port="999" ech="some+base64+encoded+value///" +95 @ 300 IN HTTPS 3 example.com. alpn="h2,h3" port="999" +96 @ 300 IN HTTPS 3 example.com. alpn="h2" port="80" ech="another+base64+encoded+value" +97 @ 300 IN HTTPS 3 example.com. alpn="h2" port="80" ech="some+base64+encoded+value///" +98 @ 300 IN HTTPS 3 yetanother.com. alpn="h2" port="80" ech="another+base64+encoded+value" +99 @ 300 IN LOC 42 21 54.000 N 71 06 18.000 W -24.05m 30m 0.00m 0.00m +100 @ 300 IN LOC 42 21 54.000 N 71 06 18.000 W -24.06m 30m 10m 0.00m +101 @ 300 IN LOC 42 21 54.000 N 71 06 18.000 W -24m 30m 0.00m 0.00m +102 a 300 IN LOC 42 21 43.950 N 71 05 6.340 W -24.33m 1m 200m 10m +103 b 300 IN LOC 52 14 5.000 N 00 08 50.000 E 10.22m 0.00m 0.00m 0.00m +104 c 300 IN LOC 32 07 19.000 S 116 02 25.000 E 10m 0.00m 0.00m 0.00m +105 d 300 IN LOC 42 21 28.760 N 71 00 51.620 W -44m 2000m 0.00m 0.00m +106 @ 300 IN MX 0 . +107 @ 300 IN MX 2 tomontime.com. +107 @ 300 IN MX 8 www.tomontime.com. +108 @ 300 IN MX 5 bar.com. +109 @ 300 IN MX 5 foo.com. +110 bar 300 IN MX 5 bar.com. +111 foo 300 IN MX 10 aspmx.l.google.com. +111 foo 300 IN MX 20 alt1.aspmx.l.google.com. +112 foo 300 IN MX 10 foo.tomontime.com. +112 foo 300 IN MX 20 bar.tomontime.com. +113 foo 300 IN MX 5 mx.google.com. +114 foo 300 IN MX 8 tomontime.com. +115 nmx 300 IN MX 0 . +116 nmx 300 IN MX 3 nmx.tomontime.com. +116 nmx 300 IN MX 9 www.tomontime.com. +117 testmx 300 IN MX 100 foo.com. +118 testmx 300 IN MX 5 bar.com. +119 testmx 300 IN MX 5 foo.com. +119 testmx 300 IN MX 100 bar.com. +120 testmx 300 IN MX 5 foo.com. +121 foo 300 IN NS tomontime.com. +122 xyz 300 IN NS ns1.foo.com. +122 xyz 300 IN NS ns2.foo.com. +123 xyz 300 IN NS ns2.foo.com. +124 6c9b19cb967b563d9d96b341ad4a89a74444c6f18e9530f4623817fe._openpgpkey 300 IN OPENPGPKEY mDMEAAAAARYJKwYBBAHaRw8BAQdAQWiJ4gXP6wC2wQ7h7odcLpZU+mQD2rHiqtTgj+1e6ou0JEV4YW1wbGUgMiA8ZXhhbXBsZS0yQGRuc2NvbnRyb2wub3JnPoh+BBMWCgAmFiEE/tuN1tP/jpKko/EvTN4yJT7efAsFAgAAAAECGwECHgUCF4AACgkQTN4yJT7efAuxPQD/aEhrJaCX9FD1IkjA/8UmK0nokjtJNy46It3IWTGT4EQBAJI6goeRQBJqu/UnHmjv0OfqBQQCt87f9zXqZxLjiIQN +125 6c9b19cb967b563d9d96b341ad4a89a74444c6f18e9530f4623817fe._openpgpkey 300 IN OPENPGPKEY mDMEAAAAARYJKwYBBAHaRw8BAQdAxCQnAKBDmA75+73+3lYVXDwrMUbaR61fNZgGeOHwmDq0JEV4YW1wbGUgMiA8ZXhhbXBsZS0yQGRuc2NvbnRyb2wub3JnPoh+BBMWCgAmFiEEYZ3PIZnaOWQrPxj6VX+9VdC3r4wFAgAAAAECGwECHgUCF4AACgkQVX+9VdC3r4xq6wEAl2ujFSqWwc2wQuHedpFrSTN9Gh7cIziKCZ3f8BGSRTgBAIvjKlWLLLBu0FPpCVlcfkpsZMV5YRrg90k+D+O4zZ4M +126 bb7d0cf1ee44aca0bcc0f739b77b935f13aec2fd537f5c29dedd883d._openpgpkey 300 IN OPENPGPKEY mDMEAAAAARYJKwYBBAHaRw8BAQdAFHHsHVzE1rvYcCmX7Sn5X3p71eF5qo02mO/IuULrCPW0JEV4YW1wbGUgMSA8ZXhhbXBsZS0xQGRuc2NvbnRyb2wub3JnPoh+BBMWCgAmFiEEkwXxX/eDCW05Qn5tBI42Nn4+OuIFAgAAAAECGwECHgUCF4AACgkQBI42Nn4+OuL/qgD/S2rZm2Lafp11mr5q4jIBZ4DCS/Xl+Gm4ADvoPGpzkzwBALZqxlCToP4KQ0RI2ZlqtGQSy+fHDVxat0q7pFZsRo0K +127 bb7d0cf1ee44aca0bcc0f739b77b935f13aec2fd537f5c29dedd883d._openpgpkey 300 IN OPENPGPKEY mDMEAAAAARYJKwYBBAHaRw8BAQdAO2uf8a0MUkNWUHzey8FhYJP2SS+061pF+GFK23egV9K0JEV4YW1wbGUgMSA8ZXhhbXBsZS0xQGRuc2NvbnRyb2wub3JnPoh+BBMWCgAmFiEEwP53wg/jSbhjzamYC/4c89luNM4FAgAAAAECGwECHgUCF4AACgkQC/4c89luNM4/LgEA8ARj4iJ0fVrpRRnhrTtlGwos170TDhTuZfPoGMqweS0A/1GWtg6/ywR4EPtRu+p9WogsQmO1HOk3ag3I5d7iP18C +128 4 300 IN PTR bar.com. +129 4 300 IN PTR foo.com. +130 foo 300 IN RP other.example.com. bar.com. +131 foo 300 IN RP other.example.com. example.com. +132 foo 300 IN RP user.example.com. bar.com. +133 foo 300 IN RP user.tomontime.com. server.tomontime.com. +134 foo 300 IN RP user2.tomontime.com. server.tomontime.com. +135 foo 300 IN RP user2.tomontime.com. waiter.tomontime.com. +136 _sip._tcp 300 IN SRV 15 65 75 . +137 _sip._tcp 300 IN SRV 15 65 75 foo4.com. +137 _sip._tcp 300 IN SRV 52 6 7 foo.com. +138 _sip._tcp 300 IN SRV 15 65 75 foo4.com. +138 _sip._tcp 300 IN SRV 52 62 7 foo.com. +139 _sip._tcp 300 IN SRV 15 65 75 foo4.com. +139 _sip._tcp 300 IN SRV 52 62 72 foo.com. +140 _sip._tcp 300 IN SRV 5 6 7 foo.com. +140 _sip._tcp 300 IN SRV 15 65 75 foo3.com. +141 _sip._tcp 300 IN SRV 5 6 7 foo.com. +141 _sip._tcp 300 IN SRV 15 65 75 foo4.com. +142 _sip._tcp 300 IN SRV 5 6 7 foo.com. +142 _sip._tcp 300 IN SRV 5 60 70 foo2.com. +142 _sip._tcp 300 IN SRV 15 65 75 foo3.com. +143 _sip._tcp 300 IN SRV 5 6 7 foo.com. +143 _sip._tcp 300 IN SRV 5 60 70 foo2.com. +144 _sip._tcp 300 IN SRV 5 6 7 foo.com. +145 _sip._tcp 333 IN SRV 5 6 7 foo.com. +146 _sip._tcp 4400 IN SRV 5 6 7 foo.com. +147 @ 300 IN SSHFP 1 1 66C7D5540B7D75A1FB4C84FEBFA178AD99BDD67C +148 @ 300 IN SSHFP 2 1 66C7D5540B7D75A1FB4C84FEBFA178AD99BDD67C +149 @ 300 IN SSHFP 2 2 745A635BC46A397A5C4F21D437483005BCC40D7511FF15FBFAFE913A081559BC +150 @ 300 IN SVCB 0 test.com. +151 @ 300 IN SVCB 1 test.com. alpn="h2" port="99" +152 @ 300 IN SVCB 1 test.com. port="80" +153 @ 300 IN SVCB 1 test.com. port="99" +154 @ 300 IN SVCB 3 example.com. alpn="h2,h3" port="999" ech="some+base64+encoded+value///" +155 @ 300 IN SVCB 3 example.com. alpn="h2,h3" port="999" +156 @ 300 IN SVCB 3 example.com. alpn="h2" port="80" ech="another+base64+encoded+value" +157 @ 300 IN SVCB 3 example.com. alpn="h2" port="80" ech="some+base64+encoded+value///" +158 @ 300 IN SVCB 3 yetanother.com. alpn="h2" port="80" ech="another+base64+encoded+value" +159 _443._tcp 300 IN TLSA 2 0 1 0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF +160 _443._tcp 300 IN TLSA 2 0 2 0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF +161 _443._tcp 300 IN TLSA 2 0 2 FEDCBA9876543210FEDCBA9876543210FEDCBA9876543210FEDCBA9876543210FEDCBA9876543210FEDCBA9876543210FEDCBA9876543210FEDCBA9876543210 +162 _443._tcp 300 IN TLSA 2 1 1 0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF +163 _443._tcp 300 IN TLSA 3 1 1 0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF +164 @ 300 IN TXT "asimple" +165 @ 300 IN TXT "simple" +166 final 300 IN TXT "TestDNSProviders was successful!" +167 foo 300 IN TXT "simple" +168 foo 300 IN TXT "v=spf1 ip4:99.99.99.99 -all" +169 foo.bat 300 IN TXT "simple" +170 foo0 300 IN TXT "" +171 foo254 300 IN TXT "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" +172 foo255 300 IN TXT "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" +173 foo256 300 IN TXT "CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC" "C" +174 foo509 300 IN TXT "DDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDD" "DDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDD" +175 foo510 300 IN TXT "EEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE" "EEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE" +176 foo511 300 IN TXT "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF" "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF" "F" +177 foo764 300 IN TXT "GGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGG" "GGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGG" "GGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGG" +178 foo765 300 IN TXT "HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH" "HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH" "HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH" +179 foo766 300 IN TXT "JJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJ" "JJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJ" "JJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJ" "J" +180 foobt 300 IN TXT "blah`blah" +181 foodq 300 IN TXT "in\"side" +182 foodqs 300 IN TXT "\"left" +183 foodqs 300 IN TXT "in\"ter\"ior" +184 foodqs 300 IN TXT "right\"" +185 fooosbs1 300 IN TXT "1back\\slash" +186 fooosbs2 300 IN TXT "2back\\\\slash" +187 fooosbs3 300 IN TXT "3back\\\\\\slash" +188 fooosbs4 300 IN TXT "4back\\\\\\\\slash" +189 foosc1 300 IN TXT "semi;colon" +190 foosc2 300 IN TXT "wssemi ; colon" +191 foosp 300 IN TXT "with spaces" +192 foosq 300 IN TXT "quo'te" +193 foows1 300 IN TXT "trailingws " +194 testtxt 300 IN TXT "changed" +195 testtxt 300 IN TXT "simple" diff --git a/providers/gandiv5/test_data/meta.json b/providers/gandiv5/test_data/meta.json new file mode 100644 index 0000000000..3f671ae7a5 --- /dev/null +++ b/providers/gandiv5/test_data/meta.json @@ -0,0 +1,11 @@ +{ + "version": 1, + "recordings": [ + { + "domain": "tomontime.com", + "to_rc": [ + "nativeToRecords" + ] + } + ] +} diff --git a/providers/gandiv5/test_data/recorded_torc_input_nativeToRecords_tomontime.com.json b/providers/gandiv5/test_data/recorded_torc_input_nativeToRecords_tomontime.com.json new file mode 100644 index 0000000000..1157709723 --- /dev/null +++ b/providers/gandiv5/test_data/recorded_torc_input_nativeToRecords_tomontime.com.json @@ -0,0 +1,2378 @@ +[ + { + "index": 1, + "value": { + "rrset_type": "A", + "rrset_ttl": 1000, + "rrset_name": "@", + "rrset_href": "https://api.gandi.net/v5/livedns/domains/tomontime.com/records/%40/A", + "rrset_values": [ + "8.8.8.8" + ] + } + }, + { + "index": 2, + "value": { + "rrset_type": "A", + "rrset_ttl": 300, + "rrset_name": "*", + "rrset_href": "https://api.gandi.net/v5/livedns/domains/tomontime.com/records/%2A/A", + "rrset_values": [ + "3.3.3.3" + ] + } + }, + { + "index": 3, + "value": { + "rrset_type": "A", + "rrset_ttl": 300, + "rrset_name": "@", + "rrset_href": "https://api.gandi.net/v5/livedns/domains/tomontime.com/records/%40/A", + "rrset_values": [ + "1.2.3.2" + ] + } + }, + { + "index": 4, + "value": { + "rrset_type": "A", + "rrset_ttl": 300, + "rrset_name": "@", + "rrset_href": "https://api.gandi.net/v5/livedns/domains/tomontime.com/records/%40/A", + "rrset_values": [ + "1.2.3.4", + "2.3.4.5" + ] + } + }, + { + "index": 5, + "value": { + "rrset_type": "A", + "rrset_ttl": 300, + "rrset_name": "@", + "rrset_href": "https://api.gandi.net/v5/livedns/domains/tomontime.com/records/%40/A", + "rrset_values": [ + "1.2.3.4" + ] + } + }, + { + "index": 6, + "value": { + "rrset_type": "A", + "rrset_ttl": 300, + "rrset_name": "@", + "rrset_href": "https://api.gandi.net/v5/livedns/domains/tomontime.com/records/%40/A", + "rrset_values": [ + "2.2.2.2" + ] + } + }, + { + "index": 7, + "value": { + "rrset_type": "A", + "rrset_ttl": 300, + "rrset_name": "@", + "rrset_href": "https://api.gandi.net/v5/livedns/domains/tomontime.com/records/%40/A", + "rrset_values": [ + "4.4.4.4" + ] + } + }, + { + "index": 8, + "value": { + "rrset_type": "A", + "rrset_ttl": 300, + "rrset_name": "bar", + "rrset_href": "https://api.gandi.net/v5/livedns/domains/tomontime.com/records/bar/A", + "rrset_values": [ + "1.2.3.4" + ] + } + }, + { + "index": 9, + "value": { + "rrset_type": "A", + "rrset_ttl": 300, + "rrset_name": "bar", + "rrset_href": "https://api.gandi.net/v5/livedns/domains/tomontime.com/records/bar/A", + "rrset_values": [ + "5.5.5.5" + ] + } + }, + { + "index": 10, + "value": { + "rrset_type": "A", + "rrset_ttl": 300, + "rrset_name": "bar.bat", + "rrset_href": "https://api.gandi.net/v5/livedns/domains/tomontime.com/records/bar.bat/A", + "rrset_values": [ + "5.5.5.5" + ] + } + }, + { + "index": 11, + "value": { + "rrset_type": "A", + "rrset_ttl": 300, + "rrset_name": "decoy", + "rrset_href": "https://api.gandi.net/v5/livedns/domains/tomontime.com/records/decoy/A", + "rrset_values": [ + "1.1.1.1" + ] + } + }, + { + "index": 12, + "value": { + "rrset_type": "A", + "rrset_ttl": 300, + "rrset_name": "decoy", + "rrset_href": "https://api.gandi.net/v5/livedns/domains/tomontime.com/records/decoy/A", + "rrset_values": [ + "2.2.2.2" + ] + } + }, + { + "index": 13, + "value": { + "rrset_type": "A", + "rrset_ttl": 300, + "rrset_name": "decoy", + "rrset_href": "https://api.gandi.net/v5/livedns/domains/tomontime.com/records/decoy/A", + "rrset_values": [ + "3.3.3.3" + ] + } + }, + { + "index": 14, + "value": { + "rrset_type": "A", + "rrset_ttl": 300, + "rrset_name": "dyndns-city1", + "rrset_href": "https://api.gandi.net/v5/livedns/domains/tomontime.com/records/dyndns-city1/A", + "rrset_values": [ + "91.42.1.1" + ] + } + }, + { + "index": 15, + "value": { + "rrset_type": "A", + "rrset_ttl": 300, + "rrset_name": "dyndns-city2", + "rrset_href": "https://api.gandi.net/v5/livedns/domains/tomontime.com/records/dyndns-city2/A", + "rrset_values": [ + "91.42.1.2" + ] + } + }, + { + "index": 16, + "value": { + "rrset_type": "A", + "rrset_ttl": 300, + "rrset_name": "foo", + "rrset_href": "https://api.gandi.net/v5/livedns/domains/tomontime.com/records/foo/A", + "rrset_values": [ + "1.1.1.1", + "10.10.10.10" + ] + } + }, + { + "index": 17, + "value": { + "rrset_type": "A", + "rrset_ttl": 300, + "rrset_name": "foo", + "rrset_href": "https://api.gandi.net/v5/livedns/domains/tomontime.com/records/foo/A", + "rrset_values": [ + "1.1.1.1", + "11.11.11.11" + ] + } + }, + { + "index": 18, + "value": { + "rrset_type": "A", + "rrset_ttl": 300, + "rrset_name": "foo", + "rrset_href": "https://api.gandi.net/v5/livedns/domains/tomontime.com/records/foo/A", + "rrset_values": [ + "1.1.1.1", + "12.12.12.12" + ] + } + }, + { + "index": 19, + "value": { + "rrset_type": "A", + "rrset_ttl": 300, + "rrset_name": "foo", + "rrset_href": "https://api.gandi.net/v5/livedns/domains/tomontime.com/records/foo/A", + "rrset_values": [ + "1.1.1.1", + "13.13.13.13" + ] + } + }, + { + "index": 20, + "value": { + "rrset_type": "A", + "rrset_ttl": 300, + "rrset_name": "foo", + "rrset_href": "https://api.gandi.net/v5/livedns/domains/tomontime.com/records/foo/A", + "rrset_values": [ + "1.1.1.1", + "14.14.14.14" + ] + } + }, + { + "index": 21, + "value": { + "rrset_type": "A", + "rrset_ttl": 300, + "rrset_name": "foo", + "rrset_href": "https://api.gandi.net/v5/livedns/domains/tomontime.com/records/foo/A", + "rrset_values": [ + "1.2.3.4", + "2.3.4.5" + ] + } + }, + { + "index": 22, + "value": { + "rrset_type": "A", + "rrset_ttl": 300, + "rrset_name": "foo", + "rrset_href": "https://api.gandi.net/v5/livedns/domains/tomontime.com/records/foo/A", + "rrset_values": [ + "1.2.3.4", + "3.4.5.6" + ] + } + }, + { + "index": 23, + "value": { + "rrset_type": "A", + "rrset_ttl": 300, + "rrset_name": "foo", + "rrset_href": "https://api.gandi.net/v5/livedns/domains/tomontime.com/records/foo/A", + "rrset_values": [ + "1.2.3.4" + ] + } + }, + { + "index": 24, + "value": { + "rrset_type": "A", + "rrset_ttl": 300, + "rrset_name": "foo", + "rrset_href": "https://api.gandi.net/v5/livedns/domains/tomontime.com/records/foo/A", + "rrset_values": [ + "2.3.4.5", + "3.4.5.6" + ] + } + }, + { + "index": 25, + "value": { + "rrset_type": "A", + "rrset_ttl": 300, + "rrset_name": "foo", + "rrset_href": "https://api.gandi.net/v5/livedns/domains/tomontime.com/records/foo/A", + "rrset_values": [ + "2.3.4.5", + "8.8.8.8" + ] + } + }, + { + "index": 26, + "value": { + "rrset_type": "A", + "rrset_ttl": 300, + "rrset_name": "foo", + "rrset_href": "https://api.gandi.net/v5/livedns/domains/tomontime.com/records/foo/A", + "rrset_values": [ + "2.3.4.5" + ] + } + }, + { + "index": 27, + "value": { + "rrset_type": "A", + "rrset_ttl": 300, + "rrset_name": "foo", + "rrset_href": "https://api.gandi.net/v5/livedns/domains/tomontime.com/records/foo/A", + "rrset_values": [ + "4.5.6.7" + ] + } + }, + { + "index": 28, + "value": { + "rrset_type": "A", + "rrset_ttl": 300, + "rrset_name": "foo.bat", + "rrset_href": "https://api.gandi.net/v5/livedns/domains/tomontime.com/records/foo.bat/A", + "rrset_values": [ + "1.2.3.4", + "2.3.4.5" + ] + } + }, + { + "index": 29, + "value": { + "rrset_type": "A", + "rrset_ttl": 300, + "rrset_name": "nmx", + "rrset_href": "https://api.gandi.net/v5/livedns/domains/tomontime.com/records/nmx/A", + "rrset_values": [ + "1.2.3.3" + ] + } + }, + { + "index": 30, + "value": { + "rrset_type": "A", + "rrset_ttl": 300, + "rrset_name": "testa", + "rrset_href": "https://api.gandi.net/v5/livedns/domains/tomontime.com/records/testa/A", + "rrset_values": [ + "1.1.1.1" + ] + } + }, + { + "index": 31, + "value": { + "rrset_type": "A", + "rrset_ttl": 300, + "rrset_name": "testa", + "rrset_href": "https://api.gandi.net/v5/livedns/domains/tomontime.com/records/testa/A", + "rrset_values": [ + "3.3.3.3" + ] + } + }, + { + "index": 32, + "value": { + "rrset_type": "A", + "rrset_ttl": 300, + "rrset_name": "testdefined", + "rrset_href": "https://api.gandi.net/v5/livedns/domains/tomontime.com/records/testdefined/A", + "rrset_values": [ + "2.2.2.2" + ] + } + }, + { + "index": 33, + "value": { + "rrset_type": "A", + "rrset_ttl": 300, + "rrset_name": "testdefined", + "rrset_href": "https://api.gandi.net/v5/livedns/domains/tomontime.com/records/testdefined/A", + "rrset_values": [ + "9.9.9.9" + ] + } + }, + { + "index": 34, + "value": { + "rrset_type": "A", + "rrset_ttl": 300, + "rrset_name": "testignore", + "rrset_href": "https://api.gandi.net/v5/livedns/domains/tomontime.com/records/testignore/A", + "rrset_values": [ + "8.8.8.8" + ] + } + }, + { + "index": 35, + "value": { + "rrset_type": "A", + "rrset_ttl": 300, + "rrset_name": "www", + "rrset_href": "https://api.gandi.net/v5/livedns/domains/tomontime.com/records/www/A", + "rrset_values": [ + "1.1.1.1", + "2.2.2.2", + "3.3.3.3" + ] + } + }, + { + "index": 36, + "value": { + "rrset_type": "A", + "rrset_ttl": 300, + "rrset_name": "www", + "rrset_href": "https://api.gandi.net/v5/livedns/domains/tomontime.com/records/www/A", + "rrset_values": [ + "1.1.1.1", + "2.2.2.2" + ] + } + }, + { + "index": 37, + "value": { + "rrset_type": "A", + "rrset_ttl": 300, + "rrset_name": "www", + "rrset_href": "https://api.gandi.net/v5/livedns/domains/tomontime.com/records/www/A", + "rrset_values": [ + "1.1.1.1" + ] + } + }, + { + "index": 38, + "value": { + "rrset_type": "A", + "rrset_ttl": 300, + "rrset_name": "www", + "rrset_href": "https://api.gandi.net/v5/livedns/domains/tomontime.com/records/www/A", + "rrset_values": [ + "1.2.3.4", + "5.6.7.8" + ] + } + }, + { + "index": 39, + "value": { + "rrset_type": "A", + "rrset_ttl": 300, + "rrset_name": "www", + "rrset_href": "https://api.gandi.net/v5/livedns/domains/tomontime.com/records/www/A", + "rrset_values": [ + "1.2.3.8" + ] + } + }, + { + "index": 40, + "value": { + "rrset_type": "A", + "rrset_ttl": 300, + "rrset_name": "www", + "rrset_href": "https://api.gandi.net/v5/livedns/domains/tomontime.com/records/www/A", + "rrset_values": [ + "1.2.3.9" + ] + } + }, + { + "index": 41, + "value": { + "rrset_type": "A", + "rrset_ttl": 300, + "rrset_name": "www", + "rrset_href": "https://api.gandi.net/v5/livedns/domains/tomontime.com/records/www/A", + "rrset_values": [ + "2.2.2.2", + "5.6.7.8" + ] + } + }, + { + "index": 42, + "value": { + "rrset_type": "A", + "rrset_ttl": 300, + "rrset_name": "www", + "rrset_href": "https://api.gandi.net/v5/livedns/domains/tomontime.com/records/www/A", + "rrset_values": [ + "5.5.5.5" + ] + } + }, + { + "index": 43, + "value": { + "rrset_type": "A", + "rrset_ttl": 300, + "rrset_name": "xn--fiq228c", + "rrset_href": "https://api.gandi.net/v5/livedns/domains/tomontime.com/records/xn--fiq228c/A", + "rrset_values": [ + "1.2.3.4" + ] + } + }, + { + "index": 44, + "value": { + "rrset_type": "A", + "rrset_ttl": 300, + "rrset_name": "xn--ndaaa", + "rrset_href": "https://api.gandi.net/v5/livedns/domains/tomontime.com/records/xn--ndaaa/A", + "rrset_values": [ + "1.2.3.4" + ] + } + }, + { + "index": 45, + "value": { + "rrset_type": "A", + "rrset_ttl": 300, + "rrset_name": "xn--ndaaa", + "rrset_href": "https://api.gandi.net/v5/livedns/domains/tomontime.com/records/xn--ndaaa/A", + "rrset_values": [ + "2.2.2.2" + ] + } + }, + { + "index": 46, + "value": { + "rrset_type": "A", + "rrset_ttl": 300, + "rrset_name": "zzz", + "rrset_href": "https://api.gandi.net/v5/livedns/domains/tomontime.com/records/zzz/A", + "rrset_values": [ + "3.3.3.3", + "4.4.4.4" + ] + } + }, + { + "index": 47, + "value": { + "rrset_type": "A", + "rrset_ttl": 333, + "rrset_name": "testa", + "rrset_href": "https://api.gandi.net/v5/livedns/domains/tomontime.com/records/testa/A", + "rrset_values": [ + "1.1.1.1" + ] + } + }, + { + "index": 48, + "value": { + "rrset_type": "A", + "rrset_ttl": 400, + "rrset_name": "www", + "rrset_href": "https://api.gandi.net/v5/livedns/domains/tomontime.com/records/www/A", + "rrset_values": [ + "2.2.2.2", + "5.6.7.8" + ] + } + }, + { + "index": 49, + "value": { + "rrset_type": "A", + "rrset_ttl": 400, + "rrset_name": "www", + "rrset_href": "https://api.gandi.net/v5/livedns/domains/tomontime.com/records/www/A", + "rrset_values": [ + "5.6.7.8" + ] + } + }, + { + "index": 50, + "value": { + "rrset_type": "A", + "rrset_ttl": 500, + "rrset_name": "@", + "rrset_href": "https://api.gandi.net/v5/livedns/domains/tomontime.com/records/%40/A", + "rrset_values": [ + "8.8.8.8" + ] + } + }, + { + "index": 51, + "value": { + "rrset_type": "A", + "rrset_ttl": 666, + "rrset_name": "@", + "rrset_href": "https://api.gandi.net/v5/livedns/domains/tomontime.com/records/%40/A", + "rrset_values": [ + "8.8.8.8" + ] + } + }, + { + "index": 52, + "value": { + "rrset_type": "A", + "rrset_ttl": 700, + "rrset_name": "www", + "rrset_href": "https://api.gandi.net/v5/livedns/domains/tomontime.com/records/www/A", + "rrset_values": [ + "1.2.3.4", + "5.6.7.8" + ] + } + }, + { + "index": 53, + "value": { + "rrset_type": "A", + "rrset_ttl": 999, + "rrset_name": "testa", + "rrset_href": "https://api.gandi.net/v5/livedns/domains/tomontime.com/records/testa/A", + "rrset_values": [ + "1.1.1.1" + ] + } + }, + { + "index": 54, + "value": { + "rrset_type": "AAAA", + "rrset_ttl": 300, + "rrset_name": "dyndns-city1", + "rrset_href": "https://api.gandi.net/v5/livedns/domains/tomontime.com/records/dyndns-city1/AAAA", + "rrset_values": [ + "2003:dd:d7ff::fe71:ce77" + ] + } + }, + { + "index": 55, + "value": { + "rrset_type": "AAAA", + "rrset_ttl": 300, + "rrset_name": "dyndns-city2", + "rrset_href": "https://api.gandi.net/v5/livedns/domains/tomontime.com/records/dyndns-city2/AAAA", + "rrset_values": [ + "2003:dd:d7ff::fe71:ce78" + ] + } + }, + { + "index": 56, + "value": { + "rrset_type": "AAAA", + "rrset_ttl": 300, + "rrset_name": "foo", + "rrset_href": "https://api.gandi.net/v5/livedns/domains/tomontime.com/records/foo/AAAA", + "rrset_values": [ + "2003:dd:d7ff::fe71:aaaa" + ] + } + }, + { + "index": 57, + "value": { + "rrset_type": "AAAA", + "rrset_ttl": 300, + "rrset_name": "testaaaa", + "rrset_href": "https://api.gandi.net/v5/livedns/domains/tomontime.com/records/testaaaa/AAAA", + "rrset_values": [ + "2607:f8b0:4006:820::2006" + ] + } + }, + { + "index": 58, + "value": { + "rrset_type": "AAAA", + "rrset_ttl": 300, + "rrset_name": "testaaaa", + "rrset_href": "https://api.gandi.net/v5/livedns/domains/tomontime.com/records/testaaaa/AAAA", + "rrset_values": [ + "2607:f8b0:4006:820::2013" + ] + } + }, + { + "index": 59, + "value": { + "rrset_type": "AAAA", + "rrset_ttl": 300, + "rrset_name": "zzz", + "rrset_href": "https://api.gandi.net/v5/livedns/domains/tomontime.com/records/zzz/AAAA", + "rrset_values": [ + "2003:dd:d7ff::fe71:cccc" + ] + } + }, + { + "index": 60, + "value": { + "rrset_type": "ALIAS", + "rrset_ttl": 300, + "rrset_name": "@", + "rrset_href": "https://api.gandi.net/v5/livedns/domains/tomontime.com/records/%40/ALIAS", + "rrset_values": [ + "foo.com." + ] + } + }, + { + "index": 61, + "value": { + "rrset_type": "ALIAS", + "rrset_ttl": 300, + "rrset_name": "@", + "rrset_href": "https://api.gandi.net/v5/livedns/domains/tomontime.com/records/%40/ALIAS", + "rrset_values": [ + "foo.tomontime.com." + ] + } + }, + { + "index": 62, + "value": { + "rrset_type": "ALIAS", + "rrset_ttl": 300, + "rrset_name": "@", + "rrset_href": "https://api.gandi.net/v5/livedns/domains/tomontime.com/records/%40/ALIAS", + "rrset_values": [ + "foo2.com." + ] + } + }, + { + "index": 63, + "value": { + "rrset_type": "CAA", + "rrset_ttl": 300, + "rrset_name": "@", + "rrset_href": "https://api.gandi.net/v5/livedns/domains/tomontime.com/records/%40/CAA", + "rrset_values": [ + "0 issue \"letsencrypt.org; validationmethods=dns-01; accounturi=https://acme-v02.api.letsencrypt.org/acme/acct/1234\"" + ] + } + }, + { + "index": 64, + "value": { + "rrset_type": "CAA", + "rrset_ttl": 300, + "rrset_name": "@", + "rrset_href": "https://api.gandi.net/v5/livedns/domains/tomontime.com/records/%40/CAA", + "rrset_values": [ + "0 issue \"letsencrypt.org\"" + ] + } + }, + { + "index": 65, + "value": { + "rrset_type": "CAA", + "rrset_ttl": 300, + "rrset_name": "@", + "rrset_href": "https://api.gandi.net/v5/livedns/domains/tomontime.com/records/%40/CAA", + "rrset_values": [ + "0 issuewild \";\"" + ] + } + }, + { + "index": 66, + "value": { + "rrset_type": "CAA", + "rrset_ttl": 300, + "rrset_name": "@", + "rrset_href": "https://api.gandi.net/v5/livedns/domains/tomontime.com/records/%40/CAA", + "rrset_values": [ + "0 issuewild \"example.com\"" + ] + } + }, + { + "index": 67, + "value": { + "rrset_type": "CAA", + "rrset_ttl": 300, + "rrset_name": "@", + "rrset_href": "https://api.gandi.net/v5/livedns/domains/tomontime.com/records/%40/CAA", + "rrset_values": [ + "0 issuewild \"letsencrypt.org\"" + ] + } + }, + { + "index": 68, + "value": { + "rrset_type": "CAA", + "rrset_ttl": 300, + "rrset_name": "@", + "rrset_href": "https://api.gandi.net/v5/livedns/domains/tomontime.com/records/%40/CAA", + "rrset_values": [ + "128 issue \"letsencrypt.org\"" + ] + } + }, + { + "index": 69, + "value": { + "rrset_type": "CNAME", + "rrset_ttl": 300, + "rrset_name": "a", + "rrset_href": "https://api.gandi.net/v5/livedns/domains/tomontime.com/records/a/CNAME", + "rrset_values": [ + "xn--ndaaa.com." + ] + } + }, + { + "index": 70, + "value": { + "rrset_type": "CNAME", + "rrset_ttl": 300, + "rrset_name": "bar", + "rrset_href": "https://api.gandi.net/v5/livedns/domains/tomontime.com/records/bar/CNAME", + "rrset_values": [ + "redact2.acm-validations.aws." + ] + } + }, + { + "index": 71, + "value": { + "rrset_type": "CNAME", + "rrset_ttl": 300, + "rrset_name": "foo", + "rrset_href": "https://api.gandi.net/v5/livedns/domains/tomontime.com/records/foo/CNAME", + "rrset_values": [ + "google.com." + ] + } + }, + { + "index": 72, + "value": { + "rrset_type": "CNAME", + "rrset_ttl": 300, + "rrset_name": "foo", + "rrset_href": "https://api.gandi.net/v5/livedns/domains/tomontime.com/records/foo/CNAME", + "rrset_values": [ + "google2.com." + ] + } + }, + { + "index": 73, + "value": { + "rrset_type": "CNAME", + "rrset_ttl": 300, + "rrset_name": "foo", + "rrset_href": "https://api.gandi.net/v5/livedns/domains/tomontime.com/records/foo/CNAME", + "rrset_values": [ + "redact1.acm-validations.aws." + ] + } + }, + { + "index": 74, + "value": { + "rrset_type": "CNAME", + "rrset_ttl": 300, + "rrset_name": "foo", + "rrset_href": "https://api.gandi.net/v5/livedns/domains/tomontime.com/records/foo/CNAME", + "rrset_values": [ + "tomontime.com." + ] + } + }, + { + "index": 75, + "value": { + "rrset_type": "CNAME", + "rrset_ttl": 300, + "rrset_name": "mail", + "rrset_href": "https://api.gandi.net/v5/livedns/domains/tomontime.com/records/mail/CNAME", + "rrset_values": [ + "ghs.googlehosted.com." + ] + } + }, + { + "index": 76, + "value": { + "rrset_type": "CNAME", + "rrset_ttl": 300, + "rrset_name": "mail.bat", + "rrset_href": "https://api.gandi.net/v5/livedns/domains/tomontime.com/records/mail.bat/CNAME", + "rrset_values": [ + "ghs.googlehosted.com." + ] + } + }, + { + "index": 77, + "value": { + "rrset_type": "CNAME", + "rrset_ttl": 300, + "rrset_name": "test", + "rrset_href": "https://api.gandi.net/v5/livedns/domains/tomontime.com/records/test/CNAME", + "rrset_values": [ + "foo.com." + ] + } + }, + { + "index": 78, + "value": { + "rrset_type": "CNAME", + "rrset_ttl": 300, + "rrset_name": "test", + "rrset_href": "https://api.gandi.net/v5/livedns/domains/tomontime.com/records/test/CNAME", + "rrset_values": [ + "foo2.com." + ] + } + }, + { + "index": 79, + "value": { + "rrset_type": "CNAME", + "rrset_ttl": 300, + "rrset_name": "testcname", + "rrset_href": "https://api.gandi.net/v5/livedns/domains/tomontime.com/records/testcname/CNAME", + "rrset_values": [ + "foo.tomontime.com." + ] + } + }, + { + "index": 80, + "value": { + "rrset_type": "CNAME", + "rrset_ttl": 300, + "rrset_name": "testcname", + "rrset_href": "https://api.gandi.net/v5/livedns/domains/tomontime.com/records/testcname/CNAME", + "rrset_values": [ + "www.google.com." + ] + } + }, + { + "index": 81, + "value": { + "rrset_type": "CNAME", + "rrset_ttl": 300, + "rrset_name": "testcname", + "rrset_href": "https://api.gandi.net/v5/livedns/domains/tomontime.com/records/testcname/CNAME", + "rrset_values": [ + "www.yahoo.com." + ] + } + }, + { + "index": 82, + "value": { + "rrset_type": "CNAME", + "rrset_ttl": 300, + "rrset_name": "xn--o-0gab", + "rrset_href": "https://api.gandi.net/v5/livedns/domains/tomontime.com/records/xn--o-0gab/CNAME", + "rrset_values": [ + "xn--ndaaa.xn--vhquv." + ] + } + }, + { + "index": 83, + "value": { + "rrset_type": "DS", + "rrset_ttl": 300, + "rrset_name": "another-child", + "rrset_href": "https://api.gandi.net/v5/livedns/domains/tomontime.com/records/another-child/DS", + "rrset_values": [ + "44 13 2 4B9B6B073EDD97FEB5BC12DC4E1B32D2C6AF7AE23A293936CEB87BB10494EC44", + "1501 14 4 109BB6B5B6D5547C1CE03C7A8BD7D8F80C1CB0957F50C4F7FDA04692079917E4F9CAD52B878F3D8234E1A170B154B72D", + "1502 8 2 2FA14F53E6B15CAC9AC77846C7BE87862C2A7E9EC0C6CEA319DB939317F126ED", + "65535 13 2 2FA14F53E6B15CAC9AC77846C7BE87862C2A7E9EC0C6CEA319DB939317F126ED" + ] + } + }, + { + "index": 84, + "value": { + "rrset_type": "DS", + "rrset_ttl": 300, + "rrset_name": "another-child", + "rrset_href": "https://api.gandi.net/v5/livedns/domains/tomontime.com/records/another-child/DS", + "rrset_values": [ + "44 13 2 4B9B6B073EDD97FEB5BC12DC4E1B32D2C6AF7AE23A293936CEB87BB10494EC44" + ] + } + }, + { + "index": 85, + "value": { + "rrset_type": "DS", + "rrset_ttl": 300, + "rrset_name": "child", + "rrset_href": "https://api.gandi.net/v5/livedns/domains/tomontime.com/records/child/DS", + "rrset_values": [ + "1 14 4 417212FD1C8BC5896FEFD8DB58AF824545E85B0D0546409366A30AEF7269FAE258173BD185FB262C86F3BB86FBA04368" + ] + } + }, + { + "index": 86, + "value": { + "rrset_type": "DS", + "rrset_ttl": 300, + "rrset_name": "child", + "rrset_href": "https://api.gandi.net/v5/livedns/domains/tomontime.com/records/child/DS", + "rrset_values": [ + "3 13 2 4B9B6B073EDD97FEB5BC12DC4E1B32D2C6AF7AE23A293936CEB87BB10494EC44" + ] + } + }, + { + "index": 87, + "value": { + "rrset_type": "DS", + "rrset_ttl": 300, + "rrset_name": "child", + "rrset_href": "https://api.gandi.net/v5/livedns/domains/tomontime.com/records/child/DS", + "rrset_values": [ + "3 14 4 3115238F89E0BF5252D9718113B1B9FFF854608D84BE94EEFB9210DC1CC0B4F3557342A27465CFACC42EF137AE9A5489" + ] + } + }, + { + "index": 88, + "value": { + "rrset_type": "DS", + "rrset_ttl": 300, + "rrset_name": "child", + "rrset_href": "https://api.gandi.net/v5/livedns/domains/tomontime.com/records/child/DS", + "rrset_values": [ + "3 8 2 4B9B6B073EDD97FEB5BC12DC4E1B32D2C6AF7AE23A293936CEB87BB10494EC44" + ] + } + }, + { + "index": 89, + "value": { + "rrset_type": "DS", + "rrset_ttl": 300, + "rrset_name": "child", + "rrset_href": "https://api.gandi.net/v5/livedns/domains/tomontime.com/records/child/DS", + "rrset_values": [ + "8857 8 2 4B9B6B073EDD97FEB5BC12DC4E1B32D2C6AF7AE23A293936CEB87BB10494EC44" + ] + } + }, + { + "index": 90, + "value": { + "rrset_type": "HTTPS", + "rrset_ttl": 300, + "rrset_name": "@", + "rrset_href": "https://api.gandi.net/v5/livedns/domains/tomontime.com/records/%40/HTTPS", + "rrset_values": [ + "0 test.com." + ] + } + }, + { + "index": 91, + "value": { + "rrset_type": "HTTPS", + "rrset_ttl": 300, + "rrset_name": "@", + "rrset_href": "https://api.gandi.net/v5/livedns/domains/tomontime.com/records/%40/HTTPS", + "rrset_values": [ + "1 test.com. alpn=\"h2\" port=\"99\"" + ] + } + }, + { + "index": 92, + "value": { + "rrset_type": "HTTPS", + "rrset_ttl": 300, + "rrset_name": "@", + "rrset_href": "https://api.gandi.net/v5/livedns/domains/tomontime.com/records/%40/HTTPS", + "rrset_values": [ + "1 test.com. port=\"80\"" + ] + } + }, + { + "index": 93, + "value": { + "rrset_type": "HTTPS", + "rrset_ttl": 300, + "rrset_name": "@", + "rrset_href": "https://api.gandi.net/v5/livedns/domains/tomontime.com/records/%40/HTTPS", + "rrset_values": [ + "1 test.com. port=\"99\"" + ] + } + }, + { + "index": 94, + "value": { + "rrset_type": "HTTPS", + "rrset_ttl": 300, + "rrset_name": "@", + "rrset_href": "https://api.gandi.net/v5/livedns/domains/tomontime.com/records/%40/HTTPS", + "rrset_values": [ + "3 example.com. alpn=\"h2,h3\" port=\"999\" ech=\"some+base64+encoded+value///\"" + ] + } + }, + { + "index": 95, + "value": { + "rrset_type": "HTTPS", + "rrset_ttl": 300, + "rrset_name": "@", + "rrset_href": "https://api.gandi.net/v5/livedns/domains/tomontime.com/records/%40/HTTPS", + "rrset_values": [ + "3 example.com. alpn=\"h2,h3\" port=\"999\"" + ] + } + }, + { + "index": 96, + "value": { + "rrset_type": "HTTPS", + "rrset_ttl": 300, + "rrset_name": "@", + "rrset_href": "https://api.gandi.net/v5/livedns/domains/tomontime.com/records/%40/HTTPS", + "rrset_values": [ + "3 example.com. alpn=\"h2\" port=\"80\" ech=\"another+base64+encoded+value\"" + ] + } + }, + { + "index": 97, + "value": { + "rrset_type": "HTTPS", + "rrset_ttl": 300, + "rrset_name": "@", + "rrset_href": "https://api.gandi.net/v5/livedns/domains/tomontime.com/records/%40/HTTPS", + "rrset_values": [ + "3 example.com. alpn=\"h2\" port=\"80\" ech=\"some+base64+encoded+value///\"" + ] + } + }, + { + "index": 98, + "value": { + "rrset_type": "HTTPS", + "rrset_ttl": 300, + "rrset_name": "@", + "rrset_href": "https://api.gandi.net/v5/livedns/domains/tomontime.com/records/%40/HTTPS", + "rrset_values": [ + "3 yetanother.com. alpn=\"h2\" port=\"80\" ech=\"another+base64+encoded+value\"" + ] + } + }, + { + "index": 99, + "value": { + "rrset_type": "LOC", + "rrset_ttl": 300, + "rrset_name": "@", + "rrset_href": "https://api.gandi.net/v5/livedns/domains/tomontime.com/records/%40/LOC", + "rrset_values": [ + "42 21 54.000 N 71 06 18.000 W -24.05m 30m 0.00m 0.00m" + ] + } + }, + { + "index": 100, + "value": { + "rrset_type": "LOC", + "rrset_ttl": 300, + "rrset_name": "@", + "rrset_href": "https://api.gandi.net/v5/livedns/domains/tomontime.com/records/%40/LOC", + "rrset_values": [ + "42 21 54.000 N 71 06 18.000 W -24.06m 30m 10m 0.00m" + ] + } + }, + { + "index": 101, + "value": { + "rrset_type": "LOC", + "rrset_ttl": 300, + "rrset_name": "@", + "rrset_href": "https://api.gandi.net/v5/livedns/domains/tomontime.com/records/%40/LOC", + "rrset_values": [ + "42 21 54.000 N 71 06 18.000 W -24m 30m 0.00m 0.00m" + ] + } + }, + { + "index": 102, + "value": { + "rrset_type": "LOC", + "rrset_ttl": 300, + "rrset_name": "a", + "rrset_href": "https://api.gandi.net/v5/livedns/domains/tomontime.com/records/a/LOC", + "rrset_values": [ + "42 21 43.950 N 71 05 6.340 W -24.33m 1m 200m 10m" + ] + } + }, + { + "index": 103, + "value": { + "rrset_type": "LOC", + "rrset_ttl": 300, + "rrset_name": "b", + "rrset_href": "https://api.gandi.net/v5/livedns/domains/tomontime.com/records/b/LOC", + "rrset_values": [ + "52 14 5.000 N 00 08 50.000 E 10.22m 0.00m 0.00m 0.00m" + ] + } + }, + { + "index": 104, + "value": { + "rrset_type": "LOC", + "rrset_ttl": 300, + "rrset_name": "c", + "rrset_href": "https://api.gandi.net/v5/livedns/domains/tomontime.com/records/c/LOC", + "rrset_values": [ + "32 07 19.000 S 116 02 25.000 E 10m 0.00m 0.00m 0.00m" + ] + } + }, + { + "index": 105, + "value": { + "rrset_type": "LOC", + "rrset_ttl": 300, + "rrset_name": "d", + "rrset_href": "https://api.gandi.net/v5/livedns/domains/tomontime.com/records/d/LOC", + "rrset_values": [ + "42 21 28.760 N 71 00 51.620 W -44m 2000m 0.00m 0.00m" + ] + } + }, + { + "index": 106, + "value": { + "rrset_type": "MX", + "rrset_ttl": 300, + "rrset_name": "@", + "rrset_href": "https://api.gandi.net/v5/livedns/domains/tomontime.com/records/%40/MX", + "rrset_values": [ + "0 ." + ] + } + }, + { + "index": 107, + "value": { + "rrset_type": "MX", + "rrset_ttl": 300, + "rrset_name": "@", + "rrset_href": "https://api.gandi.net/v5/livedns/domains/tomontime.com/records/%40/MX", + "rrset_values": [ + "2 tomontime.com.", + "8 www.tomontime.com." + ] + } + }, + { + "index": 108, + "value": { + "rrset_type": "MX", + "rrset_ttl": 300, + "rrset_name": "@", + "rrset_href": "https://api.gandi.net/v5/livedns/domains/tomontime.com/records/%40/MX", + "rrset_values": [ + "5 bar.com." + ] + } + }, + { + "index": 109, + "value": { + "rrset_type": "MX", + "rrset_ttl": 300, + "rrset_name": "@", + "rrset_href": "https://api.gandi.net/v5/livedns/domains/tomontime.com/records/%40/MX", + "rrset_values": [ + "5 foo.com." + ] + } + }, + { + "index": 110, + "value": { + "rrset_type": "MX", + "rrset_ttl": 300, + "rrset_name": "bar", + "rrset_href": "https://api.gandi.net/v5/livedns/domains/tomontime.com/records/bar/MX", + "rrset_values": [ + "5 bar.com." + ] + } + }, + { + "index": 111, + "value": { + "rrset_type": "MX", + "rrset_ttl": 300, + "rrset_name": "foo", + "rrset_href": "https://api.gandi.net/v5/livedns/domains/tomontime.com/records/foo/MX", + "rrset_values": [ + "10 aspmx.l.google.com.", + "20 alt1.aspmx.l.google.com." + ] + } + }, + { + "index": 112, + "value": { + "rrset_type": "MX", + "rrset_ttl": 300, + "rrset_name": "foo", + "rrset_href": "https://api.gandi.net/v5/livedns/domains/tomontime.com/records/foo/MX", + "rrset_values": [ + "10 foo.tomontime.com.", + "20 bar.tomontime.com." + ] + } + }, + { + "index": 113, + "value": { + "rrset_type": "MX", + "rrset_ttl": 300, + "rrset_name": "foo", + "rrset_href": "https://api.gandi.net/v5/livedns/domains/tomontime.com/records/foo/MX", + "rrset_values": [ + "5 mx.google.com." + ] + } + }, + { + "index": 114, + "value": { + "rrset_type": "MX", + "rrset_ttl": 300, + "rrset_name": "foo", + "rrset_href": "https://api.gandi.net/v5/livedns/domains/tomontime.com/records/foo/MX", + "rrset_values": [ + "8 tomontime.com." + ] + } + }, + { + "index": 115, + "value": { + "rrset_type": "MX", + "rrset_ttl": 300, + "rrset_name": "nmx", + "rrset_href": "https://api.gandi.net/v5/livedns/domains/tomontime.com/records/nmx/MX", + "rrset_values": [ + "0 ." + ] + } + }, + { + "index": 116, + "value": { + "rrset_type": "MX", + "rrset_ttl": 300, + "rrset_name": "nmx", + "rrset_href": "https://api.gandi.net/v5/livedns/domains/tomontime.com/records/nmx/MX", + "rrset_values": [ + "3 nmx.tomontime.com.", + "9 www.tomontime.com." + ] + } + }, + { + "index": 117, + "value": { + "rrset_type": "MX", + "rrset_ttl": 300, + "rrset_name": "testmx", + "rrset_href": "https://api.gandi.net/v5/livedns/domains/tomontime.com/records/testmx/MX", + "rrset_values": [ + "100 foo.com." + ] + } + }, + { + "index": 118, + "value": { + "rrset_type": "MX", + "rrset_ttl": 300, + "rrset_name": "testmx", + "rrset_href": "https://api.gandi.net/v5/livedns/domains/tomontime.com/records/testmx/MX", + "rrset_values": [ + "5 bar.com." + ] + } + }, + { + "index": 119, + "value": { + "rrset_type": "MX", + "rrset_ttl": 300, + "rrset_name": "testmx", + "rrset_href": "https://api.gandi.net/v5/livedns/domains/tomontime.com/records/testmx/MX", + "rrset_values": [ + "5 foo.com.", + "100 bar.com." + ] + } + }, + { + "index": 120, + "value": { + "rrset_type": "MX", + "rrset_ttl": 300, + "rrset_name": "testmx", + "rrset_href": "https://api.gandi.net/v5/livedns/domains/tomontime.com/records/testmx/MX", + "rrset_values": [ + "5 foo.com." + ] + } + }, + { + "index": 121, + "value": { + "rrset_type": "NS", + "rrset_ttl": 300, + "rrset_name": "foo", + "rrset_href": "https://api.gandi.net/v5/livedns/domains/tomontime.com/records/foo/NS", + "rrset_values": [ + "tomontime.com." + ] + } + }, + { + "index": 122, + "value": { + "rrset_type": "NS", + "rrset_ttl": 300, + "rrset_name": "xyz", + "rrset_href": "https://api.gandi.net/v5/livedns/domains/tomontime.com/records/xyz/NS", + "rrset_values": [ + "ns1.foo.com.", + "ns2.foo.com." + ] + } + }, + { + "index": 123, + "value": { + "rrset_type": "NS", + "rrset_ttl": 300, + "rrset_name": "xyz", + "rrset_href": "https://api.gandi.net/v5/livedns/domains/tomontime.com/records/xyz/NS", + "rrset_values": [ + "ns2.foo.com." + ] + } + }, + { + "index": 124, + "value": { + "rrset_type": "OPENPGPKEY", + "rrset_ttl": 300, + "rrset_name": "6c9b19cb967b563d9d96b341ad4a89a74444c6f18e9530f4623817fe._openpgpkey", + "rrset_href": "https://api.gandi.net/v5/livedns/domains/tomontime.com/records/6c9b19cb967b563d9d96b341ad4a89a74444c6f18e9530f4623817fe._openpgpkey/OPENPGPKEY", + "rrset_values": [ + "mDMEAAAAARYJKwYBBAHaRw8BAQdAQWiJ4gXP6wC2wQ7h7odcLpZU+mQD2rHiqtTgj+1e6ou0JEV4YW1wbGUgMiA8ZXhhbXBsZS0yQGRuc2NvbnRyb2wub3JnPoh+BBMWCgAmFiEE/tuN1tP/jpKko/EvTN4yJT7efAsFAgAAAAECGwECHgUCF4AACgkQTN4yJT7efAuxPQD/aEhrJaCX9FD1IkjA/8UmK0nokjtJNy46It3IWTGT4EQBAJI6goeRQBJqu/UnHmjv0OfqBQQCt87f9zXqZxLjiIQN" + ] + } + }, + { + "index": 125, + "value": { + "rrset_type": "OPENPGPKEY", + "rrset_ttl": 300, + "rrset_name": "6c9b19cb967b563d9d96b341ad4a89a74444c6f18e9530f4623817fe._openpgpkey", + "rrset_href": "https://api.gandi.net/v5/livedns/domains/tomontime.com/records/6c9b19cb967b563d9d96b341ad4a89a74444c6f18e9530f4623817fe._openpgpkey/OPENPGPKEY", + "rrset_values": [ + "mDMEAAAAARYJKwYBBAHaRw8BAQdAxCQnAKBDmA75+73+3lYVXDwrMUbaR61fNZgGeOHwmDq0JEV4YW1wbGUgMiA8ZXhhbXBsZS0yQGRuc2NvbnRyb2wub3JnPoh+BBMWCgAmFiEEYZ3PIZnaOWQrPxj6VX+9VdC3r4wFAgAAAAECGwECHgUCF4AACgkQVX+9VdC3r4xq6wEAl2ujFSqWwc2wQuHedpFrSTN9Gh7cIziKCZ3f8BGSRTgBAIvjKlWLLLBu0FPpCVlcfkpsZMV5YRrg90k+D+O4zZ4M" + ] + } + }, + { + "index": 126, + "value": { + "rrset_type": "OPENPGPKEY", + "rrset_ttl": 300, + "rrset_name": "bb7d0cf1ee44aca0bcc0f739b77b935f13aec2fd537f5c29dedd883d._openpgpkey", + "rrset_href": "https://api.gandi.net/v5/livedns/domains/tomontime.com/records/bb7d0cf1ee44aca0bcc0f739b77b935f13aec2fd537f5c29dedd883d._openpgpkey/OPENPGPKEY", + "rrset_values": [ + "mDMEAAAAARYJKwYBBAHaRw8BAQdAFHHsHVzE1rvYcCmX7Sn5X3p71eF5qo02mO/IuULrCPW0JEV4YW1wbGUgMSA8ZXhhbXBsZS0xQGRuc2NvbnRyb2wub3JnPoh+BBMWCgAmFiEEkwXxX/eDCW05Qn5tBI42Nn4+OuIFAgAAAAECGwECHgUCF4AACgkQBI42Nn4+OuL/qgD/S2rZm2Lafp11mr5q4jIBZ4DCS/Xl+Gm4ADvoPGpzkzwBALZqxlCToP4KQ0RI2ZlqtGQSy+fHDVxat0q7pFZsRo0K" + ] + } + }, + { + "index": 127, + "value": { + "rrset_type": "OPENPGPKEY", + "rrset_ttl": 300, + "rrset_name": "bb7d0cf1ee44aca0bcc0f739b77b935f13aec2fd537f5c29dedd883d._openpgpkey", + "rrset_href": "https://api.gandi.net/v5/livedns/domains/tomontime.com/records/bb7d0cf1ee44aca0bcc0f739b77b935f13aec2fd537f5c29dedd883d._openpgpkey/OPENPGPKEY", + "rrset_values": [ + "mDMEAAAAARYJKwYBBAHaRw8BAQdAO2uf8a0MUkNWUHzey8FhYJP2SS+061pF+GFK23egV9K0JEV4YW1wbGUgMSA8ZXhhbXBsZS0xQGRuc2NvbnRyb2wub3JnPoh+BBMWCgAmFiEEwP53wg/jSbhjzamYC/4c89luNM4FAgAAAAECGwECHgUCF4AACgkQC/4c89luNM4/LgEA8ARj4iJ0fVrpRRnhrTtlGwos170TDhTuZfPoGMqweS0A/1GWtg6/ywR4EPtRu+p9WogsQmO1HOk3ag3I5d7iP18C" + ] + } + }, + { + "index": 128, + "value": { + "rrset_type": "PTR", + "rrset_ttl": 300, + "rrset_name": "4", + "rrset_href": "https://api.gandi.net/v5/livedns/domains/tomontime.com/records/4/PTR", + "rrset_values": [ + "bar.com." + ] + } + }, + { + "index": 129, + "value": { + "rrset_type": "PTR", + "rrset_ttl": 300, + "rrset_name": "4", + "rrset_href": "https://api.gandi.net/v5/livedns/domains/tomontime.com/records/4/PTR", + "rrset_values": [ + "foo.com." + ] + } + }, + { + "index": 130, + "value": { + "rrset_type": "RP", + "rrset_ttl": 300, + "rrset_name": "foo", + "rrset_href": "https://api.gandi.net/v5/livedns/domains/tomontime.com/records/foo/RP", + "rrset_values": [ + "other.example.com. bar.com." + ] + } + }, + { + "index": 131, + "value": { + "rrset_type": "RP", + "rrset_ttl": 300, + "rrset_name": "foo", + "rrset_href": "https://api.gandi.net/v5/livedns/domains/tomontime.com/records/foo/RP", + "rrset_values": [ + "other.example.com. example.com." + ] + } + }, + { + "index": 132, + "value": { + "rrset_type": "RP", + "rrset_ttl": 300, + "rrset_name": "foo", + "rrset_href": "https://api.gandi.net/v5/livedns/domains/tomontime.com/records/foo/RP", + "rrset_values": [ + "user.example.com. bar.com." + ] + } + }, + { + "index": 133, + "value": { + "rrset_type": "RP", + "rrset_ttl": 300, + "rrset_name": "foo", + "rrset_href": "https://api.gandi.net/v5/livedns/domains/tomontime.com/records/foo/RP", + "rrset_values": [ + "user.tomontime.com. server.tomontime.com." + ] + } + }, + { + "index": 134, + "value": { + "rrset_type": "RP", + "rrset_ttl": 300, + "rrset_name": "foo", + "rrset_href": "https://api.gandi.net/v5/livedns/domains/tomontime.com/records/foo/RP", + "rrset_values": [ + "user2.tomontime.com. server.tomontime.com." + ] + } + }, + { + "index": 135, + "value": { + "rrset_type": "RP", + "rrset_ttl": 300, + "rrset_name": "foo", + "rrset_href": "https://api.gandi.net/v5/livedns/domains/tomontime.com/records/foo/RP", + "rrset_values": [ + "user2.tomontime.com. waiter.tomontime.com." + ] + } + }, + { + "index": 136, + "value": { + "rrset_type": "SRV", + "rrset_ttl": 300, + "rrset_name": "_sip._tcp", + "rrset_href": "https://api.gandi.net/v5/livedns/domains/tomontime.com/records/_sip._tcp/SRV", + "rrset_values": [ + "15 65 75 ." + ] + } + }, + { + "index": 137, + "value": { + "rrset_type": "SRV", + "rrset_ttl": 300, + "rrset_name": "_sip._tcp", + "rrset_href": "https://api.gandi.net/v5/livedns/domains/tomontime.com/records/_sip._tcp/SRV", + "rrset_values": [ + "15 65 75 foo4.com.", + "52 6 7 foo.com." + ] + } + }, + { + "index": 138, + "value": { + "rrset_type": "SRV", + "rrset_ttl": 300, + "rrset_name": "_sip._tcp", + "rrset_href": "https://api.gandi.net/v5/livedns/domains/tomontime.com/records/_sip._tcp/SRV", + "rrset_values": [ + "15 65 75 foo4.com.", + "52 62 7 foo.com." + ] + } + }, + { + "index": 139, + "value": { + "rrset_type": "SRV", + "rrset_ttl": 300, + "rrset_name": "_sip._tcp", + "rrset_href": "https://api.gandi.net/v5/livedns/domains/tomontime.com/records/_sip._tcp/SRV", + "rrset_values": [ + "15 65 75 foo4.com.", + "52 62 72 foo.com." + ] + } + }, + { + "index": 140, + "value": { + "rrset_type": "SRV", + "rrset_ttl": 300, + "rrset_name": "_sip._tcp", + "rrset_href": "https://api.gandi.net/v5/livedns/domains/tomontime.com/records/_sip._tcp/SRV", + "rrset_values": [ + "5 6 7 foo.com.", + "15 65 75 foo3.com." + ] + } + }, + { + "index": 141, + "value": { + "rrset_type": "SRV", + "rrset_ttl": 300, + "rrset_name": "_sip._tcp", + "rrset_href": "https://api.gandi.net/v5/livedns/domains/tomontime.com/records/_sip._tcp/SRV", + "rrset_values": [ + "5 6 7 foo.com.", + "15 65 75 foo4.com." + ] + } + }, + { + "index": 142, + "value": { + "rrset_type": "SRV", + "rrset_ttl": 300, + "rrset_name": "_sip._tcp", + "rrset_href": "https://api.gandi.net/v5/livedns/domains/tomontime.com/records/_sip._tcp/SRV", + "rrset_values": [ + "5 6 7 foo.com.", + "5 60 70 foo2.com.", + "15 65 75 foo3.com." + ] + } + }, + { + "index": 143, + "value": { + "rrset_type": "SRV", + "rrset_ttl": 300, + "rrset_name": "_sip._tcp", + "rrset_href": "https://api.gandi.net/v5/livedns/domains/tomontime.com/records/_sip._tcp/SRV", + "rrset_values": [ + "5 6 7 foo.com.", + "5 60 70 foo2.com." + ] + } + }, + { + "index": 144, + "value": { + "rrset_type": "SRV", + "rrset_ttl": 300, + "rrset_name": "_sip._tcp", + "rrset_href": "https://api.gandi.net/v5/livedns/domains/tomontime.com/records/_sip._tcp/SRV", + "rrset_values": [ + "5 6 7 foo.com." + ] + } + }, + { + "index": 145, + "value": { + "rrset_type": "SRV", + "rrset_ttl": 333, + "rrset_name": "_sip._tcp", + "rrset_href": "https://api.gandi.net/v5/livedns/domains/tomontime.com/records/_sip._tcp/SRV", + "rrset_values": [ + "5 6 7 foo.com." + ] + } + }, + { + "index": 146, + "value": { + "rrset_type": "SRV", + "rrset_ttl": 4400, + "rrset_name": "_sip._tcp", + "rrset_href": "https://api.gandi.net/v5/livedns/domains/tomontime.com/records/_sip._tcp/SRV", + "rrset_values": [ + "5 6 7 foo.com." + ] + } + }, + { + "index": 147, + "value": { + "rrset_type": "SSHFP", + "rrset_ttl": 300, + "rrset_name": "@", + "rrset_href": "https://api.gandi.net/v5/livedns/domains/tomontime.com/records/%40/SSHFP", + "rrset_values": [ + "1 1 66C7D5540B7D75A1FB4C84FEBFA178AD99BDD67C" + ] + } + }, + { + "index": 148, + "value": { + "rrset_type": "SSHFP", + "rrset_ttl": 300, + "rrset_name": "@", + "rrset_href": "https://api.gandi.net/v5/livedns/domains/tomontime.com/records/%40/SSHFP", + "rrset_values": [ + "2 1 66C7D5540B7D75A1FB4C84FEBFA178AD99BDD67C" + ] + } + }, + { + "index": 149, + "value": { + "rrset_type": "SSHFP", + "rrset_ttl": 300, + "rrset_name": "@", + "rrset_href": "https://api.gandi.net/v5/livedns/domains/tomontime.com/records/%40/SSHFP", + "rrset_values": [ + "2 2 745A635BC46A397A5C4F21D437483005BCC40D7511FF15FBFAFE913A081559BC" + ] + } + }, + { + "index": 150, + "value": { + "rrset_type": "SVCB", + "rrset_ttl": 300, + "rrset_name": "@", + "rrset_href": "https://api.gandi.net/v5/livedns/domains/tomontime.com/records/%40/SVCB", + "rrset_values": [ + "0 test.com." + ] + } + }, + { + "index": 151, + "value": { + "rrset_type": "SVCB", + "rrset_ttl": 300, + "rrset_name": "@", + "rrset_href": "https://api.gandi.net/v5/livedns/domains/tomontime.com/records/%40/SVCB", + "rrset_values": [ + "1 test.com. alpn=\"h2\" port=\"99\"" + ] + } + }, + { + "index": 152, + "value": { + "rrset_type": "SVCB", + "rrset_ttl": 300, + "rrset_name": "@", + "rrset_href": "https://api.gandi.net/v5/livedns/domains/tomontime.com/records/%40/SVCB", + "rrset_values": [ + "1 test.com. port=\"80\"" + ] + } + }, + { + "index": 153, + "value": { + "rrset_type": "SVCB", + "rrset_ttl": 300, + "rrset_name": "@", + "rrset_href": "https://api.gandi.net/v5/livedns/domains/tomontime.com/records/%40/SVCB", + "rrset_values": [ + "1 test.com. port=\"99\"" + ] + } + }, + { + "index": 154, + "value": { + "rrset_type": "SVCB", + "rrset_ttl": 300, + "rrset_name": "@", + "rrset_href": "https://api.gandi.net/v5/livedns/domains/tomontime.com/records/%40/SVCB", + "rrset_values": [ + "3 example.com. alpn=\"h2,h3\" port=\"999\" ech=\"some+base64+encoded+value///\"" + ] + } + }, + { + "index": 155, + "value": { + "rrset_type": "SVCB", + "rrset_ttl": 300, + "rrset_name": "@", + "rrset_href": "https://api.gandi.net/v5/livedns/domains/tomontime.com/records/%40/SVCB", + "rrset_values": [ + "3 example.com. alpn=\"h2,h3\" port=\"999\"" + ] + } + }, + { + "index": 156, + "value": { + "rrset_type": "SVCB", + "rrset_ttl": 300, + "rrset_name": "@", + "rrset_href": "https://api.gandi.net/v5/livedns/domains/tomontime.com/records/%40/SVCB", + "rrset_values": [ + "3 example.com. alpn=\"h2\" port=\"80\" ech=\"another+base64+encoded+value\"" + ] + } + }, + { + "index": 157, + "value": { + "rrset_type": "SVCB", + "rrset_ttl": 300, + "rrset_name": "@", + "rrset_href": "https://api.gandi.net/v5/livedns/domains/tomontime.com/records/%40/SVCB", + "rrset_values": [ + "3 example.com. alpn=\"h2\" port=\"80\" ech=\"some+base64+encoded+value///\"" + ] + } + }, + { + "index": 158, + "value": { + "rrset_type": "SVCB", + "rrset_ttl": 300, + "rrset_name": "@", + "rrset_href": "https://api.gandi.net/v5/livedns/domains/tomontime.com/records/%40/SVCB", + "rrset_values": [ + "3 yetanother.com. alpn=\"h2\" port=\"80\" ech=\"another+base64+encoded+value\"" + ] + } + }, + { + "index": 159, + "value": { + "rrset_type": "TLSA", + "rrset_ttl": 300, + "rrset_name": "_443._tcp", + "rrset_href": "https://api.gandi.net/v5/livedns/domains/tomontime.com/records/_443._tcp/TLSA", + "rrset_values": [ + "2 0 1 0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF" + ] + } + }, + { + "index": 160, + "value": { + "rrset_type": "TLSA", + "rrset_ttl": 300, + "rrset_name": "_443._tcp", + "rrset_href": "https://api.gandi.net/v5/livedns/domains/tomontime.com/records/_443._tcp/TLSA", + "rrset_values": [ + "2 0 2 0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF" + ] + } + }, + { + "index": 161, + "value": { + "rrset_type": "TLSA", + "rrset_ttl": 300, + "rrset_name": "_443._tcp", + "rrset_href": "https://api.gandi.net/v5/livedns/domains/tomontime.com/records/_443._tcp/TLSA", + "rrset_values": [ + "2 0 2 FEDCBA9876543210FEDCBA9876543210FEDCBA9876543210FEDCBA9876543210FEDCBA9876543210FEDCBA9876543210FEDCBA9876543210FEDCBA9876543210" + ] + } + }, + { + "index": 162, + "value": { + "rrset_type": "TLSA", + "rrset_ttl": 300, + "rrset_name": "_443._tcp", + "rrset_href": "https://api.gandi.net/v5/livedns/domains/tomontime.com/records/_443._tcp/TLSA", + "rrset_values": [ + "2 1 1 0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF" + ] + } + }, + { + "index": 163, + "value": { + "rrset_type": "TLSA", + "rrset_ttl": 300, + "rrset_name": "_443._tcp", + "rrset_href": "https://api.gandi.net/v5/livedns/domains/tomontime.com/records/_443._tcp/TLSA", + "rrset_values": [ + "3 1 1 0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF" + ] + } + }, + { + "index": 164, + "value": { + "rrset_type": "TXT", + "rrset_ttl": 300, + "rrset_name": "@", + "rrset_href": "https://api.gandi.net/v5/livedns/domains/tomontime.com/records/%40/TXT", + "rrset_values": [ + "\"asimple\"" + ] + } + }, + { + "index": 165, + "value": { + "rrset_type": "TXT", + "rrset_ttl": 300, + "rrset_name": "@", + "rrset_href": "https://api.gandi.net/v5/livedns/domains/tomontime.com/records/%40/TXT", + "rrset_values": [ + "\"simple\"" + ] + } + }, + { + "index": 166, + "value": { + "rrset_type": "TXT", + "rrset_ttl": 300, + "rrset_name": "final", + "rrset_href": "https://api.gandi.net/v5/livedns/domains/tomontime.com/records/final/TXT", + "rrset_values": [ + "\"TestDNSProviders was successful!\"" + ] + } + }, + { + "index": 167, + "value": { + "rrset_type": "TXT", + "rrset_ttl": 300, + "rrset_name": "foo", + "rrset_href": "https://api.gandi.net/v5/livedns/domains/tomontime.com/records/foo/TXT", + "rrset_values": [ + "\"simple\"" + ] + } + }, + { + "index": 168, + "value": { + "rrset_type": "TXT", + "rrset_ttl": 300, + "rrset_name": "foo", + "rrset_href": "https://api.gandi.net/v5/livedns/domains/tomontime.com/records/foo/TXT", + "rrset_values": [ + "\"v=spf1 ip4:99.99.99.99 -all\"" + ] + } + }, + { + "index": 169, + "value": { + "rrset_type": "TXT", + "rrset_ttl": 300, + "rrset_name": "foo.bat", + "rrset_href": "https://api.gandi.net/v5/livedns/domains/tomontime.com/records/foo.bat/TXT", + "rrset_values": [ + "\"simple\"" + ] + } + }, + { + "index": 170, + "value": { + "rrset_type": "TXT", + "rrset_ttl": 300, + "rrset_name": "foo0", + "rrset_href": "https://api.gandi.net/v5/livedns/domains/tomontime.com/records/foo0/TXT", + "rrset_values": [ + "\"\"" + ] + } + }, + { + "index": 171, + "value": { + "rrset_type": "TXT", + "rrset_ttl": 300, + "rrset_name": "foo254", + "rrset_href": "https://api.gandi.net/v5/livedns/domains/tomontime.com/records/foo254/TXT", + "rrset_values": [ + "\"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\"" + ] + } + }, + { + "index": 172, + "value": { + "rrset_type": "TXT", + "rrset_ttl": 300, + "rrset_name": "foo255", + "rrset_href": "https://api.gandi.net/v5/livedns/domains/tomontime.com/records/foo255/TXT", + "rrset_values": [ + "\"BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB\"" + ] + } + }, + { + "index": 173, + "value": { + "rrset_type": "TXT", + "rrset_ttl": 300, + "rrset_name": "foo256", + "rrset_href": "https://api.gandi.net/v5/livedns/domains/tomontime.com/records/foo256/TXT", + "rrset_values": [ + "\"CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC\" \"C\"" + ] + } + }, + { + "index": 174, + "value": { + "rrset_type": "TXT", + "rrset_ttl": 300, + "rrset_name": "foo509", + "rrset_href": "https://api.gandi.net/v5/livedns/domains/tomontime.com/records/foo509/TXT", + "rrset_values": [ + "\"DDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDD\" \"DDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDD\"" + ] + } + }, + { + "index": 175, + "value": { + "rrset_type": "TXT", + "rrset_ttl": 300, + "rrset_name": "foo510", + "rrset_href": "https://api.gandi.net/v5/livedns/domains/tomontime.com/records/foo510/TXT", + "rrset_values": [ + "\"EEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE\" \"EEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE\"" + ] + } + }, + { + "index": 176, + "value": { + "rrset_type": "TXT", + "rrset_ttl": 300, + "rrset_name": "foo511", + "rrset_href": "https://api.gandi.net/v5/livedns/domains/tomontime.com/records/foo511/TXT", + "rrset_values": [ + "\"FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF\" \"FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF\" \"F\"" + ] + } + }, + { + "index": 177, + "value": { + "rrset_type": "TXT", + "rrset_ttl": 300, + "rrset_name": "foo764", + "rrset_href": "https://api.gandi.net/v5/livedns/domains/tomontime.com/records/foo764/TXT", + "rrset_values": [ + "\"GGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGG\" \"GGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGG\" \"GGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGG\"" + ] + } + }, + { + "index": 178, + "value": { + "rrset_type": "TXT", + "rrset_ttl": 300, + "rrset_name": "foo765", + "rrset_href": "https://api.gandi.net/v5/livedns/domains/tomontime.com/records/foo765/TXT", + "rrset_values": [ + "\"HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH\" \"HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH\" \"HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH\"" + ] + } + }, + { + "index": 179, + "value": { + "rrset_type": "TXT", + "rrset_ttl": 300, + "rrset_name": "foo766", + "rrset_href": "https://api.gandi.net/v5/livedns/domains/tomontime.com/records/foo766/TXT", + "rrset_values": [ + "\"JJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJ\" \"JJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJ\" \"JJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJ\" \"J\"" + ] + } + }, + { + "index": 180, + "value": { + "rrset_type": "TXT", + "rrset_ttl": 300, + "rrset_name": "foobt", + "rrset_href": "https://api.gandi.net/v5/livedns/domains/tomontime.com/records/foobt/TXT", + "rrset_values": [ + "\"blah`blah\"" + ] + } + }, + { + "index": 181, + "value": { + "rrset_type": "TXT", + "rrset_ttl": 300, + "rrset_name": "foodq", + "rrset_href": "https://api.gandi.net/v5/livedns/domains/tomontime.com/records/foodq/TXT", + "rrset_values": [ + "\"in\\\"side\"" + ] + } + }, + { + "index": 182, + "value": { + "rrset_type": "TXT", + "rrset_ttl": 300, + "rrset_name": "foodqs", + "rrset_href": "https://api.gandi.net/v5/livedns/domains/tomontime.com/records/foodqs/TXT", + "rrset_values": [ + "\"\\\"left\"" + ] + } + }, + { + "index": 183, + "value": { + "rrset_type": "TXT", + "rrset_ttl": 300, + "rrset_name": "foodqs", + "rrset_href": "https://api.gandi.net/v5/livedns/domains/tomontime.com/records/foodqs/TXT", + "rrset_values": [ + "\"in\\\"ter\\\"ior\"" + ] + } + }, + { + "index": 184, + "value": { + "rrset_type": "TXT", + "rrset_ttl": 300, + "rrset_name": "foodqs", + "rrset_href": "https://api.gandi.net/v5/livedns/domains/tomontime.com/records/foodqs/TXT", + "rrset_values": [ + "\"right\\\"\"" + ] + } + }, + { + "index": 185, + "value": { + "rrset_type": "TXT", + "rrset_ttl": 300, + "rrset_name": "fooosbs1", + "rrset_href": "https://api.gandi.net/v5/livedns/domains/tomontime.com/records/fooosbs1/TXT", + "rrset_values": [ + "\"1back\\\\slash\"" + ] + } + }, + { + "index": 186, + "value": { + "rrset_type": "TXT", + "rrset_ttl": 300, + "rrset_name": "fooosbs2", + "rrset_href": "https://api.gandi.net/v5/livedns/domains/tomontime.com/records/fooosbs2/TXT", + "rrset_values": [ + "\"2back\\\\\\\\slash\"" + ] + } + }, + { + "index": 187, + "value": { + "rrset_type": "TXT", + "rrset_ttl": 300, + "rrset_name": "fooosbs3", + "rrset_href": "https://api.gandi.net/v5/livedns/domains/tomontime.com/records/fooosbs3/TXT", + "rrset_values": [ + "\"3back\\\\\\\\\\\\slash\"" + ] + } + }, + { + "index": 188, + "value": { + "rrset_type": "TXT", + "rrset_ttl": 300, + "rrset_name": "fooosbs4", + "rrset_href": "https://api.gandi.net/v5/livedns/domains/tomontime.com/records/fooosbs4/TXT", + "rrset_values": [ + "\"4back\\\\\\\\\\\\\\\\slash\"" + ] + } + }, + { + "index": 189, + "value": { + "rrset_type": "TXT", + "rrset_ttl": 300, + "rrset_name": "foosc1", + "rrset_href": "https://api.gandi.net/v5/livedns/domains/tomontime.com/records/foosc1/TXT", + "rrset_values": [ + "\"semi;colon\"" + ] + } + }, + { + "index": 190, + "value": { + "rrset_type": "TXT", + "rrset_ttl": 300, + "rrset_name": "foosc2", + "rrset_href": "https://api.gandi.net/v5/livedns/domains/tomontime.com/records/foosc2/TXT", + "rrset_values": [ + "\"wssemi ; colon\"" + ] + } + }, + { + "index": 191, + "value": { + "rrset_type": "TXT", + "rrset_ttl": 300, + "rrset_name": "foosp", + "rrset_href": "https://api.gandi.net/v5/livedns/domains/tomontime.com/records/foosp/TXT", + "rrset_values": [ + "\"with spaces\"" + ] + } + }, + { + "index": 192, + "value": { + "rrset_type": "TXT", + "rrset_ttl": 300, + "rrset_name": "foosq", + "rrset_href": "https://api.gandi.net/v5/livedns/domains/tomontime.com/records/foosq/TXT", + "rrset_values": [ + "\"quo'te\"" + ] + } + }, + { + "index": 193, + "value": { + "rrset_type": "TXT", + "rrset_ttl": 300, + "rrset_name": "foows1", + "rrset_href": "https://api.gandi.net/v5/livedns/domains/tomontime.com/records/foows1/TXT", + "rrset_values": [ + "\"trailingws \"" + ] + } + }, + { + "index": 194, + "value": { + "rrset_type": "TXT", + "rrset_ttl": 300, + "rrset_name": "testtxt", + "rrset_href": "https://api.gandi.net/v5/livedns/domains/tomontime.com/records/testtxt/TXT", + "rrset_values": [ + "\"changed\"" + ] + } + }, + { + "index": 195, + "value": { + "rrset_type": "TXT", + "rrset_ttl": 300, + "rrset_name": "testtxt", + "rrset_href": "https://api.gandi.net/v5/livedns/domains/tomontime.com/records/testtxt/TXT", + "rrset_values": [ + "\"simple\"" + ] + } + } +] diff --git a/providers/gcloud/auditrecords.go b/providers/gcloud/auditrecords.go index 74ebab494b..9ad299f62b 100644 --- a/providers/gcloud/auditrecords.go +++ b/providers/gcloud/auditrecords.go @@ -1,14 +1,14 @@ package gcloud import ( - "github.com/DNSControl/dnscontrol/v4/models" - "github.com/DNSControl/dnscontrol/v4/pkg/rejectif" + "github.com/DNSControl/dnscontrol/v5/models" + "github.com/DNSControl/dnscontrol/v5/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 { +func AuditRecords(records models.Records) []error { a := rejectif.Auditor{} a.Add("ALIAS", rejectif.LabelNotApex) // Last verified 2023-03-24 diff --git a/providers/gcloud/convert_golden_test.go b/providers/gcloud/convert_golden_test.go new file mode 100644 index 0000000000..336fcb4b53 --- /dev/null +++ b/providers/gcloud/convert_golden_test.go @@ -0,0 +1,25 @@ +package gcloud + +import ( + "testing" + + "github.com/DNSControl/dnscontrol/v5/models" + "github.com/DNSControl/dnscontrol/v5/pkg/providergolden" + gdns "google.golang.org/api/dns/v1" +) + +func TestNativeToRecordGolden(t *testing.T) { + providergolden.CheckToRC(t, "nativeToRecord", + func(dc *models.DomainConfig, native gdns.ResourceRecordSet) (models.Records, error) { + // GCLOUD returns every value of a label/rtype pair in one set. + rcs := make(models.Records, 0, len(native.Rrdatas)) + for _, rdata := range native.Rrdatas { + rc, err := nativeToRecord(&native, rdata, dc) + if err != nil { + return nil, err + } + rcs = append(rcs, rc) + } + return rcs, nil + }) +} diff --git a/providers/gcloud/dnssec.go b/providers/gcloud/dnssec.go index 32afeeb7f0..f3f5377633 100644 --- a/providers/gcloud/dnssec.go +++ b/providers/gcloud/dnssec.go @@ -2,18 +2,19 @@ package gcloud import ( "encoding/json" + "errors" "fmt" "strings" "time" - "github.com/DNSControl/dnscontrol/v4/models" + "github.com/DNSControl/dnscontrol/v5/models" gdns "google.golang.org/api/dns/v1" ) func (g *gcloudProvider) getDnssecCorrections(dc *models.DomainConfig) ([]*models.Correction, error) { // Don't allow combining AUTODNSSEC_{ON,OFF} with metadata DnssecConfig if dc.AutoDNSSEC != "" && dc.Metadata["DnssecConfig"] != "" { - return nil, fmt.Errorf("cannot use AUTODNSSEC and DnssecConfig-metadata at the same time") + return nil, errors.New("cannot use AUTODNSSEC and DnssecConfig-metadata at the same time") } if dc.Metadata["DnssecConfig"] != "" { return g.getDnssecCorrectionsFromMetadata(dc) diff --git a/providers/gcloud/gcloudProvider.go b/providers/gcloud/gcloudProvider.go index e99f7435c0..7d723c97e6 100644 --- a/providers/gcloud/gcloudProvider.go +++ b/providers/gcloud/gcloudProvider.go @@ -8,11 +8,10 @@ import ( "regexp" "strings" - "github.com/DNSControl/dnscontrol/v4/models" - "github.com/DNSControl/dnscontrol/v4/pkg/diff2" - "github.com/DNSControl/dnscontrol/v4/pkg/printer" - "github.com/DNSControl/dnscontrol/v4/pkg/providers" - "github.com/DNSControl/dnscontrol/v4/pkg/txtutil" + "github.com/DNSControl/dnscontrol/v5/models" + "github.com/DNSControl/dnscontrol/v5/pkg/diff2" + "github.com/DNSControl/dnscontrol/v5/pkg/printer" + "github.com/DNSControl/dnscontrol/v5/pkg/providers" gauth "golang.org/x/oauth2/google" gdns "google.golang.org/api/dns/v1" "google.golang.org/api/googleapi" @@ -48,11 +47,6 @@ var ( networkNameCheck = regexp.MustCompile("^[a-z]([-a-z0-9]{0,61}[a-z0-9])?$") ) -// //go:fix inline -// func sPtr(s string) *string { -// return new(s) -// } - func init() { const providerName = "GCLOUD" const providerMaintainer = "@riyadhalnur" @@ -100,6 +94,7 @@ func init() { } type gcloudProvider struct { + observer providers.ConversionObserver client *gdns.Service project string nameServerSet *string @@ -109,6 +104,10 @@ type gcloudProvider struct { Networks []string `json:"networks"` } +func (g *gcloudProvider) SetConversionObserver(observer providers.ConversionObserver) { + g.observer = observer +} + type errNoExist struct { domain string } @@ -249,30 +248,33 @@ func keyFor(r *gdns.ResourceRecordSet) key { // GetZoneRecords gets the records of a zone and returns them in RecordConfig format. func (g *gcloudProvider) GetZoneRecords(dc *models.DomainConfig) (models.Records, error) { - domain := dc.Name - - existingRecords, err := g.getZoneSets(domain) + existingRecords, err := g.getZoneSets(dc) return existingRecords, err } -func (g *gcloudProvider) getZoneSets(domain string) (models.Records, error) { +func (g *gcloudProvider) getZoneSets(dc *models.DomainConfig) (models.Records, error) { + domain := dc.Name rrs, err := g.getRecords(domain) if err != nil { return nil, err } // convert to dnscontrol RecordConfig format - existingRecords := []*models.RecordConfig{} + var existingRecords models.Records oldRRs := map[key]*gdns.ResourceRecordSet{} for _, set := range rrs { oldRRs[keyFor(set)] = set + before := providers.BeginToRC(g.observer, "nativeToRecord", set) + var converted models.Records for _, rec := range set.Rrdatas { - rt, err := nativeToRecord(set, rec, domain) + rt, err := nativeToRecord(set, rec, dc) if err != nil { + providers.EndToRC(g.observer, "nativeToRecord", before, set, converted, err) return nil, err } - - existingRecords = append(existingRecords, rt) + converted = append(converted, rt) } + providers.EndToRC(g.observer, "nativeToRecord", before, set, converted, nil) + existingRecords = append(existingRecords, converted...) } return existingRecords, err @@ -370,7 +372,7 @@ func mkRRSs(name, rType string, recs models.Records) *gdns.ResourceRecordSet { } for _, r := range recs { - newRRS.Rrdatas = append(newRRS.Rrdatas, r.GetTargetCombinedFunc(txtutil.EncodeQuoted)) + newRRS.Rrdatas = append(newRRS.Rrdatas, r.GetRDATA().String()) } return newRRS @@ -396,13 +398,8 @@ func wouldOverfill(batch *gdns.Change, adds, dels *gdns.ResourceRecordSet) bool delCount = len(dels.Rrdatas) } - if (len(batch.Additions) + addCount) > batchMax { // Would additions push us over the limit? - return true - } - if (len(batch.Deletions) + delCount) > batchMax { // Would deletions push us over the limit? - return true - } - return false + // Would additions or deletions push us over the limit? + return len(batch.Additions)+addCount > batchMax || len(batch.Deletions)+delCount > batchMax } func (g *gcloudProvider) mkCorrection(corrections []*models.Correction, accumulatedMsgs []string, batch *gdns.Change, origin string) []*models.Correction { @@ -445,16 +442,12 @@ retry: return nil } -func nativeToRecord(set *gdns.ResourceRecordSet, rec, origin string) (*models.RecordConfig, error) { - r := &models.RecordConfig{} - r.SetLabelFromFQDN(set.Name, origin) - r.TTL = uint32(set.Ttl) - rtype := set.Type - r.Original = set - err := r.PopulateFromStringFunc(rtype, rec, origin, txtutil.ParseQuoted) +func nativeToRecord(set *gdns.ResourceRecordSet, rec string, dc *models.DomainConfig) (*models.RecordConfig, error) { + r, err := dc.NewRecordConfigParse(dc.LabelFromFQDNWithDot(set.Name), uint32(set.Ttl), set.Type, rec) if err != nil { - return nil, fmt.Errorf("unparsable record %q received from GCLOUD: %w", rtype, err) + return nil, fmt.Errorf("unparsable record %q received from GCLOUD: %w", set.Type, err) } + r.Original = set return r, nil } diff --git a/providers/gcloud/test_data/expected_torc_output_nativeToRecord_dnscontroltest-gcloud.com.records b/providers/gcloud/test_data/expected_torc_output_nativeToRecord_dnscontroltest-gcloud.com.records new file mode 100644 index 0000000000..b5010e1490 --- /dev/null +++ b/providers/gcloud/test_data/expected_torc_output_nativeToRecord_dnscontroltest-gcloud.com.records @@ -0,0 +1,2734 @@ +1 * 300 IN A 3.3.3.3 +2 4 300 IN PTR bar.com. +3 4 300 IN PTR foo.com. +4 _443._tcp 300 IN TLSA 2 0 1 0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF +5 _443._tcp 300 IN TLSA 2 0 2 0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF +6 _443._tcp 300 IN TLSA 2 0 2 FEDCBA9876543210FEDCBA9876543210FEDCBA9876543210FEDCBA9876543210FEDCBA9876543210FEDCBA9876543210FEDCBA9876543210FEDCBA9876543210 +7 _443._tcp 300 IN TLSA 2 1 1 0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF +8 _443._tcp 300 IN TLSA 3 1 1 0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF +9 _sip._tcp 300 IN SRV 15 65 75 . +10 _sip._tcp 300 IN SRV 15 65 75 foo4.com. +10 _sip._tcp 300 IN SRV 52 6 7 foo.com. +11 _sip._tcp 300 IN SRV 15 65 75 foo4.com. +11 _sip._tcp 300 IN SRV 52 62 7 foo.com. +12 _sip._tcp 300 IN SRV 15 65 75 foo4.com. +12 _sip._tcp 300 IN SRV 52 62 72 foo.com. +13 _sip._tcp 300 IN SRV 5 6 7 foo.com. +13 _sip._tcp 300 IN SRV 15 65 75 foo3.com. +14 _sip._tcp 300 IN SRV 5 6 7 foo.com. +14 _sip._tcp 300 IN SRV 15 65 75 foo4.com. +15 _sip._tcp 300 IN SRV 5 6 7 foo.com. +15 _sip._tcp 300 IN SRV 5 60 70 foo2.com. +15 _sip._tcp 300 IN SRV 15 65 75 foo3.com. +16 _sip._tcp 300 IN SRV 5 6 7 foo.com. +16 _sip._tcp 300 IN SRV 5 60 70 foo2.com. +17 _sip._tcp 300 IN SRV 5 6 7 foo.com. +18 _sip._tcp 333 IN SRV 5 6 7 foo.com. +19 _sip._tcp 4400 IN SRV 5 6 7 foo.com. +20 a 300 IN CNAME xn--ndaaa.com. +21 another-child 300 IN DS 44 13 2 4B9B6B073EDD97FEB5BC12DC4E1B32D2C6AF7AE23A293936CEB87BB10494EC44 +21 another-child 300 IN DS 1501 14 4 109BB6B5B6D5547C1CE03C7A8BD7D8F80C1CB0957F50C4F7FDA04692079917E4F9CAD52B878F3D8234E1A170B154B72D +21 another-child 300 IN DS 1502 8 2 2FA14F53E6B15CAC9AC77846C7BE87862C2A7E9EC0C6CEA319DB939317F126ED +21 another-child 300 IN DS 65535 13 2 2FA14F53E6B15CAC9AC77846C7BE87862C2A7E9EC0C6CEA319DB939317F126ED +22 another-child 300 IN DS 44 13 2 4B9B6B073EDD97FEB5BC12DC4E1B32D2C6AF7AE23A293936CEB87BB10494EC44 +23 bar.bat 300 IN A 5.5.5.5 +24 bar 300 IN A 1.2.3.4 +25 bar 300 IN MX 5 bar.com. +26 bar 300 IN A 5.5.5.5 +27 bar 300 IN CNAME redact2.acm-validations.aws. +28 child 300 IN DS 1 14 4 417212FD1C8BC5896FEFD8DB58AF824545E85B0D0546409366A30AEF7269FAE258173BD185FB262C86F3BB86FBA04368 +29 child 300 IN DS 3 13 2 4B9B6B073EDD97FEB5BC12DC4E1B32D2C6AF7AE23A293936CEB87BB10494EC44 +30 child 300 IN DS 3 14 4 3115238F89E0BF5252D9718113B1B9FFF854608D84BE94EEFB9210DC1CC0B4F3557342A27465CFACC42EF137AE9A5489 +31 child 300 IN DS 3 8 2 4B9B6B073EDD97FEB5BC12DC4E1B32D2C6AF7AE23A293936CEB87BB10494EC44 +32 child 300 IN DS 8857 8 2 4B9B6B073EDD97FEB5BC12DC4E1B32D2C6AF7AE23A293936CEB87BB10494EC44 +33 decoy 300 IN A 1.1.1.1 +34 decoy 300 IN A 2.2.2.2 +35 decoy 300 IN A 3.3.3.3 +36 @ 300 IN MX 0 . +37 @ 300 IN CAA 0 issue "letsencrypt.org; validationmethods=dns-01; accounturi=https://acme-v02.api.letsencrypt.org/acme/acct/1234" +38 @ 300 IN CAA 0 issue "letsencrypt.org" +39 @ 300 IN CAA 0 issuewild ";" +40 @ 300 IN CAA 0 issuewild "example.com" +41 @ 300 IN CAA 0 issuewild "letsencrypt.org" +42 @ 300 IN HTTPS 0 test.com. +43 @ 300 IN SVCB 0 test.com. +44 @ 300 IN SSHFP 1 1 66C7D5540B7D75A1FB4C84FEBFA178AD99BDD67C +45 @ 300 IN HTTPS 1 test.com. alpn="h2" port="99" +46 @ 300 IN SVCB 1 test.com. alpn="h2" port="99" +47 @ 300 IN HTTPS 1 test.com. port="80" +48 @ 300 IN SVCB 1 test.com. port="80" +49 @ 300 IN HTTPS 1 test.com. port="99" +50 @ 300 IN SVCB 1 test.com. port="99" +51 @ 300 IN A 1.2.3.2 +52 @ 300 IN A 1.2.3.4 +52 @ 300 IN A 2.3.4.5 +53 @ 300 IN A 1.2.3.4 +54 @ 300 IN CAA 128 issue "letsencrypt.org" +55 @ 300 IN SSHFP 2 1 66C7D5540B7D75A1FB4C84FEBFA178AD99BDD67C +56 @ 300 IN SSHFP 2 2 745A635BC46A397A5C4F21D437483005BCC40D7511FF15FBFAFE913A081559BC +57 @ 300 IN MX 2 dnscontroltest-gcloud.com. +57 @ 300 IN MX 8 www.dnscontroltest-gcloud.com. +58 @ 300 IN A 2.2.2.2 +59 @ 300 IN HTTPS 3 example.com. alpn="h2,h3" port="999" ech="some+base64+encoded+value///" +60 @ 300 IN SVCB 3 example.com. alpn="h2,h3" port="999" ech="some+base64+encoded+value///" +61 @ 300 IN HTTPS 3 example.com. alpn="h2,h3" port="999" +62 @ 300 IN SVCB 3 example.com. alpn="h2,h3" port="999" +63 @ 300 IN HTTPS 3 example.com. alpn="h2" port="80" ech="another+base64+encoded+value" +64 @ 300 IN SVCB 3 example.com. alpn="h2" port="80" ech="another+base64+encoded+value" +65 @ 300 IN HTTPS 3 example.com. alpn="h2" port="80" ech="some+base64+encoded+value///" +66 @ 300 IN SVCB 3 example.com. alpn="h2" port="80" ech="some+base64+encoded+value///" +67 @ 300 IN HTTPS 3 yetanother.com. alpn="h2" port="80" ech="another+base64+encoded+value" +68 @ 300 IN SVCB 3 yetanother.com. alpn="h2" port="80" ech="another+base64+encoded+value" +69 @ 300 IN A 4.4.4.4 +70 @ 300 IN MX 5 bar.com. +71 @ 300 IN MX 5 foo.com. +72 @ 1000 IN A 8.8.8.8 +73 @ 500 IN A 8.8.8.8 +74 @ 666 IN A 8.8.8.8 +75 @ 300 IN TXT "asimple" +76 @ 300 IN TXT "simple" +77 @ 300 IN ALIAS foo.com. +78 @ 300 IN ALIAS foo.dnscontroltest-gcloud.com. +79 @ 300 IN ALIAS foo2.com. +80 @ 300 IN NS ns-cloud-a1.googledomains.com. +80 @ 300 IN NS ns-cloud-a2.googledomains.com. +80 @ 300 IN NS ns-cloud-a3.googledomains.com. +80 @ 300 IN NS ns-cloud-a4.googledomains.com. +80 @ 300 IN NS ns1.example.com. +80 @ 300 IN NS ns2.example.com. +81 @ 300 IN NS ns-cloud-a1.googledomains.com. +81 @ 300 IN NS ns-cloud-a2.googledomains.com. +81 @ 300 IN NS ns-cloud-a3.googledomains.com. +81 @ 300 IN NS ns-cloud-a4.googledomains.com. +81 @ 300 IN NS ns1.foo.com. +81 @ 300 IN NS ns2.foo.com. +82 @ 300 IN NS ns-cloud-a1.googledomains.com. +82 @ 300 IN NS ns-cloud-a2.googledomains.com. +82 @ 300 IN NS ns-cloud-a3.googledomains.com. +82 @ 300 IN NS ns-cloud-a4.googledomains.com. +82 @ 300 IN NS ns1.foo.com. +83 @ 300 IN NS ns-cloud-a1.googledomains.com. +83 @ 300 IN NS ns-cloud-a2.googledomains.com. +83 @ 300 IN NS ns-cloud-a3.googledomains.com. +83 @ 300 IN NS ns-cloud-a4.googledomains.com. +84 dyndns-city1 300 IN AAAA 2003:dd:d7ff::fe71:ce77 +85 dyndns-city1 300 IN A 91.42.1.1 +86 dyndns-city2 300 IN AAAA 2003:dd:d7ff::fe71:ce78 +87 dyndns-city2 300 IN A 91.42.1.2 +88 final 300 IN TXT "TestDNSProviders was successful!" +89 foo.bat 300 IN A 1.2.3.4 +89 foo.bat 300 IN A 2.3.4.5 +90 foo.bat 300 IN TXT "simple" +91 foo 300 IN A 1.1.1.1 +91 foo 300 IN A 10.10.10.10 +92 foo 300 IN A 1.1.1.1 +92 foo 300 IN A 11.11.11.11 +93 foo 300 IN A 1.1.1.1 +93 foo 300 IN A 12.12.12.12 +94 foo 300 IN A 1.1.1.1 +94 foo 300 IN A 13.13.13.13 +95 foo 300 IN A 1.1.1.1 +95 foo 300 IN A 14.14.14.14 +96 foo 300 IN A 1.2.3.4 +96 foo 300 IN A 2.3.4.5 +97 foo 300 IN A 1.2.3.4 +97 foo 300 IN A 3.4.5.6 +98 foo 300 IN A 1.2.3.4 +99 foo 300 IN MX 10 aspmx.l.google.com. +99 foo 300 IN MX 20 alt1.aspmx.l.google.com. +100 foo 300 IN MX 10 foo.dnscontroltest-gcloud.com. +100 foo 300 IN MX 20 bar.dnscontroltest-gcloud.com. +101 foo 300 IN A 2.3.4.5 +101 foo 300 IN A 3.4.5.6 +102 foo 300 IN A 2.3.4.5 +102 foo 300 IN A 8.8.8.8 +103 foo 300 IN A 2.3.4.5 +104 foo 300 IN AAAA 2003:dd:d7ff::fe71:aaaa +105 foo 300 IN A 4.5.6.7 +106 foo 300 IN MX 5 mx.google.com. +107 foo 300 IN MX 8 dnscontroltest-gcloud.com. +108 foo 300 IN TXT "simple" +109 foo 300 IN TXT "v=spf1 ip4:99.99.99.99 -all" +110 foo 300 IN CNAME dnscontroltest-gcloud.com. +111 foo 300 IN NS dnscontroltest-gcloud.com. +112 foo 300 IN CNAME google.com. +113 foo 300 IN CNAME google2.com. +114 foo 300 IN CNAME redact1.acm-validations.aws. +115 foo0 300 IN TXT "" +116 foo254 300 IN TXT "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" +117 foo255 300 IN TXT "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" +118 foo256 300 IN TXT "CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC" "C" +119 foo509 300 IN TXT "DDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDD" "DDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDD" +120 foo510 300 IN TXT "EEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE" "EEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE" +121 foo511 300 IN TXT "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF" "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF" "F" +122 foo764 300 IN TXT "GGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGG" "GGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGG" "GGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGG" +123 foo765 300 IN TXT "HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH" "HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH" "HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH" +124 foo766 300 IN TXT "JJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJ" "JJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJ" "JJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJ" "J" +125 foobt 300 IN TXT "blah`blah" +126 foodq 300 IN TXT "in\"side" +127 foodqs 300 IN TXT "\"left" +128 foodqs 300 IN TXT "in\"ter\"ior" +129 foodqs 300 IN TXT "right\"" +130 fooosbs1 300 IN TXT "1back\\slash" +131 fooosbs2 300 IN TXT "2back\\\\slash" +132 fooosbs3 300 IN TXT "3back\\\\\\slash" +133 fooosbs4 300 IN TXT "4back\\\\\\\\slash" +134 foosc1 300 IN TXT "semi;colon" +135 foosc2 300 IN TXT "wssemi ; colon" +136 foosp 300 IN TXT "with spaces" +137 foosq 300 IN TXT "quo'te" +138 foows1 300 IN TXT "trailingws " +139 mail.bat 300 IN CNAME ghs.googlehosted.com. +140 mail 300 IN CNAME ghs.googlehosted.com. +141 nmx 300 IN MX 0 . +142 nmx 300 IN A 1.2.3.3 +143 nmx 300 IN MX 3 nmx.dnscontroltest-gcloud.com. +143 nmx 300 IN MX 9 www.dnscontroltest-gcloud.com. +144 pager101-rec0000 300 IN A 1.2.3.4 +145 pager101-rec0001 300 IN A 1.2.3.4 +146 pager101-rec0002 300 IN A 1.2.3.4 +147 pager101-rec0003 300 IN A 1.2.3.4 +148 pager101-rec0004 300 IN A 1.2.3.4 +149 pager101-rec0005 300 IN A 1.2.3.4 +150 pager101-rec0006 300 IN A 1.2.3.4 +151 pager101-rec0007 300 IN A 1.2.3.4 +152 pager101-rec0008 300 IN A 1.2.3.4 +153 pager101-rec0009 300 IN A 1.2.3.4 +154 pager101-rec0010 300 IN A 1.2.3.4 +155 pager101-rec0011 300 IN A 1.2.3.4 +156 pager101-rec0012 300 IN A 1.2.3.4 +157 pager101-rec0013 300 IN A 1.2.3.4 +158 pager101-rec0014 300 IN A 1.2.3.4 +159 pager101-rec0015 300 IN A 1.2.3.4 +160 pager101-rec0016 300 IN A 1.2.3.4 +161 pager101-rec0017 300 IN A 1.2.3.4 +162 pager101-rec0018 300 IN A 1.2.3.4 +163 pager101-rec0019 300 IN A 1.2.3.4 +164 pager101-rec0020 300 IN A 1.2.3.4 +165 pager101-rec0021 300 IN A 1.2.3.4 +166 pager101-rec0022 300 IN A 1.2.3.4 +167 pager101-rec0023 300 IN A 1.2.3.4 +168 pager101-rec0024 300 IN A 1.2.3.4 +169 pager101-rec0025 300 IN A 1.2.3.4 +170 pager101-rec0026 300 IN A 1.2.3.4 +171 pager101-rec0027 300 IN A 1.2.3.4 +172 pager101-rec0028 300 IN A 1.2.3.4 +173 pager101-rec0029 300 IN A 1.2.3.4 +174 pager101-rec0030 300 IN A 1.2.3.4 +175 pager101-rec0031 300 IN A 1.2.3.4 +176 pager101-rec0032 300 IN A 1.2.3.4 +177 pager101-rec0033 300 IN A 1.2.3.4 +178 pager101-rec0034 300 IN A 1.2.3.4 +179 pager101-rec0035 300 IN A 1.2.3.4 +180 pager101-rec0036 300 IN A 1.2.3.4 +181 pager101-rec0037 300 IN A 1.2.3.4 +182 pager101-rec0038 300 IN A 1.2.3.4 +183 pager101-rec0039 300 IN A 1.2.3.4 +184 pager101-rec0040 300 IN A 1.2.3.4 +185 pager101-rec0041 300 IN A 1.2.3.4 +186 pager101-rec0042 300 IN A 1.2.3.4 +187 pager101-rec0043 300 IN A 1.2.3.4 +188 pager101-rec0044 300 IN A 1.2.3.4 +189 pager101-rec0045 300 IN A 1.2.3.4 +190 pager101-rec0046 300 IN A 1.2.3.4 +191 pager101-rec0047 300 IN A 1.2.3.4 +192 pager101-rec0048 300 IN A 1.2.3.4 +193 pager101-rec0049 300 IN A 1.2.3.4 +194 pager101-rec0050 300 IN A 1.2.3.4 +195 pager101-rec0051 300 IN A 1.2.3.4 +196 pager101-rec0052 300 IN A 1.2.3.4 +197 pager101-rec0053 300 IN A 1.2.3.4 +198 pager101-rec0054 300 IN A 1.2.3.4 +199 pager101-rec0055 300 IN A 1.2.3.4 +200 pager101-rec0056 300 IN A 1.2.3.4 +201 pager101-rec0057 300 IN A 1.2.3.4 +202 pager101-rec0058 300 IN A 1.2.3.4 +203 pager101-rec0059 300 IN A 1.2.3.4 +204 pager101-rec0060 300 IN A 1.2.3.4 +205 pager101-rec0061 300 IN A 1.2.3.4 +206 pager101-rec0062 300 IN A 1.2.3.4 +207 pager101-rec0063 300 IN A 1.2.3.4 +208 pager101-rec0064 300 IN A 1.2.3.4 +209 pager101-rec0065 300 IN A 1.2.3.4 +210 pager101-rec0066 300 IN A 1.2.3.4 +211 pager101-rec0067 300 IN A 1.2.3.4 +212 pager101-rec0068 300 IN A 1.2.3.4 +213 pager101-rec0069 300 IN A 1.2.3.4 +214 pager101-rec0070 300 IN A 1.2.3.4 +215 pager101-rec0071 300 IN A 1.2.3.4 +216 pager101-rec0072 300 IN A 1.2.3.4 +217 pager101-rec0073 300 IN A 1.2.3.4 +218 pager101-rec0074 300 IN A 1.2.3.4 +219 pager101-rec0075 300 IN A 1.2.3.4 +220 pager101-rec0076 300 IN A 1.2.3.4 +221 pager101-rec0077 300 IN A 1.2.3.4 +222 pager101-rec0078 300 IN A 1.2.3.4 +223 pager101-rec0079 300 IN A 1.2.3.4 +224 pager101-rec0080 300 IN A 1.2.3.4 +225 pager101-rec0081 300 IN A 1.2.3.4 +226 pager101-rec0082 300 IN A 1.2.3.4 +227 pager101-rec0083 300 IN A 1.2.3.4 +228 pager101-rec0084 300 IN A 1.2.3.4 +229 pager101-rec0085 300 IN A 1.2.3.4 +230 pager101-rec0086 300 IN A 1.2.3.4 +231 pager101-rec0087 300 IN A 1.2.3.4 +232 pager101-rec0088 300 IN A 1.2.3.4 +233 pager101-rec0089 300 IN A 1.2.3.4 +234 pager101-rec0090 300 IN A 1.2.3.4 +235 pager101-rec0091 300 IN A 1.2.3.4 +236 pager101-rec0092 300 IN A 1.2.3.4 +237 pager101-rec0093 300 IN A 1.2.3.4 +238 pager101-rec0094 300 IN A 1.2.3.4 +239 pager101-rec0095 300 IN A 1.2.3.4 +240 pager101-rec0096 300 IN A 1.2.3.4 +241 pager101-rec0097 300 IN A 1.2.3.4 +242 pager101-rec0098 300 IN A 1.2.3.4 +243 pager101-rec0099 300 IN A 1.2.3.4 +244 pager101-rec0100 300 IN A 1.2.3.4 +245 pager1201-rec0000 300 IN A 1.2.3.4 +246 pager1201-rec0000 300 IN A 1.2.3.5 +247 pager1201-rec0001 300 IN A 1.2.3.4 +248 pager1201-rec0001 300 IN A 1.2.3.5 +249 pager1201-rec0002 300 IN A 1.2.3.4 +250 pager1201-rec0002 300 IN A 1.2.3.5 +251 pager1201-rec0003 300 IN A 1.2.3.4 +252 pager1201-rec0003 300 IN A 1.2.3.5 +253 pager1201-rec0004 300 IN A 1.2.3.4 +254 pager1201-rec0004 300 IN A 1.2.3.5 +255 pager1201-rec0005 300 IN A 1.2.3.4 +256 pager1201-rec0005 300 IN A 1.2.3.5 +257 pager1201-rec0006 300 IN A 1.2.3.4 +258 pager1201-rec0006 300 IN A 1.2.3.5 +259 pager1201-rec0007 300 IN A 1.2.3.4 +260 pager1201-rec0007 300 IN A 1.2.3.5 +261 pager1201-rec0008 300 IN A 1.2.3.4 +262 pager1201-rec0008 300 IN A 1.2.3.5 +263 pager1201-rec0009 300 IN A 1.2.3.4 +264 pager1201-rec0009 300 IN A 1.2.3.5 +265 pager1201-rec0010 300 IN A 1.2.3.4 +266 pager1201-rec0010 300 IN A 1.2.3.5 +267 pager1201-rec0011 300 IN A 1.2.3.4 +268 pager1201-rec0011 300 IN A 1.2.3.5 +269 pager1201-rec0012 300 IN A 1.2.3.4 +270 pager1201-rec0012 300 IN A 1.2.3.5 +271 pager1201-rec0013 300 IN A 1.2.3.4 +272 pager1201-rec0013 300 IN A 1.2.3.5 +273 pager1201-rec0014 300 IN A 1.2.3.4 +274 pager1201-rec0014 300 IN A 1.2.3.5 +275 pager1201-rec0015 300 IN A 1.2.3.4 +276 pager1201-rec0015 300 IN A 1.2.3.5 +277 pager1201-rec0016 300 IN A 1.2.3.4 +278 pager1201-rec0016 300 IN A 1.2.3.5 +279 pager1201-rec0017 300 IN A 1.2.3.4 +280 pager1201-rec0017 300 IN A 1.2.3.5 +281 pager1201-rec0018 300 IN A 1.2.3.4 +282 pager1201-rec0018 300 IN A 1.2.3.5 +283 pager1201-rec0019 300 IN A 1.2.3.4 +284 pager1201-rec0019 300 IN A 1.2.3.5 +285 pager1201-rec0020 300 IN A 1.2.3.4 +286 pager1201-rec0020 300 IN A 1.2.3.5 +287 pager1201-rec0021 300 IN A 1.2.3.4 +288 pager1201-rec0021 300 IN A 1.2.3.5 +289 pager1201-rec0022 300 IN A 1.2.3.4 +290 pager1201-rec0022 300 IN A 1.2.3.5 +291 pager1201-rec0023 300 IN A 1.2.3.4 +292 pager1201-rec0023 300 IN A 1.2.3.5 +293 pager1201-rec0024 300 IN A 1.2.3.4 +294 pager1201-rec0024 300 IN A 1.2.3.5 +295 pager1201-rec0025 300 IN A 1.2.3.4 +296 pager1201-rec0025 300 IN A 1.2.3.5 +297 pager1201-rec0026 300 IN A 1.2.3.4 +298 pager1201-rec0026 300 IN A 1.2.3.5 +299 pager1201-rec0027 300 IN A 1.2.3.4 +300 pager1201-rec0027 300 IN A 1.2.3.5 +301 pager1201-rec0028 300 IN A 1.2.3.4 +302 pager1201-rec0028 300 IN A 1.2.3.5 +303 pager1201-rec0029 300 IN A 1.2.3.4 +304 pager1201-rec0029 300 IN A 1.2.3.5 +305 pager1201-rec0030 300 IN A 1.2.3.4 +306 pager1201-rec0030 300 IN A 1.2.3.5 +307 pager1201-rec0031 300 IN A 1.2.3.4 +308 pager1201-rec0031 300 IN A 1.2.3.5 +309 pager1201-rec0032 300 IN A 1.2.3.4 +310 pager1201-rec0032 300 IN A 1.2.3.5 +311 pager1201-rec0033 300 IN A 1.2.3.4 +312 pager1201-rec0033 300 IN A 1.2.3.5 +313 pager1201-rec0034 300 IN A 1.2.3.4 +314 pager1201-rec0034 300 IN A 1.2.3.5 +315 pager1201-rec0035 300 IN A 1.2.3.4 +316 pager1201-rec0035 300 IN A 1.2.3.5 +317 pager1201-rec0036 300 IN A 1.2.3.4 +318 pager1201-rec0036 300 IN A 1.2.3.5 +319 pager1201-rec0037 300 IN A 1.2.3.4 +320 pager1201-rec0037 300 IN A 1.2.3.5 +321 pager1201-rec0038 300 IN A 1.2.3.4 +322 pager1201-rec0038 300 IN A 1.2.3.5 +323 pager1201-rec0039 300 IN A 1.2.3.4 +324 pager1201-rec0039 300 IN A 1.2.3.5 +325 pager1201-rec0040 300 IN A 1.2.3.4 +326 pager1201-rec0040 300 IN A 1.2.3.5 +327 pager1201-rec0041 300 IN A 1.2.3.4 +328 pager1201-rec0041 300 IN A 1.2.3.5 +329 pager1201-rec0042 300 IN A 1.2.3.4 +330 pager1201-rec0042 300 IN A 1.2.3.5 +331 pager1201-rec0043 300 IN A 1.2.3.4 +332 pager1201-rec0043 300 IN A 1.2.3.5 +333 pager1201-rec0044 300 IN A 1.2.3.4 +334 pager1201-rec0044 300 IN A 1.2.3.5 +335 pager1201-rec0045 300 IN A 1.2.3.4 +336 pager1201-rec0045 300 IN A 1.2.3.5 +337 pager1201-rec0046 300 IN A 1.2.3.4 +338 pager1201-rec0046 300 IN A 1.2.3.5 +339 pager1201-rec0047 300 IN A 1.2.3.4 +340 pager1201-rec0047 300 IN A 1.2.3.5 +341 pager1201-rec0048 300 IN A 1.2.3.4 +342 pager1201-rec0048 300 IN A 1.2.3.5 +343 pager1201-rec0049 300 IN A 1.2.3.4 +344 pager1201-rec0049 300 IN A 1.2.3.5 +345 pager1201-rec0050 300 IN A 1.2.3.4 +346 pager1201-rec0050 300 IN A 1.2.3.5 +347 pager1201-rec0051 300 IN A 1.2.3.4 +348 pager1201-rec0051 300 IN A 1.2.3.5 +349 pager1201-rec0052 300 IN A 1.2.3.4 +350 pager1201-rec0052 300 IN A 1.2.3.5 +351 pager1201-rec0053 300 IN A 1.2.3.4 +352 pager1201-rec0053 300 IN A 1.2.3.5 +353 pager1201-rec0054 300 IN A 1.2.3.4 +354 pager1201-rec0054 300 IN A 1.2.3.5 +355 pager1201-rec0055 300 IN A 1.2.3.4 +356 pager1201-rec0055 300 IN A 1.2.3.5 +357 pager1201-rec0056 300 IN A 1.2.3.4 +358 pager1201-rec0056 300 IN A 1.2.3.5 +359 pager1201-rec0057 300 IN A 1.2.3.4 +360 pager1201-rec0057 300 IN A 1.2.3.5 +361 pager1201-rec0058 300 IN A 1.2.3.4 +362 pager1201-rec0058 300 IN A 1.2.3.5 +363 pager1201-rec0059 300 IN A 1.2.3.4 +364 pager1201-rec0059 300 IN A 1.2.3.5 +365 pager1201-rec0060 300 IN A 1.2.3.4 +366 pager1201-rec0060 300 IN A 1.2.3.5 +367 pager1201-rec0061 300 IN A 1.2.3.4 +368 pager1201-rec0061 300 IN A 1.2.3.5 +369 pager1201-rec0062 300 IN A 1.2.3.4 +370 pager1201-rec0062 300 IN A 1.2.3.5 +371 pager1201-rec0063 300 IN A 1.2.3.4 +372 pager1201-rec0063 300 IN A 1.2.3.5 +373 pager1201-rec0064 300 IN A 1.2.3.4 +374 pager1201-rec0064 300 IN A 1.2.3.5 +375 pager1201-rec0065 300 IN A 1.2.3.4 +376 pager1201-rec0065 300 IN A 1.2.3.5 +377 pager1201-rec0066 300 IN A 1.2.3.4 +378 pager1201-rec0066 300 IN A 1.2.3.5 +379 pager1201-rec0067 300 IN A 1.2.3.4 +380 pager1201-rec0067 300 IN A 1.2.3.5 +381 pager1201-rec0068 300 IN A 1.2.3.4 +382 pager1201-rec0068 300 IN A 1.2.3.5 +383 pager1201-rec0069 300 IN A 1.2.3.4 +384 pager1201-rec0069 300 IN A 1.2.3.5 +385 pager1201-rec0070 300 IN A 1.2.3.4 +386 pager1201-rec0070 300 IN A 1.2.3.5 +387 pager1201-rec0071 300 IN A 1.2.3.4 +388 pager1201-rec0071 300 IN A 1.2.3.5 +389 pager1201-rec0072 300 IN A 1.2.3.4 +390 pager1201-rec0072 300 IN A 1.2.3.5 +391 pager1201-rec0073 300 IN A 1.2.3.4 +392 pager1201-rec0073 300 IN A 1.2.3.5 +393 pager1201-rec0074 300 IN A 1.2.3.4 +394 pager1201-rec0074 300 IN A 1.2.3.5 +395 pager1201-rec0075 300 IN A 1.2.3.4 +396 pager1201-rec0075 300 IN A 1.2.3.5 +397 pager1201-rec0076 300 IN A 1.2.3.4 +398 pager1201-rec0076 300 IN A 1.2.3.5 +399 pager1201-rec0077 300 IN A 1.2.3.4 +400 pager1201-rec0077 300 IN A 1.2.3.5 +401 pager1201-rec0078 300 IN A 1.2.3.4 +402 pager1201-rec0078 300 IN A 1.2.3.5 +403 pager1201-rec0079 300 IN A 1.2.3.4 +404 pager1201-rec0079 300 IN A 1.2.3.5 +405 pager1201-rec0080 300 IN A 1.2.3.4 +406 pager1201-rec0080 300 IN A 1.2.3.5 +407 pager1201-rec0081 300 IN A 1.2.3.4 +408 pager1201-rec0081 300 IN A 1.2.3.5 +409 pager1201-rec0082 300 IN A 1.2.3.4 +410 pager1201-rec0082 300 IN A 1.2.3.5 +411 pager1201-rec0083 300 IN A 1.2.3.4 +412 pager1201-rec0083 300 IN A 1.2.3.5 +413 pager1201-rec0084 300 IN A 1.2.3.4 +414 pager1201-rec0084 300 IN A 1.2.3.5 +415 pager1201-rec0085 300 IN A 1.2.3.4 +416 pager1201-rec0085 300 IN A 1.2.3.5 +417 pager1201-rec0086 300 IN A 1.2.3.4 +418 pager1201-rec0086 300 IN A 1.2.3.5 +419 pager1201-rec0087 300 IN A 1.2.3.4 +420 pager1201-rec0087 300 IN A 1.2.3.5 +421 pager1201-rec0088 300 IN A 1.2.3.4 +422 pager1201-rec0088 300 IN A 1.2.3.5 +423 pager1201-rec0089 300 IN A 1.2.3.4 +424 pager1201-rec0089 300 IN A 1.2.3.5 +425 pager1201-rec0090 300 IN A 1.2.3.4 +426 pager1201-rec0090 300 IN A 1.2.3.5 +427 pager1201-rec0091 300 IN A 1.2.3.4 +428 pager1201-rec0091 300 IN A 1.2.3.5 +429 pager1201-rec0092 300 IN A 1.2.3.4 +430 pager1201-rec0092 300 IN A 1.2.3.5 +431 pager1201-rec0093 300 IN A 1.2.3.4 +432 pager1201-rec0093 300 IN A 1.2.3.5 +433 pager1201-rec0094 300 IN A 1.2.3.4 +434 pager1201-rec0094 300 IN A 1.2.3.5 +435 pager1201-rec0095 300 IN A 1.2.3.4 +436 pager1201-rec0095 300 IN A 1.2.3.5 +437 pager1201-rec0096 300 IN A 1.2.3.4 +438 pager1201-rec0096 300 IN A 1.2.3.5 +439 pager1201-rec0097 300 IN A 1.2.3.4 +440 pager1201-rec0097 300 IN A 1.2.3.5 +441 pager1201-rec0098 300 IN A 1.2.3.4 +442 pager1201-rec0098 300 IN A 1.2.3.5 +443 pager1201-rec0099 300 IN A 1.2.3.4 +444 pager1201-rec0099 300 IN A 1.2.3.5 +445 pager1201-rec0100 300 IN A 1.2.3.4 +446 pager1201-rec0100 300 IN A 1.2.3.5 +447 pager1201-rec0101 300 IN A 1.2.3.4 +448 pager1201-rec0101 300 IN A 1.2.3.5 +449 pager1201-rec0102 300 IN A 1.2.3.4 +450 pager1201-rec0102 300 IN A 1.2.3.5 +451 pager1201-rec0103 300 IN A 1.2.3.4 +452 pager1201-rec0103 300 IN A 1.2.3.5 +453 pager1201-rec0104 300 IN A 1.2.3.4 +454 pager1201-rec0104 300 IN A 1.2.3.5 +455 pager1201-rec0105 300 IN A 1.2.3.4 +456 pager1201-rec0105 300 IN A 1.2.3.5 +457 pager1201-rec0106 300 IN A 1.2.3.4 +458 pager1201-rec0106 300 IN A 1.2.3.5 +459 pager1201-rec0107 300 IN A 1.2.3.4 +460 pager1201-rec0107 300 IN A 1.2.3.5 +461 pager1201-rec0108 300 IN A 1.2.3.4 +462 pager1201-rec0108 300 IN A 1.2.3.5 +463 pager1201-rec0109 300 IN A 1.2.3.4 +464 pager1201-rec0109 300 IN A 1.2.3.5 +465 pager1201-rec0110 300 IN A 1.2.3.4 +466 pager1201-rec0110 300 IN A 1.2.3.5 +467 pager1201-rec0111 300 IN A 1.2.3.4 +468 pager1201-rec0111 300 IN A 1.2.3.5 +469 pager1201-rec0112 300 IN A 1.2.3.4 +470 pager1201-rec0112 300 IN A 1.2.3.5 +471 pager1201-rec0113 300 IN A 1.2.3.4 +472 pager1201-rec0113 300 IN A 1.2.3.5 +473 pager1201-rec0114 300 IN A 1.2.3.4 +474 pager1201-rec0114 300 IN A 1.2.3.5 +475 pager1201-rec0115 300 IN A 1.2.3.4 +476 pager1201-rec0115 300 IN A 1.2.3.5 +477 pager1201-rec0116 300 IN A 1.2.3.4 +478 pager1201-rec0116 300 IN A 1.2.3.5 +479 pager1201-rec0117 300 IN A 1.2.3.4 +480 pager1201-rec0117 300 IN A 1.2.3.5 +481 pager1201-rec0118 300 IN A 1.2.3.4 +482 pager1201-rec0118 300 IN A 1.2.3.5 +483 pager1201-rec0119 300 IN A 1.2.3.4 +484 pager1201-rec0119 300 IN A 1.2.3.5 +485 pager1201-rec0120 300 IN A 1.2.3.4 +486 pager1201-rec0120 300 IN A 1.2.3.5 +487 pager1201-rec0121 300 IN A 1.2.3.4 +488 pager1201-rec0121 300 IN A 1.2.3.5 +489 pager1201-rec0122 300 IN A 1.2.3.4 +490 pager1201-rec0122 300 IN A 1.2.3.5 +491 pager1201-rec0123 300 IN A 1.2.3.4 +492 pager1201-rec0123 300 IN A 1.2.3.5 +493 pager1201-rec0124 300 IN A 1.2.3.4 +494 pager1201-rec0124 300 IN A 1.2.3.5 +495 pager1201-rec0125 300 IN A 1.2.3.4 +496 pager1201-rec0125 300 IN A 1.2.3.5 +497 pager1201-rec0126 300 IN A 1.2.3.4 +498 pager1201-rec0126 300 IN A 1.2.3.5 +499 pager1201-rec0127 300 IN A 1.2.3.4 +500 pager1201-rec0127 300 IN A 1.2.3.5 +501 pager1201-rec0128 300 IN A 1.2.3.4 +502 pager1201-rec0128 300 IN A 1.2.3.5 +503 pager1201-rec0129 300 IN A 1.2.3.4 +504 pager1201-rec0129 300 IN A 1.2.3.5 +505 pager1201-rec0130 300 IN A 1.2.3.4 +506 pager1201-rec0130 300 IN A 1.2.3.5 +507 pager1201-rec0131 300 IN A 1.2.3.4 +508 pager1201-rec0131 300 IN A 1.2.3.5 +509 pager1201-rec0132 300 IN A 1.2.3.4 +510 pager1201-rec0132 300 IN A 1.2.3.5 +511 pager1201-rec0133 300 IN A 1.2.3.4 +512 pager1201-rec0133 300 IN A 1.2.3.5 +513 pager1201-rec0134 300 IN A 1.2.3.4 +514 pager1201-rec0134 300 IN A 1.2.3.5 +515 pager1201-rec0135 300 IN A 1.2.3.4 +516 pager1201-rec0135 300 IN A 1.2.3.5 +517 pager1201-rec0136 300 IN A 1.2.3.4 +518 pager1201-rec0136 300 IN A 1.2.3.5 +519 pager1201-rec0137 300 IN A 1.2.3.4 +520 pager1201-rec0137 300 IN A 1.2.3.5 +521 pager1201-rec0138 300 IN A 1.2.3.4 +522 pager1201-rec0138 300 IN A 1.2.3.5 +523 pager1201-rec0139 300 IN A 1.2.3.4 +524 pager1201-rec0139 300 IN A 1.2.3.5 +525 pager1201-rec0140 300 IN A 1.2.3.4 +526 pager1201-rec0140 300 IN A 1.2.3.5 +527 pager1201-rec0141 300 IN A 1.2.3.4 +528 pager1201-rec0141 300 IN A 1.2.3.5 +529 pager1201-rec0142 300 IN A 1.2.3.4 +530 pager1201-rec0142 300 IN A 1.2.3.5 +531 pager1201-rec0143 300 IN A 1.2.3.4 +532 pager1201-rec0143 300 IN A 1.2.3.5 +533 pager1201-rec0144 300 IN A 1.2.3.4 +534 pager1201-rec0144 300 IN A 1.2.3.5 +535 pager1201-rec0145 300 IN A 1.2.3.4 +536 pager1201-rec0145 300 IN A 1.2.3.5 +537 pager1201-rec0146 300 IN A 1.2.3.4 +538 pager1201-rec0146 300 IN A 1.2.3.5 +539 pager1201-rec0147 300 IN A 1.2.3.4 +540 pager1201-rec0147 300 IN A 1.2.3.5 +541 pager1201-rec0148 300 IN A 1.2.3.4 +542 pager1201-rec0148 300 IN A 1.2.3.5 +543 pager1201-rec0149 300 IN A 1.2.3.4 +544 pager1201-rec0149 300 IN A 1.2.3.5 +545 pager1201-rec0150 300 IN A 1.2.3.4 +546 pager1201-rec0150 300 IN A 1.2.3.5 +547 pager1201-rec0151 300 IN A 1.2.3.4 +548 pager1201-rec0151 300 IN A 1.2.3.5 +549 pager1201-rec0152 300 IN A 1.2.3.4 +550 pager1201-rec0152 300 IN A 1.2.3.5 +551 pager1201-rec0153 300 IN A 1.2.3.4 +552 pager1201-rec0153 300 IN A 1.2.3.5 +553 pager1201-rec0154 300 IN A 1.2.3.4 +554 pager1201-rec0154 300 IN A 1.2.3.5 +555 pager1201-rec0155 300 IN A 1.2.3.4 +556 pager1201-rec0155 300 IN A 1.2.3.5 +557 pager1201-rec0156 300 IN A 1.2.3.4 +558 pager1201-rec0156 300 IN A 1.2.3.5 +559 pager1201-rec0157 300 IN A 1.2.3.4 +560 pager1201-rec0157 300 IN A 1.2.3.5 +561 pager1201-rec0158 300 IN A 1.2.3.4 +562 pager1201-rec0158 300 IN A 1.2.3.5 +563 pager1201-rec0159 300 IN A 1.2.3.4 +564 pager1201-rec0159 300 IN A 1.2.3.5 +565 pager1201-rec0160 300 IN A 1.2.3.4 +566 pager1201-rec0160 300 IN A 1.2.3.5 +567 pager1201-rec0161 300 IN A 1.2.3.4 +568 pager1201-rec0161 300 IN A 1.2.3.5 +569 pager1201-rec0162 300 IN A 1.2.3.4 +570 pager1201-rec0162 300 IN A 1.2.3.5 +571 pager1201-rec0163 300 IN A 1.2.3.4 +572 pager1201-rec0163 300 IN A 1.2.3.5 +573 pager1201-rec0164 300 IN A 1.2.3.4 +574 pager1201-rec0164 300 IN A 1.2.3.5 +575 pager1201-rec0165 300 IN A 1.2.3.4 +576 pager1201-rec0165 300 IN A 1.2.3.5 +577 pager1201-rec0166 300 IN A 1.2.3.4 +578 pager1201-rec0166 300 IN A 1.2.3.5 +579 pager1201-rec0167 300 IN A 1.2.3.4 +580 pager1201-rec0167 300 IN A 1.2.3.5 +581 pager1201-rec0168 300 IN A 1.2.3.4 +582 pager1201-rec0168 300 IN A 1.2.3.5 +583 pager1201-rec0169 300 IN A 1.2.3.4 +584 pager1201-rec0169 300 IN A 1.2.3.5 +585 pager1201-rec0170 300 IN A 1.2.3.4 +586 pager1201-rec0170 300 IN A 1.2.3.5 +587 pager1201-rec0171 300 IN A 1.2.3.4 +588 pager1201-rec0171 300 IN A 1.2.3.5 +589 pager1201-rec0172 300 IN A 1.2.3.4 +590 pager1201-rec0172 300 IN A 1.2.3.5 +591 pager1201-rec0173 300 IN A 1.2.3.4 +592 pager1201-rec0173 300 IN A 1.2.3.5 +593 pager1201-rec0174 300 IN A 1.2.3.4 +594 pager1201-rec0174 300 IN A 1.2.3.5 +595 pager1201-rec0175 300 IN A 1.2.3.4 +596 pager1201-rec0175 300 IN A 1.2.3.5 +597 pager1201-rec0176 300 IN A 1.2.3.4 +598 pager1201-rec0176 300 IN A 1.2.3.5 +599 pager1201-rec0177 300 IN A 1.2.3.4 +600 pager1201-rec0177 300 IN A 1.2.3.5 +601 pager1201-rec0178 300 IN A 1.2.3.4 +602 pager1201-rec0178 300 IN A 1.2.3.5 +603 pager1201-rec0179 300 IN A 1.2.3.4 +604 pager1201-rec0179 300 IN A 1.2.3.5 +605 pager1201-rec0180 300 IN A 1.2.3.4 +606 pager1201-rec0180 300 IN A 1.2.3.5 +607 pager1201-rec0181 300 IN A 1.2.3.4 +608 pager1201-rec0181 300 IN A 1.2.3.5 +609 pager1201-rec0182 300 IN A 1.2.3.4 +610 pager1201-rec0182 300 IN A 1.2.3.5 +611 pager1201-rec0183 300 IN A 1.2.3.4 +612 pager1201-rec0183 300 IN A 1.2.3.5 +613 pager1201-rec0184 300 IN A 1.2.3.4 +614 pager1201-rec0184 300 IN A 1.2.3.5 +615 pager1201-rec0185 300 IN A 1.2.3.4 +616 pager1201-rec0185 300 IN A 1.2.3.5 +617 pager1201-rec0186 300 IN A 1.2.3.4 +618 pager1201-rec0186 300 IN A 1.2.3.5 +619 pager1201-rec0187 300 IN A 1.2.3.4 +620 pager1201-rec0187 300 IN A 1.2.3.5 +621 pager1201-rec0188 300 IN A 1.2.3.4 +622 pager1201-rec0188 300 IN A 1.2.3.5 +623 pager1201-rec0189 300 IN A 1.2.3.4 +624 pager1201-rec0189 300 IN A 1.2.3.5 +625 pager1201-rec0190 300 IN A 1.2.3.4 +626 pager1201-rec0190 300 IN A 1.2.3.5 +627 pager1201-rec0191 300 IN A 1.2.3.4 +628 pager1201-rec0191 300 IN A 1.2.3.5 +629 pager1201-rec0192 300 IN A 1.2.3.4 +630 pager1201-rec0192 300 IN A 1.2.3.5 +631 pager1201-rec0193 300 IN A 1.2.3.4 +632 pager1201-rec0193 300 IN A 1.2.3.5 +633 pager1201-rec0194 300 IN A 1.2.3.4 +634 pager1201-rec0194 300 IN A 1.2.3.5 +635 pager1201-rec0195 300 IN A 1.2.3.4 +636 pager1201-rec0195 300 IN A 1.2.3.5 +637 pager1201-rec0196 300 IN A 1.2.3.4 +638 pager1201-rec0196 300 IN A 1.2.3.5 +639 pager1201-rec0197 300 IN A 1.2.3.4 +640 pager1201-rec0197 300 IN A 1.2.3.5 +641 pager1201-rec0198 300 IN A 1.2.3.4 +642 pager1201-rec0198 300 IN A 1.2.3.5 +643 pager1201-rec0199 300 IN A 1.2.3.4 +644 pager1201-rec0199 300 IN A 1.2.3.5 +645 pager1201-rec0200 300 IN A 1.2.3.4 +646 pager1201-rec0200 300 IN A 1.2.3.5 +647 pager1201-rec0201 300 IN A 1.2.3.4 +648 pager1201-rec0201 300 IN A 1.2.3.5 +649 pager1201-rec0202 300 IN A 1.2.3.4 +650 pager1201-rec0202 300 IN A 1.2.3.5 +651 pager1201-rec0203 300 IN A 1.2.3.4 +652 pager1201-rec0203 300 IN A 1.2.3.5 +653 pager1201-rec0204 300 IN A 1.2.3.4 +654 pager1201-rec0204 300 IN A 1.2.3.5 +655 pager1201-rec0205 300 IN A 1.2.3.4 +656 pager1201-rec0205 300 IN A 1.2.3.5 +657 pager1201-rec0206 300 IN A 1.2.3.4 +658 pager1201-rec0206 300 IN A 1.2.3.5 +659 pager1201-rec0207 300 IN A 1.2.3.4 +660 pager1201-rec0207 300 IN A 1.2.3.5 +661 pager1201-rec0208 300 IN A 1.2.3.4 +662 pager1201-rec0208 300 IN A 1.2.3.5 +663 pager1201-rec0209 300 IN A 1.2.3.4 +664 pager1201-rec0209 300 IN A 1.2.3.5 +665 pager1201-rec0210 300 IN A 1.2.3.4 +666 pager1201-rec0210 300 IN A 1.2.3.5 +667 pager1201-rec0211 300 IN A 1.2.3.4 +668 pager1201-rec0211 300 IN A 1.2.3.5 +669 pager1201-rec0212 300 IN A 1.2.3.4 +670 pager1201-rec0212 300 IN A 1.2.3.5 +671 pager1201-rec0213 300 IN A 1.2.3.4 +672 pager1201-rec0213 300 IN A 1.2.3.5 +673 pager1201-rec0214 300 IN A 1.2.3.4 +674 pager1201-rec0214 300 IN A 1.2.3.5 +675 pager1201-rec0215 300 IN A 1.2.3.4 +676 pager1201-rec0215 300 IN A 1.2.3.5 +677 pager1201-rec0216 300 IN A 1.2.3.4 +678 pager1201-rec0216 300 IN A 1.2.3.5 +679 pager1201-rec0217 300 IN A 1.2.3.4 +680 pager1201-rec0217 300 IN A 1.2.3.5 +681 pager1201-rec0218 300 IN A 1.2.3.4 +682 pager1201-rec0218 300 IN A 1.2.3.5 +683 pager1201-rec0219 300 IN A 1.2.3.4 +684 pager1201-rec0219 300 IN A 1.2.3.5 +685 pager1201-rec0220 300 IN A 1.2.3.4 +686 pager1201-rec0220 300 IN A 1.2.3.5 +687 pager1201-rec0221 300 IN A 1.2.3.4 +688 pager1201-rec0221 300 IN A 1.2.3.5 +689 pager1201-rec0222 300 IN A 1.2.3.4 +690 pager1201-rec0222 300 IN A 1.2.3.5 +691 pager1201-rec0223 300 IN A 1.2.3.4 +692 pager1201-rec0223 300 IN A 1.2.3.5 +693 pager1201-rec0224 300 IN A 1.2.3.4 +694 pager1201-rec0224 300 IN A 1.2.3.5 +695 pager1201-rec0225 300 IN A 1.2.3.4 +696 pager1201-rec0225 300 IN A 1.2.3.5 +697 pager1201-rec0226 300 IN A 1.2.3.4 +698 pager1201-rec0226 300 IN A 1.2.3.5 +699 pager1201-rec0227 300 IN A 1.2.3.4 +700 pager1201-rec0227 300 IN A 1.2.3.5 +701 pager1201-rec0228 300 IN A 1.2.3.4 +702 pager1201-rec0228 300 IN A 1.2.3.5 +703 pager1201-rec0229 300 IN A 1.2.3.4 +704 pager1201-rec0229 300 IN A 1.2.3.5 +705 pager1201-rec0230 300 IN A 1.2.3.4 +706 pager1201-rec0230 300 IN A 1.2.3.5 +707 pager1201-rec0231 300 IN A 1.2.3.4 +708 pager1201-rec0231 300 IN A 1.2.3.5 +709 pager1201-rec0232 300 IN A 1.2.3.4 +710 pager1201-rec0232 300 IN A 1.2.3.5 +711 pager1201-rec0233 300 IN A 1.2.3.4 +712 pager1201-rec0233 300 IN A 1.2.3.5 +713 pager1201-rec0234 300 IN A 1.2.3.4 +714 pager1201-rec0234 300 IN A 1.2.3.5 +715 pager1201-rec0235 300 IN A 1.2.3.4 +716 pager1201-rec0235 300 IN A 1.2.3.5 +717 pager1201-rec0236 300 IN A 1.2.3.4 +718 pager1201-rec0236 300 IN A 1.2.3.5 +719 pager1201-rec0237 300 IN A 1.2.3.4 +720 pager1201-rec0237 300 IN A 1.2.3.5 +721 pager1201-rec0238 300 IN A 1.2.3.4 +722 pager1201-rec0238 300 IN A 1.2.3.5 +723 pager1201-rec0239 300 IN A 1.2.3.4 +724 pager1201-rec0239 300 IN A 1.2.3.5 +725 pager1201-rec0240 300 IN A 1.2.3.4 +726 pager1201-rec0240 300 IN A 1.2.3.5 +727 pager1201-rec0241 300 IN A 1.2.3.4 +728 pager1201-rec0241 300 IN A 1.2.3.5 +729 pager1201-rec0242 300 IN A 1.2.3.4 +730 pager1201-rec0242 300 IN A 1.2.3.5 +731 pager1201-rec0243 300 IN A 1.2.3.4 +732 pager1201-rec0243 300 IN A 1.2.3.5 +733 pager1201-rec0244 300 IN A 1.2.3.4 +734 pager1201-rec0244 300 IN A 1.2.3.5 +735 pager1201-rec0245 300 IN A 1.2.3.4 +736 pager1201-rec0245 300 IN A 1.2.3.5 +737 pager1201-rec0246 300 IN A 1.2.3.4 +738 pager1201-rec0246 300 IN A 1.2.3.5 +739 pager1201-rec0247 300 IN A 1.2.3.4 +740 pager1201-rec0247 300 IN A 1.2.3.5 +741 pager1201-rec0248 300 IN A 1.2.3.4 +742 pager1201-rec0248 300 IN A 1.2.3.5 +743 pager1201-rec0249 300 IN A 1.2.3.4 +744 pager1201-rec0249 300 IN A 1.2.3.5 +745 pager1201-rec0250 300 IN A 1.2.3.4 +746 pager1201-rec0250 300 IN A 1.2.3.5 +747 pager1201-rec0251 300 IN A 1.2.3.4 +748 pager1201-rec0251 300 IN A 1.2.3.5 +749 pager1201-rec0252 300 IN A 1.2.3.4 +750 pager1201-rec0252 300 IN A 1.2.3.5 +751 pager1201-rec0253 300 IN A 1.2.3.4 +752 pager1201-rec0253 300 IN A 1.2.3.5 +753 pager1201-rec0254 300 IN A 1.2.3.4 +754 pager1201-rec0254 300 IN A 1.2.3.5 +755 pager1201-rec0255 300 IN A 1.2.3.4 +756 pager1201-rec0255 300 IN A 1.2.3.5 +757 pager1201-rec0256 300 IN A 1.2.3.4 +758 pager1201-rec0256 300 IN A 1.2.3.5 +759 pager1201-rec0257 300 IN A 1.2.3.4 +760 pager1201-rec0257 300 IN A 1.2.3.5 +761 pager1201-rec0258 300 IN A 1.2.3.4 +762 pager1201-rec0258 300 IN A 1.2.3.5 +763 pager1201-rec0259 300 IN A 1.2.3.4 +764 pager1201-rec0259 300 IN A 1.2.3.5 +765 pager1201-rec0260 300 IN A 1.2.3.4 +766 pager1201-rec0260 300 IN A 1.2.3.5 +767 pager1201-rec0261 300 IN A 1.2.3.4 +768 pager1201-rec0261 300 IN A 1.2.3.5 +769 pager1201-rec0262 300 IN A 1.2.3.4 +770 pager1201-rec0262 300 IN A 1.2.3.5 +771 pager1201-rec0263 300 IN A 1.2.3.4 +772 pager1201-rec0263 300 IN A 1.2.3.5 +773 pager1201-rec0264 300 IN A 1.2.3.4 +774 pager1201-rec0264 300 IN A 1.2.3.5 +775 pager1201-rec0265 300 IN A 1.2.3.4 +776 pager1201-rec0265 300 IN A 1.2.3.5 +777 pager1201-rec0266 300 IN A 1.2.3.4 +778 pager1201-rec0266 300 IN A 1.2.3.5 +779 pager1201-rec0267 300 IN A 1.2.3.4 +780 pager1201-rec0267 300 IN A 1.2.3.5 +781 pager1201-rec0268 300 IN A 1.2.3.4 +782 pager1201-rec0268 300 IN A 1.2.3.5 +783 pager1201-rec0269 300 IN A 1.2.3.4 +784 pager1201-rec0269 300 IN A 1.2.3.5 +785 pager1201-rec0270 300 IN A 1.2.3.4 +786 pager1201-rec0270 300 IN A 1.2.3.5 +787 pager1201-rec0271 300 IN A 1.2.3.4 +788 pager1201-rec0271 300 IN A 1.2.3.5 +789 pager1201-rec0272 300 IN A 1.2.3.4 +790 pager1201-rec0272 300 IN A 1.2.3.5 +791 pager1201-rec0273 300 IN A 1.2.3.4 +792 pager1201-rec0273 300 IN A 1.2.3.5 +793 pager1201-rec0274 300 IN A 1.2.3.4 +794 pager1201-rec0274 300 IN A 1.2.3.5 +795 pager1201-rec0275 300 IN A 1.2.3.4 +796 pager1201-rec0275 300 IN A 1.2.3.5 +797 pager1201-rec0276 300 IN A 1.2.3.4 +798 pager1201-rec0276 300 IN A 1.2.3.5 +799 pager1201-rec0277 300 IN A 1.2.3.4 +800 pager1201-rec0277 300 IN A 1.2.3.5 +801 pager1201-rec0278 300 IN A 1.2.3.4 +802 pager1201-rec0278 300 IN A 1.2.3.5 +803 pager1201-rec0279 300 IN A 1.2.3.4 +804 pager1201-rec0279 300 IN A 1.2.3.5 +805 pager1201-rec0280 300 IN A 1.2.3.4 +806 pager1201-rec0280 300 IN A 1.2.3.5 +807 pager1201-rec0281 300 IN A 1.2.3.4 +808 pager1201-rec0281 300 IN A 1.2.3.5 +809 pager1201-rec0282 300 IN A 1.2.3.4 +810 pager1201-rec0282 300 IN A 1.2.3.5 +811 pager1201-rec0283 300 IN A 1.2.3.4 +812 pager1201-rec0283 300 IN A 1.2.3.5 +813 pager1201-rec0284 300 IN A 1.2.3.4 +814 pager1201-rec0284 300 IN A 1.2.3.5 +815 pager1201-rec0285 300 IN A 1.2.3.4 +816 pager1201-rec0285 300 IN A 1.2.3.5 +817 pager1201-rec0286 300 IN A 1.2.3.4 +818 pager1201-rec0286 300 IN A 1.2.3.5 +819 pager1201-rec0287 300 IN A 1.2.3.4 +820 pager1201-rec0287 300 IN A 1.2.3.5 +821 pager1201-rec0288 300 IN A 1.2.3.4 +822 pager1201-rec0288 300 IN A 1.2.3.5 +823 pager1201-rec0289 300 IN A 1.2.3.4 +824 pager1201-rec0289 300 IN A 1.2.3.5 +825 pager1201-rec0290 300 IN A 1.2.3.4 +826 pager1201-rec0290 300 IN A 1.2.3.5 +827 pager1201-rec0291 300 IN A 1.2.3.4 +828 pager1201-rec0291 300 IN A 1.2.3.5 +829 pager1201-rec0292 300 IN A 1.2.3.4 +830 pager1201-rec0292 300 IN A 1.2.3.5 +831 pager1201-rec0293 300 IN A 1.2.3.4 +832 pager1201-rec0293 300 IN A 1.2.3.5 +833 pager1201-rec0294 300 IN A 1.2.3.4 +834 pager1201-rec0294 300 IN A 1.2.3.5 +835 pager1201-rec0295 300 IN A 1.2.3.4 +836 pager1201-rec0295 300 IN A 1.2.3.5 +837 pager1201-rec0296 300 IN A 1.2.3.4 +838 pager1201-rec0296 300 IN A 1.2.3.5 +839 pager1201-rec0297 300 IN A 1.2.3.4 +840 pager1201-rec0297 300 IN A 1.2.3.5 +841 pager1201-rec0298 300 IN A 1.2.3.4 +842 pager1201-rec0298 300 IN A 1.2.3.5 +843 pager1201-rec0299 300 IN A 1.2.3.4 +844 pager1201-rec0299 300 IN A 1.2.3.5 +845 pager1201-rec0300 300 IN A 1.2.3.4 +846 pager1201-rec0300 300 IN A 1.2.3.5 +847 pager1201-rec0301 300 IN A 1.2.3.4 +848 pager1201-rec0301 300 IN A 1.2.3.5 +849 pager1201-rec0302 300 IN A 1.2.3.4 +850 pager1201-rec0302 300 IN A 1.2.3.5 +851 pager1201-rec0303 300 IN A 1.2.3.4 +852 pager1201-rec0303 300 IN A 1.2.3.5 +853 pager1201-rec0304 300 IN A 1.2.3.4 +854 pager1201-rec0304 300 IN A 1.2.3.5 +855 pager1201-rec0305 300 IN A 1.2.3.4 +856 pager1201-rec0305 300 IN A 1.2.3.5 +857 pager1201-rec0306 300 IN A 1.2.3.4 +858 pager1201-rec0306 300 IN A 1.2.3.5 +859 pager1201-rec0307 300 IN A 1.2.3.4 +860 pager1201-rec0307 300 IN A 1.2.3.5 +861 pager1201-rec0308 300 IN A 1.2.3.4 +862 pager1201-rec0308 300 IN A 1.2.3.5 +863 pager1201-rec0309 300 IN A 1.2.3.4 +864 pager1201-rec0309 300 IN A 1.2.3.5 +865 pager1201-rec0310 300 IN A 1.2.3.4 +866 pager1201-rec0310 300 IN A 1.2.3.5 +867 pager1201-rec0311 300 IN A 1.2.3.4 +868 pager1201-rec0311 300 IN A 1.2.3.5 +869 pager1201-rec0312 300 IN A 1.2.3.4 +870 pager1201-rec0312 300 IN A 1.2.3.5 +871 pager1201-rec0313 300 IN A 1.2.3.4 +872 pager1201-rec0313 300 IN A 1.2.3.5 +873 pager1201-rec0314 300 IN A 1.2.3.4 +874 pager1201-rec0314 300 IN A 1.2.3.5 +875 pager1201-rec0315 300 IN A 1.2.3.4 +876 pager1201-rec0315 300 IN A 1.2.3.5 +877 pager1201-rec0316 300 IN A 1.2.3.4 +878 pager1201-rec0316 300 IN A 1.2.3.5 +879 pager1201-rec0317 300 IN A 1.2.3.4 +880 pager1201-rec0317 300 IN A 1.2.3.5 +881 pager1201-rec0318 300 IN A 1.2.3.4 +882 pager1201-rec0318 300 IN A 1.2.3.5 +883 pager1201-rec0319 300 IN A 1.2.3.4 +884 pager1201-rec0319 300 IN A 1.2.3.5 +885 pager1201-rec0320 300 IN A 1.2.3.4 +886 pager1201-rec0320 300 IN A 1.2.3.5 +887 pager1201-rec0321 300 IN A 1.2.3.4 +888 pager1201-rec0321 300 IN A 1.2.3.5 +889 pager1201-rec0322 300 IN A 1.2.3.4 +890 pager1201-rec0322 300 IN A 1.2.3.5 +891 pager1201-rec0323 300 IN A 1.2.3.4 +892 pager1201-rec0323 300 IN A 1.2.3.5 +893 pager1201-rec0324 300 IN A 1.2.3.4 +894 pager1201-rec0324 300 IN A 1.2.3.5 +895 pager1201-rec0325 300 IN A 1.2.3.4 +896 pager1201-rec0325 300 IN A 1.2.3.5 +897 pager1201-rec0326 300 IN A 1.2.3.4 +898 pager1201-rec0326 300 IN A 1.2.3.5 +899 pager1201-rec0327 300 IN A 1.2.3.4 +900 pager1201-rec0327 300 IN A 1.2.3.5 +901 pager1201-rec0328 300 IN A 1.2.3.4 +902 pager1201-rec0328 300 IN A 1.2.3.5 +903 pager1201-rec0329 300 IN A 1.2.3.4 +904 pager1201-rec0329 300 IN A 1.2.3.5 +905 pager1201-rec0330 300 IN A 1.2.3.4 +906 pager1201-rec0330 300 IN A 1.2.3.5 +907 pager1201-rec0331 300 IN A 1.2.3.4 +908 pager1201-rec0331 300 IN A 1.2.3.5 +909 pager1201-rec0332 300 IN A 1.2.3.4 +910 pager1201-rec0332 300 IN A 1.2.3.5 +911 pager1201-rec0333 300 IN A 1.2.3.4 +912 pager1201-rec0333 300 IN A 1.2.3.5 +913 pager1201-rec0334 300 IN A 1.2.3.4 +914 pager1201-rec0334 300 IN A 1.2.3.5 +915 pager1201-rec0335 300 IN A 1.2.3.4 +916 pager1201-rec0335 300 IN A 1.2.3.5 +917 pager1201-rec0336 300 IN A 1.2.3.4 +918 pager1201-rec0336 300 IN A 1.2.3.5 +919 pager1201-rec0337 300 IN A 1.2.3.4 +920 pager1201-rec0337 300 IN A 1.2.3.5 +921 pager1201-rec0338 300 IN A 1.2.3.4 +922 pager1201-rec0338 300 IN A 1.2.3.5 +923 pager1201-rec0339 300 IN A 1.2.3.4 +924 pager1201-rec0339 300 IN A 1.2.3.5 +925 pager1201-rec0340 300 IN A 1.2.3.4 +926 pager1201-rec0340 300 IN A 1.2.3.5 +927 pager1201-rec0341 300 IN A 1.2.3.4 +928 pager1201-rec0341 300 IN A 1.2.3.5 +929 pager1201-rec0342 300 IN A 1.2.3.4 +930 pager1201-rec0342 300 IN A 1.2.3.5 +931 pager1201-rec0343 300 IN A 1.2.3.4 +932 pager1201-rec0343 300 IN A 1.2.3.5 +933 pager1201-rec0344 300 IN A 1.2.3.4 +934 pager1201-rec0344 300 IN A 1.2.3.5 +935 pager1201-rec0345 300 IN A 1.2.3.4 +936 pager1201-rec0345 300 IN A 1.2.3.5 +937 pager1201-rec0346 300 IN A 1.2.3.4 +938 pager1201-rec0346 300 IN A 1.2.3.5 +939 pager1201-rec0347 300 IN A 1.2.3.4 +940 pager1201-rec0347 300 IN A 1.2.3.5 +941 pager1201-rec0348 300 IN A 1.2.3.4 +942 pager1201-rec0348 300 IN A 1.2.3.5 +943 pager1201-rec0349 300 IN A 1.2.3.4 +944 pager1201-rec0349 300 IN A 1.2.3.5 +945 pager1201-rec0350 300 IN A 1.2.3.4 +946 pager1201-rec0350 300 IN A 1.2.3.5 +947 pager1201-rec0351 300 IN A 1.2.3.4 +948 pager1201-rec0351 300 IN A 1.2.3.5 +949 pager1201-rec0352 300 IN A 1.2.3.4 +950 pager1201-rec0352 300 IN A 1.2.3.5 +951 pager1201-rec0353 300 IN A 1.2.3.4 +952 pager1201-rec0353 300 IN A 1.2.3.5 +953 pager1201-rec0354 300 IN A 1.2.3.4 +954 pager1201-rec0354 300 IN A 1.2.3.5 +955 pager1201-rec0355 300 IN A 1.2.3.4 +956 pager1201-rec0355 300 IN A 1.2.3.5 +957 pager1201-rec0356 300 IN A 1.2.3.4 +958 pager1201-rec0356 300 IN A 1.2.3.5 +959 pager1201-rec0357 300 IN A 1.2.3.4 +960 pager1201-rec0357 300 IN A 1.2.3.5 +961 pager1201-rec0358 300 IN A 1.2.3.4 +962 pager1201-rec0358 300 IN A 1.2.3.5 +963 pager1201-rec0359 300 IN A 1.2.3.4 +964 pager1201-rec0359 300 IN A 1.2.3.5 +965 pager1201-rec0360 300 IN A 1.2.3.4 +966 pager1201-rec0360 300 IN A 1.2.3.5 +967 pager1201-rec0361 300 IN A 1.2.3.4 +968 pager1201-rec0361 300 IN A 1.2.3.5 +969 pager1201-rec0362 300 IN A 1.2.3.4 +970 pager1201-rec0362 300 IN A 1.2.3.5 +971 pager1201-rec0363 300 IN A 1.2.3.4 +972 pager1201-rec0363 300 IN A 1.2.3.5 +973 pager1201-rec0364 300 IN A 1.2.3.4 +974 pager1201-rec0364 300 IN A 1.2.3.5 +975 pager1201-rec0365 300 IN A 1.2.3.4 +976 pager1201-rec0365 300 IN A 1.2.3.5 +977 pager1201-rec0366 300 IN A 1.2.3.4 +978 pager1201-rec0366 300 IN A 1.2.3.5 +979 pager1201-rec0367 300 IN A 1.2.3.4 +980 pager1201-rec0367 300 IN A 1.2.3.5 +981 pager1201-rec0368 300 IN A 1.2.3.4 +982 pager1201-rec0368 300 IN A 1.2.3.5 +983 pager1201-rec0369 300 IN A 1.2.3.4 +984 pager1201-rec0369 300 IN A 1.2.3.5 +985 pager1201-rec0370 300 IN A 1.2.3.4 +986 pager1201-rec0370 300 IN A 1.2.3.5 +987 pager1201-rec0371 300 IN A 1.2.3.4 +988 pager1201-rec0371 300 IN A 1.2.3.5 +989 pager1201-rec0372 300 IN A 1.2.3.4 +990 pager1201-rec0372 300 IN A 1.2.3.5 +991 pager1201-rec0373 300 IN A 1.2.3.4 +992 pager1201-rec0373 300 IN A 1.2.3.5 +993 pager1201-rec0374 300 IN A 1.2.3.4 +994 pager1201-rec0374 300 IN A 1.2.3.5 +995 pager1201-rec0375 300 IN A 1.2.3.4 +996 pager1201-rec0375 300 IN A 1.2.3.5 +997 pager1201-rec0376 300 IN A 1.2.3.4 +998 pager1201-rec0376 300 IN A 1.2.3.5 +999 pager1201-rec0377 300 IN A 1.2.3.4 +1000 pager1201-rec0377 300 IN A 1.2.3.5 +1001 pager1201-rec0378 300 IN A 1.2.3.4 +1002 pager1201-rec0378 300 IN A 1.2.3.5 +1003 pager1201-rec0379 300 IN A 1.2.3.4 +1004 pager1201-rec0379 300 IN A 1.2.3.5 +1005 pager1201-rec0380 300 IN A 1.2.3.4 +1006 pager1201-rec0380 300 IN A 1.2.3.5 +1007 pager1201-rec0381 300 IN A 1.2.3.4 +1008 pager1201-rec0381 300 IN A 1.2.3.5 +1009 pager1201-rec0382 300 IN A 1.2.3.4 +1010 pager1201-rec0382 300 IN A 1.2.3.5 +1011 pager1201-rec0383 300 IN A 1.2.3.4 +1012 pager1201-rec0383 300 IN A 1.2.3.5 +1013 pager1201-rec0384 300 IN A 1.2.3.4 +1014 pager1201-rec0384 300 IN A 1.2.3.5 +1015 pager1201-rec0385 300 IN A 1.2.3.4 +1016 pager1201-rec0385 300 IN A 1.2.3.5 +1017 pager1201-rec0386 300 IN A 1.2.3.4 +1018 pager1201-rec0386 300 IN A 1.2.3.5 +1019 pager1201-rec0387 300 IN A 1.2.3.4 +1020 pager1201-rec0387 300 IN A 1.2.3.5 +1021 pager1201-rec0388 300 IN A 1.2.3.4 +1022 pager1201-rec0388 300 IN A 1.2.3.5 +1023 pager1201-rec0389 300 IN A 1.2.3.4 +1024 pager1201-rec0389 300 IN A 1.2.3.5 +1025 pager1201-rec0390 300 IN A 1.2.3.4 +1026 pager1201-rec0390 300 IN A 1.2.3.5 +1027 pager1201-rec0391 300 IN A 1.2.3.4 +1028 pager1201-rec0391 300 IN A 1.2.3.5 +1029 pager1201-rec0392 300 IN A 1.2.3.4 +1030 pager1201-rec0392 300 IN A 1.2.3.5 +1031 pager1201-rec0393 300 IN A 1.2.3.4 +1032 pager1201-rec0393 300 IN A 1.2.3.5 +1033 pager1201-rec0394 300 IN A 1.2.3.4 +1034 pager1201-rec0394 300 IN A 1.2.3.5 +1035 pager1201-rec0395 300 IN A 1.2.3.4 +1036 pager1201-rec0395 300 IN A 1.2.3.5 +1037 pager1201-rec0396 300 IN A 1.2.3.4 +1038 pager1201-rec0396 300 IN A 1.2.3.5 +1039 pager1201-rec0397 300 IN A 1.2.3.4 +1040 pager1201-rec0397 300 IN A 1.2.3.5 +1041 pager1201-rec0398 300 IN A 1.2.3.4 +1042 pager1201-rec0398 300 IN A 1.2.3.5 +1043 pager1201-rec0399 300 IN A 1.2.3.4 +1044 pager1201-rec0399 300 IN A 1.2.3.5 +1045 pager1201-rec0400 300 IN A 1.2.3.4 +1046 pager1201-rec0400 300 IN A 1.2.3.5 +1047 pager1201-rec0401 300 IN A 1.2.3.4 +1048 pager1201-rec0401 300 IN A 1.2.3.5 +1049 pager1201-rec0402 300 IN A 1.2.3.4 +1050 pager1201-rec0402 300 IN A 1.2.3.5 +1051 pager1201-rec0403 300 IN A 1.2.3.4 +1052 pager1201-rec0403 300 IN A 1.2.3.5 +1053 pager1201-rec0404 300 IN A 1.2.3.4 +1054 pager1201-rec0404 300 IN A 1.2.3.5 +1055 pager1201-rec0405 300 IN A 1.2.3.4 +1056 pager1201-rec0405 300 IN A 1.2.3.5 +1057 pager1201-rec0406 300 IN A 1.2.3.4 +1058 pager1201-rec0406 300 IN A 1.2.3.5 +1059 pager1201-rec0407 300 IN A 1.2.3.4 +1060 pager1201-rec0407 300 IN A 1.2.3.5 +1061 pager1201-rec0408 300 IN A 1.2.3.4 +1062 pager1201-rec0408 300 IN A 1.2.3.5 +1063 pager1201-rec0409 300 IN A 1.2.3.4 +1064 pager1201-rec0409 300 IN A 1.2.3.5 +1065 pager1201-rec0410 300 IN A 1.2.3.4 +1066 pager1201-rec0410 300 IN A 1.2.3.5 +1067 pager1201-rec0411 300 IN A 1.2.3.4 +1068 pager1201-rec0411 300 IN A 1.2.3.5 +1069 pager1201-rec0412 300 IN A 1.2.3.4 +1070 pager1201-rec0412 300 IN A 1.2.3.5 +1071 pager1201-rec0413 300 IN A 1.2.3.4 +1072 pager1201-rec0413 300 IN A 1.2.3.5 +1073 pager1201-rec0414 300 IN A 1.2.3.4 +1074 pager1201-rec0414 300 IN A 1.2.3.5 +1075 pager1201-rec0415 300 IN A 1.2.3.4 +1076 pager1201-rec0415 300 IN A 1.2.3.5 +1077 pager1201-rec0416 300 IN A 1.2.3.4 +1078 pager1201-rec0416 300 IN A 1.2.3.5 +1079 pager1201-rec0417 300 IN A 1.2.3.4 +1080 pager1201-rec0417 300 IN A 1.2.3.5 +1081 pager1201-rec0418 300 IN A 1.2.3.4 +1082 pager1201-rec0418 300 IN A 1.2.3.5 +1083 pager1201-rec0419 300 IN A 1.2.3.4 +1084 pager1201-rec0419 300 IN A 1.2.3.5 +1085 pager1201-rec0420 300 IN A 1.2.3.4 +1086 pager1201-rec0420 300 IN A 1.2.3.5 +1087 pager1201-rec0421 300 IN A 1.2.3.4 +1088 pager1201-rec0421 300 IN A 1.2.3.5 +1089 pager1201-rec0422 300 IN A 1.2.3.4 +1090 pager1201-rec0422 300 IN A 1.2.3.5 +1091 pager1201-rec0423 300 IN A 1.2.3.4 +1092 pager1201-rec0423 300 IN A 1.2.3.5 +1093 pager1201-rec0424 300 IN A 1.2.3.4 +1094 pager1201-rec0424 300 IN A 1.2.3.5 +1095 pager1201-rec0425 300 IN A 1.2.3.4 +1096 pager1201-rec0425 300 IN A 1.2.3.5 +1097 pager1201-rec0426 300 IN A 1.2.3.4 +1098 pager1201-rec0426 300 IN A 1.2.3.5 +1099 pager1201-rec0427 300 IN A 1.2.3.4 +1100 pager1201-rec0427 300 IN A 1.2.3.5 +1101 pager1201-rec0428 300 IN A 1.2.3.4 +1102 pager1201-rec0428 300 IN A 1.2.3.5 +1103 pager1201-rec0429 300 IN A 1.2.3.4 +1104 pager1201-rec0429 300 IN A 1.2.3.5 +1105 pager1201-rec0430 300 IN A 1.2.3.4 +1106 pager1201-rec0430 300 IN A 1.2.3.5 +1107 pager1201-rec0431 300 IN A 1.2.3.4 +1108 pager1201-rec0431 300 IN A 1.2.3.5 +1109 pager1201-rec0432 300 IN A 1.2.3.4 +1110 pager1201-rec0432 300 IN A 1.2.3.5 +1111 pager1201-rec0433 300 IN A 1.2.3.4 +1112 pager1201-rec0433 300 IN A 1.2.3.5 +1113 pager1201-rec0434 300 IN A 1.2.3.4 +1114 pager1201-rec0434 300 IN A 1.2.3.5 +1115 pager1201-rec0435 300 IN A 1.2.3.4 +1116 pager1201-rec0435 300 IN A 1.2.3.5 +1117 pager1201-rec0436 300 IN A 1.2.3.4 +1118 pager1201-rec0436 300 IN A 1.2.3.5 +1119 pager1201-rec0437 300 IN A 1.2.3.4 +1120 pager1201-rec0437 300 IN A 1.2.3.5 +1121 pager1201-rec0438 300 IN A 1.2.3.4 +1122 pager1201-rec0438 300 IN A 1.2.3.5 +1123 pager1201-rec0439 300 IN A 1.2.3.4 +1124 pager1201-rec0439 300 IN A 1.2.3.5 +1125 pager1201-rec0440 300 IN A 1.2.3.4 +1126 pager1201-rec0440 300 IN A 1.2.3.5 +1127 pager1201-rec0441 300 IN A 1.2.3.4 +1128 pager1201-rec0441 300 IN A 1.2.3.5 +1129 pager1201-rec0442 300 IN A 1.2.3.4 +1130 pager1201-rec0442 300 IN A 1.2.3.5 +1131 pager1201-rec0443 300 IN A 1.2.3.4 +1132 pager1201-rec0443 300 IN A 1.2.3.5 +1133 pager1201-rec0444 300 IN A 1.2.3.4 +1134 pager1201-rec0444 300 IN A 1.2.3.5 +1135 pager1201-rec0445 300 IN A 1.2.3.4 +1136 pager1201-rec0445 300 IN A 1.2.3.5 +1137 pager1201-rec0446 300 IN A 1.2.3.4 +1138 pager1201-rec0446 300 IN A 1.2.3.5 +1139 pager1201-rec0447 300 IN A 1.2.3.4 +1140 pager1201-rec0447 300 IN A 1.2.3.5 +1141 pager1201-rec0448 300 IN A 1.2.3.4 +1142 pager1201-rec0448 300 IN A 1.2.3.5 +1143 pager1201-rec0449 300 IN A 1.2.3.4 +1144 pager1201-rec0449 300 IN A 1.2.3.5 +1145 pager1201-rec0450 300 IN A 1.2.3.4 +1146 pager1201-rec0450 300 IN A 1.2.3.5 +1147 pager1201-rec0451 300 IN A 1.2.3.4 +1148 pager1201-rec0451 300 IN A 1.2.3.5 +1149 pager1201-rec0452 300 IN A 1.2.3.4 +1150 pager1201-rec0452 300 IN A 1.2.3.5 +1151 pager1201-rec0453 300 IN A 1.2.3.4 +1152 pager1201-rec0453 300 IN A 1.2.3.5 +1153 pager1201-rec0454 300 IN A 1.2.3.4 +1154 pager1201-rec0454 300 IN A 1.2.3.5 +1155 pager1201-rec0455 300 IN A 1.2.3.4 +1156 pager1201-rec0455 300 IN A 1.2.3.5 +1157 pager1201-rec0456 300 IN A 1.2.3.4 +1158 pager1201-rec0456 300 IN A 1.2.3.5 +1159 pager1201-rec0457 300 IN A 1.2.3.4 +1160 pager1201-rec0457 300 IN A 1.2.3.5 +1161 pager1201-rec0458 300 IN A 1.2.3.4 +1162 pager1201-rec0458 300 IN A 1.2.3.5 +1163 pager1201-rec0459 300 IN A 1.2.3.4 +1164 pager1201-rec0459 300 IN A 1.2.3.5 +1165 pager1201-rec0460 300 IN A 1.2.3.4 +1166 pager1201-rec0460 300 IN A 1.2.3.5 +1167 pager1201-rec0461 300 IN A 1.2.3.4 +1168 pager1201-rec0461 300 IN A 1.2.3.5 +1169 pager1201-rec0462 300 IN A 1.2.3.4 +1170 pager1201-rec0462 300 IN A 1.2.3.5 +1171 pager1201-rec0463 300 IN A 1.2.3.4 +1172 pager1201-rec0463 300 IN A 1.2.3.5 +1173 pager1201-rec0464 300 IN A 1.2.3.4 +1174 pager1201-rec0464 300 IN A 1.2.3.5 +1175 pager1201-rec0465 300 IN A 1.2.3.4 +1176 pager1201-rec0465 300 IN A 1.2.3.5 +1177 pager1201-rec0466 300 IN A 1.2.3.4 +1178 pager1201-rec0466 300 IN A 1.2.3.5 +1179 pager1201-rec0467 300 IN A 1.2.3.4 +1180 pager1201-rec0467 300 IN A 1.2.3.5 +1181 pager1201-rec0468 300 IN A 1.2.3.4 +1182 pager1201-rec0468 300 IN A 1.2.3.5 +1183 pager1201-rec0469 300 IN A 1.2.3.4 +1184 pager1201-rec0469 300 IN A 1.2.3.5 +1185 pager1201-rec0470 300 IN A 1.2.3.4 +1186 pager1201-rec0470 300 IN A 1.2.3.5 +1187 pager1201-rec0471 300 IN A 1.2.3.4 +1188 pager1201-rec0471 300 IN A 1.2.3.5 +1189 pager1201-rec0472 300 IN A 1.2.3.4 +1190 pager1201-rec0472 300 IN A 1.2.3.5 +1191 pager1201-rec0473 300 IN A 1.2.3.4 +1192 pager1201-rec0473 300 IN A 1.2.3.5 +1193 pager1201-rec0474 300 IN A 1.2.3.4 +1194 pager1201-rec0474 300 IN A 1.2.3.5 +1195 pager1201-rec0475 300 IN A 1.2.3.4 +1196 pager1201-rec0475 300 IN A 1.2.3.5 +1197 pager1201-rec0476 300 IN A 1.2.3.4 +1198 pager1201-rec0476 300 IN A 1.2.3.5 +1199 pager1201-rec0477 300 IN A 1.2.3.4 +1200 pager1201-rec0477 300 IN A 1.2.3.5 +1201 pager1201-rec0478 300 IN A 1.2.3.4 +1202 pager1201-rec0478 300 IN A 1.2.3.5 +1203 pager1201-rec0479 300 IN A 1.2.3.4 +1204 pager1201-rec0479 300 IN A 1.2.3.5 +1205 pager1201-rec0480 300 IN A 1.2.3.4 +1206 pager1201-rec0480 300 IN A 1.2.3.5 +1207 pager1201-rec0481 300 IN A 1.2.3.4 +1208 pager1201-rec0481 300 IN A 1.2.3.5 +1209 pager1201-rec0482 300 IN A 1.2.3.4 +1210 pager1201-rec0482 300 IN A 1.2.3.5 +1211 pager1201-rec0483 300 IN A 1.2.3.4 +1212 pager1201-rec0483 300 IN A 1.2.3.5 +1213 pager1201-rec0484 300 IN A 1.2.3.4 +1214 pager1201-rec0484 300 IN A 1.2.3.5 +1215 pager1201-rec0485 300 IN A 1.2.3.4 +1216 pager1201-rec0485 300 IN A 1.2.3.5 +1217 pager1201-rec0486 300 IN A 1.2.3.4 +1218 pager1201-rec0486 300 IN A 1.2.3.5 +1219 pager1201-rec0487 300 IN A 1.2.3.4 +1220 pager1201-rec0487 300 IN A 1.2.3.5 +1221 pager1201-rec0488 300 IN A 1.2.3.4 +1222 pager1201-rec0488 300 IN A 1.2.3.5 +1223 pager1201-rec0489 300 IN A 1.2.3.4 +1224 pager1201-rec0489 300 IN A 1.2.3.5 +1225 pager1201-rec0490 300 IN A 1.2.3.4 +1226 pager1201-rec0490 300 IN A 1.2.3.5 +1227 pager1201-rec0491 300 IN A 1.2.3.4 +1228 pager1201-rec0491 300 IN A 1.2.3.5 +1229 pager1201-rec0492 300 IN A 1.2.3.4 +1230 pager1201-rec0492 300 IN A 1.2.3.5 +1231 pager1201-rec0493 300 IN A 1.2.3.4 +1232 pager1201-rec0493 300 IN A 1.2.3.5 +1233 pager1201-rec0494 300 IN A 1.2.3.4 +1234 pager1201-rec0494 300 IN A 1.2.3.5 +1235 pager1201-rec0495 300 IN A 1.2.3.4 +1236 pager1201-rec0495 300 IN A 1.2.3.5 +1237 pager1201-rec0496 300 IN A 1.2.3.4 +1238 pager1201-rec0496 300 IN A 1.2.3.5 +1239 pager1201-rec0497 300 IN A 1.2.3.4 +1240 pager1201-rec0497 300 IN A 1.2.3.5 +1241 pager1201-rec0498 300 IN A 1.2.3.4 +1242 pager1201-rec0498 300 IN A 1.2.3.5 +1243 pager1201-rec0499 300 IN A 1.2.3.4 +1244 pager1201-rec0499 300 IN A 1.2.3.5 +1245 pager1201-rec0500 300 IN A 1.2.3.4 +1246 pager1201-rec0500 300 IN A 1.2.3.5 +1247 pager1201-rec0501 300 IN A 1.2.3.4 +1248 pager1201-rec0501 300 IN A 1.2.3.5 +1249 pager1201-rec0502 300 IN A 1.2.3.4 +1250 pager1201-rec0502 300 IN A 1.2.3.5 +1251 pager1201-rec0503 300 IN A 1.2.3.4 +1252 pager1201-rec0503 300 IN A 1.2.3.5 +1253 pager1201-rec0504 300 IN A 1.2.3.4 +1254 pager1201-rec0504 300 IN A 1.2.3.5 +1255 pager1201-rec0505 300 IN A 1.2.3.4 +1256 pager1201-rec0505 300 IN A 1.2.3.5 +1257 pager1201-rec0506 300 IN A 1.2.3.4 +1258 pager1201-rec0506 300 IN A 1.2.3.5 +1259 pager1201-rec0507 300 IN A 1.2.3.4 +1260 pager1201-rec0507 300 IN A 1.2.3.5 +1261 pager1201-rec0508 300 IN A 1.2.3.4 +1262 pager1201-rec0508 300 IN A 1.2.3.5 +1263 pager1201-rec0509 300 IN A 1.2.3.4 +1264 pager1201-rec0509 300 IN A 1.2.3.5 +1265 pager1201-rec0510 300 IN A 1.2.3.4 +1266 pager1201-rec0510 300 IN A 1.2.3.5 +1267 pager1201-rec0511 300 IN A 1.2.3.4 +1268 pager1201-rec0511 300 IN A 1.2.3.5 +1269 pager1201-rec0512 300 IN A 1.2.3.4 +1270 pager1201-rec0512 300 IN A 1.2.3.5 +1271 pager1201-rec0513 300 IN A 1.2.3.4 +1272 pager1201-rec0513 300 IN A 1.2.3.5 +1273 pager1201-rec0514 300 IN A 1.2.3.4 +1274 pager1201-rec0514 300 IN A 1.2.3.5 +1275 pager1201-rec0515 300 IN A 1.2.3.4 +1276 pager1201-rec0515 300 IN A 1.2.3.5 +1277 pager1201-rec0516 300 IN A 1.2.3.4 +1278 pager1201-rec0516 300 IN A 1.2.3.5 +1279 pager1201-rec0517 300 IN A 1.2.3.4 +1280 pager1201-rec0517 300 IN A 1.2.3.5 +1281 pager1201-rec0518 300 IN A 1.2.3.4 +1282 pager1201-rec0518 300 IN A 1.2.3.5 +1283 pager1201-rec0519 300 IN A 1.2.3.4 +1284 pager1201-rec0519 300 IN A 1.2.3.5 +1285 pager1201-rec0520 300 IN A 1.2.3.4 +1286 pager1201-rec0520 300 IN A 1.2.3.5 +1287 pager1201-rec0521 300 IN A 1.2.3.4 +1288 pager1201-rec0521 300 IN A 1.2.3.5 +1289 pager1201-rec0522 300 IN A 1.2.3.4 +1290 pager1201-rec0522 300 IN A 1.2.3.5 +1291 pager1201-rec0523 300 IN A 1.2.3.4 +1292 pager1201-rec0523 300 IN A 1.2.3.5 +1293 pager1201-rec0524 300 IN A 1.2.3.4 +1294 pager1201-rec0524 300 IN A 1.2.3.5 +1295 pager1201-rec0525 300 IN A 1.2.3.4 +1296 pager1201-rec0525 300 IN A 1.2.3.5 +1297 pager1201-rec0526 300 IN A 1.2.3.4 +1298 pager1201-rec0526 300 IN A 1.2.3.5 +1299 pager1201-rec0527 300 IN A 1.2.3.4 +1300 pager1201-rec0527 300 IN A 1.2.3.5 +1301 pager1201-rec0528 300 IN A 1.2.3.4 +1302 pager1201-rec0528 300 IN A 1.2.3.5 +1303 pager1201-rec0529 300 IN A 1.2.3.4 +1304 pager1201-rec0529 300 IN A 1.2.3.5 +1305 pager1201-rec0530 300 IN A 1.2.3.4 +1306 pager1201-rec0530 300 IN A 1.2.3.5 +1307 pager1201-rec0531 300 IN A 1.2.3.4 +1308 pager1201-rec0531 300 IN A 1.2.3.5 +1309 pager1201-rec0532 300 IN A 1.2.3.4 +1310 pager1201-rec0532 300 IN A 1.2.3.5 +1311 pager1201-rec0533 300 IN A 1.2.3.4 +1312 pager1201-rec0533 300 IN A 1.2.3.5 +1313 pager1201-rec0534 300 IN A 1.2.3.4 +1314 pager1201-rec0534 300 IN A 1.2.3.5 +1315 pager1201-rec0535 300 IN A 1.2.3.4 +1316 pager1201-rec0535 300 IN A 1.2.3.5 +1317 pager1201-rec0536 300 IN A 1.2.3.4 +1318 pager1201-rec0536 300 IN A 1.2.3.5 +1319 pager1201-rec0537 300 IN A 1.2.3.4 +1320 pager1201-rec0537 300 IN A 1.2.3.5 +1321 pager1201-rec0538 300 IN A 1.2.3.4 +1322 pager1201-rec0538 300 IN A 1.2.3.5 +1323 pager1201-rec0539 300 IN A 1.2.3.4 +1324 pager1201-rec0539 300 IN A 1.2.3.5 +1325 pager1201-rec0540 300 IN A 1.2.3.4 +1326 pager1201-rec0540 300 IN A 1.2.3.5 +1327 pager1201-rec0541 300 IN A 1.2.3.4 +1328 pager1201-rec0541 300 IN A 1.2.3.5 +1329 pager1201-rec0542 300 IN A 1.2.3.4 +1330 pager1201-rec0542 300 IN A 1.2.3.5 +1331 pager1201-rec0543 300 IN A 1.2.3.4 +1332 pager1201-rec0543 300 IN A 1.2.3.5 +1333 pager1201-rec0544 300 IN A 1.2.3.4 +1334 pager1201-rec0544 300 IN A 1.2.3.5 +1335 pager1201-rec0545 300 IN A 1.2.3.4 +1336 pager1201-rec0545 300 IN A 1.2.3.5 +1337 pager1201-rec0546 300 IN A 1.2.3.4 +1338 pager1201-rec0546 300 IN A 1.2.3.5 +1339 pager1201-rec0547 300 IN A 1.2.3.4 +1340 pager1201-rec0547 300 IN A 1.2.3.5 +1341 pager1201-rec0548 300 IN A 1.2.3.4 +1342 pager1201-rec0548 300 IN A 1.2.3.5 +1343 pager1201-rec0549 300 IN A 1.2.3.4 +1344 pager1201-rec0549 300 IN A 1.2.3.5 +1345 pager1201-rec0550 300 IN A 1.2.3.4 +1346 pager1201-rec0550 300 IN A 1.2.3.5 +1347 pager1201-rec0551 300 IN A 1.2.3.4 +1348 pager1201-rec0551 300 IN A 1.2.3.5 +1349 pager1201-rec0552 300 IN A 1.2.3.4 +1350 pager1201-rec0552 300 IN A 1.2.3.5 +1351 pager1201-rec0553 300 IN A 1.2.3.4 +1352 pager1201-rec0553 300 IN A 1.2.3.5 +1353 pager1201-rec0554 300 IN A 1.2.3.4 +1354 pager1201-rec0554 300 IN A 1.2.3.5 +1355 pager1201-rec0555 300 IN A 1.2.3.4 +1356 pager1201-rec0555 300 IN A 1.2.3.5 +1357 pager1201-rec0556 300 IN A 1.2.3.4 +1358 pager1201-rec0556 300 IN A 1.2.3.5 +1359 pager1201-rec0557 300 IN A 1.2.3.4 +1360 pager1201-rec0557 300 IN A 1.2.3.5 +1361 pager1201-rec0558 300 IN A 1.2.3.4 +1362 pager1201-rec0558 300 IN A 1.2.3.5 +1363 pager1201-rec0559 300 IN A 1.2.3.4 +1364 pager1201-rec0559 300 IN A 1.2.3.5 +1365 pager1201-rec0560 300 IN A 1.2.3.4 +1366 pager1201-rec0560 300 IN A 1.2.3.5 +1367 pager1201-rec0561 300 IN A 1.2.3.4 +1368 pager1201-rec0561 300 IN A 1.2.3.5 +1369 pager1201-rec0562 300 IN A 1.2.3.4 +1370 pager1201-rec0562 300 IN A 1.2.3.5 +1371 pager1201-rec0563 300 IN A 1.2.3.4 +1372 pager1201-rec0563 300 IN A 1.2.3.5 +1373 pager1201-rec0564 300 IN A 1.2.3.4 +1374 pager1201-rec0564 300 IN A 1.2.3.5 +1375 pager1201-rec0565 300 IN A 1.2.3.4 +1376 pager1201-rec0565 300 IN A 1.2.3.5 +1377 pager1201-rec0566 300 IN A 1.2.3.4 +1378 pager1201-rec0566 300 IN A 1.2.3.5 +1379 pager1201-rec0567 300 IN A 1.2.3.4 +1380 pager1201-rec0567 300 IN A 1.2.3.5 +1381 pager1201-rec0568 300 IN A 1.2.3.4 +1382 pager1201-rec0568 300 IN A 1.2.3.5 +1383 pager1201-rec0569 300 IN A 1.2.3.4 +1384 pager1201-rec0569 300 IN A 1.2.3.5 +1385 pager1201-rec0570 300 IN A 1.2.3.4 +1386 pager1201-rec0570 300 IN A 1.2.3.5 +1387 pager1201-rec0571 300 IN A 1.2.3.4 +1388 pager1201-rec0571 300 IN A 1.2.3.5 +1389 pager1201-rec0572 300 IN A 1.2.3.4 +1390 pager1201-rec0572 300 IN A 1.2.3.5 +1391 pager1201-rec0573 300 IN A 1.2.3.4 +1392 pager1201-rec0573 300 IN A 1.2.3.5 +1393 pager1201-rec0574 300 IN A 1.2.3.4 +1394 pager1201-rec0574 300 IN A 1.2.3.5 +1395 pager1201-rec0575 300 IN A 1.2.3.4 +1396 pager1201-rec0575 300 IN A 1.2.3.5 +1397 pager1201-rec0576 300 IN A 1.2.3.4 +1398 pager1201-rec0576 300 IN A 1.2.3.5 +1399 pager1201-rec0577 300 IN A 1.2.3.4 +1400 pager1201-rec0577 300 IN A 1.2.3.5 +1401 pager1201-rec0578 300 IN A 1.2.3.4 +1402 pager1201-rec0578 300 IN A 1.2.3.5 +1403 pager1201-rec0579 300 IN A 1.2.3.4 +1404 pager1201-rec0579 300 IN A 1.2.3.5 +1405 pager1201-rec0580 300 IN A 1.2.3.4 +1406 pager1201-rec0580 300 IN A 1.2.3.5 +1407 pager1201-rec0581 300 IN A 1.2.3.4 +1408 pager1201-rec0581 300 IN A 1.2.3.5 +1409 pager1201-rec0582 300 IN A 1.2.3.4 +1410 pager1201-rec0582 300 IN A 1.2.3.5 +1411 pager1201-rec0583 300 IN A 1.2.3.4 +1412 pager1201-rec0583 300 IN A 1.2.3.5 +1413 pager1201-rec0584 300 IN A 1.2.3.4 +1414 pager1201-rec0584 300 IN A 1.2.3.5 +1415 pager1201-rec0585 300 IN A 1.2.3.4 +1416 pager1201-rec0585 300 IN A 1.2.3.5 +1417 pager1201-rec0586 300 IN A 1.2.3.4 +1418 pager1201-rec0586 300 IN A 1.2.3.5 +1419 pager1201-rec0587 300 IN A 1.2.3.4 +1420 pager1201-rec0587 300 IN A 1.2.3.5 +1421 pager1201-rec0588 300 IN A 1.2.3.4 +1422 pager1201-rec0588 300 IN A 1.2.3.5 +1423 pager1201-rec0589 300 IN A 1.2.3.4 +1424 pager1201-rec0589 300 IN A 1.2.3.5 +1425 pager1201-rec0590 300 IN A 1.2.3.4 +1426 pager1201-rec0590 300 IN A 1.2.3.5 +1427 pager1201-rec0591 300 IN A 1.2.3.4 +1428 pager1201-rec0591 300 IN A 1.2.3.5 +1429 pager1201-rec0592 300 IN A 1.2.3.4 +1430 pager1201-rec0592 300 IN A 1.2.3.5 +1431 pager1201-rec0593 300 IN A 1.2.3.4 +1432 pager1201-rec0593 300 IN A 1.2.3.5 +1433 pager1201-rec0594 300 IN A 1.2.3.4 +1434 pager1201-rec0594 300 IN A 1.2.3.5 +1435 pager1201-rec0595 300 IN A 1.2.3.4 +1436 pager1201-rec0595 300 IN A 1.2.3.5 +1437 pager1201-rec0596 300 IN A 1.2.3.4 +1438 pager1201-rec0596 300 IN A 1.2.3.5 +1439 pager1201-rec0597 300 IN A 1.2.3.4 +1440 pager1201-rec0597 300 IN A 1.2.3.5 +1441 pager1201-rec0598 300 IN A 1.2.3.4 +1442 pager1201-rec0598 300 IN A 1.2.3.5 +1443 pager1201-rec0599 300 IN A 1.2.3.4 +1444 pager1201-rec0599 300 IN A 1.2.3.5 +1445 pager1201-rec0600 300 IN A 1.2.3.4 +1446 pager1201-rec0600 300 IN A 1.2.3.5 +1447 pager1201-rec0601 300 IN A 1.2.3.4 +1448 pager1201-rec0601 300 IN A 1.2.3.5 +1449 pager1201-rec0602 300 IN A 1.2.3.4 +1450 pager1201-rec0602 300 IN A 1.2.3.5 +1451 pager1201-rec0603 300 IN A 1.2.3.4 +1452 pager1201-rec0603 300 IN A 1.2.3.5 +1453 pager1201-rec0604 300 IN A 1.2.3.4 +1454 pager1201-rec0604 300 IN A 1.2.3.5 +1455 pager1201-rec0605 300 IN A 1.2.3.4 +1456 pager1201-rec0605 300 IN A 1.2.3.5 +1457 pager1201-rec0606 300 IN A 1.2.3.4 +1458 pager1201-rec0606 300 IN A 1.2.3.5 +1459 pager1201-rec0607 300 IN A 1.2.3.4 +1460 pager1201-rec0607 300 IN A 1.2.3.5 +1461 pager1201-rec0608 300 IN A 1.2.3.4 +1462 pager1201-rec0608 300 IN A 1.2.3.5 +1463 pager1201-rec0609 300 IN A 1.2.3.4 +1464 pager1201-rec0609 300 IN A 1.2.3.5 +1465 pager1201-rec0610 300 IN A 1.2.3.4 +1466 pager1201-rec0610 300 IN A 1.2.3.5 +1467 pager1201-rec0611 300 IN A 1.2.3.4 +1468 pager1201-rec0611 300 IN A 1.2.3.5 +1469 pager1201-rec0612 300 IN A 1.2.3.4 +1470 pager1201-rec0612 300 IN A 1.2.3.5 +1471 pager1201-rec0613 300 IN A 1.2.3.4 +1472 pager1201-rec0613 300 IN A 1.2.3.5 +1473 pager1201-rec0614 300 IN A 1.2.3.4 +1474 pager1201-rec0614 300 IN A 1.2.3.5 +1475 pager1201-rec0615 300 IN A 1.2.3.4 +1476 pager1201-rec0615 300 IN A 1.2.3.5 +1477 pager1201-rec0616 300 IN A 1.2.3.4 +1478 pager1201-rec0616 300 IN A 1.2.3.5 +1479 pager1201-rec0617 300 IN A 1.2.3.4 +1480 pager1201-rec0617 300 IN A 1.2.3.5 +1481 pager1201-rec0618 300 IN A 1.2.3.4 +1482 pager1201-rec0618 300 IN A 1.2.3.5 +1483 pager1201-rec0619 300 IN A 1.2.3.4 +1484 pager1201-rec0619 300 IN A 1.2.3.5 +1485 pager1201-rec0620 300 IN A 1.2.3.4 +1486 pager1201-rec0620 300 IN A 1.2.3.5 +1487 pager1201-rec0621 300 IN A 1.2.3.4 +1488 pager1201-rec0621 300 IN A 1.2.3.5 +1489 pager1201-rec0622 300 IN A 1.2.3.4 +1490 pager1201-rec0622 300 IN A 1.2.3.5 +1491 pager1201-rec0623 300 IN A 1.2.3.4 +1492 pager1201-rec0623 300 IN A 1.2.3.5 +1493 pager1201-rec0624 300 IN A 1.2.3.4 +1494 pager1201-rec0624 300 IN A 1.2.3.5 +1495 pager1201-rec0625 300 IN A 1.2.3.4 +1496 pager1201-rec0625 300 IN A 1.2.3.5 +1497 pager1201-rec0626 300 IN A 1.2.3.4 +1498 pager1201-rec0626 300 IN A 1.2.3.5 +1499 pager1201-rec0627 300 IN A 1.2.3.4 +1500 pager1201-rec0627 300 IN A 1.2.3.5 +1501 pager1201-rec0628 300 IN A 1.2.3.4 +1502 pager1201-rec0628 300 IN A 1.2.3.5 +1503 pager1201-rec0629 300 IN A 1.2.3.4 +1504 pager1201-rec0629 300 IN A 1.2.3.5 +1505 pager1201-rec0630 300 IN A 1.2.3.4 +1506 pager1201-rec0630 300 IN A 1.2.3.5 +1507 pager1201-rec0631 300 IN A 1.2.3.4 +1508 pager1201-rec0631 300 IN A 1.2.3.5 +1509 pager1201-rec0632 300 IN A 1.2.3.4 +1510 pager1201-rec0632 300 IN A 1.2.3.5 +1511 pager1201-rec0633 300 IN A 1.2.3.4 +1512 pager1201-rec0633 300 IN A 1.2.3.5 +1513 pager1201-rec0634 300 IN A 1.2.3.4 +1514 pager1201-rec0634 300 IN A 1.2.3.5 +1515 pager1201-rec0635 300 IN A 1.2.3.4 +1516 pager1201-rec0635 300 IN A 1.2.3.5 +1517 pager1201-rec0636 300 IN A 1.2.3.4 +1518 pager1201-rec0636 300 IN A 1.2.3.5 +1519 pager1201-rec0637 300 IN A 1.2.3.4 +1520 pager1201-rec0637 300 IN A 1.2.3.5 +1521 pager1201-rec0638 300 IN A 1.2.3.4 +1522 pager1201-rec0638 300 IN A 1.2.3.5 +1523 pager1201-rec0639 300 IN A 1.2.3.4 +1524 pager1201-rec0639 300 IN A 1.2.3.5 +1525 pager1201-rec0640 300 IN A 1.2.3.4 +1526 pager1201-rec0640 300 IN A 1.2.3.5 +1527 pager1201-rec0641 300 IN A 1.2.3.4 +1528 pager1201-rec0641 300 IN A 1.2.3.5 +1529 pager1201-rec0642 300 IN A 1.2.3.4 +1530 pager1201-rec0642 300 IN A 1.2.3.5 +1531 pager1201-rec0643 300 IN A 1.2.3.4 +1532 pager1201-rec0643 300 IN A 1.2.3.5 +1533 pager1201-rec0644 300 IN A 1.2.3.4 +1534 pager1201-rec0644 300 IN A 1.2.3.5 +1535 pager1201-rec0645 300 IN A 1.2.3.4 +1536 pager1201-rec0645 300 IN A 1.2.3.5 +1537 pager1201-rec0646 300 IN A 1.2.3.4 +1538 pager1201-rec0646 300 IN A 1.2.3.5 +1539 pager1201-rec0647 300 IN A 1.2.3.4 +1540 pager1201-rec0647 300 IN A 1.2.3.5 +1541 pager1201-rec0648 300 IN A 1.2.3.4 +1542 pager1201-rec0648 300 IN A 1.2.3.5 +1543 pager1201-rec0649 300 IN A 1.2.3.4 +1544 pager1201-rec0649 300 IN A 1.2.3.5 +1545 pager1201-rec0650 300 IN A 1.2.3.4 +1546 pager1201-rec0650 300 IN A 1.2.3.5 +1547 pager1201-rec0651 300 IN A 1.2.3.4 +1548 pager1201-rec0651 300 IN A 1.2.3.5 +1549 pager1201-rec0652 300 IN A 1.2.3.4 +1550 pager1201-rec0652 300 IN A 1.2.3.5 +1551 pager1201-rec0653 300 IN A 1.2.3.4 +1552 pager1201-rec0653 300 IN A 1.2.3.5 +1553 pager1201-rec0654 300 IN A 1.2.3.4 +1554 pager1201-rec0654 300 IN A 1.2.3.5 +1555 pager1201-rec0655 300 IN A 1.2.3.4 +1556 pager1201-rec0655 300 IN A 1.2.3.5 +1557 pager1201-rec0656 300 IN A 1.2.3.4 +1558 pager1201-rec0656 300 IN A 1.2.3.5 +1559 pager1201-rec0657 300 IN A 1.2.3.4 +1560 pager1201-rec0657 300 IN A 1.2.3.5 +1561 pager1201-rec0658 300 IN A 1.2.3.4 +1562 pager1201-rec0658 300 IN A 1.2.3.5 +1563 pager1201-rec0659 300 IN A 1.2.3.4 +1564 pager1201-rec0659 300 IN A 1.2.3.5 +1565 pager1201-rec0660 300 IN A 1.2.3.4 +1566 pager1201-rec0660 300 IN A 1.2.3.5 +1567 pager1201-rec0661 300 IN A 1.2.3.4 +1568 pager1201-rec0661 300 IN A 1.2.3.5 +1569 pager1201-rec0662 300 IN A 1.2.3.4 +1570 pager1201-rec0662 300 IN A 1.2.3.5 +1571 pager1201-rec0663 300 IN A 1.2.3.4 +1572 pager1201-rec0663 300 IN A 1.2.3.5 +1573 pager1201-rec0664 300 IN A 1.2.3.4 +1574 pager1201-rec0664 300 IN A 1.2.3.5 +1575 pager1201-rec0665 300 IN A 1.2.3.4 +1576 pager1201-rec0665 300 IN A 1.2.3.5 +1577 pager1201-rec0666 300 IN A 1.2.3.4 +1578 pager1201-rec0666 300 IN A 1.2.3.5 +1579 pager1201-rec0667 300 IN A 1.2.3.4 +1580 pager1201-rec0667 300 IN A 1.2.3.5 +1581 pager1201-rec0668 300 IN A 1.2.3.4 +1582 pager1201-rec0668 300 IN A 1.2.3.5 +1583 pager1201-rec0669 300 IN A 1.2.3.4 +1584 pager1201-rec0669 300 IN A 1.2.3.5 +1585 pager1201-rec0670 300 IN A 1.2.3.4 +1586 pager1201-rec0670 300 IN A 1.2.3.5 +1587 pager1201-rec0671 300 IN A 1.2.3.4 +1588 pager1201-rec0671 300 IN A 1.2.3.5 +1589 pager1201-rec0672 300 IN A 1.2.3.4 +1590 pager1201-rec0672 300 IN A 1.2.3.5 +1591 pager1201-rec0673 300 IN A 1.2.3.4 +1592 pager1201-rec0673 300 IN A 1.2.3.5 +1593 pager1201-rec0674 300 IN A 1.2.3.4 +1594 pager1201-rec0674 300 IN A 1.2.3.5 +1595 pager1201-rec0675 300 IN A 1.2.3.4 +1596 pager1201-rec0675 300 IN A 1.2.3.5 +1597 pager1201-rec0676 300 IN A 1.2.3.4 +1598 pager1201-rec0676 300 IN A 1.2.3.5 +1599 pager1201-rec0677 300 IN A 1.2.3.4 +1600 pager1201-rec0677 300 IN A 1.2.3.5 +1601 pager1201-rec0678 300 IN A 1.2.3.4 +1602 pager1201-rec0678 300 IN A 1.2.3.5 +1603 pager1201-rec0679 300 IN A 1.2.3.4 +1604 pager1201-rec0679 300 IN A 1.2.3.5 +1605 pager1201-rec0680 300 IN A 1.2.3.4 +1606 pager1201-rec0680 300 IN A 1.2.3.5 +1607 pager1201-rec0681 300 IN A 1.2.3.4 +1608 pager1201-rec0681 300 IN A 1.2.3.5 +1609 pager1201-rec0682 300 IN A 1.2.3.4 +1610 pager1201-rec0682 300 IN A 1.2.3.5 +1611 pager1201-rec0683 300 IN A 1.2.3.4 +1612 pager1201-rec0683 300 IN A 1.2.3.5 +1613 pager1201-rec0684 300 IN A 1.2.3.4 +1614 pager1201-rec0684 300 IN A 1.2.3.5 +1615 pager1201-rec0685 300 IN A 1.2.3.4 +1616 pager1201-rec0685 300 IN A 1.2.3.5 +1617 pager1201-rec0686 300 IN A 1.2.3.4 +1618 pager1201-rec0686 300 IN A 1.2.3.5 +1619 pager1201-rec0687 300 IN A 1.2.3.4 +1620 pager1201-rec0687 300 IN A 1.2.3.5 +1621 pager1201-rec0688 300 IN A 1.2.3.4 +1622 pager1201-rec0688 300 IN A 1.2.3.5 +1623 pager1201-rec0689 300 IN A 1.2.3.4 +1624 pager1201-rec0689 300 IN A 1.2.3.5 +1625 pager1201-rec0690 300 IN A 1.2.3.4 +1626 pager1201-rec0690 300 IN A 1.2.3.5 +1627 pager1201-rec0691 300 IN A 1.2.3.4 +1628 pager1201-rec0691 300 IN A 1.2.3.5 +1629 pager1201-rec0692 300 IN A 1.2.3.4 +1630 pager1201-rec0692 300 IN A 1.2.3.5 +1631 pager1201-rec0693 300 IN A 1.2.3.4 +1632 pager1201-rec0693 300 IN A 1.2.3.5 +1633 pager1201-rec0694 300 IN A 1.2.3.4 +1634 pager1201-rec0694 300 IN A 1.2.3.5 +1635 pager1201-rec0695 300 IN A 1.2.3.4 +1636 pager1201-rec0695 300 IN A 1.2.3.5 +1637 pager1201-rec0696 300 IN A 1.2.3.4 +1638 pager1201-rec0696 300 IN A 1.2.3.5 +1639 pager1201-rec0697 300 IN A 1.2.3.4 +1640 pager1201-rec0697 300 IN A 1.2.3.5 +1641 pager1201-rec0698 300 IN A 1.2.3.4 +1642 pager1201-rec0698 300 IN A 1.2.3.5 +1643 pager1201-rec0699 300 IN A 1.2.3.4 +1644 pager1201-rec0699 300 IN A 1.2.3.5 +1645 pager1201-rec0700 300 IN A 1.2.3.4 +1646 pager1201-rec0700 300 IN A 1.2.3.5 +1647 pager1201-rec0701 300 IN A 1.2.3.4 +1648 pager1201-rec0701 300 IN A 1.2.3.5 +1649 pager1201-rec0702 300 IN A 1.2.3.4 +1650 pager1201-rec0702 300 IN A 1.2.3.5 +1651 pager1201-rec0703 300 IN A 1.2.3.4 +1652 pager1201-rec0703 300 IN A 1.2.3.5 +1653 pager1201-rec0704 300 IN A 1.2.3.4 +1654 pager1201-rec0704 300 IN A 1.2.3.5 +1655 pager1201-rec0705 300 IN A 1.2.3.4 +1656 pager1201-rec0705 300 IN A 1.2.3.5 +1657 pager1201-rec0706 300 IN A 1.2.3.4 +1658 pager1201-rec0706 300 IN A 1.2.3.5 +1659 pager1201-rec0707 300 IN A 1.2.3.4 +1660 pager1201-rec0707 300 IN A 1.2.3.5 +1661 pager1201-rec0708 300 IN A 1.2.3.4 +1662 pager1201-rec0708 300 IN A 1.2.3.5 +1663 pager1201-rec0709 300 IN A 1.2.3.4 +1664 pager1201-rec0709 300 IN A 1.2.3.5 +1665 pager1201-rec0710 300 IN A 1.2.3.4 +1666 pager1201-rec0710 300 IN A 1.2.3.5 +1667 pager1201-rec0711 300 IN A 1.2.3.4 +1668 pager1201-rec0711 300 IN A 1.2.3.5 +1669 pager1201-rec0712 300 IN A 1.2.3.4 +1670 pager1201-rec0712 300 IN A 1.2.3.5 +1671 pager1201-rec0713 300 IN A 1.2.3.4 +1672 pager1201-rec0713 300 IN A 1.2.3.5 +1673 pager1201-rec0714 300 IN A 1.2.3.4 +1674 pager1201-rec0714 300 IN A 1.2.3.5 +1675 pager1201-rec0715 300 IN A 1.2.3.4 +1676 pager1201-rec0715 300 IN A 1.2.3.5 +1677 pager1201-rec0716 300 IN A 1.2.3.4 +1678 pager1201-rec0716 300 IN A 1.2.3.5 +1679 pager1201-rec0717 300 IN A 1.2.3.4 +1680 pager1201-rec0717 300 IN A 1.2.3.5 +1681 pager1201-rec0718 300 IN A 1.2.3.4 +1682 pager1201-rec0718 300 IN A 1.2.3.5 +1683 pager1201-rec0719 300 IN A 1.2.3.4 +1684 pager1201-rec0719 300 IN A 1.2.3.5 +1685 pager1201-rec0720 300 IN A 1.2.3.4 +1686 pager1201-rec0720 300 IN A 1.2.3.5 +1687 pager1201-rec0721 300 IN A 1.2.3.4 +1688 pager1201-rec0721 300 IN A 1.2.3.5 +1689 pager1201-rec0722 300 IN A 1.2.3.4 +1690 pager1201-rec0722 300 IN A 1.2.3.5 +1691 pager1201-rec0723 300 IN A 1.2.3.4 +1692 pager1201-rec0723 300 IN A 1.2.3.5 +1693 pager1201-rec0724 300 IN A 1.2.3.4 +1694 pager1201-rec0724 300 IN A 1.2.3.5 +1695 pager1201-rec0725 300 IN A 1.2.3.4 +1696 pager1201-rec0725 300 IN A 1.2.3.5 +1697 pager1201-rec0726 300 IN A 1.2.3.4 +1698 pager1201-rec0726 300 IN A 1.2.3.5 +1699 pager1201-rec0727 300 IN A 1.2.3.4 +1700 pager1201-rec0727 300 IN A 1.2.3.5 +1701 pager1201-rec0728 300 IN A 1.2.3.4 +1702 pager1201-rec0728 300 IN A 1.2.3.5 +1703 pager1201-rec0729 300 IN A 1.2.3.4 +1704 pager1201-rec0729 300 IN A 1.2.3.5 +1705 pager1201-rec0730 300 IN A 1.2.3.4 +1706 pager1201-rec0730 300 IN A 1.2.3.5 +1707 pager1201-rec0731 300 IN A 1.2.3.4 +1708 pager1201-rec0731 300 IN A 1.2.3.5 +1709 pager1201-rec0732 300 IN A 1.2.3.4 +1710 pager1201-rec0732 300 IN A 1.2.3.5 +1711 pager1201-rec0733 300 IN A 1.2.3.4 +1712 pager1201-rec0733 300 IN A 1.2.3.5 +1713 pager1201-rec0734 300 IN A 1.2.3.4 +1714 pager1201-rec0734 300 IN A 1.2.3.5 +1715 pager1201-rec0735 300 IN A 1.2.3.4 +1716 pager1201-rec0735 300 IN A 1.2.3.5 +1717 pager1201-rec0736 300 IN A 1.2.3.4 +1718 pager1201-rec0736 300 IN A 1.2.3.5 +1719 pager1201-rec0737 300 IN A 1.2.3.4 +1720 pager1201-rec0737 300 IN A 1.2.3.5 +1721 pager1201-rec0738 300 IN A 1.2.3.4 +1722 pager1201-rec0738 300 IN A 1.2.3.5 +1723 pager1201-rec0739 300 IN A 1.2.3.4 +1724 pager1201-rec0739 300 IN A 1.2.3.5 +1725 pager1201-rec0740 300 IN A 1.2.3.4 +1726 pager1201-rec0740 300 IN A 1.2.3.5 +1727 pager1201-rec0741 300 IN A 1.2.3.4 +1728 pager1201-rec0741 300 IN A 1.2.3.5 +1729 pager1201-rec0742 300 IN A 1.2.3.4 +1730 pager1201-rec0742 300 IN A 1.2.3.5 +1731 pager1201-rec0743 300 IN A 1.2.3.4 +1732 pager1201-rec0743 300 IN A 1.2.3.5 +1733 pager1201-rec0744 300 IN A 1.2.3.4 +1734 pager1201-rec0744 300 IN A 1.2.3.5 +1735 pager1201-rec0745 300 IN A 1.2.3.4 +1736 pager1201-rec0745 300 IN A 1.2.3.5 +1737 pager1201-rec0746 300 IN A 1.2.3.4 +1738 pager1201-rec0746 300 IN A 1.2.3.5 +1739 pager1201-rec0747 300 IN A 1.2.3.4 +1740 pager1201-rec0747 300 IN A 1.2.3.5 +1741 pager1201-rec0748 300 IN A 1.2.3.4 +1742 pager1201-rec0748 300 IN A 1.2.3.5 +1743 pager1201-rec0749 300 IN A 1.2.3.4 +1744 pager1201-rec0749 300 IN A 1.2.3.5 +1745 pager1201-rec0750 300 IN A 1.2.3.4 +1746 pager1201-rec0750 300 IN A 1.2.3.5 +1747 pager1201-rec0751 300 IN A 1.2.3.4 +1748 pager1201-rec0751 300 IN A 1.2.3.5 +1749 pager1201-rec0752 300 IN A 1.2.3.4 +1750 pager1201-rec0752 300 IN A 1.2.3.5 +1751 pager1201-rec0753 300 IN A 1.2.3.4 +1752 pager1201-rec0753 300 IN A 1.2.3.5 +1753 pager1201-rec0754 300 IN A 1.2.3.4 +1754 pager1201-rec0754 300 IN A 1.2.3.5 +1755 pager1201-rec0755 300 IN A 1.2.3.4 +1756 pager1201-rec0755 300 IN A 1.2.3.5 +1757 pager1201-rec0756 300 IN A 1.2.3.4 +1758 pager1201-rec0756 300 IN A 1.2.3.5 +1759 pager1201-rec0757 300 IN A 1.2.3.4 +1760 pager1201-rec0757 300 IN A 1.2.3.5 +1761 pager1201-rec0758 300 IN A 1.2.3.4 +1762 pager1201-rec0758 300 IN A 1.2.3.5 +1763 pager1201-rec0759 300 IN A 1.2.3.4 +1764 pager1201-rec0759 300 IN A 1.2.3.5 +1765 pager1201-rec0760 300 IN A 1.2.3.4 +1766 pager1201-rec0760 300 IN A 1.2.3.5 +1767 pager1201-rec0761 300 IN A 1.2.3.4 +1768 pager1201-rec0761 300 IN A 1.2.3.5 +1769 pager1201-rec0762 300 IN A 1.2.3.4 +1770 pager1201-rec0762 300 IN A 1.2.3.5 +1771 pager1201-rec0763 300 IN A 1.2.3.4 +1772 pager1201-rec0763 300 IN A 1.2.3.5 +1773 pager1201-rec0764 300 IN A 1.2.3.4 +1774 pager1201-rec0764 300 IN A 1.2.3.5 +1775 pager1201-rec0765 300 IN A 1.2.3.4 +1776 pager1201-rec0765 300 IN A 1.2.3.5 +1777 pager1201-rec0766 300 IN A 1.2.3.4 +1778 pager1201-rec0766 300 IN A 1.2.3.5 +1779 pager1201-rec0767 300 IN A 1.2.3.4 +1780 pager1201-rec0767 300 IN A 1.2.3.5 +1781 pager1201-rec0768 300 IN A 1.2.3.4 +1782 pager1201-rec0768 300 IN A 1.2.3.5 +1783 pager1201-rec0769 300 IN A 1.2.3.4 +1784 pager1201-rec0769 300 IN A 1.2.3.5 +1785 pager1201-rec0770 300 IN A 1.2.3.4 +1786 pager1201-rec0770 300 IN A 1.2.3.5 +1787 pager1201-rec0771 300 IN A 1.2.3.4 +1788 pager1201-rec0771 300 IN A 1.2.3.5 +1789 pager1201-rec0772 300 IN A 1.2.3.4 +1790 pager1201-rec0772 300 IN A 1.2.3.5 +1791 pager1201-rec0773 300 IN A 1.2.3.4 +1792 pager1201-rec0773 300 IN A 1.2.3.5 +1793 pager1201-rec0774 300 IN A 1.2.3.4 +1794 pager1201-rec0774 300 IN A 1.2.3.5 +1795 pager1201-rec0775 300 IN A 1.2.3.4 +1796 pager1201-rec0775 300 IN A 1.2.3.5 +1797 pager1201-rec0776 300 IN A 1.2.3.4 +1798 pager1201-rec0776 300 IN A 1.2.3.5 +1799 pager1201-rec0777 300 IN A 1.2.3.4 +1800 pager1201-rec0777 300 IN A 1.2.3.5 +1801 pager1201-rec0778 300 IN A 1.2.3.4 +1802 pager1201-rec0778 300 IN A 1.2.3.5 +1803 pager1201-rec0779 300 IN A 1.2.3.4 +1804 pager1201-rec0779 300 IN A 1.2.3.5 +1805 pager1201-rec0780 300 IN A 1.2.3.4 +1806 pager1201-rec0780 300 IN A 1.2.3.5 +1807 pager1201-rec0781 300 IN A 1.2.3.4 +1808 pager1201-rec0781 300 IN A 1.2.3.5 +1809 pager1201-rec0782 300 IN A 1.2.3.4 +1810 pager1201-rec0782 300 IN A 1.2.3.5 +1811 pager1201-rec0783 300 IN A 1.2.3.4 +1812 pager1201-rec0783 300 IN A 1.2.3.5 +1813 pager1201-rec0784 300 IN A 1.2.3.4 +1814 pager1201-rec0784 300 IN A 1.2.3.5 +1815 pager1201-rec0785 300 IN A 1.2.3.4 +1816 pager1201-rec0785 300 IN A 1.2.3.5 +1817 pager1201-rec0786 300 IN A 1.2.3.4 +1818 pager1201-rec0786 300 IN A 1.2.3.5 +1819 pager1201-rec0787 300 IN A 1.2.3.4 +1820 pager1201-rec0787 300 IN A 1.2.3.5 +1821 pager1201-rec0788 300 IN A 1.2.3.4 +1822 pager1201-rec0788 300 IN A 1.2.3.5 +1823 pager1201-rec0789 300 IN A 1.2.3.4 +1824 pager1201-rec0789 300 IN A 1.2.3.5 +1825 pager1201-rec0790 300 IN A 1.2.3.4 +1826 pager1201-rec0790 300 IN A 1.2.3.5 +1827 pager1201-rec0791 300 IN A 1.2.3.4 +1828 pager1201-rec0791 300 IN A 1.2.3.5 +1829 pager1201-rec0792 300 IN A 1.2.3.4 +1830 pager1201-rec0792 300 IN A 1.2.3.5 +1831 pager1201-rec0793 300 IN A 1.2.3.4 +1832 pager1201-rec0793 300 IN A 1.2.3.5 +1833 pager1201-rec0794 300 IN A 1.2.3.4 +1834 pager1201-rec0794 300 IN A 1.2.3.5 +1835 pager1201-rec0795 300 IN A 1.2.3.4 +1836 pager1201-rec0795 300 IN A 1.2.3.5 +1837 pager1201-rec0796 300 IN A 1.2.3.4 +1838 pager1201-rec0796 300 IN A 1.2.3.5 +1839 pager1201-rec0797 300 IN A 1.2.3.4 +1840 pager1201-rec0797 300 IN A 1.2.3.5 +1841 pager1201-rec0798 300 IN A 1.2.3.4 +1842 pager1201-rec0798 300 IN A 1.2.3.5 +1843 pager1201-rec0799 300 IN A 1.2.3.4 +1844 pager1201-rec0799 300 IN A 1.2.3.5 +1845 pager1201-rec0800 300 IN A 1.2.3.4 +1846 pager1201-rec0800 300 IN A 1.2.3.5 +1847 pager1201-rec0801 300 IN A 1.2.3.4 +1848 pager1201-rec0801 300 IN A 1.2.3.5 +1849 pager1201-rec0802 300 IN A 1.2.3.4 +1850 pager1201-rec0802 300 IN A 1.2.3.5 +1851 pager1201-rec0803 300 IN A 1.2.3.4 +1852 pager1201-rec0803 300 IN A 1.2.3.5 +1853 pager1201-rec0804 300 IN A 1.2.3.4 +1854 pager1201-rec0804 300 IN A 1.2.3.5 +1855 pager1201-rec0805 300 IN A 1.2.3.4 +1856 pager1201-rec0805 300 IN A 1.2.3.5 +1857 pager1201-rec0806 300 IN A 1.2.3.4 +1858 pager1201-rec0806 300 IN A 1.2.3.5 +1859 pager1201-rec0807 300 IN A 1.2.3.4 +1860 pager1201-rec0807 300 IN A 1.2.3.5 +1861 pager1201-rec0808 300 IN A 1.2.3.4 +1862 pager1201-rec0808 300 IN A 1.2.3.5 +1863 pager1201-rec0809 300 IN A 1.2.3.4 +1864 pager1201-rec0809 300 IN A 1.2.3.5 +1865 pager1201-rec0810 300 IN A 1.2.3.4 +1866 pager1201-rec0810 300 IN A 1.2.3.5 +1867 pager1201-rec0811 300 IN A 1.2.3.4 +1868 pager1201-rec0811 300 IN A 1.2.3.5 +1869 pager1201-rec0812 300 IN A 1.2.3.4 +1870 pager1201-rec0812 300 IN A 1.2.3.5 +1871 pager1201-rec0813 300 IN A 1.2.3.4 +1872 pager1201-rec0813 300 IN A 1.2.3.5 +1873 pager1201-rec0814 300 IN A 1.2.3.4 +1874 pager1201-rec0814 300 IN A 1.2.3.5 +1875 pager1201-rec0815 300 IN A 1.2.3.4 +1876 pager1201-rec0815 300 IN A 1.2.3.5 +1877 pager1201-rec0816 300 IN A 1.2.3.4 +1878 pager1201-rec0816 300 IN A 1.2.3.5 +1879 pager1201-rec0817 300 IN A 1.2.3.4 +1880 pager1201-rec0817 300 IN A 1.2.3.5 +1881 pager1201-rec0818 300 IN A 1.2.3.4 +1882 pager1201-rec0818 300 IN A 1.2.3.5 +1883 pager1201-rec0819 300 IN A 1.2.3.4 +1884 pager1201-rec0819 300 IN A 1.2.3.5 +1885 pager1201-rec0820 300 IN A 1.2.3.4 +1886 pager1201-rec0820 300 IN A 1.2.3.5 +1887 pager1201-rec0821 300 IN A 1.2.3.4 +1888 pager1201-rec0821 300 IN A 1.2.3.5 +1889 pager1201-rec0822 300 IN A 1.2.3.4 +1890 pager1201-rec0822 300 IN A 1.2.3.5 +1891 pager1201-rec0823 300 IN A 1.2.3.4 +1892 pager1201-rec0823 300 IN A 1.2.3.5 +1893 pager1201-rec0824 300 IN A 1.2.3.4 +1894 pager1201-rec0824 300 IN A 1.2.3.5 +1895 pager1201-rec0825 300 IN A 1.2.3.4 +1896 pager1201-rec0825 300 IN A 1.2.3.5 +1897 pager1201-rec0826 300 IN A 1.2.3.4 +1898 pager1201-rec0826 300 IN A 1.2.3.5 +1899 pager1201-rec0827 300 IN A 1.2.3.4 +1900 pager1201-rec0827 300 IN A 1.2.3.5 +1901 pager1201-rec0828 300 IN A 1.2.3.4 +1902 pager1201-rec0828 300 IN A 1.2.3.5 +1903 pager1201-rec0829 300 IN A 1.2.3.4 +1904 pager1201-rec0829 300 IN A 1.2.3.5 +1905 pager1201-rec0830 300 IN A 1.2.3.4 +1906 pager1201-rec0830 300 IN A 1.2.3.5 +1907 pager1201-rec0831 300 IN A 1.2.3.4 +1908 pager1201-rec0831 300 IN A 1.2.3.5 +1909 pager1201-rec0832 300 IN A 1.2.3.4 +1910 pager1201-rec0832 300 IN A 1.2.3.5 +1911 pager1201-rec0833 300 IN A 1.2.3.4 +1912 pager1201-rec0833 300 IN A 1.2.3.5 +1913 pager1201-rec0834 300 IN A 1.2.3.4 +1914 pager1201-rec0834 300 IN A 1.2.3.5 +1915 pager1201-rec0835 300 IN A 1.2.3.4 +1916 pager1201-rec0835 300 IN A 1.2.3.5 +1917 pager1201-rec0836 300 IN A 1.2.3.4 +1918 pager1201-rec0836 300 IN A 1.2.3.5 +1919 pager1201-rec0837 300 IN A 1.2.3.4 +1920 pager1201-rec0837 300 IN A 1.2.3.5 +1921 pager1201-rec0838 300 IN A 1.2.3.4 +1922 pager1201-rec0838 300 IN A 1.2.3.5 +1923 pager1201-rec0839 300 IN A 1.2.3.4 +1924 pager1201-rec0839 300 IN A 1.2.3.5 +1925 pager1201-rec0840 300 IN A 1.2.3.4 +1926 pager1201-rec0840 300 IN A 1.2.3.5 +1927 pager1201-rec0841 300 IN A 1.2.3.4 +1928 pager1201-rec0841 300 IN A 1.2.3.5 +1929 pager1201-rec0842 300 IN A 1.2.3.4 +1930 pager1201-rec0842 300 IN A 1.2.3.5 +1931 pager1201-rec0843 300 IN A 1.2.3.4 +1932 pager1201-rec0843 300 IN A 1.2.3.5 +1933 pager1201-rec0844 300 IN A 1.2.3.4 +1934 pager1201-rec0844 300 IN A 1.2.3.5 +1935 pager1201-rec0845 300 IN A 1.2.3.4 +1936 pager1201-rec0845 300 IN A 1.2.3.5 +1937 pager1201-rec0846 300 IN A 1.2.3.4 +1938 pager1201-rec0846 300 IN A 1.2.3.5 +1939 pager1201-rec0847 300 IN A 1.2.3.4 +1940 pager1201-rec0847 300 IN A 1.2.3.5 +1941 pager1201-rec0848 300 IN A 1.2.3.4 +1942 pager1201-rec0848 300 IN A 1.2.3.5 +1943 pager1201-rec0849 300 IN A 1.2.3.4 +1944 pager1201-rec0849 300 IN A 1.2.3.5 +1945 pager1201-rec0850 300 IN A 1.2.3.4 +1946 pager1201-rec0850 300 IN A 1.2.3.5 +1947 pager1201-rec0851 300 IN A 1.2.3.4 +1948 pager1201-rec0851 300 IN A 1.2.3.5 +1949 pager1201-rec0852 300 IN A 1.2.3.4 +1950 pager1201-rec0852 300 IN A 1.2.3.5 +1951 pager1201-rec0853 300 IN A 1.2.3.4 +1952 pager1201-rec0853 300 IN A 1.2.3.5 +1953 pager1201-rec0854 300 IN A 1.2.3.4 +1954 pager1201-rec0854 300 IN A 1.2.3.5 +1955 pager1201-rec0855 300 IN A 1.2.3.4 +1956 pager1201-rec0855 300 IN A 1.2.3.5 +1957 pager1201-rec0856 300 IN A 1.2.3.4 +1958 pager1201-rec0856 300 IN A 1.2.3.5 +1959 pager1201-rec0857 300 IN A 1.2.3.4 +1960 pager1201-rec0857 300 IN A 1.2.3.5 +1961 pager1201-rec0858 300 IN A 1.2.3.4 +1962 pager1201-rec0858 300 IN A 1.2.3.5 +1963 pager1201-rec0859 300 IN A 1.2.3.4 +1964 pager1201-rec0859 300 IN A 1.2.3.5 +1965 pager1201-rec0860 300 IN A 1.2.3.4 +1966 pager1201-rec0860 300 IN A 1.2.3.5 +1967 pager1201-rec0861 300 IN A 1.2.3.4 +1968 pager1201-rec0861 300 IN A 1.2.3.5 +1969 pager1201-rec0862 300 IN A 1.2.3.4 +1970 pager1201-rec0862 300 IN A 1.2.3.5 +1971 pager1201-rec0863 300 IN A 1.2.3.4 +1972 pager1201-rec0863 300 IN A 1.2.3.5 +1973 pager1201-rec0864 300 IN A 1.2.3.4 +1974 pager1201-rec0864 300 IN A 1.2.3.5 +1975 pager1201-rec0865 300 IN A 1.2.3.4 +1976 pager1201-rec0865 300 IN A 1.2.3.5 +1977 pager1201-rec0866 300 IN A 1.2.3.4 +1978 pager1201-rec0866 300 IN A 1.2.3.5 +1979 pager1201-rec0867 300 IN A 1.2.3.4 +1980 pager1201-rec0867 300 IN A 1.2.3.5 +1981 pager1201-rec0868 300 IN A 1.2.3.4 +1982 pager1201-rec0868 300 IN A 1.2.3.5 +1983 pager1201-rec0869 300 IN A 1.2.3.4 +1984 pager1201-rec0869 300 IN A 1.2.3.5 +1985 pager1201-rec0870 300 IN A 1.2.3.4 +1986 pager1201-rec0870 300 IN A 1.2.3.5 +1987 pager1201-rec0871 300 IN A 1.2.3.4 +1988 pager1201-rec0871 300 IN A 1.2.3.5 +1989 pager1201-rec0872 300 IN A 1.2.3.4 +1990 pager1201-rec0872 300 IN A 1.2.3.5 +1991 pager1201-rec0873 300 IN A 1.2.3.4 +1992 pager1201-rec0873 300 IN A 1.2.3.5 +1993 pager1201-rec0874 300 IN A 1.2.3.4 +1994 pager1201-rec0874 300 IN A 1.2.3.5 +1995 pager1201-rec0875 300 IN A 1.2.3.4 +1996 pager1201-rec0875 300 IN A 1.2.3.5 +1997 pager1201-rec0876 300 IN A 1.2.3.4 +1998 pager1201-rec0876 300 IN A 1.2.3.5 +1999 pager1201-rec0877 300 IN A 1.2.3.4 +2000 pager1201-rec0877 300 IN A 1.2.3.5 +2001 pager1201-rec0878 300 IN A 1.2.3.4 +2002 pager1201-rec0878 300 IN A 1.2.3.5 +2003 pager1201-rec0879 300 IN A 1.2.3.4 +2004 pager1201-rec0879 300 IN A 1.2.3.5 +2005 pager1201-rec0880 300 IN A 1.2.3.4 +2006 pager1201-rec0880 300 IN A 1.2.3.5 +2007 pager1201-rec0881 300 IN A 1.2.3.4 +2008 pager1201-rec0881 300 IN A 1.2.3.5 +2009 pager1201-rec0882 300 IN A 1.2.3.4 +2010 pager1201-rec0882 300 IN A 1.2.3.5 +2011 pager1201-rec0883 300 IN A 1.2.3.4 +2012 pager1201-rec0883 300 IN A 1.2.3.5 +2013 pager1201-rec0884 300 IN A 1.2.3.4 +2014 pager1201-rec0884 300 IN A 1.2.3.5 +2015 pager1201-rec0885 300 IN A 1.2.3.4 +2016 pager1201-rec0885 300 IN A 1.2.3.5 +2017 pager1201-rec0886 300 IN A 1.2.3.4 +2018 pager1201-rec0886 300 IN A 1.2.3.5 +2019 pager1201-rec0887 300 IN A 1.2.3.4 +2020 pager1201-rec0887 300 IN A 1.2.3.5 +2021 pager1201-rec0888 300 IN A 1.2.3.4 +2022 pager1201-rec0888 300 IN A 1.2.3.5 +2023 pager1201-rec0889 300 IN A 1.2.3.4 +2024 pager1201-rec0889 300 IN A 1.2.3.5 +2025 pager1201-rec0890 300 IN A 1.2.3.4 +2026 pager1201-rec0890 300 IN A 1.2.3.5 +2027 pager1201-rec0891 300 IN A 1.2.3.4 +2028 pager1201-rec0891 300 IN A 1.2.3.5 +2029 pager1201-rec0892 300 IN A 1.2.3.4 +2030 pager1201-rec0892 300 IN A 1.2.3.5 +2031 pager1201-rec0893 300 IN A 1.2.3.4 +2032 pager1201-rec0893 300 IN A 1.2.3.5 +2033 pager1201-rec0894 300 IN A 1.2.3.4 +2034 pager1201-rec0894 300 IN A 1.2.3.5 +2035 pager1201-rec0895 300 IN A 1.2.3.4 +2036 pager1201-rec0895 300 IN A 1.2.3.5 +2037 pager1201-rec0896 300 IN A 1.2.3.4 +2038 pager1201-rec0896 300 IN A 1.2.3.5 +2039 pager1201-rec0897 300 IN A 1.2.3.4 +2040 pager1201-rec0897 300 IN A 1.2.3.5 +2041 pager1201-rec0898 300 IN A 1.2.3.4 +2042 pager1201-rec0898 300 IN A 1.2.3.5 +2043 pager1201-rec0899 300 IN A 1.2.3.4 +2044 pager1201-rec0899 300 IN A 1.2.3.5 +2045 pager1201-rec0900 300 IN A 1.2.3.4 +2046 pager1201-rec0900 300 IN A 1.2.3.5 +2047 pager1201-rec0901 300 IN A 1.2.3.4 +2048 pager1201-rec0901 300 IN A 1.2.3.5 +2049 pager1201-rec0902 300 IN A 1.2.3.4 +2050 pager1201-rec0902 300 IN A 1.2.3.5 +2051 pager1201-rec0903 300 IN A 1.2.3.4 +2052 pager1201-rec0903 300 IN A 1.2.3.5 +2053 pager1201-rec0904 300 IN A 1.2.3.4 +2054 pager1201-rec0904 300 IN A 1.2.3.5 +2055 pager1201-rec0905 300 IN A 1.2.3.4 +2056 pager1201-rec0905 300 IN A 1.2.3.5 +2057 pager1201-rec0906 300 IN A 1.2.3.4 +2058 pager1201-rec0906 300 IN A 1.2.3.5 +2059 pager1201-rec0907 300 IN A 1.2.3.4 +2060 pager1201-rec0907 300 IN A 1.2.3.5 +2061 pager1201-rec0908 300 IN A 1.2.3.4 +2062 pager1201-rec0908 300 IN A 1.2.3.5 +2063 pager1201-rec0909 300 IN A 1.2.3.4 +2064 pager1201-rec0909 300 IN A 1.2.3.5 +2065 pager1201-rec0910 300 IN A 1.2.3.4 +2066 pager1201-rec0910 300 IN A 1.2.3.5 +2067 pager1201-rec0911 300 IN A 1.2.3.4 +2068 pager1201-rec0911 300 IN A 1.2.3.5 +2069 pager1201-rec0912 300 IN A 1.2.3.4 +2070 pager1201-rec0912 300 IN A 1.2.3.5 +2071 pager1201-rec0913 300 IN A 1.2.3.4 +2072 pager1201-rec0913 300 IN A 1.2.3.5 +2073 pager1201-rec0914 300 IN A 1.2.3.4 +2074 pager1201-rec0914 300 IN A 1.2.3.5 +2075 pager1201-rec0915 300 IN A 1.2.3.4 +2076 pager1201-rec0915 300 IN A 1.2.3.5 +2077 pager1201-rec0916 300 IN A 1.2.3.4 +2078 pager1201-rec0916 300 IN A 1.2.3.5 +2079 pager1201-rec0917 300 IN A 1.2.3.4 +2080 pager1201-rec0917 300 IN A 1.2.3.5 +2081 pager1201-rec0918 300 IN A 1.2.3.4 +2082 pager1201-rec0918 300 IN A 1.2.3.5 +2083 pager1201-rec0919 300 IN A 1.2.3.4 +2084 pager1201-rec0919 300 IN A 1.2.3.5 +2085 pager1201-rec0920 300 IN A 1.2.3.4 +2086 pager1201-rec0920 300 IN A 1.2.3.5 +2087 pager1201-rec0921 300 IN A 1.2.3.4 +2088 pager1201-rec0921 300 IN A 1.2.3.5 +2089 pager1201-rec0922 300 IN A 1.2.3.4 +2090 pager1201-rec0922 300 IN A 1.2.3.5 +2091 pager1201-rec0923 300 IN A 1.2.3.4 +2092 pager1201-rec0923 300 IN A 1.2.3.5 +2093 pager1201-rec0924 300 IN A 1.2.3.4 +2094 pager1201-rec0924 300 IN A 1.2.3.5 +2095 pager1201-rec0925 300 IN A 1.2.3.4 +2096 pager1201-rec0925 300 IN A 1.2.3.5 +2097 pager1201-rec0926 300 IN A 1.2.3.4 +2098 pager1201-rec0926 300 IN A 1.2.3.5 +2099 pager1201-rec0927 300 IN A 1.2.3.4 +2100 pager1201-rec0927 300 IN A 1.2.3.5 +2101 pager1201-rec0928 300 IN A 1.2.3.4 +2102 pager1201-rec0928 300 IN A 1.2.3.5 +2103 pager1201-rec0929 300 IN A 1.2.3.4 +2104 pager1201-rec0929 300 IN A 1.2.3.5 +2105 pager1201-rec0930 300 IN A 1.2.3.4 +2106 pager1201-rec0930 300 IN A 1.2.3.5 +2107 pager1201-rec0931 300 IN A 1.2.3.4 +2108 pager1201-rec0931 300 IN A 1.2.3.5 +2109 pager1201-rec0932 300 IN A 1.2.3.4 +2110 pager1201-rec0932 300 IN A 1.2.3.5 +2111 pager1201-rec0933 300 IN A 1.2.3.4 +2112 pager1201-rec0933 300 IN A 1.2.3.5 +2113 pager1201-rec0934 300 IN A 1.2.3.4 +2114 pager1201-rec0934 300 IN A 1.2.3.5 +2115 pager1201-rec0935 300 IN A 1.2.3.4 +2116 pager1201-rec0935 300 IN A 1.2.3.5 +2117 pager1201-rec0936 300 IN A 1.2.3.4 +2118 pager1201-rec0936 300 IN A 1.2.3.5 +2119 pager1201-rec0937 300 IN A 1.2.3.4 +2120 pager1201-rec0937 300 IN A 1.2.3.5 +2121 pager1201-rec0938 300 IN A 1.2.3.4 +2122 pager1201-rec0938 300 IN A 1.2.3.5 +2123 pager1201-rec0939 300 IN A 1.2.3.4 +2124 pager1201-rec0939 300 IN A 1.2.3.5 +2125 pager1201-rec0940 300 IN A 1.2.3.4 +2126 pager1201-rec0940 300 IN A 1.2.3.5 +2127 pager1201-rec0941 300 IN A 1.2.3.4 +2128 pager1201-rec0941 300 IN A 1.2.3.5 +2129 pager1201-rec0942 300 IN A 1.2.3.4 +2130 pager1201-rec0942 300 IN A 1.2.3.5 +2131 pager1201-rec0943 300 IN A 1.2.3.4 +2132 pager1201-rec0943 300 IN A 1.2.3.5 +2133 pager1201-rec0944 300 IN A 1.2.3.4 +2134 pager1201-rec0944 300 IN A 1.2.3.5 +2135 pager1201-rec0945 300 IN A 1.2.3.4 +2136 pager1201-rec0945 300 IN A 1.2.3.5 +2137 pager1201-rec0946 300 IN A 1.2.3.4 +2138 pager1201-rec0946 300 IN A 1.2.3.5 +2139 pager1201-rec0947 300 IN A 1.2.3.4 +2140 pager1201-rec0947 300 IN A 1.2.3.5 +2141 pager1201-rec0948 300 IN A 1.2.3.4 +2142 pager1201-rec0948 300 IN A 1.2.3.5 +2143 pager1201-rec0949 300 IN A 1.2.3.4 +2144 pager1201-rec0949 300 IN A 1.2.3.5 +2145 pager1201-rec0950 300 IN A 1.2.3.4 +2146 pager1201-rec0950 300 IN A 1.2.3.5 +2147 pager1201-rec0951 300 IN A 1.2.3.4 +2148 pager1201-rec0951 300 IN A 1.2.3.5 +2149 pager1201-rec0952 300 IN A 1.2.3.4 +2150 pager1201-rec0952 300 IN A 1.2.3.5 +2151 pager1201-rec0953 300 IN A 1.2.3.4 +2152 pager1201-rec0953 300 IN A 1.2.3.5 +2153 pager1201-rec0954 300 IN A 1.2.3.4 +2154 pager1201-rec0954 300 IN A 1.2.3.5 +2155 pager1201-rec0955 300 IN A 1.2.3.4 +2156 pager1201-rec0955 300 IN A 1.2.3.5 +2157 pager1201-rec0956 300 IN A 1.2.3.4 +2158 pager1201-rec0956 300 IN A 1.2.3.5 +2159 pager1201-rec0957 300 IN A 1.2.3.4 +2160 pager1201-rec0957 300 IN A 1.2.3.5 +2161 pager1201-rec0958 300 IN A 1.2.3.4 +2162 pager1201-rec0958 300 IN A 1.2.3.5 +2163 pager1201-rec0959 300 IN A 1.2.3.4 +2164 pager1201-rec0959 300 IN A 1.2.3.5 +2165 pager1201-rec0960 300 IN A 1.2.3.4 +2166 pager1201-rec0960 300 IN A 1.2.3.5 +2167 pager1201-rec0961 300 IN A 1.2.3.4 +2168 pager1201-rec0961 300 IN A 1.2.3.5 +2169 pager1201-rec0962 300 IN A 1.2.3.4 +2170 pager1201-rec0962 300 IN A 1.2.3.5 +2171 pager1201-rec0963 300 IN A 1.2.3.4 +2172 pager1201-rec0963 300 IN A 1.2.3.5 +2173 pager1201-rec0964 300 IN A 1.2.3.4 +2174 pager1201-rec0964 300 IN A 1.2.3.5 +2175 pager1201-rec0965 300 IN A 1.2.3.4 +2176 pager1201-rec0965 300 IN A 1.2.3.5 +2177 pager1201-rec0966 300 IN A 1.2.3.4 +2178 pager1201-rec0966 300 IN A 1.2.3.5 +2179 pager1201-rec0967 300 IN A 1.2.3.4 +2180 pager1201-rec0967 300 IN A 1.2.3.5 +2181 pager1201-rec0968 300 IN A 1.2.3.4 +2182 pager1201-rec0968 300 IN A 1.2.3.5 +2183 pager1201-rec0969 300 IN A 1.2.3.4 +2184 pager1201-rec0969 300 IN A 1.2.3.5 +2185 pager1201-rec0970 300 IN A 1.2.3.4 +2186 pager1201-rec0970 300 IN A 1.2.3.5 +2187 pager1201-rec0971 300 IN A 1.2.3.4 +2188 pager1201-rec0971 300 IN A 1.2.3.5 +2189 pager1201-rec0972 300 IN A 1.2.3.4 +2190 pager1201-rec0972 300 IN A 1.2.3.5 +2191 pager1201-rec0973 300 IN A 1.2.3.4 +2192 pager1201-rec0973 300 IN A 1.2.3.5 +2193 pager1201-rec0974 300 IN A 1.2.3.4 +2194 pager1201-rec0974 300 IN A 1.2.3.5 +2195 pager1201-rec0975 300 IN A 1.2.3.4 +2196 pager1201-rec0975 300 IN A 1.2.3.5 +2197 pager1201-rec0976 300 IN A 1.2.3.4 +2198 pager1201-rec0976 300 IN A 1.2.3.5 +2199 pager1201-rec0977 300 IN A 1.2.3.4 +2200 pager1201-rec0977 300 IN A 1.2.3.5 +2201 pager1201-rec0978 300 IN A 1.2.3.4 +2202 pager1201-rec0978 300 IN A 1.2.3.5 +2203 pager1201-rec0979 300 IN A 1.2.3.4 +2204 pager1201-rec0979 300 IN A 1.2.3.5 +2205 pager1201-rec0980 300 IN A 1.2.3.4 +2206 pager1201-rec0980 300 IN A 1.2.3.5 +2207 pager1201-rec0981 300 IN A 1.2.3.4 +2208 pager1201-rec0981 300 IN A 1.2.3.5 +2209 pager1201-rec0982 300 IN A 1.2.3.4 +2210 pager1201-rec0982 300 IN A 1.2.3.5 +2211 pager1201-rec0983 300 IN A 1.2.3.4 +2212 pager1201-rec0983 300 IN A 1.2.3.5 +2213 pager1201-rec0984 300 IN A 1.2.3.4 +2214 pager1201-rec0984 300 IN A 1.2.3.5 +2215 pager1201-rec0985 300 IN A 1.2.3.4 +2216 pager1201-rec0985 300 IN A 1.2.3.5 +2217 pager1201-rec0986 300 IN A 1.2.3.4 +2218 pager1201-rec0986 300 IN A 1.2.3.5 +2219 pager1201-rec0987 300 IN A 1.2.3.4 +2220 pager1201-rec0987 300 IN A 1.2.3.5 +2221 pager1201-rec0988 300 IN A 1.2.3.4 +2222 pager1201-rec0988 300 IN A 1.2.3.5 +2223 pager1201-rec0989 300 IN A 1.2.3.4 +2224 pager1201-rec0989 300 IN A 1.2.3.5 +2225 pager1201-rec0990 300 IN A 1.2.3.4 +2226 pager1201-rec0990 300 IN A 1.2.3.5 +2227 pager1201-rec0991 300 IN A 1.2.3.4 +2228 pager1201-rec0991 300 IN A 1.2.3.5 +2229 pager1201-rec0992 300 IN A 1.2.3.4 +2230 pager1201-rec0992 300 IN A 1.2.3.5 +2231 pager1201-rec0993 300 IN A 1.2.3.4 +2232 pager1201-rec0993 300 IN A 1.2.3.5 +2233 pager1201-rec0994 300 IN A 1.2.3.4 +2234 pager1201-rec0994 300 IN A 1.2.3.5 +2235 pager1201-rec0995 300 IN A 1.2.3.4 +2236 pager1201-rec0995 300 IN A 1.2.3.5 +2237 pager1201-rec0996 300 IN A 1.2.3.4 +2238 pager1201-rec0996 300 IN A 1.2.3.5 +2239 pager1201-rec0997 300 IN A 1.2.3.4 +2240 pager1201-rec0997 300 IN A 1.2.3.5 +2241 pager1201-rec0998 300 IN A 1.2.3.4 +2242 pager1201-rec0998 300 IN A 1.2.3.5 +2243 pager1201-rec0999 300 IN A 1.2.3.4 +2244 pager1201-rec0999 300 IN A 1.2.3.5 +2245 pager1201-rec1000 300 IN A 1.2.3.4 +2246 pager1201-rec1000 300 IN A 1.2.3.5 +2247 pager1201-rec1001 300 IN A 1.2.3.4 +2248 pager1201-rec1001 300 IN A 1.2.3.5 +2249 pager1201-rec1002 300 IN A 1.2.3.4 +2250 pager1201-rec1002 300 IN A 1.2.3.5 +2251 pager1201-rec1003 300 IN A 1.2.3.4 +2252 pager1201-rec1003 300 IN A 1.2.3.5 +2253 pager1201-rec1004 300 IN A 1.2.3.4 +2254 pager1201-rec1004 300 IN A 1.2.3.5 +2255 pager1201-rec1005 300 IN A 1.2.3.4 +2256 pager1201-rec1005 300 IN A 1.2.3.5 +2257 pager1201-rec1006 300 IN A 1.2.3.4 +2258 pager1201-rec1006 300 IN A 1.2.3.5 +2259 pager1201-rec1007 300 IN A 1.2.3.4 +2260 pager1201-rec1007 300 IN A 1.2.3.5 +2261 pager1201-rec1008 300 IN A 1.2.3.4 +2262 pager1201-rec1008 300 IN A 1.2.3.5 +2263 pager1201-rec1009 300 IN A 1.2.3.4 +2264 pager1201-rec1009 300 IN A 1.2.3.5 +2265 pager1201-rec1010 300 IN A 1.2.3.4 +2266 pager1201-rec1010 300 IN A 1.2.3.5 +2267 pager1201-rec1011 300 IN A 1.2.3.4 +2268 pager1201-rec1011 300 IN A 1.2.3.5 +2269 pager1201-rec1012 300 IN A 1.2.3.4 +2270 pager1201-rec1012 300 IN A 1.2.3.5 +2271 pager1201-rec1013 300 IN A 1.2.3.4 +2272 pager1201-rec1013 300 IN A 1.2.3.5 +2273 pager1201-rec1014 300 IN A 1.2.3.4 +2274 pager1201-rec1014 300 IN A 1.2.3.5 +2275 pager1201-rec1015 300 IN A 1.2.3.4 +2276 pager1201-rec1015 300 IN A 1.2.3.5 +2277 pager1201-rec1016 300 IN A 1.2.3.4 +2278 pager1201-rec1016 300 IN A 1.2.3.5 +2279 pager1201-rec1017 300 IN A 1.2.3.4 +2280 pager1201-rec1017 300 IN A 1.2.3.5 +2281 pager1201-rec1018 300 IN A 1.2.3.4 +2282 pager1201-rec1018 300 IN A 1.2.3.5 +2283 pager1201-rec1019 300 IN A 1.2.3.4 +2284 pager1201-rec1019 300 IN A 1.2.3.5 +2285 pager1201-rec1020 300 IN A 1.2.3.4 +2286 pager1201-rec1020 300 IN A 1.2.3.5 +2287 pager1201-rec1021 300 IN A 1.2.3.4 +2288 pager1201-rec1021 300 IN A 1.2.3.5 +2289 pager1201-rec1022 300 IN A 1.2.3.4 +2290 pager1201-rec1022 300 IN A 1.2.3.5 +2291 pager1201-rec1023 300 IN A 1.2.3.4 +2292 pager1201-rec1023 300 IN A 1.2.3.5 +2293 pager1201-rec1024 300 IN A 1.2.3.4 +2294 pager1201-rec1024 300 IN A 1.2.3.5 +2295 pager1201-rec1025 300 IN A 1.2.3.4 +2296 pager1201-rec1025 300 IN A 1.2.3.5 +2297 pager1201-rec1026 300 IN A 1.2.3.4 +2298 pager1201-rec1026 300 IN A 1.2.3.5 +2299 pager1201-rec1027 300 IN A 1.2.3.4 +2300 pager1201-rec1027 300 IN A 1.2.3.5 +2301 pager1201-rec1028 300 IN A 1.2.3.4 +2302 pager1201-rec1028 300 IN A 1.2.3.5 +2303 pager1201-rec1029 300 IN A 1.2.3.4 +2304 pager1201-rec1029 300 IN A 1.2.3.5 +2305 pager1201-rec1030 300 IN A 1.2.3.4 +2306 pager1201-rec1030 300 IN A 1.2.3.5 +2307 pager1201-rec1031 300 IN A 1.2.3.4 +2308 pager1201-rec1031 300 IN A 1.2.3.5 +2309 pager1201-rec1032 300 IN A 1.2.3.4 +2310 pager1201-rec1032 300 IN A 1.2.3.5 +2311 pager1201-rec1033 300 IN A 1.2.3.4 +2312 pager1201-rec1033 300 IN A 1.2.3.5 +2313 pager1201-rec1034 300 IN A 1.2.3.4 +2314 pager1201-rec1034 300 IN A 1.2.3.5 +2315 pager1201-rec1035 300 IN A 1.2.3.4 +2316 pager1201-rec1035 300 IN A 1.2.3.5 +2317 pager1201-rec1036 300 IN A 1.2.3.4 +2318 pager1201-rec1036 300 IN A 1.2.3.5 +2319 pager1201-rec1037 300 IN A 1.2.3.4 +2320 pager1201-rec1037 300 IN A 1.2.3.5 +2321 pager1201-rec1038 300 IN A 1.2.3.4 +2322 pager1201-rec1038 300 IN A 1.2.3.5 +2323 pager1201-rec1039 300 IN A 1.2.3.4 +2324 pager1201-rec1039 300 IN A 1.2.3.5 +2325 pager1201-rec1040 300 IN A 1.2.3.4 +2326 pager1201-rec1040 300 IN A 1.2.3.5 +2327 pager1201-rec1041 300 IN A 1.2.3.4 +2328 pager1201-rec1041 300 IN A 1.2.3.5 +2329 pager1201-rec1042 300 IN A 1.2.3.4 +2330 pager1201-rec1042 300 IN A 1.2.3.5 +2331 pager1201-rec1043 300 IN A 1.2.3.4 +2332 pager1201-rec1043 300 IN A 1.2.3.5 +2333 pager1201-rec1044 300 IN A 1.2.3.4 +2334 pager1201-rec1044 300 IN A 1.2.3.5 +2335 pager1201-rec1045 300 IN A 1.2.3.4 +2336 pager1201-rec1045 300 IN A 1.2.3.5 +2337 pager1201-rec1046 300 IN A 1.2.3.4 +2338 pager1201-rec1046 300 IN A 1.2.3.5 +2339 pager1201-rec1047 300 IN A 1.2.3.4 +2340 pager1201-rec1047 300 IN A 1.2.3.5 +2341 pager1201-rec1048 300 IN A 1.2.3.4 +2342 pager1201-rec1048 300 IN A 1.2.3.5 +2343 pager1201-rec1049 300 IN A 1.2.3.4 +2344 pager1201-rec1049 300 IN A 1.2.3.5 +2345 pager1201-rec1050 300 IN A 1.2.3.4 +2346 pager1201-rec1050 300 IN A 1.2.3.5 +2347 pager1201-rec1051 300 IN A 1.2.3.4 +2348 pager1201-rec1051 300 IN A 1.2.3.5 +2349 pager1201-rec1052 300 IN A 1.2.3.4 +2350 pager1201-rec1052 300 IN A 1.2.3.5 +2351 pager1201-rec1053 300 IN A 1.2.3.4 +2352 pager1201-rec1053 300 IN A 1.2.3.5 +2353 pager1201-rec1054 300 IN A 1.2.3.4 +2354 pager1201-rec1054 300 IN A 1.2.3.5 +2355 pager1201-rec1055 300 IN A 1.2.3.4 +2356 pager1201-rec1055 300 IN A 1.2.3.5 +2357 pager1201-rec1056 300 IN A 1.2.3.4 +2358 pager1201-rec1056 300 IN A 1.2.3.5 +2359 pager1201-rec1057 300 IN A 1.2.3.4 +2360 pager1201-rec1057 300 IN A 1.2.3.5 +2361 pager1201-rec1058 300 IN A 1.2.3.4 +2362 pager1201-rec1058 300 IN A 1.2.3.5 +2363 pager1201-rec1059 300 IN A 1.2.3.4 +2364 pager1201-rec1059 300 IN A 1.2.3.5 +2365 pager1201-rec1060 300 IN A 1.2.3.4 +2366 pager1201-rec1060 300 IN A 1.2.3.5 +2367 pager1201-rec1061 300 IN A 1.2.3.4 +2368 pager1201-rec1061 300 IN A 1.2.3.5 +2369 pager1201-rec1062 300 IN A 1.2.3.4 +2370 pager1201-rec1062 300 IN A 1.2.3.5 +2371 pager1201-rec1063 300 IN A 1.2.3.4 +2372 pager1201-rec1063 300 IN A 1.2.3.5 +2373 pager1201-rec1064 300 IN A 1.2.3.4 +2374 pager1201-rec1064 300 IN A 1.2.3.5 +2375 pager1201-rec1065 300 IN A 1.2.3.4 +2376 pager1201-rec1065 300 IN A 1.2.3.5 +2377 pager1201-rec1066 300 IN A 1.2.3.4 +2378 pager1201-rec1066 300 IN A 1.2.3.5 +2379 pager1201-rec1067 300 IN A 1.2.3.4 +2380 pager1201-rec1067 300 IN A 1.2.3.5 +2381 pager1201-rec1068 300 IN A 1.2.3.4 +2382 pager1201-rec1068 300 IN A 1.2.3.5 +2383 pager1201-rec1069 300 IN A 1.2.3.4 +2384 pager1201-rec1069 300 IN A 1.2.3.5 +2385 pager1201-rec1070 300 IN A 1.2.3.4 +2386 pager1201-rec1070 300 IN A 1.2.3.5 +2387 pager1201-rec1071 300 IN A 1.2.3.4 +2388 pager1201-rec1071 300 IN A 1.2.3.5 +2389 pager1201-rec1072 300 IN A 1.2.3.4 +2390 pager1201-rec1072 300 IN A 1.2.3.5 +2391 pager1201-rec1073 300 IN A 1.2.3.4 +2392 pager1201-rec1073 300 IN A 1.2.3.5 +2393 pager1201-rec1074 300 IN A 1.2.3.4 +2394 pager1201-rec1074 300 IN A 1.2.3.5 +2395 pager1201-rec1075 300 IN A 1.2.3.4 +2396 pager1201-rec1075 300 IN A 1.2.3.5 +2397 pager1201-rec1076 300 IN A 1.2.3.4 +2398 pager1201-rec1076 300 IN A 1.2.3.5 +2399 pager1201-rec1077 300 IN A 1.2.3.4 +2400 pager1201-rec1077 300 IN A 1.2.3.5 +2401 pager1201-rec1078 300 IN A 1.2.3.4 +2402 pager1201-rec1078 300 IN A 1.2.3.5 +2403 pager1201-rec1079 300 IN A 1.2.3.4 +2404 pager1201-rec1079 300 IN A 1.2.3.5 +2405 pager1201-rec1080 300 IN A 1.2.3.4 +2406 pager1201-rec1080 300 IN A 1.2.3.5 +2407 pager1201-rec1081 300 IN A 1.2.3.4 +2408 pager1201-rec1081 300 IN A 1.2.3.5 +2409 pager1201-rec1082 300 IN A 1.2.3.4 +2410 pager1201-rec1082 300 IN A 1.2.3.5 +2411 pager1201-rec1083 300 IN A 1.2.3.4 +2412 pager1201-rec1083 300 IN A 1.2.3.5 +2413 pager1201-rec1084 300 IN A 1.2.3.4 +2414 pager1201-rec1084 300 IN A 1.2.3.5 +2415 pager1201-rec1085 300 IN A 1.2.3.4 +2416 pager1201-rec1085 300 IN A 1.2.3.5 +2417 pager1201-rec1086 300 IN A 1.2.3.4 +2418 pager1201-rec1086 300 IN A 1.2.3.5 +2419 pager1201-rec1087 300 IN A 1.2.3.4 +2420 pager1201-rec1087 300 IN A 1.2.3.5 +2421 pager1201-rec1088 300 IN A 1.2.3.4 +2422 pager1201-rec1088 300 IN A 1.2.3.5 +2423 pager1201-rec1089 300 IN A 1.2.3.4 +2424 pager1201-rec1089 300 IN A 1.2.3.5 +2425 pager1201-rec1090 300 IN A 1.2.3.4 +2426 pager1201-rec1090 300 IN A 1.2.3.5 +2427 pager1201-rec1091 300 IN A 1.2.3.4 +2428 pager1201-rec1091 300 IN A 1.2.3.5 +2429 pager1201-rec1092 300 IN A 1.2.3.4 +2430 pager1201-rec1092 300 IN A 1.2.3.5 +2431 pager1201-rec1093 300 IN A 1.2.3.4 +2432 pager1201-rec1093 300 IN A 1.2.3.5 +2433 pager1201-rec1094 300 IN A 1.2.3.4 +2434 pager1201-rec1094 300 IN A 1.2.3.5 +2435 pager1201-rec1095 300 IN A 1.2.3.4 +2436 pager1201-rec1095 300 IN A 1.2.3.5 +2437 pager1201-rec1096 300 IN A 1.2.3.4 +2438 pager1201-rec1096 300 IN A 1.2.3.5 +2439 pager1201-rec1097 300 IN A 1.2.3.4 +2440 pager1201-rec1097 300 IN A 1.2.3.5 +2441 pager1201-rec1098 300 IN A 1.2.3.4 +2442 pager1201-rec1098 300 IN A 1.2.3.5 +2443 pager1201-rec1099 300 IN A 1.2.3.4 +2444 pager1201-rec1099 300 IN A 1.2.3.5 +2445 pager1201-rec1100 300 IN A 1.2.3.4 +2446 pager1201-rec1100 300 IN A 1.2.3.5 +2447 pager1201-rec1101 300 IN A 1.2.3.4 +2448 pager1201-rec1101 300 IN A 1.2.3.5 +2449 pager1201-rec1102 300 IN A 1.2.3.4 +2450 pager1201-rec1102 300 IN A 1.2.3.5 +2451 pager1201-rec1103 300 IN A 1.2.3.4 +2452 pager1201-rec1103 300 IN A 1.2.3.5 +2453 pager1201-rec1104 300 IN A 1.2.3.4 +2454 pager1201-rec1104 300 IN A 1.2.3.5 +2455 pager1201-rec1105 300 IN A 1.2.3.4 +2456 pager1201-rec1105 300 IN A 1.2.3.5 +2457 pager1201-rec1106 300 IN A 1.2.3.4 +2458 pager1201-rec1106 300 IN A 1.2.3.5 +2459 pager1201-rec1107 300 IN A 1.2.3.4 +2460 pager1201-rec1107 300 IN A 1.2.3.5 +2461 pager1201-rec1108 300 IN A 1.2.3.4 +2462 pager1201-rec1108 300 IN A 1.2.3.5 +2463 pager1201-rec1109 300 IN A 1.2.3.4 +2464 pager1201-rec1109 300 IN A 1.2.3.5 +2465 pager1201-rec1110 300 IN A 1.2.3.4 +2466 pager1201-rec1110 300 IN A 1.2.3.5 +2467 pager1201-rec1111 300 IN A 1.2.3.4 +2468 pager1201-rec1111 300 IN A 1.2.3.5 +2469 pager1201-rec1112 300 IN A 1.2.3.4 +2470 pager1201-rec1112 300 IN A 1.2.3.5 +2471 pager1201-rec1113 300 IN A 1.2.3.4 +2472 pager1201-rec1113 300 IN A 1.2.3.5 +2473 pager1201-rec1114 300 IN A 1.2.3.4 +2474 pager1201-rec1114 300 IN A 1.2.3.5 +2475 pager1201-rec1115 300 IN A 1.2.3.4 +2476 pager1201-rec1115 300 IN A 1.2.3.5 +2477 pager1201-rec1116 300 IN A 1.2.3.4 +2478 pager1201-rec1116 300 IN A 1.2.3.5 +2479 pager1201-rec1117 300 IN A 1.2.3.4 +2480 pager1201-rec1117 300 IN A 1.2.3.5 +2481 pager1201-rec1118 300 IN A 1.2.3.4 +2482 pager1201-rec1118 300 IN A 1.2.3.5 +2483 pager1201-rec1119 300 IN A 1.2.3.4 +2484 pager1201-rec1119 300 IN A 1.2.3.5 +2485 pager1201-rec1120 300 IN A 1.2.3.4 +2486 pager1201-rec1120 300 IN A 1.2.3.5 +2487 pager1201-rec1121 300 IN A 1.2.3.4 +2488 pager1201-rec1121 300 IN A 1.2.3.5 +2489 pager1201-rec1122 300 IN A 1.2.3.4 +2490 pager1201-rec1122 300 IN A 1.2.3.5 +2491 pager1201-rec1123 300 IN A 1.2.3.4 +2492 pager1201-rec1123 300 IN A 1.2.3.5 +2493 pager1201-rec1124 300 IN A 1.2.3.4 +2494 pager1201-rec1124 300 IN A 1.2.3.5 +2495 pager1201-rec1125 300 IN A 1.2.3.4 +2496 pager1201-rec1125 300 IN A 1.2.3.5 +2497 pager1201-rec1126 300 IN A 1.2.3.4 +2498 pager1201-rec1126 300 IN A 1.2.3.5 +2499 pager1201-rec1127 300 IN A 1.2.3.4 +2500 pager1201-rec1127 300 IN A 1.2.3.5 +2501 pager1201-rec1128 300 IN A 1.2.3.4 +2502 pager1201-rec1128 300 IN A 1.2.3.5 +2503 pager1201-rec1129 300 IN A 1.2.3.4 +2504 pager1201-rec1129 300 IN A 1.2.3.5 +2505 pager1201-rec1130 300 IN A 1.2.3.4 +2506 pager1201-rec1130 300 IN A 1.2.3.5 +2507 pager1201-rec1131 300 IN A 1.2.3.4 +2508 pager1201-rec1131 300 IN A 1.2.3.5 +2509 pager1201-rec1132 300 IN A 1.2.3.4 +2510 pager1201-rec1132 300 IN A 1.2.3.5 +2511 pager1201-rec1133 300 IN A 1.2.3.4 +2512 pager1201-rec1133 300 IN A 1.2.3.5 +2513 pager1201-rec1134 300 IN A 1.2.3.4 +2514 pager1201-rec1134 300 IN A 1.2.3.5 +2515 pager1201-rec1135 300 IN A 1.2.3.4 +2516 pager1201-rec1135 300 IN A 1.2.3.5 +2517 pager1201-rec1136 300 IN A 1.2.3.4 +2518 pager1201-rec1136 300 IN A 1.2.3.5 +2519 pager1201-rec1137 300 IN A 1.2.3.4 +2520 pager1201-rec1137 300 IN A 1.2.3.5 +2521 pager1201-rec1138 300 IN A 1.2.3.4 +2522 pager1201-rec1138 300 IN A 1.2.3.5 +2523 pager1201-rec1139 300 IN A 1.2.3.4 +2524 pager1201-rec1139 300 IN A 1.2.3.5 +2525 pager1201-rec1140 300 IN A 1.2.3.4 +2526 pager1201-rec1140 300 IN A 1.2.3.5 +2527 pager1201-rec1141 300 IN A 1.2.3.4 +2528 pager1201-rec1141 300 IN A 1.2.3.5 +2529 pager1201-rec1142 300 IN A 1.2.3.4 +2530 pager1201-rec1142 300 IN A 1.2.3.5 +2531 pager1201-rec1143 300 IN A 1.2.3.4 +2532 pager1201-rec1143 300 IN A 1.2.3.5 +2533 pager1201-rec1144 300 IN A 1.2.3.4 +2534 pager1201-rec1144 300 IN A 1.2.3.5 +2535 pager1201-rec1145 300 IN A 1.2.3.4 +2536 pager1201-rec1145 300 IN A 1.2.3.5 +2537 pager1201-rec1146 300 IN A 1.2.3.4 +2538 pager1201-rec1146 300 IN A 1.2.3.5 +2539 pager1201-rec1147 300 IN A 1.2.3.4 +2540 pager1201-rec1147 300 IN A 1.2.3.5 +2541 pager1201-rec1148 300 IN A 1.2.3.4 +2542 pager1201-rec1148 300 IN A 1.2.3.5 +2543 pager1201-rec1149 300 IN A 1.2.3.4 +2544 pager1201-rec1149 300 IN A 1.2.3.5 +2545 pager1201-rec1150 300 IN A 1.2.3.4 +2546 pager1201-rec1150 300 IN A 1.2.3.5 +2547 pager1201-rec1151 300 IN A 1.2.3.4 +2548 pager1201-rec1151 300 IN A 1.2.3.5 +2549 pager1201-rec1152 300 IN A 1.2.3.4 +2550 pager1201-rec1152 300 IN A 1.2.3.5 +2551 pager1201-rec1153 300 IN A 1.2.3.4 +2552 pager1201-rec1153 300 IN A 1.2.3.5 +2553 pager1201-rec1154 300 IN A 1.2.3.4 +2554 pager1201-rec1154 300 IN A 1.2.3.5 +2555 pager1201-rec1155 300 IN A 1.2.3.4 +2556 pager1201-rec1155 300 IN A 1.2.3.5 +2557 pager1201-rec1156 300 IN A 1.2.3.4 +2558 pager1201-rec1156 300 IN A 1.2.3.5 +2559 pager1201-rec1157 300 IN A 1.2.3.4 +2560 pager1201-rec1157 300 IN A 1.2.3.5 +2561 pager1201-rec1158 300 IN A 1.2.3.4 +2562 pager1201-rec1158 300 IN A 1.2.3.5 +2563 pager1201-rec1159 300 IN A 1.2.3.4 +2564 pager1201-rec1159 300 IN A 1.2.3.5 +2565 pager1201-rec1160 300 IN A 1.2.3.4 +2566 pager1201-rec1160 300 IN A 1.2.3.5 +2567 pager1201-rec1161 300 IN A 1.2.3.4 +2568 pager1201-rec1161 300 IN A 1.2.3.5 +2569 pager1201-rec1162 300 IN A 1.2.3.4 +2570 pager1201-rec1162 300 IN A 1.2.3.5 +2571 pager1201-rec1163 300 IN A 1.2.3.4 +2572 pager1201-rec1163 300 IN A 1.2.3.5 +2573 pager1201-rec1164 300 IN A 1.2.3.4 +2574 pager1201-rec1164 300 IN A 1.2.3.5 +2575 pager1201-rec1165 300 IN A 1.2.3.4 +2576 pager1201-rec1165 300 IN A 1.2.3.5 +2577 pager1201-rec1166 300 IN A 1.2.3.4 +2578 pager1201-rec1166 300 IN A 1.2.3.5 +2579 pager1201-rec1167 300 IN A 1.2.3.4 +2580 pager1201-rec1167 300 IN A 1.2.3.5 +2581 pager1201-rec1168 300 IN A 1.2.3.4 +2582 pager1201-rec1168 300 IN A 1.2.3.5 +2583 pager1201-rec1169 300 IN A 1.2.3.4 +2584 pager1201-rec1169 300 IN A 1.2.3.5 +2585 pager1201-rec1170 300 IN A 1.2.3.4 +2586 pager1201-rec1170 300 IN A 1.2.3.5 +2587 pager1201-rec1171 300 IN A 1.2.3.4 +2588 pager1201-rec1171 300 IN A 1.2.3.5 +2589 pager1201-rec1172 300 IN A 1.2.3.4 +2590 pager1201-rec1172 300 IN A 1.2.3.5 +2591 pager1201-rec1173 300 IN A 1.2.3.4 +2592 pager1201-rec1173 300 IN A 1.2.3.5 +2593 pager1201-rec1174 300 IN A 1.2.3.4 +2594 pager1201-rec1174 300 IN A 1.2.3.5 +2595 pager1201-rec1175 300 IN A 1.2.3.4 +2596 pager1201-rec1175 300 IN A 1.2.3.5 +2597 pager1201-rec1176 300 IN A 1.2.3.4 +2598 pager1201-rec1176 300 IN A 1.2.3.5 +2599 pager1201-rec1177 300 IN A 1.2.3.4 +2600 pager1201-rec1177 300 IN A 1.2.3.5 +2601 pager1201-rec1178 300 IN A 1.2.3.4 +2602 pager1201-rec1178 300 IN A 1.2.3.5 +2603 pager1201-rec1179 300 IN A 1.2.3.4 +2604 pager1201-rec1179 300 IN A 1.2.3.5 +2605 pager1201-rec1180 300 IN A 1.2.3.4 +2606 pager1201-rec1180 300 IN A 1.2.3.5 +2607 pager1201-rec1181 300 IN A 1.2.3.4 +2608 pager1201-rec1181 300 IN A 1.2.3.5 +2609 pager1201-rec1182 300 IN A 1.2.3.4 +2610 pager1201-rec1182 300 IN A 1.2.3.5 +2611 pager1201-rec1183 300 IN A 1.2.3.4 +2612 pager1201-rec1183 300 IN A 1.2.3.5 +2613 pager1201-rec1184 300 IN A 1.2.3.4 +2614 pager1201-rec1184 300 IN A 1.2.3.5 +2615 pager1201-rec1185 300 IN A 1.2.3.4 +2616 pager1201-rec1185 300 IN A 1.2.3.5 +2617 pager1201-rec1186 300 IN A 1.2.3.4 +2618 pager1201-rec1186 300 IN A 1.2.3.5 +2619 pager1201-rec1187 300 IN A 1.2.3.4 +2620 pager1201-rec1187 300 IN A 1.2.3.5 +2621 pager1201-rec1188 300 IN A 1.2.3.4 +2622 pager1201-rec1188 300 IN A 1.2.3.5 +2623 pager1201-rec1189 300 IN A 1.2.3.4 +2624 pager1201-rec1189 300 IN A 1.2.3.5 +2625 pager1201-rec1190 300 IN A 1.2.3.4 +2626 pager1201-rec1190 300 IN A 1.2.3.5 +2627 pager1201-rec1191 300 IN A 1.2.3.4 +2628 pager1201-rec1191 300 IN A 1.2.3.5 +2629 pager1201-rec1192 300 IN A 1.2.3.4 +2630 pager1201-rec1192 300 IN A 1.2.3.5 +2631 pager1201-rec1193 300 IN A 1.2.3.4 +2632 pager1201-rec1193 300 IN A 1.2.3.5 +2633 pager1201-rec1194 300 IN A 1.2.3.4 +2634 pager1201-rec1194 300 IN A 1.2.3.5 +2635 pager1201-rec1195 300 IN A 1.2.3.4 +2636 pager1201-rec1195 300 IN A 1.2.3.5 +2637 pager1201-rec1196 300 IN A 1.2.3.4 +2638 pager1201-rec1196 300 IN A 1.2.3.5 +2639 pager1201-rec1197 300 IN A 1.2.3.4 +2640 pager1201-rec1197 300 IN A 1.2.3.5 +2641 pager1201-rec1198 300 IN A 1.2.3.4 +2642 pager1201-rec1198 300 IN A 1.2.3.5 +2643 pager1201-rec1199 300 IN A 1.2.3.4 +2644 pager1201-rec1199 300 IN A 1.2.3.5 +2645 testa 300 IN A 1.1.1.1 +2646 testa 333 IN A 1.1.1.1 +2647 testa 999 IN A 1.1.1.1 +2648 testa 300 IN A 3.3.3.3 +2649 testaaaa 300 IN AAAA 2607:f8b0:4006:820::2006 +2650 testaaaa 300 IN AAAA 2607:f8b0:4006:820::2013 +2651 testcname 300 IN CNAME foo.dnscontroltest-gcloud.com. +2652 testcname 300 IN CNAME www.google.com. +2653 testcname 300 IN CNAME www.yahoo.com. +2654 testdefined 300 IN A 2.2.2.2 +2655 testdefined 300 IN A 9.9.9.9 +2656 testignore 300 IN A 8.8.8.8 +2657 testmx 300 IN MX 100 foo.com. +2658 testmx 300 IN MX 5 bar.com. +2659 testmx 300 IN MX 5 foo.com. +2659 testmx 300 IN MX 100 bar.com. +2660 testmx 300 IN MX 5 foo.com. +2661 testtxt 300 IN TXT "changed" +2662 testtxt 300 IN TXT "simple" +2663 www 300 IN A 1.1.1.1 +2663 www 300 IN A 2.2.2.2 +2663 www 300 IN A 3.3.3.3 +2664 www 300 IN A 1.1.1.1 +2664 www 300 IN A 2.2.2.2 +2665 www 300 IN A 1.1.1.1 +2666 www 300 IN A 1.2.3.4 +2666 www 300 IN A 5.6.7.8 +2667 www 700 IN A 1.2.3.4 +2667 www 700 IN A 5.6.7.8 +2668 www 300 IN A 1.2.3.8 +2669 www 300 IN A 1.2.3.9 +2670 www 300 IN A 2.2.2.2 +2670 www 300 IN A 5.6.7.8 +2671 www 400 IN A 2.2.2.2 +2671 www 400 IN A 5.6.7.8 +2672 www 300 IN A 5.5.5.5 +2673 www 400 IN A 5.6.7.8 +2674 xn--fiq228c 300 IN A 1.2.3.4 +2675 xn--ndaaa 300 IN A 1.2.3.4 +2676 xn--ndaaa 300 IN A 2.2.2.2 +2677 xn--o-0gab 300 IN CNAME xn--ndaaa.xn--vhquv. +2678 xyz 300 IN NS ns1.foo.com. +2678 xyz 300 IN NS ns2.foo.com. +2679 xyz 300 IN NS ns2.foo.com. +2680 zzz 300 IN AAAA 2003:dd:d7ff::fe71:cccc +2681 zzz 300 IN A 3.3.3.3 +2681 zzz 300 IN A 4.4.4.4 diff --git a/providers/gcloud/test_data/meta.json b/providers/gcloud/test_data/meta.json new file mode 100644 index 0000000000..769b1e6912 --- /dev/null +++ b/providers/gcloud/test_data/meta.json @@ -0,0 +1,11 @@ +{ + "version": 1, + "recordings": [ + { + "domain": "dnscontroltest-gcloud.com", + "to_rc": [ + "nativeToRecord" + ] + } + ] +} diff --git a/providers/gcloud/test_data/recorded_torc_input_nativeToRecord_dnscontroltest-gcloud.com.json b/providers/gcloud/test_data/recorded_torc_input_nativeToRecord_dnscontroltest-gcloud.com.json new file mode 100644 index 0000000000..590da48ca1 --- /dev/null +++ b/providers/gcloud/test_data/recorded_torc_input_nativeToRecord_dnscontroltest-gcloud.com.json @@ -0,0 +1,32227 @@ +[ + { + "index": 1, + "value": { + "kind": "dns#resourceRecordSet", + "name": "*.dnscontroltest-gcloud.com.", + "rrdatas": [ + "3.3.3.3" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 2, + "value": { + "kind": "dns#resourceRecordSet", + "name": "4.dnscontroltest-gcloud.com.", + "rrdatas": [ + "bar.com." + ], + "ttl": 300, + "type": "PTR" + } + }, + { + "index": 3, + "value": { + "kind": "dns#resourceRecordSet", + "name": "4.dnscontroltest-gcloud.com.", + "rrdatas": [ + "foo.com." + ], + "ttl": 300, + "type": "PTR" + } + }, + { + "index": 4, + "value": { + "kind": "dns#resourceRecordSet", + "name": "_443._tcp.dnscontroltest-gcloud.com.", + "rrdatas": [ + "2 0 1 0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef" + ], + "ttl": 300, + "type": "TLSA" + } + }, + { + "index": 5, + "value": { + "kind": "dns#resourceRecordSet", + "name": "_443._tcp.dnscontroltest-gcloud.com.", + "rrdatas": [ + "2 0 2 0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef" + ], + "ttl": 300, + "type": "TLSA" + } + }, + { + "index": 6, + "value": { + "kind": "dns#resourceRecordSet", + "name": "_443._tcp.dnscontroltest-gcloud.com.", + "rrdatas": [ + "2 0 2 fedcba9876543210fedcba9876543210fedcba9876543210fedcba9876543210fedcba9876543210fedcba9876543210fedcba9876543210fedcba9876543210" + ], + "ttl": 300, + "type": "TLSA" + } + }, + { + "index": 7, + "value": { + "kind": "dns#resourceRecordSet", + "name": "_443._tcp.dnscontroltest-gcloud.com.", + "rrdatas": [ + "2 1 1 0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef" + ], + "ttl": 300, + "type": "TLSA" + } + }, + { + "index": 8, + "value": { + "kind": "dns#resourceRecordSet", + "name": "_443._tcp.dnscontroltest-gcloud.com.", + "rrdatas": [ + "3 1 1 0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef" + ], + "ttl": 300, + "type": "TLSA" + } + }, + { + "index": 9, + "value": { + "kind": "dns#resourceRecordSet", + "name": "_sip._tcp.dnscontroltest-gcloud.com.", + "rrdatas": [ + "15 65 75 ." + ], + "ttl": 300, + "type": "SRV" + } + }, + { + "index": 10, + "value": { + "kind": "dns#resourceRecordSet", + "name": "_sip._tcp.dnscontroltest-gcloud.com.", + "rrdatas": [ + "15 65 75 foo4.com.", + "52 6 7 foo.com." + ], + "ttl": 300, + "type": "SRV" + } + }, + { + "index": 11, + "value": { + "kind": "dns#resourceRecordSet", + "name": "_sip._tcp.dnscontroltest-gcloud.com.", + "rrdatas": [ + "15 65 75 foo4.com.", + "52 62 7 foo.com." + ], + "ttl": 300, + "type": "SRV" + } + }, + { + "index": 12, + "value": { + "kind": "dns#resourceRecordSet", + "name": "_sip._tcp.dnscontroltest-gcloud.com.", + "rrdatas": [ + "15 65 75 foo4.com.", + "52 62 72 foo.com." + ], + "ttl": 300, + "type": "SRV" + } + }, + { + "index": 13, + "value": { + "kind": "dns#resourceRecordSet", + "name": "_sip._tcp.dnscontroltest-gcloud.com.", + "rrdatas": [ + "5 6 7 foo.com.", + "15 65 75 foo3.com." + ], + "ttl": 300, + "type": "SRV" + } + }, + { + "index": 14, + "value": { + "kind": "dns#resourceRecordSet", + "name": "_sip._tcp.dnscontroltest-gcloud.com.", + "rrdatas": [ + "5 6 7 foo.com.", + "15 65 75 foo4.com." + ], + "ttl": 300, + "type": "SRV" + } + }, + { + "index": 15, + "value": { + "kind": "dns#resourceRecordSet", + "name": "_sip._tcp.dnscontroltest-gcloud.com.", + "rrdatas": [ + "5 6 7 foo.com.", + "5 60 70 foo2.com.", + "15 65 75 foo3.com." + ], + "ttl": 300, + "type": "SRV" + } + }, + { + "index": 16, + "value": { + "kind": "dns#resourceRecordSet", + "name": "_sip._tcp.dnscontroltest-gcloud.com.", + "rrdatas": [ + "5 6 7 foo.com.", + "5 60 70 foo2.com." + ], + "ttl": 300, + "type": "SRV" + } + }, + { + "index": 17, + "value": { + "kind": "dns#resourceRecordSet", + "name": "_sip._tcp.dnscontroltest-gcloud.com.", + "rrdatas": [ + "5 6 7 foo.com." + ], + "ttl": 300, + "type": "SRV" + } + }, + { + "index": 18, + "value": { + "kind": "dns#resourceRecordSet", + "name": "_sip._tcp.dnscontroltest-gcloud.com.", + "rrdatas": [ + "5 6 7 foo.com." + ], + "ttl": 333, + "type": "SRV" + } + }, + { + "index": 19, + "value": { + "kind": "dns#resourceRecordSet", + "name": "_sip._tcp.dnscontroltest-gcloud.com.", + "rrdatas": [ + "5 6 7 foo.com." + ], + "ttl": 4400, + "type": "SRV" + } + }, + { + "index": 20, + "value": { + "kind": "dns#resourceRecordSet", + "name": "a.dnscontroltest-gcloud.com.", + "rrdatas": [ + "xn--ndaaa.com." + ], + "ttl": 300, + "type": "CNAME" + } + }, + { + "index": 21, + "value": { + "kind": "dns#resourceRecordSet", + "name": "another-child.dnscontroltest-gcloud.com.", + "rrdatas": [ + "44 13 2 4b9b6b073edd97feb5bc12dc4e1b32d2c6af7ae23a293936ceb87bb10494ec44", + "1501 14 4 109bb6b5b6d5547c1ce03c7a8bd7d8f80c1cb0957f50c4f7fda04692079917e4f9cad52b878f3d8234e1a170b154b72d", + "1502 8 2 2fa14f53e6b15cac9ac77846c7be87862c2a7e9ec0c6cea319db939317f126ed", + "65535 13 2 2fa14f53e6b15cac9ac77846c7be87862c2a7e9ec0c6cea319db939317f126ed" + ], + "ttl": 300, + "type": "DS" + } + }, + { + "index": 22, + "value": { + "kind": "dns#resourceRecordSet", + "name": "another-child.dnscontroltest-gcloud.com.", + "rrdatas": [ + "44 13 2 4b9b6b073edd97feb5bc12dc4e1b32d2c6af7ae23a293936ceb87bb10494ec44" + ], + "ttl": 300, + "type": "DS" + } + }, + { + "index": 23, + "value": { + "kind": "dns#resourceRecordSet", + "name": "bar.bat.dnscontroltest-gcloud.com.", + "rrdatas": [ + "5.5.5.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 24, + "value": { + "kind": "dns#resourceRecordSet", + "name": "bar.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 25, + "value": { + "kind": "dns#resourceRecordSet", + "name": "bar.dnscontroltest-gcloud.com.", + "rrdatas": [ + "5 bar.com." + ], + "ttl": 300, + "type": "MX" + } + }, + { + "index": 26, + "value": { + "kind": "dns#resourceRecordSet", + "name": "bar.dnscontroltest-gcloud.com.", + "rrdatas": [ + "5.5.5.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 27, + "value": { + "kind": "dns#resourceRecordSet", + "name": "bar.dnscontroltest-gcloud.com.", + "rrdatas": [ + "redact2.acm-validations.aws." + ], + "ttl": 300, + "type": "CNAME" + } + }, + { + "index": 28, + "value": { + "kind": "dns#resourceRecordSet", + "name": "child.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1 14 4 417212fd1c8bc5896fefd8db58af824545e85b0d0546409366a30aef7269fae258173bd185fb262c86f3bb86fba04368" + ], + "ttl": 300, + "type": "DS" + } + }, + { + "index": 29, + "value": { + "kind": "dns#resourceRecordSet", + "name": "child.dnscontroltest-gcloud.com.", + "rrdatas": [ + "3 13 2 4b9b6b073edd97feb5bc12dc4e1b32d2c6af7ae23a293936ceb87bb10494ec44" + ], + "ttl": 300, + "type": "DS" + } + }, + { + "index": 30, + "value": { + "kind": "dns#resourceRecordSet", + "name": "child.dnscontroltest-gcloud.com.", + "rrdatas": [ + "3 14 4 3115238f89e0bf5252d9718113b1b9fff854608d84be94eefb9210dc1cc0b4f3557342a27465cfacc42ef137ae9a5489" + ], + "ttl": 300, + "type": "DS" + } + }, + { + "index": 31, + "value": { + "kind": "dns#resourceRecordSet", + "name": "child.dnscontroltest-gcloud.com.", + "rrdatas": [ + "3 8 2 4b9b6b073edd97feb5bc12dc4e1b32d2c6af7ae23a293936ceb87bb10494ec44" + ], + "ttl": 300, + "type": "DS" + } + }, + { + "index": 32, + "value": { + "kind": "dns#resourceRecordSet", + "name": "child.dnscontroltest-gcloud.com.", + "rrdatas": [ + "8857 8 2 4b9b6b073edd97feb5bc12dc4e1b32d2c6af7ae23a293936ceb87bb10494ec44" + ], + "ttl": 300, + "type": "DS" + } + }, + { + "index": 33, + "value": { + "kind": "dns#resourceRecordSet", + "name": "decoy.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.1.1.1" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 34, + "value": { + "kind": "dns#resourceRecordSet", + "name": "decoy.dnscontroltest-gcloud.com.", + "rrdatas": [ + "2.2.2.2" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 35, + "value": { + "kind": "dns#resourceRecordSet", + "name": "decoy.dnscontroltest-gcloud.com.", + "rrdatas": [ + "3.3.3.3" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 36, + "value": { + "kind": "dns#resourceRecordSet", + "name": "dnscontroltest-gcloud.com.", + "rrdatas": [ + "0 ." + ], + "ttl": 300, + "type": "MX" + } + }, + { + "index": 37, + "value": { + "kind": "dns#resourceRecordSet", + "name": "dnscontroltest-gcloud.com.", + "rrdatas": [ + "0 issue \"letsencrypt.org; validationmethods=dns-01; accounturi=https://acme-v02.api.letsencrypt.org/acme/acct/1234\"" + ], + "ttl": 300, + "type": "CAA" + } + }, + { + "index": 38, + "value": { + "kind": "dns#resourceRecordSet", + "name": "dnscontroltest-gcloud.com.", + "rrdatas": [ + "0 issue \"letsencrypt.org\"" + ], + "ttl": 300, + "type": "CAA" + } + }, + { + "index": 39, + "value": { + "kind": "dns#resourceRecordSet", + "name": "dnscontroltest-gcloud.com.", + "rrdatas": [ + "0 issuewild \";\"" + ], + "ttl": 300, + "type": "CAA" + } + }, + { + "index": 40, + "value": { + "kind": "dns#resourceRecordSet", + "name": "dnscontroltest-gcloud.com.", + "rrdatas": [ + "0 issuewild \"example.com\"" + ], + "ttl": 300, + "type": "CAA" + } + }, + { + "index": 41, + "value": { + "kind": "dns#resourceRecordSet", + "name": "dnscontroltest-gcloud.com.", + "rrdatas": [ + "0 issuewild \"letsencrypt.org\"" + ], + "ttl": 300, + "type": "CAA" + } + }, + { + "index": 42, + "value": { + "kind": "dns#resourceRecordSet", + "name": "dnscontroltest-gcloud.com.", + "rrdatas": [ + "0 test.com." + ], + "ttl": 300, + "type": "HTTPS" + } + }, + { + "index": 43, + "value": { + "kind": "dns#resourceRecordSet", + "name": "dnscontroltest-gcloud.com.", + "rrdatas": [ + "0 test.com." + ], + "ttl": 300, + "type": "SVCB" + } + }, + { + "index": 44, + "value": { + "kind": "dns#resourceRecordSet", + "name": "dnscontroltest-gcloud.com.", + "rrdatas": [ + "1 1 66c7d5540b7d75a1fb4c84febfa178ad99bdd67c" + ], + "ttl": 300, + "type": "SSHFP" + } + }, + { + "index": 45, + "value": { + "kind": "dns#resourceRecordSet", + "name": "dnscontroltest-gcloud.com.", + "rrdatas": [ + "1 test.com. alpn=\"h2\" port=\"99\"" + ], + "ttl": 300, + "type": "HTTPS" + } + }, + { + "index": 46, + "value": { + "kind": "dns#resourceRecordSet", + "name": "dnscontroltest-gcloud.com.", + "rrdatas": [ + "1 test.com. alpn=\"h2\" port=\"99\"" + ], + "ttl": 300, + "type": "SVCB" + } + }, + { + "index": 47, + "value": { + "kind": "dns#resourceRecordSet", + "name": "dnscontroltest-gcloud.com.", + "rrdatas": [ + "1 test.com. port=\"80\"" + ], + "ttl": 300, + "type": "HTTPS" + } + }, + { + "index": 48, + "value": { + "kind": "dns#resourceRecordSet", + "name": "dnscontroltest-gcloud.com.", + "rrdatas": [ + "1 test.com. port=\"80\"" + ], + "ttl": 300, + "type": "SVCB" + } + }, + { + "index": 49, + "value": { + "kind": "dns#resourceRecordSet", + "name": "dnscontroltest-gcloud.com.", + "rrdatas": [ + "1 test.com. port=\"99\"" + ], + "ttl": 300, + "type": "HTTPS" + } + }, + { + "index": 50, + "value": { + "kind": "dns#resourceRecordSet", + "name": "dnscontroltest-gcloud.com.", + "rrdatas": [ + "1 test.com. port=\"99\"" + ], + "ttl": 300, + "type": "SVCB" + } + }, + { + "index": 51, + "value": { + "kind": "dns#resourceRecordSet", + "name": "dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.2" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 52, + "value": { + "kind": "dns#resourceRecordSet", + "name": "dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4", + "2.3.4.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 53, + "value": { + "kind": "dns#resourceRecordSet", + "name": "dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 54, + "value": { + "kind": "dns#resourceRecordSet", + "name": "dnscontroltest-gcloud.com.", + "rrdatas": [ + "128 issue \"letsencrypt.org\"" + ], + "ttl": 300, + "type": "CAA" + } + }, + { + "index": 55, + "value": { + "kind": "dns#resourceRecordSet", + "name": "dnscontroltest-gcloud.com.", + "rrdatas": [ + "2 1 66c7d5540b7d75a1fb4c84febfa178ad99bdd67c" + ], + "ttl": 300, + "type": "SSHFP" + } + }, + { + "index": 56, + "value": { + "kind": "dns#resourceRecordSet", + "name": "dnscontroltest-gcloud.com.", + "rrdatas": [ + "2 2 745a635bc46a397a5c4f21d437483005bcc40d7511ff15fbfafe913a081559bc" + ], + "ttl": 300, + "type": "SSHFP" + } + }, + { + "index": 57, + "value": { + "kind": "dns#resourceRecordSet", + "name": "dnscontroltest-gcloud.com.", + "rrdatas": [ + "2 dnscontroltest-gcloud.com.", + "8 www.dnscontroltest-gcloud.com." + ], + "ttl": 300, + "type": "MX" + } + }, + { + "index": 58, + "value": { + "kind": "dns#resourceRecordSet", + "name": "dnscontroltest-gcloud.com.", + "rrdatas": [ + "2.2.2.2" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 59, + "value": { + "kind": "dns#resourceRecordSet", + "name": "dnscontroltest-gcloud.com.", + "rrdatas": [ + "3 example.com. alpn=\"h2,h3\" port=\"999\" ech=\"some+base64+encoded+value///\"" + ], + "ttl": 300, + "type": "HTTPS" + } + }, + { + "index": 60, + "value": { + "kind": "dns#resourceRecordSet", + "name": "dnscontroltest-gcloud.com.", + "rrdatas": [ + "3 example.com. alpn=\"h2,h3\" port=\"999\" ech=\"some+base64+encoded+value///\"" + ], + "ttl": 300, + "type": "SVCB" + } + }, + { + "index": 61, + "value": { + "kind": "dns#resourceRecordSet", + "name": "dnscontroltest-gcloud.com.", + "rrdatas": [ + "3 example.com. alpn=\"h2,h3\" port=\"999\"" + ], + "ttl": 300, + "type": "HTTPS" + } + }, + { + "index": 62, + "value": { + "kind": "dns#resourceRecordSet", + "name": "dnscontroltest-gcloud.com.", + "rrdatas": [ + "3 example.com. alpn=\"h2,h3\" port=\"999\"" + ], + "ttl": 300, + "type": "SVCB" + } + }, + { + "index": 63, + "value": { + "kind": "dns#resourceRecordSet", + "name": "dnscontroltest-gcloud.com.", + "rrdatas": [ + "3 example.com. alpn=\"h2\" port=\"80\" ech=\"another+base64+encoded+value\"" + ], + "ttl": 300, + "type": "HTTPS" + } + }, + { + "index": 64, + "value": { + "kind": "dns#resourceRecordSet", + "name": "dnscontroltest-gcloud.com.", + "rrdatas": [ + "3 example.com. alpn=\"h2\" port=\"80\" ech=\"another+base64+encoded+value\"" + ], + "ttl": 300, + "type": "SVCB" + } + }, + { + "index": 65, + "value": { + "kind": "dns#resourceRecordSet", + "name": "dnscontroltest-gcloud.com.", + "rrdatas": [ + "3 example.com. alpn=\"h2\" port=\"80\" ech=\"some+base64+encoded+value///\"" + ], + "ttl": 300, + "type": "HTTPS" + } + }, + { + "index": 66, + "value": { + "kind": "dns#resourceRecordSet", + "name": "dnscontroltest-gcloud.com.", + "rrdatas": [ + "3 example.com. alpn=\"h2\" port=\"80\" ech=\"some+base64+encoded+value///\"" + ], + "ttl": 300, + "type": "SVCB" + } + }, + { + "index": 67, + "value": { + "kind": "dns#resourceRecordSet", + "name": "dnscontroltest-gcloud.com.", + "rrdatas": [ + "3 yetanother.com. alpn=\"h2\" port=\"80\" ech=\"another+base64+encoded+value\"" + ], + "ttl": 300, + "type": "HTTPS" + } + }, + { + "index": 68, + "value": { + "kind": "dns#resourceRecordSet", + "name": "dnscontroltest-gcloud.com.", + "rrdatas": [ + "3 yetanother.com. alpn=\"h2\" port=\"80\" ech=\"another+base64+encoded+value\"" + ], + "ttl": 300, + "type": "SVCB" + } + }, + { + "index": 69, + "value": { + "kind": "dns#resourceRecordSet", + "name": "dnscontroltest-gcloud.com.", + "rrdatas": [ + "4.4.4.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 70, + "value": { + "kind": "dns#resourceRecordSet", + "name": "dnscontroltest-gcloud.com.", + "rrdatas": [ + "5 bar.com." + ], + "ttl": 300, + "type": "MX" + } + }, + { + "index": 71, + "value": { + "kind": "dns#resourceRecordSet", + "name": "dnscontroltest-gcloud.com.", + "rrdatas": [ + "5 foo.com." + ], + "ttl": 300, + "type": "MX" + } + }, + { + "index": 72, + "value": { + "kind": "dns#resourceRecordSet", + "name": "dnscontroltest-gcloud.com.", + "rrdatas": [ + "8.8.8.8" + ], + "ttl": 1000, + "type": "A" + } + }, + { + "index": 73, + "value": { + "kind": "dns#resourceRecordSet", + "name": "dnscontroltest-gcloud.com.", + "rrdatas": [ + "8.8.8.8" + ], + "ttl": 500, + "type": "A" + } + }, + { + "index": 74, + "value": { + "kind": "dns#resourceRecordSet", + "name": "dnscontroltest-gcloud.com.", + "rrdatas": [ + "8.8.8.8" + ], + "ttl": 666, + "type": "A" + } + }, + { + "index": 75, + "value": { + "kind": "dns#resourceRecordSet", + "name": "dnscontroltest-gcloud.com.", + "rrdatas": [ + "\"asimple\"" + ], + "ttl": 300, + "type": "TXT" + } + }, + { + "index": 76, + "value": { + "kind": "dns#resourceRecordSet", + "name": "dnscontroltest-gcloud.com.", + "rrdatas": [ + "\"simple\"" + ], + "ttl": 300, + "type": "TXT" + } + }, + { + "index": 77, + "value": { + "kind": "dns#resourceRecordSet", + "name": "dnscontroltest-gcloud.com.", + "rrdatas": [ + "foo.com." + ], + "ttl": 300, + "type": "ALIAS" + } + }, + { + "index": 78, + "value": { + "kind": "dns#resourceRecordSet", + "name": "dnscontroltest-gcloud.com.", + "rrdatas": [ + "foo.dnscontroltest-gcloud.com." + ], + "ttl": 300, + "type": "ALIAS" + } + }, + { + "index": 79, + "value": { + "kind": "dns#resourceRecordSet", + "name": "dnscontroltest-gcloud.com.", + "rrdatas": [ + "foo2.com." + ], + "ttl": 300, + "type": "ALIAS" + } + }, + { + "index": 80, + "value": { + "kind": "dns#resourceRecordSet", + "name": "dnscontroltest-gcloud.com.", + "rrdatas": [ + "ns-cloud-a1.googledomains.com.", + "ns-cloud-a2.googledomains.com.", + "ns-cloud-a3.googledomains.com.", + "ns-cloud-a4.googledomains.com.", + "ns1.example.com.", + "ns2.example.com." + ], + "ttl": 300, + "type": "NS" + } + }, + { + "index": 81, + "value": { + "kind": "dns#resourceRecordSet", + "name": "dnscontroltest-gcloud.com.", + "rrdatas": [ + "ns-cloud-a1.googledomains.com.", + "ns-cloud-a2.googledomains.com.", + "ns-cloud-a3.googledomains.com.", + "ns-cloud-a4.googledomains.com.", + "ns1.foo.com.", + "ns2.foo.com." + ], + "ttl": 300, + "type": "NS" + } + }, + { + "index": 82, + "value": { + "kind": "dns#resourceRecordSet", + "name": "dnscontroltest-gcloud.com.", + "rrdatas": [ + "ns-cloud-a1.googledomains.com.", + "ns-cloud-a2.googledomains.com.", + "ns-cloud-a3.googledomains.com.", + "ns-cloud-a4.googledomains.com.", + "ns1.foo.com." + ], + "ttl": 300, + "type": "NS" + } + }, + { + "index": 83, + "value": { + "kind": "dns#resourceRecordSet", + "name": "dnscontroltest-gcloud.com.", + "rrdatas": [ + "ns-cloud-a1.googledomains.com.", + "ns-cloud-a2.googledomains.com.", + "ns-cloud-a3.googledomains.com.", + "ns-cloud-a4.googledomains.com." + ], + "ttl": 300, + "type": "NS" + } + }, + { + "index": 84, + "value": { + "kind": "dns#resourceRecordSet", + "name": "dyndns-city1.dnscontroltest-gcloud.com.", + "rrdatas": [ + "2003:dd:d7ff::fe71:ce77" + ], + "ttl": 300, + "type": "AAAA" + } + }, + { + "index": 85, + "value": { + "kind": "dns#resourceRecordSet", + "name": "dyndns-city1.dnscontroltest-gcloud.com.", + "rrdatas": [ + "91.42.1.1" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 86, + "value": { + "kind": "dns#resourceRecordSet", + "name": "dyndns-city2.dnscontroltest-gcloud.com.", + "rrdatas": [ + "2003:dd:d7ff::fe71:ce78" + ], + "ttl": 300, + "type": "AAAA" + } + }, + { + "index": 87, + "value": { + "kind": "dns#resourceRecordSet", + "name": "dyndns-city2.dnscontroltest-gcloud.com.", + "rrdatas": [ + "91.42.1.2" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 88, + "value": { + "kind": "dns#resourceRecordSet", + "name": "final.dnscontroltest-gcloud.com.", + "rrdatas": [ + "\"TestDNSProviders was successful!\"" + ], + "ttl": 300, + "type": "TXT" + } + }, + { + "index": 89, + "value": { + "kind": "dns#resourceRecordSet", + "name": "foo.bat.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4", + "2.3.4.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 90, + "value": { + "kind": "dns#resourceRecordSet", + "name": "foo.bat.dnscontroltest-gcloud.com.", + "rrdatas": [ + "\"simple\"" + ], + "ttl": 300, + "type": "TXT" + } + }, + { + "index": 91, + "value": { + "kind": "dns#resourceRecordSet", + "name": "foo.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.1.1.1", + "10.10.10.10" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 92, + "value": { + "kind": "dns#resourceRecordSet", + "name": "foo.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.1.1.1", + "11.11.11.11" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 93, + "value": { + "kind": "dns#resourceRecordSet", + "name": "foo.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.1.1.1", + "12.12.12.12" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 94, + "value": { + "kind": "dns#resourceRecordSet", + "name": "foo.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.1.1.1", + "13.13.13.13" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 95, + "value": { + "kind": "dns#resourceRecordSet", + "name": "foo.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.1.1.1", + "14.14.14.14" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 96, + "value": { + "kind": "dns#resourceRecordSet", + "name": "foo.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4", + "2.3.4.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 97, + "value": { + "kind": "dns#resourceRecordSet", + "name": "foo.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4", + "3.4.5.6" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 98, + "value": { + "kind": "dns#resourceRecordSet", + "name": "foo.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 99, + "value": { + "kind": "dns#resourceRecordSet", + "name": "foo.dnscontroltest-gcloud.com.", + "rrdatas": [ + "10 aspmx.l.google.com.", + "20 alt1.aspmx.l.google.com." + ], + "ttl": 300, + "type": "MX" + } + }, + { + "index": 100, + "value": { + "kind": "dns#resourceRecordSet", + "name": "foo.dnscontroltest-gcloud.com.", + "rrdatas": [ + "10 foo.dnscontroltest-gcloud.com.", + "20 bar.dnscontroltest-gcloud.com." + ], + "ttl": 300, + "type": "MX" + } + }, + { + "index": 101, + "value": { + "kind": "dns#resourceRecordSet", + "name": "foo.dnscontroltest-gcloud.com.", + "rrdatas": [ + "2.3.4.5", + "3.4.5.6" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 102, + "value": { + "kind": "dns#resourceRecordSet", + "name": "foo.dnscontroltest-gcloud.com.", + "rrdatas": [ + "2.3.4.5", + "8.8.8.8" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 103, + "value": { + "kind": "dns#resourceRecordSet", + "name": "foo.dnscontroltest-gcloud.com.", + "rrdatas": [ + "2.3.4.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 104, + "value": { + "kind": "dns#resourceRecordSet", + "name": "foo.dnscontroltest-gcloud.com.", + "rrdatas": [ + "2003:dd:d7ff::fe71:aaaa" + ], + "ttl": 300, + "type": "AAAA" + } + }, + { + "index": 105, + "value": { + "kind": "dns#resourceRecordSet", + "name": "foo.dnscontroltest-gcloud.com.", + "rrdatas": [ + "4.5.6.7" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 106, + "value": { + "kind": "dns#resourceRecordSet", + "name": "foo.dnscontroltest-gcloud.com.", + "rrdatas": [ + "5 mx.google.com." + ], + "ttl": 300, + "type": "MX" + } + }, + { + "index": 107, + "value": { + "kind": "dns#resourceRecordSet", + "name": "foo.dnscontroltest-gcloud.com.", + "rrdatas": [ + "8 dnscontroltest-gcloud.com." + ], + "ttl": 300, + "type": "MX" + } + }, + { + "index": 108, + "value": { + "kind": "dns#resourceRecordSet", + "name": "foo.dnscontroltest-gcloud.com.", + "rrdatas": [ + "\"simple\"" + ], + "ttl": 300, + "type": "TXT" + } + }, + { + "index": 109, + "value": { + "kind": "dns#resourceRecordSet", + "name": "foo.dnscontroltest-gcloud.com.", + "rrdatas": [ + "\"v=spf1 ip4:99.99.99.99 -all\"" + ], + "ttl": 300, + "type": "TXT" + } + }, + { + "index": 110, + "value": { + "kind": "dns#resourceRecordSet", + "name": "foo.dnscontroltest-gcloud.com.", + "rrdatas": [ + "dnscontroltest-gcloud.com." + ], + "ttl": 300, + "type": "CNAME" + } + }, + { + "index": 111, + "value": { + "kind": "dns#resourceRecordSet", + "name": "foo.dnscontroltest-gcloud.com.", + "rrdatas": [ + "dnscontroltest-gcloud.com." + ], + "ttl": 300, + "type": "NS" + } + }, + { + "index": 112, + "value": { + "kind": "dns#resourceRecordSet", + "name": "foo.dnscontroltest-gcloud.com.", + "rrdatas": [ + "google.com." + ], + "ttl": 300, + "type": "CNAME" + } + }, + { + "index": 113, + "value": { + "kind": "dns#resourceRecordSet", + "name": "foo.dnscontroltest-gcloud.com.", + "rrdatas": [ + "google2.com." + ], + "ttl": 300, + "type": "CNAME" + } + }, + { + "index": 114, + "value": { + "kind": "dns#resourceRecordSet", + "name": "foo.dnscontroltest-gcloud.com.", + "rrdatas": [ + "redact1.acm-validations.aws." + ], + "ttl": 300, + "type": "CNAME" + } + }, + { + "index": 115, + "value": { + "kind": "dns#resourceRecordSet", + "name": "foo0.dnscontroltest-gcloud.com.", + "rrdatas": [ + "\"\"" + ], + "ttl": 300, + "type": "TXT" + } + }, + { + "index": 116, + "value": { + "kind": "dns#resourceRecordSet", + "name": "foo254.dnscontroltest-gcloud.com.", + "rrdatas": [ + "\"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\"" + ], + "ttl": 300, + "type": "TXT" + } + }, + { + "index": 117, + "value": { + "kind": "dns#resourceRecordSet", + "name": "foo255.dnscontroltest-gcloud.com.", + "rrdatas": [ + "\"BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB\"" + ], + "ttl": 300, + "type": "TXT" + } + }, + { + "index": 118, + "value": { + "kind": "dns#resourceRecordSet", + "name": "foo256.dnscontroltest-gcloud.com.", + "rrdatas": [ + "\"CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC\" \"C\"" + ], + "ttl": 300, + "type": "TXT" + } + }, + { + "index": 119, + "value": { + "kind": "dns#resourceRecordSet", + "name": "foo509.dnscontroltest-gcloud.com.", + "rrdatas": [ + "\"DDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDD\" \"DDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDD\"" + ], + "ttl": 300, + "type": "TXT" + } + }, + { + "index": 120, + "value": { + "kind": "dns#resourceRecordSet", + "name": "foo510.dnscontroltest-gcloud.com.", + "rrdatas": [ + "\"EEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE\" \"EEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE\"" + ], + "ttl": 300, + "type": "TXT" + } + }, + { + "index": 121, + "value": { + "kind": "dns#resourceRecordSet", + "name": "foo511.dnscontroltest-gcloud.com.", + "rrdatas": [ + "\"FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF\" \"FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF\" \"F\"" + ], + "ttl": 300, + "type": "TXT" + } + }, + { + "index": 122, + "value": { + "kind": "dns#resourceRecordSet", + "name": "foo764.dnscontroltest-gcloud.com.", + "rrdatas": [ + "\"GGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGG\" \"GGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGG\" \"GGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGG\"" + ], + "ttl": 300, + "type": "TXT" + } + }, + { + "index": 123, + "value": { + "kind": "dns#resourceRecordSet", + "name": "foo765.dnscontroltest-gcloud.com.", + "rrdatas": [ + "\"HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH\" \"HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH\" \"HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH\"" + ], + "ttl": 300, + "type": "TXT" + } + }, + { + "index": 124, + "value": { + "kind": "dns#resourceRecordSet", + "name": "foo766.dnscontroltest-gcloud.com.", + "rrdatas": [ + "\"JJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJ\" \"JJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJ\" \"JJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJ\" \"J\"" + ], + "ttl": 300, + "type": "TXT" + } + }, + { + "index": 125, + "value": { + "kind": "dns#resourceRecordSet", + "name": "foobt.dnscontroltest-gcloud.com.", + "rrdatas": [ + "\"blah`blah\"" + ], + "ttl": 300, + "type": "TXT" + } + }, + { + "index": 126, + "value": { + "kind": "dns#resourceRecordSet", + "name": "foodq.dnscontroltest-gcloud.com.", + "rrdatas": [ + "\"in\\\"side\"" + ], + "ttl": 300, + "type": "TXT" + } + }, + { + "index": 127, + "value": { + "kind": "dns#resourceRecordSet", + "name": "foodqs.dnscontroltest-gcloud.com.", + "rrdatas": [ + "\"\\\"left\"" + ], + "ttl": 300, + "type": "TXT" + } + }, + { + "index": 128, + "value": { + "kind": "dns#resourceRecordSet", + "name": "foodqs.dnscontroltest-gcloud.com.", + "rrdatas": [ + "\"in\\\"ter\\\"ior\"" + ], + "ttl": 300, + "type": "TXT" + } + }, + { + "index": 129, + "value": { + "kind": "dns#resourceRecordSet", + "name": "foodqs.dnscontroltest-gcloud.com.", + "rrdatas": [ + "\"right\\\"\"" + ], + "ttl": 300, + "type": "TXT" + } + }, + { + "index": 130, + "value": { + "kind": "dns#resourceRecordSet", + "name": "fooosbs1.dnscontroltest-gcloud.com.", + "rrdatas": [ + "\"1back\\\\slash\"" + ], + "ttl": 300, + "type": "TXT" + } + }, + { + "index": 131, + "value": { + "kind": "dns#resourceRecordSet", + "name": "fooosbs2.dnscontroltest-gcloud.com.", + "rrdatas": [ + "\"2back\\\\\\\\slash\"" + ], + "ttl": 300, + "type": "TXT" + } + }, + { + "index": 132, + "value": { + "kind": "dns#resourceRecordSet", + "name": "fooosbs3.dnscontroltest-gcloud.com.", + "rrdatas": [ + "\"3back\\\\\\\\\\\\slash\"" + ], + "ttl": 300, + "type": "TXT" + } + }, + { + "index": 133, + "value": { + "kind": "dns#resourceRecordSet", + "name": "fooosbs4.dnscontroltest-gcloud.com.", + "rrdatas": [ + "\"4back\\\\\\\\\\\\\\\\slash\"" + ], + "ttl": 300, + "type": "TXT" + } + }, + { + "index": 134, + "value": { + "kind": "dns#resourceRecordSet", + "name": "foosc1.dnscontroltest-gcloud.com.", + "rrdatas": [ + "\"semi;colon\"" + ], + "ttl": 300, + "type": "TXT" + } + }, + { + "index": 135, + "value": { + "kind": "dns#resourceRecordSet", + "name": "foosc2.dnscontroltest-gcloud.com.", + "rrdatas": [ + "\"wssemi ; colon\"" + ], + "ttl": 300, + "type": "TXT" + } + }, + { + "index": 136, + "value": { + "kind": "dns#resourceRecordSet", + "name": "foosp.dnscontroltest-gcloud.com.", + "rrdatas": [ + "\"with spaces\"" + ], + "ttl": 300, + "type": "TXT" + } + }, + { + "index": 137, + "value": { + "kind": "dns#resourceRecordSet", + "name": "foosq.dnscontroltest-gcloud.com.", + "rrdatas": [ + "\"quo'te\"" + ], + "ttl": 300, + "type": "TXT" + } + }, + { + "index": 138, + "value": { + "kind": "dns#resourceRecordSet", + "name": "foows1.dnscontroltest-gcloud.com.", + "rrdatas": [ + "\"trailingws \"" + ], + "ttl": 300, + "type": "TXT" + } + }, + { + "index": 139, + "value": { + "kind": "dns#resourceRecordSet", + "name": "mail.bat.dnscontroltest-gcloud.com.", + "rrdatas": [ + "ghs.googlehosted.com." + ], + "ttl": 300, + "type": "CNAME" + } + }, + { + "index": 140, + "value": { + "kind": "dns#resourceRecordSet", + "name": "mail.dnscontroltest-gcloud.com.", + "rrdatas": [ + "ghs.googlehosted.com." + ], + "ttl": 300, + "type": "CNAME" + } + }, + { + "index": 141, + "value": { + "kind": "dns#resourceRecordSet", + "name": "nmx.dnscontroltest-gcloud.com.", + "rrdatas": [ + "0 ." + ], + "ttl": 300, + "type": "MX" + } + }, + { + "index": 142, + "value": { + "kind": "dns#resourceRecordSet", + "name": "nmx.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.3" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 143, + "value": { + "kind": "dns#resourceRecordSet", + "name": "nmx.dnscontroltest-gcloud.com.", + "rrdatas": [ + "3 nmx.dnscontroltest-gcloud.com.", + "9 www.dnscontroltest-gcloud.com." + ], + "ttl": 300, + "type": "MX" + } + }, + { + "index": 144, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager101-rec0000.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 145, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager101-rec0001.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 146, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager101-rec0002.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 147, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager101-rec0003.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 148, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager101-rec0004.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 149, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager101-rec0005.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 150, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager101-rec0006.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 151, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager101-rec0007.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 152, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager101-rec0008.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 153, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager101-rec0009.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 154, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager101-rec0010.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 155, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager101-rec0011.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 156, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager101-rec0012.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 157, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager101-rec0013.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 158, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager101-rec0014.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 159, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager101-rec0015.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 160, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager101-rec0016.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 161, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager101-rec0017.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 162, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager101-rec0018.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 163, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager101-rec0019.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 164, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager101-rec0020.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 165, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager101-rec0021.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 166, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager101-rec0022.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 167, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager101-rec0023.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 168, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager101-rec0024.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 169, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager101-rec0025.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 170, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager101-rec0026.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 171, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager101-rec0027.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 172, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager101-rec0028.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 173, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager101-rec0029.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 174, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager101-rec0030.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 175, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager101-rec0031.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 176, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager101-rec0032.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 177, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager101-rec0033.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 178, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager101-rec0034.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 179, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager101-rec0035.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 180, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager101-rec0036.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 181, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager101-rec0037.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 182, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager101-rec0038.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 183, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager101-rec0039.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 184, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager101-rec0040.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 185, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager101-rec0041.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 186, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager101-rec0042.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 187, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager101-rec0043.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 188, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager101-rec0044.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 189, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager101-rec0045.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 190, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager101-rec0046.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 191, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager101-rec0047.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 192, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager101-rec0048.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 193, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager101-rec0049.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 194, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager101-rec0050.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 195, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager101-rec0051.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 196, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager101-rec0052.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 197, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager101-rec0053.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 198, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager101-rec0054.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 199, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager101-rec0055.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 200, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager101-rec0056.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 201, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager101-rec0057.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 202, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager101-rec0058.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 203, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager101-rec0059.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 204, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager101-rec0060.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 205, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager101-rec0061.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 206, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager101-rec0062.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 207, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager101-rec0063.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 208, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager101-rec0064.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 209, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager101-rec0065.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 210, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager101-rec0066.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 211, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager101-rec0067.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 212, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager101-rec0068.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 213, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager101-rec0069.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 214, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager101-rec0070.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 215, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager101-rec0071.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 216, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager101-rec0072.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 217, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager101-rec0073.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 218, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager101-rec0074.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 219, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager101-rec0075.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 220, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager101-rec0076.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 221, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager101-rec0077.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 222, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager101-rec0078.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 223, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager101-rec0079.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 224, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager101-rec0080.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 225, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager101-rec0081.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 226, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager101-rec0082.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 227, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager101-rec0083.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 228, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager101-rec0084.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 229, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager101-rec0085.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 230, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager101-rec0086.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 231, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager101-rec0087.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 232, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager101-rec0088.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 233, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager101-rec0089.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 234, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager101-rec0090.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 235, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager101-rec0091.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 236, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager101-rec0092.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 237, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager101-rec0093.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 238, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager101-rec0094.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 239, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager101-rec0095.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 240, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager101-rec0096.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 241, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager101-rec0097.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 242, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager101-rec0098.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 243, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager101-rec0099.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 244, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager101-rec0100.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 245, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0000.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 246, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0000.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 247, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0001.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 248, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0001.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 249, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0002.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 250, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0002.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 251, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0003.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 252, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0003.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 253, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0004.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 254, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0004.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 255, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0005.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 256, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0005.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 257, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0006.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 258, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0006.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 259, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0007.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 260, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0007.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 261, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0008.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 262, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0008.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 263, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0009.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 264, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0009.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 265, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0010.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 266, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0010.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 267, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0011.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 268, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0011.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 269, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0012.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 270, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0012.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 271, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0013.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 272, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0013.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 273, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0014.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 274, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0014.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 275, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0015.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 276, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0015.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 277, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0016.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 278, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0016.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 279, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0017.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 280, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0017.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 281, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0018.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 282, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0018.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 283, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0019.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 284, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0019.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 285, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0020.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 286, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0020.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 287, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0021.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 288, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0021.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 289, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0022.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 290, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0022.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 291, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0023.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 292, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0023.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 293, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0024.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 294, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0024.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 295, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0025.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 296, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0025.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 297, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0026.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 298, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0026.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 299, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0027.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 300, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0027.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 301, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0028.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 302, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0028.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 303, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0029.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 304, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0029.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 305, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0030.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 306, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0030.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 307, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0031.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 308, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0031.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 309, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0032.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 310, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0032.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 311, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0033.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 312, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0033.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 313, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0034.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 314, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0034.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 315, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0035.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 316, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0035.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 317, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0036.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 318, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0036.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 319, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0037.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 320, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0037.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 321, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0038.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 322, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0038.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 323, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0039.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 324, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0039.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 325, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0040.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 326, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0040.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 327, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0041.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 328, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0041.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 329, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0042.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 330, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0042.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 331, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0043.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 332, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0043.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 333, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0044.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 334, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0044.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 335, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0045.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 336, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0045.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 337, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0046.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 338, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0046.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 339, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0047.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 340, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0047.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 341, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0048.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 342, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0048.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 343, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0049.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 344, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0049.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 345, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0050.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 346, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0050.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 347, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0051.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 348, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0051.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 349, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0052.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 350, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0052.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 351, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0053.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 352, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0053.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 353, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0054.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 354, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0054.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 355, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0055.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 356, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0055.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 357, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0056.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 358, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0056.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 359, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0057.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 360, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0057.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 361, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0058.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 362, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0058.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 363, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0059.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 364, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0059.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 365, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0060.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 366, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0060.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 367, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0061.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 368, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0061.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 369, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0062.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 370, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0062.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 371, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0063.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 372, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0063.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 373, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0064.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 374, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0064.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 375, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0065.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 376, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0065.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 377, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0066.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 378, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0066.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 379, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0067.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 380, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0067.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 381, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0068.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 382, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0068.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 383, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0069.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 384, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0069.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 385, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0070.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 386, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0070.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 387, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0071.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 388, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0071.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 389, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0072.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 390, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0072.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 391, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0073.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 392, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0073.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 393, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0074.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 394, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0074.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 395, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0075.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 396, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0075.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 397, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0076.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 398, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0076.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 399, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0077.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 400, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0077.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 401, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0078.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 402, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0078.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 403, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0079.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 404, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0079.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 405, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0080.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 406, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0080.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 407, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0081.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 408, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0081.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 409, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0082.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 410, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0082.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 411, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0083.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 412, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0083.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 413, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0084.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 414, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0084.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 415, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0085.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 416, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0085.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 417, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0086.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 418, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0086.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 419, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0087.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 420, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0087.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 421, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0088.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 422, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0088.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 423, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0089.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 424, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0089.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 425, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0090.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 426, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0090.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 427, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0091.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 428, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0091.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 429, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0092.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 430, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0092.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 431, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0093.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 432, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0093.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 433, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0094.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 434, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0094.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 435, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0095.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 436, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0095.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 437, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0096.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 438, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0096.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 439, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0097.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 440, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0097.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 441, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0098.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 442, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0098.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 443, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0099.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 444, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0099.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 445, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0100.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 446, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0100.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 447, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0101.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 448, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0101.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 449, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0102.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 450, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0102.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 451, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0103.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 452, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0103.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 453, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0104.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 454, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0104.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 455, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0105.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 456, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0105.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 457, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0106.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 458, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0106.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 459, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0107.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 460, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0107.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 461, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0108.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 462, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0108.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 463, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0109.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 464, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0109.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 465, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0110.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 466, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0110.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 467, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0111.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 468, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0111.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 469, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0112.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 470, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0112.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 471, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0113.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 472, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0113.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 473, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0114.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 474, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0114.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 475, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0115.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 476, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0115.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 477, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0116.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 478, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0116.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 479, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0117.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 480, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0117.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 481, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0118.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 482, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0118.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 483, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0119.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 484, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0119.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 485, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0120.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 486, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0120.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 487, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0121.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 488, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0121.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 489, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0122.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 490, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0122.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 491, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0123.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 492, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0123.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 493, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0124.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 494, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0124.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 495, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0125.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 496, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0125.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 497, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0126.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 498, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0126.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 499, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0127.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 500, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0127.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 501, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0128.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 502, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0128.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 503, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0129.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 504, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0129.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 505, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0130.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 506, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0130.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 507, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0131.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 508, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0131.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 509, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0132.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 510, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0132.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 511, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0133.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 512, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0133.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 513, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0134.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 514, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0134.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 515, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0135.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 516, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0135.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 517, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0136.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 518, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0136.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 519, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0137.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 520, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0137.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 521, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0138.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 522, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0138.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 523, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0139.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 524, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0139.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 525, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0140.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 526, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0140.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 527, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0141.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 528, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0141.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 529, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0142.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 530, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0142.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 531, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0143.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 532, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0143.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 533, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0144.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 534, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0144.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 535, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0145.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 536, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0145.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 537, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0146.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 538, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0146.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 539, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0147.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 540, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0147.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 541, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0148.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 542, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0148.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 543, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0149.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 544, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0149.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 545, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0150.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 546, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0150.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 547, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0151.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 548, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0151.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 549, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0152.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 550, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0152.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 551, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0153.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 552, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0153.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 553, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0154.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 554, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0154.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 555, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0155.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 556, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0155.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 557, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0156.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 558, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0156.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 559, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0157.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 560, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0157.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 561, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0158.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 562, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0158.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 563, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0159.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 564, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0159.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 565, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0160.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 566, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0160.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 567, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0161.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 568, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0161.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 569, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0162.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 570, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0162.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 571, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0163.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 572, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0163.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 573, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0164.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 574, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0164.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 575, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0165.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 576, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0165.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 577, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0166.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 578, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0166.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 579, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0167.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 580, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0167.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 581, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0168.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 582, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0168.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 583, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0169.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 584, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0169.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 585, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0170.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 586, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0170.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 587, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0171.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 588, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0171.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 589, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0172.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 590, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0172.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 591, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0173.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 592, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0173.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 593, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0174.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 594, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0174.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 595, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0175.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 596, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0175.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 597, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0176.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 598, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0176.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 599, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0177.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 600, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0177.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 601, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0178.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 602, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0178.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 603, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0179.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 604, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0179.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 605, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0180.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 606, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0180.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 607, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0181.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 608, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0181.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 609, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0182.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 610, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0182.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 611, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0183.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 612, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0183.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 613, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0184.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 614, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0184.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 615, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0185.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 616, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0185.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 617, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0186.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 618, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0186.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 619, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0187.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 620, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0187.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 621, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0188.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 622, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0188.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 623, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0189.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 624, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0189.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 625, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0190.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 626, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0190.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 627, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0191.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 628, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0191.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 629, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0192.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 630, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0192.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 631, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0193.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 632, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0193.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 633, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0194.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 634, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0194.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 635, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0195.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 636, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0195.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 637, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0196.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 638, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0196.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 639, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0197.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 640, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0197.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 641, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0198.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 642, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0198.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 643, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0199.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 644, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0199.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 645, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0200.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 646, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0200.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 647, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0201.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 648, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0201.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 649, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0202.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 650, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0202.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 651, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0203.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 652, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0203.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 653, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0204.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 654, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0204.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 655, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0205.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 656, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0205.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 657, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0206.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 658, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0206.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 659, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0207.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 660, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0207.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 661, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0208.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 662, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0208.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 663, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0209.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 664, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0209.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 665, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0210.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 666, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0210.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 667, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0211.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 668, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0211.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 669, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0212.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 670, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0212.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 671, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0213.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 672, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0213.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 673, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0214.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 674, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0214.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 675, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0215.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 676, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0215.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 677, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0216.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 678, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0216.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 679, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0217.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 680, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0217.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 681, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0218.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 682, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0218.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 683, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0219.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 684, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0219.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 685, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0220.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 686, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0220.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 687, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0221.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 688, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0221.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 689, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0222.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 690, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0222.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 691, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0223.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 692, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0223.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 693, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0224.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 694, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0224.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 695, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0225.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 696, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0225.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 697, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0226.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 698, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0226.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 699, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0227.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 700, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0227.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 701, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0228.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 702, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0228.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 703, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0229.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 704, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0229.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 705, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0230.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 706, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0230.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 707, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0231.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 708, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0231.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 709, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0232.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 710, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0232.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 711, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0233.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 712, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0233.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 713, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0234.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 714, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0234.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 715, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0235.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 716, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0235.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 717, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0236.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 718, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0236.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 719, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0237.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 720, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0237.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 721, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0238.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 722, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0238.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 723, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0239.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 724, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0239.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 725, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0240.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 726, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0240.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 727, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0241.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 728, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0241.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 729, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0242.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 730, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0242.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 731, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0243.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 732, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0243.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 733, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0244.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 734, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0244.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 735, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0245.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 736, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0245.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 737, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0246.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 738, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0246.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 739, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0247.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 740, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0247.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 741, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0248.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 742, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0248.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 743, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0249.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 744, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0249.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 745, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0250.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 746, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0250.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 747, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0251.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 748, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0251.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 749, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0252.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 750, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0252.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 751, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0253.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 752, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0253.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 753, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0254.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 754, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0254.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 755, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0255.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 756, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0255.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 757, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0256.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 758, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0256.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 759, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0257.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 760, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0257.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 761, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0258.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 762, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0258.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 763, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0259.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 764, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0259.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 765, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0260.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 766, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0260.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 767, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0261.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 768, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0261.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 769, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0262.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 770, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0262.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 771, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0263.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 772, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0263.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 773, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0264.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 774, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0264.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 775, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0265.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 776, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0265.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 777, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0266.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 778, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0266.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 779, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0267.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 780, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0267.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 781, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0268.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 782, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0268.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 783, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0269.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 784, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0269.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 785, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0270.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 786, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0270.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 787, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0271.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 788, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0271.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 789, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0272.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 790, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0272.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 791, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0273.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 792, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0273.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 793, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0274.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 794, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0274.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 795, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0275.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 796, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0275.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 797, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0276.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 798, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0276.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 799, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0277.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 800, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0277.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 801, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0278.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 802, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0278.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 803, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0279.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 804, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0279.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 805, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0280.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 806, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0280.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 807, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0281.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 808, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0281.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 809, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0282.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 810, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0282.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 811, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0283.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 812, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0283.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 813, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0284.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 814, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0284.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 815, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0285.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 816, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0285.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 817, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0286.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 818, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0286.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 819, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0287.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 820, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0287.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 821, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0288.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 822, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0288.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 823, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0289.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 824, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0289.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 825, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0290.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 826, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0290.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 827, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0291.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 828, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0291.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 829, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0292.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 830, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0292.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 831, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0293.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 832, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0293.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 833, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0294.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 834, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0294.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 835, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0295.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 836, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0295.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 837, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0296.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 838, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0296.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 839, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0297.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 840, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0297.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 841, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0298.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 842, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0298.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 843, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0299.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 844, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0299.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 845, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0300.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 846, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0300.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 847, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0301.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 848, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0301.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 849, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0302.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 850, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0302.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 851, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0303.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 852, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0303.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 853, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0304.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 854, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0304.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 855, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0305.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 856, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0305.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 857, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0306.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 858, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0306.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 859, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0307.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 860, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0307.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 861, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0308.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 862, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0308.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 863, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0309.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 864, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0309.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 865, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0310.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 866, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0310.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 867, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0311.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 868, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0311.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 869, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0312.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 870, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0312.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 871, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0313.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 872, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0313.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 873, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0314.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 874, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0314.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 875, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0315.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 876, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0315.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 877, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0316.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 878, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0316.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 879, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0317.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 880, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0317.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 881, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0318.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 882, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0318.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 883, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0319.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 884, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0319.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 885, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0320.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 886, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0320.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 887, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0321.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 888, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0321.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 889, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0322.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 890, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0322.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 891, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0323.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 892, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0323.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 893, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0324.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 894, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0324.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 895, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0325.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 896, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0325.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 897, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0326.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 898, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0326.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 899, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0327.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 900, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0327.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 901, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0328.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 902, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0328.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 903, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0329.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 904, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0329.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 905, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0330.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 906, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0330.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 907, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0331.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 908, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0331.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 909, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0332.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 910, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0332.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 911, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0333.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 912, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0333.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 913, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0334.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 914, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0334.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 915, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0335.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 916, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0335.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 917, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0336.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 918, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0336.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 919, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0337.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 920, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0337.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 921, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0338.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 922, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0338.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 923, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0339.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 924, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0339.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 925, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0340.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 926, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0340.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 927, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0341.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 928, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0341.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 929, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0342.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 930, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0342.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 931, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0343.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 932, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0343.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 933, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0344.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 934, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0344.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 935, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0345.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 936, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0345.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 937, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0346.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 938, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0346.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 939, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0347.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 940, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0347.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 941, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0348.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 942, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0348.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 943, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0349.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 944, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0349.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 945, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0350.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 946, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0350.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 947, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0351.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 948, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0351.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 949, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0352.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 950, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0352.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 951, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0353.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 952, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0353.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 953, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0354.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 954, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0354.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 955, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0355.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 956, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0355.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 957, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0356.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 958, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0356.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 959, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0357.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 960, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0357.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 961, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0358.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 962, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0358.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 963, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0359.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 964, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0359.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 965, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0360.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 966, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0360.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 967, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0361.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 968, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0361.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 969, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0362.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 970, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0362.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 971, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0363.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 972, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0363.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 973, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0364.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 974, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0364.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 975, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0365.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 976, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0365.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 977, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0366.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 978, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0366.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 979, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0367.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 980, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0367.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 981, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0368.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 982, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0368.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 983, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0369.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 984, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0369.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 985, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0370.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 986, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0370.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 987, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0371.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 988, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0371.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 989, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0372.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 990, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0372.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 991, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0373.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 992, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0373.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 993, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0374.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 994, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0374.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 995, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0375.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 996, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0375.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 997, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0376.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 998, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0376.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 999, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0377.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1000, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0377.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1001, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0378.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1002, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0378.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1003, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0379.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1004, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0379.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1005, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0380.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1006, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0380.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1007, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0381.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1008, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0381.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1009, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0382.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1010, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0382.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1011, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0383.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1012, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0383.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1013, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0384.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1014, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0384.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1015, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0385.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1016, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0385.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1017, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0386.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1018, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0386.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1019, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0387.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1020, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0387.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1021, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0388.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1022, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0388.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1023, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0389.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1024, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0389.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1025, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0390.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1026, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0390.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1027, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0391.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1028, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0391.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1029, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0392.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1030, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0392.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1031, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0393.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1032, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0393.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1033, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0394.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1034, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0394.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1035, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0395.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1036, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0395.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1037, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0396.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1038, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0396.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1039, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0397.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1040, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0397.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1041, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0398.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1042, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0398.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1043, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0399.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1044, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0399.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1045, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0400.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1046, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0400.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1047, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0401.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1048, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0401.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1049, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0402.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1050, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0402.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1051, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0403.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1052, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0403.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1053, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0404.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1054, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0404.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1055, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0405.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1056, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0405.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1057, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0406.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1058, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0406.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1059, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0407.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1060, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0407.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1061, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0408.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1062, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0408.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1063, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0409.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1064, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0409.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1065, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0410.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1066, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0410.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1067, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0411.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1068, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0411.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1069, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0412.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1070, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0412.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1071, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0413.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1072, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0413.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1073, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0414.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1074, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0414.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1075, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0415.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1076, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0415.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1077, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0416.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1078, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0416.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1079, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0417.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1080, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0417.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1081, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0418.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1082, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0418.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1083, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0419.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1084, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0419.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1085, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0420.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1086, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0420.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1087, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0421.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1088, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0421.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1089, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0422.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1090, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0422.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1091, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0423.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1092, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0423.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1093, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0424.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1094, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0424.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1095, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0425.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1096, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0425.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1097, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0426.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1098, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0426.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1099, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0427.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1100, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0427.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1101, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0428.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1102, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0428.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1103, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0429.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1104, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0429.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1105, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0430.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1106, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0430.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1107, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0431.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1108, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0431.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1109, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0432.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1110, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0432.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1111, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0433.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1112, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0433.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1113, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0434.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1114, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0434.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1115, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0435.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1116, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0435.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1117, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0436.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1118, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0436.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1119, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0437.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1120, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0437.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1121, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0438.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1122, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0438.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1123, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0439.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1124, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0439.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1125, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0440.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1126, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0440.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1127, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0441.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1128, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0441.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1129, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0442.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1130, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0442.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1131, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0443.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1132, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0443.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1133, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0444.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1134, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0444.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1135, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0445.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1136, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0445.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1137, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0446.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1138, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0446.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1139, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0447.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1140, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0447.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1141, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0448.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1142, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0448.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1143, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0449.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1144, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0449.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1145, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0450.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1146, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0450.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1147, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0451.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1148, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0451.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1149, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0452.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1150, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0452.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1151, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0453.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1152, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0453.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1153, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0454.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1154, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0454.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1155, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0455.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1156, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0455.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1157, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0456.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1158, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0456.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1159, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0457.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1160, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0457.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1161, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0458.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1162, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0458.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1163, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0459.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1164, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0459.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1165, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0460.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1166, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0460.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1167, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0461.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1168, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0461.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1169, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0462.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1170, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0462.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1171, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0463.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1172, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0463.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1173, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0464.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1174, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0464.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1175, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0465.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1176, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0465.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1177, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0466.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1178, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0466.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1179, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0467.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1180, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0467.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1181, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0468.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1182, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0468.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1183, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0469.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1184, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0469.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1185, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0470.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1186, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0470.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1187, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0471.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1188, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0471.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1189, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0472.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1190, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0472.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1191, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0473.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1192, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0473.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1193, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0474.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1194, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0474.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1195, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0475.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1196, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0475.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1197, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0476.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1198, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0476.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1199, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0477.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1200, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0477.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1201, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0478.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1202, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0478.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1203, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0479.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1204, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0479.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1205, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0480.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1206, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0480.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1207, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0481.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1208, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0481.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1209, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0482.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1210, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0482.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1211, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0483.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1212, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0483.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1213, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0484.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1214, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0484.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1215, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0485.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1216, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0485.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1217, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0486.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1218, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0486.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1219, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0487.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1220, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0487.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1221, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0488.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1222, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0488.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1223, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0489.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1224, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0489.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1225, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0490.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1226, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0490.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1227, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0491.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1228, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0491.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1229, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0492.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1230, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0492.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1231, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0493.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1232, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0493.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1233, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0494.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1234, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0494.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1235, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0495.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1236, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0495.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1237, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0496.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1238, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0496.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1239, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0497.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1240, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0497.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1241, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0498.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1242, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0498.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1243, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0499.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1244, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0499.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1245, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0500.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1246, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0500.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1247, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0501.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1248, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0501.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1249, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0502.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1250, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0502.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1251, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0503.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1252, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0503.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1253, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0504.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1254, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0504.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1255, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0505.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1256, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0505.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1257, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0506.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1258, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0506.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1259, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0507.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1260, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0507.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1261, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0508.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1262, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0508.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1263, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0509.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1264, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0509.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1265, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0510.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1266, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0510.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1267, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0511.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1268, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0511.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1269, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0512.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1270, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0512.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1271, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0513.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1272, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0513.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1273, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0514.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1274, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0514.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1275, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0515.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1276, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0515.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1277, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0516.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1278, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0516.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1279, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0517.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1280, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0517.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1281, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0518.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1282, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0518.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1283, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0519.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1284, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0519.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1285, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0520.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1286, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0520.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1287, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0521.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1288, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0521.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1289, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0522.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1290, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0522.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1291, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0523.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1292, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0523.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1293, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0524.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1294, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0524.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1295, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0525.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1296, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0525.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1297, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0526.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1298, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0526.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1299, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0527.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1300, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0527.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1301, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0528.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1302, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0528.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1303, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0529.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1304, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0529.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1305, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0530.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1306, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0530.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1307, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0531.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1308, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0531.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1309, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0532.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1310, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0532.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1311, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0533.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1312, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0533.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1313, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0534.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1314, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0534.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1315, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0535.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1316, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0535.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1317, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0536.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1318, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0536.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1319, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0537.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1320, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0537.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1321, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0538.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1322, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0538.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1323, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0539.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1324, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0539.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1325, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0540.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1326, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0540.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1327, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0541.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1328, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0541.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1329, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0542.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1330, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0542.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1331, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0543.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1332, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0543.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1333, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0544.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1334, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0544.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1335, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0545.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1336, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0545.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1337, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0546.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1338, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0546.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1339, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0547.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1340, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0547.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1341, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0548.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1342, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0548.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1343, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0549.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1344, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0549.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1345, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0550.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1346, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0550.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1347, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0551.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1348, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0551.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1349, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0552.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1350, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0552.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1351, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0553.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1352, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0553.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1353, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0554.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1354, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0554.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1355, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0555.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1356, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0555.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1357, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0556.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1358, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0556.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1359, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0557.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1360, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0557.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1361, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0558.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1362, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0558.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1363, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0559.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1364, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0559.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1365, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0560.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1366, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0560.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1367, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0561.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1368, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0561.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1369, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0562.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1370, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0562.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1371, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0563.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1372, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0563.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1373, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0564.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1374, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0564.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1375, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0565.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1376, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0565.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1377, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0566.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1378, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0566.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1379, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0567.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1380, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0567.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1381, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0568.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1382, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0568.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1383, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0569.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1384, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0569.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1385, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0570.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1386, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0570.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1387, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0571.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1388, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0571.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1389, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0572.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1390, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0572.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1391, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0573.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1392, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0573.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1393, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0574.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1394, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0574.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1395, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0575.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1396, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0575.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1397, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0576.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1398, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0576.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1399, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0577.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1400, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0577.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1401, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0578.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1402, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0578.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1403, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0579.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1404, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0579.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1405, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0580.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1406, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0580.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1407, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0581.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1408, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0581.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1409, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0582.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1410, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0582.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1411, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0583.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1412, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0583.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1413, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0584.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1414, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0584.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1415, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0585.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1416, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0585.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1417, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0586.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1418, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0586.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1419, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0587.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1420, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0587.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1421, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0588.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1422, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0588.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1423, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0589.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1424, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0589.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1425, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0590.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1426, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0590.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1427, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0591.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1428, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0591.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1429, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0592.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1430, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0592.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1431, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0593.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1432, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0593.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1433, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0594.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1434, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0594.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1435, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0595.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1436, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0595.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1437, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0596.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1438, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0596.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1439, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0597.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1440, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0597.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1441, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0598.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1442, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0598.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1443, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0599.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1444, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0599.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1445, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0600.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1446, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0600.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1447, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0601.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1448, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0601.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1449, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0602.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1450, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0602.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1451, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0603.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1452, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0603.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1453, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0604.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1454, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0604.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1455, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0605.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1456, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0605.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1457, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0606.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1458, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0606.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1459, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0607.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1460, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0607.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1461, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0608.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1462, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0608.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1463, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0609.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1464, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0609.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1465, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0610.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1466, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0610.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1467, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0611.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1468, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0611.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1469, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0612.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1470, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0612.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1471, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0613.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1472, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0613.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1473, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0614.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1474, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0614.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1475, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0615.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1476, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0615.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1477, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0616.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1478, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0616.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1479, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0617.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1480, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0617.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1481, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0618.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1482, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0618.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1483, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0619.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1484, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0619.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1485, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0620.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1486, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0620.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1487, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0621.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1488, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0621.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1489, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0622.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1490, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0622.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1491, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0623.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1492, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0623.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1493, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0624.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1494, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0624.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1495, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0625.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1496, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0625.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1497, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0626.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1498, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0626.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1499, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0627.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1500, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0627.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1501, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0628.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1502, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0628.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1503, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0629.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1504, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0629.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1505, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0630.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1506, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0630.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1507, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0631.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1508, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0631.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1509, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0632.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1510, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0632.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1511, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0633.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1512, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0633.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1513, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0634.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1514, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0634.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1515, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0635.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1516, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0635.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1517, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0636.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1518, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0636.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1519, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0637.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1520, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0637.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1521, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0638.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1522, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0638.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1523, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0639.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1524, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0639.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1525, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0640.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1526, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0640.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1527, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0641.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1528, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0641.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1529, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0642.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1530, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0642.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1531, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0643.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1532, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0643.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1533, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0644.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1534, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0644.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1535, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0645.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1536, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0645.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1537, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0646.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1538, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0646.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1539, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0647.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1540, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0647.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1541, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0648.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1542, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0648.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1543, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0649.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1544, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0649.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1545, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0650.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1546, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0650.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1547, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0651.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1548, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0651.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1549, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0652.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1550, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0652.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1551, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0653.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1552, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0653.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1553, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0654.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1554, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0654.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1555, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0655.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1556, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0655.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1557, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0656.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1558, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0656.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1559, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0657.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1560, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0657.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1561, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0658.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1562, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0658.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1563, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0659.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1564, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0659.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1565, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0660.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1566, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0660.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1567, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0661.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1568, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0661.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1569, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0662.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1570, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0662.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1571, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0663.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1572, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0663.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1573, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0664.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1574, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0664.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1575, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0665.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1576, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0665.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1577, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0666.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1578, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0666.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1579, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0667.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1580, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0667.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1581, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0668.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1582, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0668.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1583, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0669.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1584, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0669.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1585, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0670.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1586, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0670.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1587, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0671.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1588, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0671.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1589, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0672.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1590, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0672.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1591, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0673.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1592, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0673.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1593, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0674.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1594, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0674.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1595, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0675.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1596, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0675.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1597, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0676.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1598, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0676.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1599, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0677.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1600, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0677.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1601, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0678.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1602, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0678.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1603, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0679.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1604, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0679.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1605, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0680.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1606, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0680.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1607, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0681.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1608, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0681.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1609, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0682.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1610, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0682.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1611, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0683.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1612, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0683.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1613, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0684.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1614, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0684.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1615, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0685.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1616, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0685.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1617, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0686.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1618, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0686.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1619, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0687.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1620, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0687.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1621, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0688.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1622, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0688.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1623, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0689.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1624, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0689.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1625, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0690.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1626, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0690.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1627, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0691.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1628, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0691.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1629, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0692.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1630, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0692.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1631, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0693.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1632, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0693.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1633, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0694.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1634, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0694.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1635, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0695.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1636, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0695.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1637, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0696.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1638, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0696.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1639, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0697.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1640, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0697.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1641, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0698.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1642, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0698.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1643, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0699.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1644, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0699.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1645, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0700.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1646, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0700.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1647, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0701.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1648, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0701.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1649, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0702.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1650, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0702.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1651, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0703.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1652, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0703.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1653, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0704.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1654, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0704.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1655, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0705.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1656, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0705.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1657, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0706.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1658, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0706.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1659, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0707.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1660, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0707.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1661, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0708.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1662, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0708.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1663, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0709.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1664, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0709.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1665, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0710.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1666, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0710.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1667, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0711.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1668, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0711.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1669, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0712.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1670, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0712.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1671, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0713.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1672, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0713.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1673, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0714.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1674, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0714.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1675, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0715.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1676, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0715.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1677, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0716.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1678, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0716.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1679, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0717.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1680, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0717.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1681, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0718.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1682, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0718.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1683, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0719.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1684, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0719.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1685, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0720.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1686, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0720.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1687, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0721.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1688, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0721.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1689, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0722.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1690, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0722.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1691, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0723.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1692, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0723.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1693, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0724.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1694, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0724.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1695, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0725.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1696, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0725.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1697, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0726.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1698, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0726.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1699, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0727.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1700, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0727.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1701, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0728.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1702, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0728.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1703, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0729.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1704, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0729.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1705, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0730.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1706, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0730.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1707, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0731.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1708, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0731.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1709, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0732.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1710, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0732.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1711, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0733.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1712, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0733.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1713, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0734.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1714, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0734.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1715, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0735.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1716, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0735.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1717, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0736.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1718, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0736.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1719, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0737.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1720, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0737.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1721, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0738.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1722, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0738.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1723, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0739.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1724, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0739.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1725, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0740.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1726, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0740.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1727, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0741.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1728, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0741.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1729, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0742.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1730, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0742.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1731, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0743.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1732, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0743.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1733, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0744.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1734, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0744.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1735, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0745.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1736, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0745.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1737, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0746.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1738, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0746.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1739, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0747.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1740, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0747.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1741, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0748.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1742, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0748.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1743, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0749.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1744, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0749.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1745, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0750.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1746, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0750.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1747, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0751.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1748, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0751.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1749, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0752.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1750, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0752.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1751, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0753.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1752, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0753.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1753, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0754.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1754, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0754.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1755, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0755.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1756, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0755.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1757, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0756.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1758, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0756.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1759, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0757.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1760, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0757.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1761, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0758.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1762, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0758.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1763, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0759.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1764, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0759.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1765, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0760.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1766, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0760.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1767, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0761.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1768, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0761.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1769, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0762.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1770, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0762.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1771, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0763.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1772, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0763.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1773, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0764.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1774, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0764.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1775, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0765.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1776, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0765.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1777, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0766.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1778, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0766.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1779, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0767.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1780, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0767.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1781, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0768.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1782, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0768.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1783, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0769.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1784, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0769.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1785, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0770.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1786, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0770.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1787, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0771.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1788, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0771.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1789, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0772.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1790, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0772.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1791, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0773.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1792, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0773.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1793, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0774.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1794, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0774.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1795, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0775.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1796, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0775.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1797, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0776.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1798, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0776.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1799, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0777.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1800, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0777.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1801, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0778.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1802, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0778.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1803, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0779.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1804, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0779.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1805, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0780.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1806, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0780.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1807, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0781.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1808, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0781.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1809, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0782.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1810, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0782.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1811, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0783.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1812, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0783.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1813, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0784.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1814, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0784.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1815, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0785.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1816, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0785.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1817, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0786.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1818, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0786.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1819, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0787.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1820, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0787.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1821, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0788.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1822, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0788.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1823, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0789.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1824, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0789.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1825, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0790.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1826, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0790.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1827, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0791.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1828, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0791.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1829, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0792.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1830, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0792.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1831, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0793.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1832, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0793.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1833, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0794.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1834, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0794.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1835, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0795.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1836, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0795.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1837, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0796.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1838, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0796.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1839, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0797.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1840, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0797.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1841, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0798.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1842, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0798.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1843, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0799.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1844, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0799.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1845, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0800.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1846, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0800.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1847, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0801.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1848, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0801.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1849, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0802.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1850, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0802.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1851, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0803.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1852, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0803.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1853, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0804.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1854, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0804.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1855, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0805.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1856, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0805.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1857, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0806.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1858, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0806.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1859, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0807.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1860, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0807.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1861, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0808.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1862, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0808.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1863, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0809.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1864, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0809.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1865, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0810.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1866, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0810.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1867, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0811.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1868, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0811.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1869, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0812.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1870, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0812.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1871, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0813.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1872, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0813.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1873, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0814.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1874, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0814.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1875, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0815.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1876, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0815.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1877, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0816.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1878, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0816.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1879, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0817.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1880, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0817.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1881, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0818.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1882, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0818.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1883, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0819.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1884, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0819.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1885, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0820.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1886, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0820.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1887, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0821.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1888, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0821.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1889, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0822.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1890, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0822.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1891, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0823.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1892, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0823.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1893, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0824.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1894, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0824.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1895, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0825.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1896, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0825.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1897, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0826.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1898, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0826.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1899, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0827.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1900, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0827.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1901, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0828.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1902, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0828.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1903, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0829.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1904, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0829.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1905, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0830.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1906, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0830.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1907, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0831.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1908, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0831.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1909, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0832.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1910, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0832.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1911, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0833.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1912, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0833.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1913, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0834.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1914, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0834.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1915, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0835.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1916, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0835.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1917, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0836.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1918, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0836.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1919, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0837.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1920, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0837.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1921, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0838.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1922, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0838.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1923, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0839.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1924, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0839.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1925, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0840.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1926, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0840.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1927, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0841.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1928, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0841.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1929, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0842.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1930, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0842.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1931, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0843.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1932, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0843.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1933, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0844.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1934, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0844.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1935, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0845.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1936, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0845.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1937, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0846.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1938, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0846.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1939, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0847.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1940, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0847.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1941, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0848.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1942, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0848.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1943, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0849.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1944, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0849.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1945, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0850.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1946, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0850.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1947, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0851.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1948, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0851.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1949, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0852.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1950, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0852.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1951, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0853.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1952, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0853.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1953, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0854.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1954, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0854.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1955, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0855.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1956, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0855.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1957, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0856.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1958, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0856.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1959, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0857.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1960, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0857.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1961, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0858.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1962, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0858.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1963, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0859.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1964, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0859.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1965, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0860.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1966, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0860.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1967, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0861.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1968, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0861.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1969, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0862.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1970, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0862.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1971, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0863.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1972, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0863.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1973, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0864.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1974, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0864.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1975, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0865.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1976, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0865.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1977, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0866.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1978, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0866.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1979, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0867.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1980, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0867.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1981, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0868.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1982, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0868.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1983, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0869.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1984, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0869.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1985, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0870.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1986, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0870.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1987, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0871.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1988, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0871.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1989, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0872.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1990, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0872.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1991, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0873.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1992, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0873.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1993, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0874.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1994, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0874.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1995, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0875.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1996, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0875.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1997, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0876.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1998, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0876.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 1999, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0877.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 2000, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0877.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 2001, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0878.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 2002, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0878.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 2003, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0879.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 2004, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0879.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 2005, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0880.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 2006, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0880.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 2007, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0881.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 2008, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0881.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 2009, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0882.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 2010, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0882.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 2011, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0883.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 2012, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0883.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 2013, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0884.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 2014, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0884.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 2015, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0885.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 2016, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0885.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 2017, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0886.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 2018, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0886.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 2019, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0887.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 2020, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0887.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 2021, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0888.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 2022, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0888.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 2023, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0889.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 2024, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0889.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 2025, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0890.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 2026, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0890.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 2027, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0891.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 2028, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0891.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 2029, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0892.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 2030, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0892.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 2031, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0893.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 2032, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0893.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 2033, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0894.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 2034, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0894.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 2035, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0895.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 2036, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0895.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 2037, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0896.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 2038, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0896.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 2039, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0897.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 2040, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0897.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 2041, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0898.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 2042, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0898.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 2043, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0899.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 2044, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0899.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 2045, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0900.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 2046, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0900.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 2047, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0901.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 2048, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0901.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 2049, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0902.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 2050, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0902.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 2051, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0903.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 2052, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0903.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 2053, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0904.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 2054, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0904.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 2055, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0905.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 2056, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0905.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 2057, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0906.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 2058, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0906.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 2059, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0907.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 2060, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0907.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 2061, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0908.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 2062, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0908.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 2063, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0909.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 2064, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0909.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 2065, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0910.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 2066, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0910.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 2067, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0911.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 2068, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0911.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 2069, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0912.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 2070, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0912.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 2071, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0913.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 2072, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0913.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 2073, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0914.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 2074, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0914.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 2075, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0915.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 2076, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0915.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 2077, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0916.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 2078, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0916.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 2079, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0917.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 2080, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0917.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 2081, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0918.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 2082, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0918.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 2083, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0919.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 2084, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0919.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 2085, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0920.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 2086, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0920.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 2087, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0921.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 2088, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0921.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 2089, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0922.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 2090, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0922.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 2091, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0923.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 2092, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0923.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 2093, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0924.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 2094, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0924.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 2095, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0925.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 2096, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0925.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 2097, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0926.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 2098, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0926.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 2099, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0927.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 2100, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0927.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 2101, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0928.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 2102, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0928.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 2103, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0929.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 2104, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0929.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 2105, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0930.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 2106, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0930.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 2107, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0931.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 2108, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0931.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 2109, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0932.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 2110, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0932.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 2111, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0933.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 2112, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0933.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 2113, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0934.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 2114, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0934.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 2115, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0935.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 2116, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0935.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 2117, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0936.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 2118, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0936.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 2119, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0937.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 2120, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0937.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 2121, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0938.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 2122, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0938.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 2123, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0939.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 2124, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0939.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 2125, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0940.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 2126, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0940.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 2127, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0941.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 2128, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0941.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 2129, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0942.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 2130, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0942.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 2131, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0943.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 2132, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0943.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 2133, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0944.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 2134, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0944.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 2135, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0945.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 2136, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0945.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 2137, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0946.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 2138, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0946.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 2139, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0947.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 2140, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0947.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 2141, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0948.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 2142, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0948.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 2143, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0949.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 2144, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0949.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 2145, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0950.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 2146, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0950.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 2147, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0951.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 2148, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0951.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 2149, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0952.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 2150, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0952.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 2151, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0953.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 2152, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0953.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 2153, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0954.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 2154, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0954.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 2155, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0955.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 2156, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0955.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 2157, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0956.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 2158, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0956.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 2159, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0957.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 2160, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0957.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 2161, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0958.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 2162, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0958.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 2163, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0959.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 2164, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0959.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 2165, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0960.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 2166, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0960.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 2167, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0961.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 2168, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0961.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 2169, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0962.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 2170, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0962.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 2171, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0963.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 2172, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0963.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 2173, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0964.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 2174, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0964.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 2175, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0965.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 2176, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0965.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 2177, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0966.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 2178, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0966.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 2179, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0967.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 2180, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0967.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 2181, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0968.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 2182, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0968.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 2183, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0969.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 2184, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0969.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 2185, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0970.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 2186, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0970.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 2187, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0971.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 2188, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0971.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 2189, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0972.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 2190, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0972.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 2191, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0973.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 2192, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0973.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 2193, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0974.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 2194, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0974.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 2195, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0975.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 2196, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0975.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 2197, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0976.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 2198, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0976.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 2199, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0977.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 2200, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0977.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 2201, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0978.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 2202, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0978.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 2203, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0979.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 2204, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0979.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 2205, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0980.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 2206, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0980.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 2207, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0981.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 2208, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0981.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 2209, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0982.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 2210, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0982.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 2211, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0983.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 2212, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0983.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 2213, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0984.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 2214, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0984.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 2215, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0985.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 2216, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0985.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 2217, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0986.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 2218, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0986.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 2219, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0987.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 2220, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0987.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 2221, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0988.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 2222, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0988.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 2223, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0989.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 2224, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0989.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 2225, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0990.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 2226, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0990.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 2227, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0991.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 2228, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0991.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 2229, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0992.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 2230, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0992.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 2231, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0993.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 2232, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0993.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 2233, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0994.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 2234, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0994.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 2235, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0995.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 2236, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0995.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 2237, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0996.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 2238, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0996.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 2239, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0997.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 2240, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0997.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 2241, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0998.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 2242, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0998.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 2243, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0999.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 2244, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec0999.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 2245, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec1000.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 2246, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec1000.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 2247, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec1001.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 2248, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec1001.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 2249, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec1002.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 2250, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec1002.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 2251, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec1003.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 2252, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec1003.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 2253, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec1004.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 2254, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec1004.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 2255, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec1005.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 2256, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec1005.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 2257, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec1006.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 2258, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec1006.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 2259, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec1007.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 2260, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec1007.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 2261, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec1008.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 2262, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec1008.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 2263, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec1009.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 2264, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec1009.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 2265, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec1010.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 2266, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec1010.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 2267, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec1011.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 2268, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec1011.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 2269, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec1012.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 2270, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec1012.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 2271, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec1013.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 2272, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec1013.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 2273, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec1014.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 2274, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec1014.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 2275, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec1015.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 2276, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec1015.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 2277, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec1016.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 2278, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec1016.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 2279, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec1017.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 2280, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec1017.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 2281, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec1018.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 2282, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec1018.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 2283, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec1019.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 2284, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec1019.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 2285, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec1020.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 2286, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec1020.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 2287, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec1021.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 2288, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec1021.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 2289, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec1022.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 2290, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec1022.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 2291, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec1023.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 2292, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec1023.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 2293, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec1024.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 2294, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec1024.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 2295, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec1025.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 2296, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec1025.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 2297, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec1026.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 2298, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec1026.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 2299, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec1027.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 2300, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec1027.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 2301, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec1028.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 2302, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec1028.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 2303, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec1029.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 2304, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec1029.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 2305, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec1030.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 2306, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec1030.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 2307, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec1031.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 2308, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec1031.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 2309, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec1032.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 2310, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec1032.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 2311, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec1033.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 2312, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec1033.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 2313, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec1034.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 2314, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec1034.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 2315, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec1035.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 2316, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec1035.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 2317, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec1036.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 2318, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec1036.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 2319, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec1037.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 2320, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec1037.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 2321, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec1038.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 2322, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec1038.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 2323, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec1039.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 2324, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec1039.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 2325, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec1040.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 2326, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec1040.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 2327, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec1041.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 2328, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec1041.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 2329, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec1042.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 2330, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec1042.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 2331, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec1043.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 2332, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec1043.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 2333, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec1044.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 2334, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec1044.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 2335, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec1045.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 2336, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec1045.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 2337, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec1046.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 2338, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec1046.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 2339, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec1047.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 2340, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec1047.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 2341, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec1048.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 2342, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec1048.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 2343, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec1049.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 2344, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec1049.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 2345, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec1050.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 2346, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec1050.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 2347, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec1051.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 2348, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec1051.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 2349, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec1052.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 2350, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec1052.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 2351, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec1053.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 2352, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec1053.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 2353, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec1054.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 2354, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec1054.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 2355, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec1055.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 2356, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec1055.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 2357, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec1056.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 2358, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec1056.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 2359, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec1057.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 2360, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec1057.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 2361, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec1058.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 2362, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec1058.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 2363, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec1059.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 2364, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec1059.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 2365, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec1060.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 2366, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec1060.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 2367, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec1061.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 2368, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec1061.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 2369, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec1062.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 2370, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec1062.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 2371, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec1063.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 2372, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec1063.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 2373, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec1064.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 2374, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec1064.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 2375, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec1065.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 2376, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec1065.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 2377, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec1066.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 2378, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec1066.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 2379, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec1067.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 2380, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec1067.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 2381, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec1068.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 2382, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec1068.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 2383, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec1069.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 2384, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec1069.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 2385, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec1070.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 2386, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec1070.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 2387, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec1071.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 2388, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec1071.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 2389, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec1072.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 2390, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec1072.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 2391, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec1073.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 2392, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec1073.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 2393, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec1074.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 2394, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec1074.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 2395, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec1075.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 2396, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec1075.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 2397, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec1076.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 2398, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec1076.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 2399, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec1077.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 2400, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec1077.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 2401, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec1078.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 2402, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec1078.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 2403, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec1079.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 2404, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec1079.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 2405, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec1080.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 2406, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec1080.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 2407, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec1081.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 2408, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec1081.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 2409, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec1082.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 2410, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec1082.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 2411, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec1083.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 2412, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec1083.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 2413, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec1084.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 2414, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec1084.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 2415, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec1085.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 2416, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec1085.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 2417, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec1086.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 2418, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec1086.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 2419, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec1087.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 2420, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec1087.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 2421, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec1088.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 2422, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec1088.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 2423, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec1089.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 2424, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec1089.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 2425, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec1090.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 2426, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec1090.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 2427, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec1091.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 2428, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec1091.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 2429, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec1092.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 2430, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec1092.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 2431, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec1093.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 2432, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec1093.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 2433, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec1094.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 2434, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec1094.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 2435, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec1095.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 2436, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec1095.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 2437, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec1096.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 2438, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec1096.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 2439, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec1097.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 2440, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec1097.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 2441, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec1098.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 2442, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec1098.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 2443, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec1099.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 2444, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec1099.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 2445, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec1100.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 2446, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec1100.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 2447, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec1101.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 2448, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec1101.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 2449, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec1102.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 2450, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec1102.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 2451, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec1103.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 2452, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec1103.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 2453, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec1104.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 2454, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec1104.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 2455, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec1105.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 2456, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec1105.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 2457, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec1106.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 2458, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec1106.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 2459, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec1107.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 2460, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec1107.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 2461, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec1108.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 2462, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec1108.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 2463, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec1109.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 2464, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec1109.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 2465, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec1110.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 2466, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec1110.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 2467, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec1111.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 2468, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec1111.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 2469, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec1112.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 2470, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec1112.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 2471, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec1113.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 2472, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec1113.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 2473, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec1114.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 2474, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec1114.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 2475, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec1115.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 2476, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec1115.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 2477, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec1116.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 2478, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec1116.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 2479, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec1117.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 2480, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec1117.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 2481, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec1118.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 2482, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec1118.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 2483, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec1119.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 2484, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec1119.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 2485, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec1120.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 2486, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec1120.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 2487, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec1121.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 2488, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec1121.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 2489, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec1122.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 2490, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec1122.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 2491, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec1123.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 2492, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec1123.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 2493, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec1124.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 2494, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec1124.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 2495, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec1125.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 2496, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec1125.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 2497, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec1126.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 2498, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec1126.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 2499, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec1127.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 2500, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec1127.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 2501, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec1128.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 2502, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec1128.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 2503, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec1129.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 2504, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec1129.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 2505, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec1130.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 2506, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec1130.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 2507, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec1131.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 2508, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec1131.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 2509, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec1132.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 2510, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec1132.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 2511, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec1133.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 2512, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec1133.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 2513, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec1134.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 2514, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec1134.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 2515, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec1135.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 2516, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec1135.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 2517, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec1136.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 2518, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec1136.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 2519, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec1137.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 2520, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec1137.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 2521, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec1138.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 2522, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec1138.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 2523, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec1139.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 2524, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec1139.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 2525, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec1140.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 2526, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec1140.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 2527, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec1141.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 2528, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec1141.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 2529, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec1142.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 2530, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec1142.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 2531, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec1143.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 2532, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec1143.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 2533, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec1144.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 2534, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec1144.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 2535, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec1145.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 2536, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec1145.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 2537, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec1146.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 2538, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec1146.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 2539, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec1147.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 2540, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec1147.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 2541, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec1148.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 2542, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec1148.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 2543, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec1149.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 2544, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec1149.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 2545, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec1150.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 2546, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec1150.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 2547, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec1151.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 2548, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec1151.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 2549, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec1152.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 2550, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec1152.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 2551, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec1153.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 2552, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec1153.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 2553, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec1154.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 2554, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec1154.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 2555, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec1155.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 2556, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec1155.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 2557, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec1156.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 2558, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec1156.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 2559, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec1157.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 2560, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec1157.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 2561, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec1158.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 2562, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec1158.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 2563, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec1159.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 2564, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec1159.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 2565, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec1160.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 2566, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec1160.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 2567, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec1161.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 2568, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec1161.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 2569, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec1162.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 2570, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec1162.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 2571, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec1163.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 2572, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec1163.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 2573, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec1164.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 2574, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec1164.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 2575, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec1165.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 2576, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec1165.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 2577, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec1166.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 2578, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec1166.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 2579, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec1167.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 2580, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec1167.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 2581, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec1168.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 2582, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec1168.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 2583, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec1169.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 2584, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec1169.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 2585, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec1170.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 2586, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec1170.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 2587, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec1171.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 2588, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec1171.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 2589, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec1172.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 2590, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec1172.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 2591, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec1173.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 2592, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec1173.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 2593, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec1174.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 2594, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec1174.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 2595, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec1175.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 2596, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec1175.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 2597, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec1176.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 2598, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec1176.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 2599, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec1177.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 2600, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec1177.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 2601, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec1178.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 2602, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec1178.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 2603, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec1179.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 2604, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec1179.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 2605, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec1180.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 2606, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec1180.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 2607, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec1181.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 2608, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec1181.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 2609, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec1182.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 2610, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec1182.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 2611, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec1183.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 2612, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec1183.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 2613, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec1184.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 2614, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec1184.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 2615, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec1185.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 2616, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec1185.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 2617, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec1186.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 2618, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec1186.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 2619, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec1187.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 2620, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec1187.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 2621, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec1188.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 2622, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec1188.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 2623, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec1189.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 2624, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec1189.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 2625, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec1190.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 2626, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec1190.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 2627, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec1191.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 2628, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec1191.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 2629, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec1192.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 2630, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec1192.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 2631, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec1193.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 2632, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec1193.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 2633, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec1194.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 2634, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec1194.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 2635, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec1195.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 2636, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec1195.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 2637, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec1196.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 2638, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec1196.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 2639, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec1197.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 2640, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec1197.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 2641, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec1198.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 2642, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec1198.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 2643, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec1199.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 2644, + "value": { + "kind": "dns#resourceRecordSet", + "name": "pager1201-rec1199.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 2645, + "value": { + "kind": "dns#resourceRecordSet", + "name": "testa.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.1.1.1" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 2646, + "value": { + "kind": "dns#resourceRecordSet", + "name": "testa.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.1.1.1" + ], + "ttl": 333, + "type": "A" + } + }, + { + "index": 2647, + "value": { + "kind": "dns#resourceRecordSet", + "name": "testa.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.1.1.1" + ], + "ttl": 999, + "type": "A" + } + }, + { + "index": 2648, + "value": { + "kind": "dns#resourceRecordSet", + "name": "testa.dnscontroltest-gcloud.com.", + "rrdatas": [ + "3.3.3.3" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 2649, + "value": { + "kind": "dns#resourceRecordSet", + "name": "testaaaa.dnscontroltest-gcloud.com.", + "rrdatas": [ + "2607:f8b0:4006:820::2006" + ], + "ttl": 300, + "type": "AAAA" + } + }, + { + "index": 2650, + "value": { + "kind": "dns#resourceRecordSet", + "name": "testaaaa.dnscontroltest-gcloud.com.", + "rrdatas": [ + "2607:f8b0:4006:820::2013" + ], + "ttl": 300, + "type": "AAAA" + } + }, + { + "index": 2651, + "value": { + "kind": "dns#resourceRecordSet", + "name": "testcname.dnscontroltest-gcloud.com.", + "rrdatas": [ + "foo.dnscontroltest-gcloud.com." + ], + "ttl": 300, + "type": "CNAME" + } + }, + { + "index": 2652, + "value": { + "kind": "dns#resourceRecordSet", + "name": "testcname.dnscontroltest-gcloud.com.", + "rrdatas": [ + "www.google.com." + ], + "ttl": 300, + "type": "CNAME" + } + }, + { + "index": 2653, + "value": { + "kind": "dns#resourceRecordSet", + "name": "testcname.dnscontroltest-gcloud.com.", + "rrdatas": [ + "www.yahoo.com." + ], + "ttl": 300, + "type": "CNAME" + } + }, + { + "index": 2654, + "value": { + "kind": "dns#resourceRecordSet", + "name": "testdefined.dnscontroltest-gcloud.com.", + "rrdatas": [ + "2.2.2.2" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 2655, + "value": { + "kind": "dns#resourceRecordSet", + "name": "testdefined.dnscontroltest-gcloud.com.", + "rrdatas": [ + "9.9.9.9" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 2656, + "value": { + "kind": "dns#resourceRecordSet", + "name": "testignore.dnscontroltest-gcloud.com.", + "rrdatas": [ + "8.8.8.8" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 2657, + "value": { + "kind": "dns#resourceRecordSet", + "name": "testmx.dnscontroltest-gcloud.com.", + "rrdatas": [ + "100 foo.com." + ], + "ttl": 300, + "type": "MX" + } + }, + { + "index": 2658, + "value": { + "kind": "dns#resourceRecordSet", + "name": "testmx.dnscontroltest-gcloud.com.", + "rrdatas": [ + "5 bar.com." + ], + "ttl": 300, + "type": "MX" + } + }, + { + "index": 2659, + "value": { + "kind": "dns#resourceRecordSet", + "name": "testmx.dnscontroltest-gcloud.com.", + "rrdatas": [ + "5 foo.com.", + "100 bar.com." + ], + "ttl": 300, + "type": "MX" + } + }, + { + "index": 2660, + "value": { + "kind": "dns#resourceRecordSet", + "name": "testmx.dnscontroltest-gcloud.com.", + "rrdatas": [ + "5 foo.com." + ], + "ttl": 300, + "type": "MX" + } + }, + { + "index": 2661, + "value": { + "kind": "dns#resourceRecordSet", + "name": "testtxt.dnscontroltest-gcloud.com.", + "rrdatas": [ + "\"changed\"" + ], + "ttl": 300, + "type": "TXT" + } + }, + { + "index": 2662, + "value": { + "kind": "dns#resourceRecordSet", + "name": "testtxt.dnscontroltest-gcloud.com.", + "rrdatas": [ + "\"simple\"" + ], + "ttl": 300, + "type": "TXT" + } + }, + { + "index": 2663, + "value": { + "kind": "dns#resourceRecordSet", + "name": "www.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.1.1.1", + "2.2.2.2", + "3.3.3.3" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 2664, + "value": { + "kind": "dns#resourceRecordSet", + "name": "www.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.1.1.1", + "2.2.2.2" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 2665, + "value": { + "kind": "dns#resourceRecordSet", + "name": "www.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.1.1.1" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 2666, + "value": { + "kind": "dns#resourceRecordSet", + "name": "www.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4", + "5.6.7.8" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 2667, + "value": { + "kind": "dns#resourceRecordSet", + "name": "www.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4", + "5.6.7.8" + ], + "ttl": 700, + "type": "A" + } + }, + { + "index": 2668, + "value": { + "kind": "dns#resourceRecordSet", + "name": "www.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.8" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 2669, + "value": { + "kind": "dns#resourceRecordSet", + "name": "www.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.9" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 2670, + "value": { + "kind": "dns#resourceRecordSet", + "name": "www.dnscontroltest-gcloud.com.", + "rrdatas": [ + "2.2.2.2", + "5.6.7.8" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 2671, + "value": { + "kind": "dns#resourceRecordSet", + "name": "www.dnscontroltest-gcloud.com.", + "rrdatas": [ + "2.2.2.2", + "5.6.7.8" + ], + "ttl": 400, + "type": "A" + } + }, + { + "index": 2672, + "value": { + "kind": "dns#resourceRecordSet", + "name": "www.dnscontroltest-gcloud.com.", + "rrdatas": [ + "5.5.5.5" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 2673, + "value": { + "kind": "dns#resourceRecordSet", + "name": "www.dnscontroltest-gcloud.com.", + "rrdatas": [ + "5.6.7.8" + ], + "ttl": 400, + "type": "A" + } + }, + { + "index": 2674, + "value": { + "kind": "dns#resourceRecordSet", + "name": "xn--fiq228c.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 2675, + "value": { + "kind": "dns#resourceRecordSet", + "name": "xn--ndaaa.dnscontroltest-gcloud.com.", + "rrdatas": [ + "1.2.3.4" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 2676, + "value": { + "kind": "dns#resourceRecordSet", + "name": "xn--ndaaa.dnscontroltest-gcloud.com.", + "rrdatas": [ + "2.2.2.2" + ], + "ttl": 300, + "type": "A" + } + }, + { + "index": 2677, + "value": { + "kind": "dns#resourceRecordSet", + "name": "xn--o-0gab.dnscontroltest-gcloud.com.", + "rrdatas": [ + "xn--ndaaa.xn--vhquv." + ], + "ttl": 300, + "type": "CNAME" + } + }, + { + "index": 2678, + "value": { + "kind": "dns#resourceRecordSet", + "name": "xyz.dnscontroltest-gcloud.com.", + "rrdatas": [ + "ns1.foo.com.", + "ns2.foo.com." + ], + "ttl": 300, + "type": "NS" + } + }, + { + "index": 2679, + "value": { + "kind": "dns#resourceRecordSet", + "name": "xyz.dnscontroltest-gcloud.com.", + "rrdatas": [ + "ns2.foo.com." + ], + "ttl": 300, + "type": "NS" + } + }, + { + "index": 2680, + "value": { + "kind": "dns#resourceRecordSet", + "name": "zzz.dnscontroltest-gcloud.com.", + "rrdatas": [ + "2003:dd:d7ff::fe71:cccc" + ], + "ttl": 300, + "type": "AAAA" + } + }, + { + "index": 2681, + "value": { + "kind": "dns#resourceRecordSet", + "name": "zzz.dnscontroltest-gcloud.com.", + "rrdatas": [ + "3.3.3.3", + "4.4.4.4" + ], + "ttl": 300, + "type": "A" + } + } +] diff --git a/providers/gcore/auditrecords.go b/providers/gcore/auditrecords.go index f1b3d314fa..49d9e1ef6c 100644 --- a/providers/gcore/auditrecords.go +++ b/providers/gcore/auditrecords.go @@ -1,14 +1,14 @@ package gcore import ( - "github.com/DNSControl/dnscontrol/v4/models" - "github.com/DNSControl/dnscontrol/v4/pkg/rejectif" + "github.com/DNSControl/dnscontrol/v5/models" + "github.com/DNSControl/dnscontrol/v5/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 { +func AuditRecords(records models.Records) []error { a := rejectif.Auditor{} a.Add("SRV", rejectif.SrvHasNullTarget) return a.Audit(records) diff --git a/providers/gcore/convert.go b/providers/gcore/convert.go index 131e700154..835733a3a5 100644 --- a/providers/gcore/convert.go +++ b/providers/gcore/convert.go @@ -5,16 +5,17 @@ package gcore import ( "errors" "fmt" + "strings" - "github.com/DNSControl/dnscontrol/v4/models" - "github.com/DNSControl/dnscontrol/v4/pkg/printer" + "github.com/DNSControl/dnscontrol/v5/models" + "github.com/DNSControl/dnscontrol/v5/pkg/printer" dnssdk "github.com/G-Core/gcore-dns-sdk-go" ) // nativeToRecord takes a DNS record from G-Core and returns a native RecordConfig struct. -func nativeToRecords(n gcoreRRSetExtended, zoneName string) ([]*models.RecordConfig, error) { - var rcs []*models.RecordConfig - recName := n.Name +func nativeToRecords(n gcoreRRSetExtended, dc *models.DomainConfig) (models.Records, error) { + var rcs models.Records + recName := dc.LabelFromFQDNWithDot(n.Name) recType := n.Type // Split G-Core's RRset into individual records @@ -23,12 +24,8 @@ func nativeToRecords(n gcoreRRSetExtended, zoneName string) ([]*models.RecordCon if err != nil { return nil, fmt.Errorf("unparsable record received from G-Core: %w", err) } - rc := &models.RecordConfig{ - TTL: uint32(n.TTL), - Original: n, - Metadata: metadata, - } - rc.SetLabelFromFQDN(recName, zoneName) + + var rc *models.RecordConfig switch recType { case "CAA": // G-Core API don't need quotes around CAA with whitespace if len(value.Content) != 3 { @@ -41,32 +38,29 @@ func nativeToRecords(n gcoreRRSetExtended, zoneName string) ([]*models.RecordCon } flag, tag, target := parts[0], parts[1], parts[2] - if err := rc.SetTargetCAAStrings(flag, tag, target); err != nil { - return nil, fmt.Errorf("unparsable record received from G-Core: %w", err) - } + rc, err = dc.NewRecordConfig(recName, uint32(n.TTL), recType, flag, tag, target) case "TXT": // Avoid double quoting for TXT records - if err := rc.SetTargetTXTs(convertSdkAnySliceToTxtSlice(value.Content)); err != nil { - return nil, fmt.Errorf("unparsable record received from G-Core: %w", err) - } + rc, err = dc.NewRecordConfig(recName, uint32(n.TTL), recType, strings.Join(convertSdkAnySliceToTxtSlice(value.Content), "")) case "SCVB": // GCore mistypes "SVCB" as "SCVB" - if err := rc.PopulateFromString("SVCB", value.ContentToString(), zoneName); err != nil { - return nil, fmt.Errorf("unparsable record received from G-Core: %w", err) - } + rc, err = dc.NewRecordConfigParse(recName, uint32(n.TTL), "SVCB", value.ContentToString()) - default: // "A", "AAAA", "CAA", "NS", "CNAME", "MX", "PTR", "SRV" - if err := rc.PopulateFromString(recType, value.ContentToString(), zoneName); err != nil { - return nil, fmt.Errorf("unparsable record received from G-Core: %w", err) - } + default: + rc, err = dc.NewRecordConfigParse(recName, uint32(n.TTL), recType, value.ContentToString()) + } + if err != nil { + return nil, fmt.Errorf("unparsable record received from G-Core: %w", err) } + rc.Original = n + rc.Metadata = metadata rcs = append(rcs, rc) } return rcs, nil } -func recordsToNative(rcs []*models.RecordConfig, expectedKey models.RecordKey) (*dnssdk.RRSet, error) { +func recordsToNative(rcs models.Records, expectedKey models.RecordKey) (*dnssdk.RRSet, error) { // Merge DNSControl records into G-Core RRsets var result *dnssdk.RRSet @@ -96,7 +90,7 @@ func recordsToNative(rcs []*models.RecordConfig, expectedKey models.RecordKey) ( return nil, err } if !isRRSetFilterEqual { - return nil, fmt.Errorf("filter is not consistent between %s and %s in RRSet %s", resultRRSetMetaSourceRecord, r, expectedKey) + return nil, fmt.Errorf("filter is not consistent between %s and %s in RRSet %s", resultRRSetMetaSourceRecord.GetRDATA().String(), r.GetRDATA().String(), expectedKey) } isRRSetMetaEqual, err := isStructEqual(resultRRSetMeta, rrsetMeta) @@ -104,18 +98,19 @@ func recordsToNative(rcs []*models.RecordConfig, expectedKey models.RecordKey) ( return nil, err } if !isRRSetMetaEqual { - return nil, fmt.Errorf("metadata is not consistent between %s and %s in RRSet %s", resultRRSetMetaSourceRecord, r, expectedKey) + return nil, fmt.Errorf("metadata is not consistent between %s and %s in RRSet %s", resultRRSetMetaSourceRecord.GetRDATA().String(), r.GetRDATA().String(), expectedKey) } } var rr dnssdk.ResourceRecord switch key.Type { case "CAA": // G-Core API don't need quotes around CAA with whitespace + f := r.AsCAA() rr = dnssdk.ResourceRecord{ Content: []any{ - int64(r.CaaFlag), - r.CaaTag, - r.GetTargetField(), + int64(f.Flag), + f.Tag, + f.Value, }, Meta: recordMeta, Enabled: true, @@ -129,13 +124,13 @@ func recordsToNative(rcs []*models.RecordConfig, expectedKey models.RecordKey) ( case "SVCB": // GCore mistypes "SVCB" as "SCVB" rr = dnssdk.ResourceRecord{ - Content: dnssdk.ContentFromValue("SCVB", r.GetTargetCombined()), + Content: dnssdk.ContentFromValue("SCVB", r.GetRDATA().String()), Meta: recordMeta, Enabled: true, } default: rr = dnssdk.ResourceRecord{ - Content: dnssdk.ContentFromValue(key.Type, r.GetTargetCombined()), + Content: dnssdk.ContentFromValue(key.Type, r.GetRDATA().String()), Meta: recordMeta, Enabled: true, } diff --git a/providers/gcore/convertMetadata.go b/providers/gcore/convertMetadata.go index ad6d0a1fd0..63c61b1501 100644 --- a/providers/gcore/convertMetadata.go +++ b/providers/gcore/convertMetadata.go @@ -335,8 +335,8 @@ func parseRecordFilter(filterString string) ([]dnssdk.RecordFilter, error) { return nil, fmt.Errorf("filter %s has invalid format, correct format is \"type,strict[,limit]\"", s) } - record := dnssdk.RecordFilter{} - record.Type = fields[0] + record := dnssdk.RecordFilter{ + Type: fields[0]} record.Strict, err = strconv.ParseBool(fields[1]) if err != nil { diff --git a/providers/gcore/convert_test.go b/providers/gcore/convert_test.go new file mode 100644 index 0000000000..ec0a1cd053 --- /dev/null +++ b/providers/gcore/convert_test.go @@ -0,0 +1,40 @@ +package gcore + +import ( + "testing" + + "github.com/DNSControl/dnscontrol/v5/models" + dnssdk "github.com/G-Core/gcore-dns-sdk-go" +) + +func TestNativeToRecords(t *testing.T) { + dc, err := models.NewDomainConfig("example.com") + if err != nil { + t.Fatal(err) + } + tests := []struct { + name string + rrtype string + content []any + wantTarget string + }{ + {"A", "A", []any{"192.0.2.1"}, "192.0.2.1"}, + {"MX", "MX", []any{int64(10), "mail.example.net."}, "10 mail.example.net."}, + {"CAA", "CAA", []any{int64(0), "issue", "letsencrypt.org"}, `0 issue "letsencrypt.org"`}, + {"TXT", "TXT", []any{"raw text"}, `"raw text"`}, + } + for _, tc := range tests { + t.Run(tc.name, func(t *testing.T) { + records, err := nativeToRecords(gcoreRRSetExtended{ + Name: "www.example.com.", Type: tc.rrtype, TTL: 300, + Records: []dnssdk.ResourceRecord{{Content: tc.content}}, + }, dc) + if err != nil { + t.Fatal(err) + } + if got := records[0].GetRDATA().String(); got != tc.wantTarget { + t.Errorf("target = %q, want %q", got, tc.wantTarget) + } + }) + } +} diff --git a/providers/gcore/gcoreProvider.go b/providers/gcore/gcoreProvider.go index 3c2522dd28..9d6b0e328d 100644 --- a/providers/gcore/gcoreProvider.go +++ b/providers/gcore/gcoreProvider.go @@ -7,10 +7,10 @@ import ( "fmt" "strings" - "github.com/DNSControl/dnscontrol/v4/models" - "github.com/DNSControl/dnscontrol/v4/pkg/diff2" - "github.com/DNSControl/dnscontrol/v4/pkg/printer" - "github.com/DNSControl/dnscontrol/v4/pkg/providers" + "github.com/DNSControl/dnscontrol/v5/models" + "github.com/DNSControl/dnscontrol/v5/pkg/diff2" + "github.com/DNSControl/dnscontrol/v5/pkg/printer" + "github.com/DNSControl/dnscontrol/v5/pkg/providers" dnssdk "github.com/G-Core/gcore-dns-sdk-go" ) @@ -103,13 +103,13 @@ func (c *gcoreProvider) GetNameservers(domain string) ([]*models.Nameserver, err func (c *gcoreProvider) GetZoneRecords(dc *models.DomainConfig) (models.Records, error) { domain := dc.Name - zone, err := c.provider.Zone(c.ctx, domain) + _, err := c.provider.Zone(c.ctx, domain) if err != nil { return nil, err } // Convert RRsets to DNSControl format on the fly - existingRecords := []*models.RecordConfig{} + existingRecords := models.Records{} // We cannot directly use Zone's ShortAnswers, they aren't complete for CAA & SRV @@ -119,7 +119,7 @@ func (c *gcoreProvider) GetZoneRecords(dc *models.DomainConfig) (models.Records, } for _, rec := range rrsets.RRSets { - nativeRecords, err := nativeToRecords(rec, zone.Name) + nativeRecords, err := nativeToRecords(rec, dc) if err != nil { return nil, err } @@ -167,7 +167,7 @@ func (c *gcoreProvider) GetZoneRecordsCorrections(dc *models.DomainConfig, exist // Gcore auto uses ALIAS for apex zone CNAME records, just like CloudFlare for _, rec := range dc.Records { if rec.Type == "ALIAS" { - rec.ChangeType("CNAME", dc.Name) + rec.ChangeTypeToCNAME(dc, rec.AsALIAS().Target) } } diff --git a/providers/gidinet/auditrecords.go b/providers/gidinet/auditrecords.go index 3ed06df982..cb515066ef 100644 --- a/providers/gidinet/auditrecords.go +++ b/providers/gidinet/auditrecords.go @@ -1,18 +1,20 @@ package gidinet import ( - "github.com/DNSControl/dnscontrol/v4/models" - "github.com/DNSControl/dnscontrol/v4/pkg/rejectif" + "github.com/DNSControl/dnscontrol/v5/models" + "github.com/DNSControl/dnscontrol/v5/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 { +func AuditRecords(records models.Records) []error { a := rejectif.Auditor{} a.Add("MX", rejectif.MxNull) // Last verified 2026-01-24 + a.Add("SRV", rejectif.SrvHasNullTarget) // Last verified 2026-07-07 + a.Add("TXT", rejectif.TxtHasDoubleQuotes) // Last verified 2026-01-24 a.Add("TXT", rejectif.TxtIsEmpty) // Last verified 2026-01-24 diff --git a/providers/gidinet/auditrecords_test.go b/providers/gidinet/auditrecords_test.go index 66a0e15ef3..afd45e4767 100644 --- a/providers/gidinet/auditrecords_test.go +++ b/providers/gidinet/auditrecords_test.go @@ -3,48 +3,62 @@ package gidinet import ( "testing" - "github.com/DNSControl/dnscontrol/v4/models" + "github.com/DNSControl/dnscontrol/v5/models" ) func TestAuditRecords(t *testing.T) { tests := []struct { name string - records []*models.RecordConfig + records models.Records wantCount int }{ { name: "empty records", - records: []*models.RecordConfig{}, + records: models.Records{}, wantCount: 0, }, { name: "valid A record", - records: []*models.RecordConfig{ + records: models.Records{ makeRC("A", "test", "1.2.3.4"), }, wantCount: 0, }, { name: "valid TXT record", - records: []*models.RecordConfig{ + records: models.Records{ makeRC("TXT", "test", "hello world"), }, wantCount: 0, }, { name: "TXT with double quotes should fail", - records: []*models.RecordConfig{ + records: models.Records{ makeRC("TXT", "test", `hello "world"`), }, wantCount: 1, }, { name: "empty TXT should fail", - records: []*models.RecordConfig{ + records: models.Records{ makeRC("TXT", "test", ""), }, wantCount: 1, }, + { + name: "valid SRV record", + records: models.Records{ + makeRC("SRV", "_sip._tcp", "foo.com."), + }, + wantCount: 0, + }, + { + name: "SRV with null target should fail", + records: models.Records{ + makeRC("SRV", "_sip._tcp", "."), + }, + wantCount: 1, + }, } for _, tt := range tests { @@ -58,15 +72,13 @@ func TestAuditRecords(t *testing.T) { } func makeRC(rtype, label, target string) *models.RecordConfig { - rc := &models.RecordConfig{ - Type: rtype, - } - rc.SetLabel(label, "example.com") + dc, _ := models.NewDomainConfig("example.com") switch rtype { - case "TXT": - rc.SetTargetTXT(target) + case "SRV": + return dc.MustNewRecordConfig(label, 300, rtype, 0, 0, 0, target) + // case "TXT": + // return dc.MustNewRecordConfig(label, 300, rtype, target) default: - rc.SetTarget(target) + return dc.MustNewRecordConfig(label, 300, rtype, target) } - return rc } diff --git a/providers/gidinet/gidinetProvider.go b/providers/gidinet/gidinetProvider.go index 1e8853a3e2..788f742875 100644 --- a/providers/gidinet/gidinetProvider.go +++ b/providers/gidinet/gidinetProvider.go @@ -7,11 +7,11 @@ import ( "strconv" "strings" - "github.com/DNSControl/dnscontrol/v4/models" - "github.com/DNSControl/dnscontrol/v4/pkg/diff2" - "github.com/DNSControl/dnscontrol/v4/pkg/printer" - "github.com/DNSControl/dnscontrol/v4/pkg/providers" - "github.com/miekg/dns/dnsutil" + dnsv2 "codeberg.org/miekg/dns" + "github.com/DNSControl/dnscontrol/v5/models" + "github.com/DNSControl/dnscontrol/v5/pkg/diff2" + "github.com/DNSControl/dnscontrol/v5/pkg/printer" + "github.com/DNSControl/dnscontrol/v5/pkg/providers" ) /* @@ -139,7 +139,7 @@ func (c *gidinetProvider) GetZoneRecords(dc *models.DomainConfig) (models.Record return nil, err } - var existingRecords []*models.RecordConfig + var existingRecords models.Records for _, r := range records { // Skip read-only records (usually NS records at apex managed by registrar) if r.ReadOnly { @@ -150,7 +150,7 @@ func (c *gidinetProvider) GetZoneRecords(dc *models.DomainConfig) (models.Record continue } - rc, err := toRecordConfig(domain, r) + rc, err := toRecordConfig(dc, r) if err != nil { return nil, err } @@ -243,30 +243,22 @@ func (c *gidinetProvider) GetZoneRecordsCorrections(dc *models.DomainConfig, exi } // toRecordConfig converts a Gidinet DNS record to a RecordConfig. -func toRecordConfig(domain string, r *DNSRecordListItem) (*models.RecordConfig, error) { - rc := &models.RecordConfig{ - Type: r.RecordType, - TTL: uint32(r.TTL), - Original: r, - } - +func toRecordConfig(dc *models.DomainConfig, r *DNSRecordListItem) (*models.RecordConfig, error) { // Set the label from the hostname // Gidinet returns full hostnames like "www.domain.com" - label := fromFQDN(r.HostName, domain) - rc.SetLabel(label, domain) + label := fromFQDN(r.HostName, dc.Name) // Handle different record types + var rc *models.RecordConfig + var err error switch r.RecordType { case "MX": - rc.MxPreference = uint16(r.Priority) // MX target should be FQDN with trailing dot target := r.Data if !strings.HasSuffix(target, ".") { - target = dnsutil.AddOrigin(target+".", domain) - } - if err := rc.SetTarget(target); err != nil { - return nil, err + target += "." } + rc, err = dc.NewRecordConfig(label, uint32(r.TTL), r.RecordType, r.Priority, target) case "SRV": // SRV records in Gidinet: Data contains "priority weight port target" @@ -280,12 +272,7 @@ func toRecordConfig(domain string, r *DNSRecordListItem) (*models.RecordConfig, if !strings.HasSuffix(target, ".") { target = target + "." } - rc.SrvPriority = uint16(priority) - rc.SrvWeight = uint16(weight) - rc.SrvPort = uint16(port) - if err := rc.SetTarget(target); err != nil { - return nil, err - } + rc, err = dc.NewRecordConfig(label, uint32(r.TTL), r.RecordType, uint16(priority), uint16(weight), uint16(port), target) } else { return nil, fmt.Errorf("invalid SRV data format: %q (expected: priority weight port target)", r.Data) } @@ -293,25 +280,23 @@ func toRecordConfig(domain string, r *DNSRecordListItem) (*models.RecordConfig, case "CNAME", "NS": target := r.Data if !strings.HasSuffix(target, ".") { - target = dnsutil.AddOrigin(target+".", domain) - } - if err := rc.SetTarget(target); err != nil { - return nil, err + target += "." } + rc, err = dc.NewRecordConfig(label, uint32(r.TTL), r.RecordType, target) case "TXT": // Gidinet may return TXT values in chunked format: "chunk1" "chunk2" // Use unchunkTXT to parse back to a single string txtData := unchunkTXT(r.Data) - if err := rc.SetTargetTXT(txtData); err != nil { - return nil, err - } + rc, err = dc.NewRecordConfig(label, uint32(r.TTL), r.RecordType, txtData) default: // A, AAAA, etc. - if err := rc.SetTarget(r.Data); err != nil { - return nil, err - } + rc, err = dc.NewRecordConfig(label, uint32(r.TTL), r.RecordType, r.Data) } + if err != nil { + return nil, err + } + rc.Original = r return rc, nil } @@ -326,34 +311,41 @@ func toGidinetRecord(domain string, rc *models.RecordConfig) *DNSRecord { Priority: 0, } - switch rc.Type { - case "MX": - rec.Priority = int(rc.MxPreference) + switch rc.TypeNum { + case dnsv2.TypeMX: + f := rc.AsMX() + rec.Priority = int(f.Preference) // Remove trailing dot from target - target := rc.GetTargetField() + target := f.Mx rec.Data = strings.TrimSuffix(target, ".") - case "SRV": + case dnsv2.TypeSRV: // SRV Data format: priority weight port target (with trailing dot per Gidinet spec) // The Priority field is only for MX records + f := rc.AsSRV() rec.Priority = 0 - target := rc.GetTargetField() + target := f.Target if !strings.HasSuffix(target, ".") { target = target + "." } - rec.Data = fmt.Sprintf("%d %d %d %s", rc.SrvPriority, rc.SrvWeight, rc.SrvPort, target) + rec.Data = fmt.Sprintf("%d %d %d %s", f.Priority, f.Weight, f.Port, target) - case "CNAME", "NS": + case dnsv2.TypeCNAME: // Remove trailing dot from target - target := rc.GetTargetField() + target := rc.AsCNAME().Target rec.Data = strings.TrimSuffix(target, ".") - case "TXT": + case dnsv2.TypeNS: + // Remove trailing dot from target + target := rc.AsNS().Ns + rec.Data = strings.TrimSuffix(target, ".") + + case dnsv2.TypeTXT: // Chunk long TXT values into quoted segments for the API rec.Data = chunkTXT(rc.GetTargetTXTJoined()) - default: // A, AAAA, etc. - rec.Data = rc.GetTargetField() + default: + rec.Data = rc.GetRDATA().String() } return rec @@ -372,12 +364,13 @@ func filterApexNS(dc *models.DomainConfig) { expected[strings.TrimSuffix(ns.Name, ".")] = true } - newList := make([]*models.RecordConfig, 0, len(dc.Records)) + newList := make(models.Records, 0, len(dc.Records)) for _, rec := range dc.Records { if rec.Type == "NS" && rec.GetLabelFQDN() == dc.Name { - target := strings.TrimSuffix(rec.GetTargetField(), ".") + ns := rec.AsNS().Ns + target := strings.TrimSuffix(ns, ".") if !expected[target] { - printer.Warnf("GIDINET does not support modifying NS records at apex. %s will not be added.\n", rec.GetTargetField()) + printer.Warnf("GIDINET does not support modifying NS records at apex. %s will not be added.\n", ns) } continue } diff --git a/providers/gidinet/registrar.go b/providers/gidinet/registrar.go index 4c72e65735..073ea4f1b3 100644 --- a/providers/gidinet/registrar.go +++ b/providers/gidinet/registrar.go @@ -5,7 +5,7 @@ import ( "sort" "strings" - "github.com/DNSControl/dnscontrol/v4/models" + "github.com/DNSControl/dnscontrol/v5/models" ) // GetRegistrarCorrections returns corrections to update domain nameserver delegation. diff --git a/providers/gigahost/api.go b/providers/gigahost/api.go index 7e6348ec7a..c763df41b3 100644 --- a/providers/gigahost/api.go +++ b/providers/gigahost/api.go @@ -10,6 +10,8 @@ import ( "strconv" "strings" "time" + + "github.com/DNSControl/dnscontrol/v5/pkg/printer" ) const baseURL = "https://api.gigahost.no/api/v0" @@ -85,13 +87,13 @@ type recordRequest struct { // request performs an HTTP request against the Gigahost API, unwraps the // standard envelope, surfaces meta-level errors, and decodes data into target. func (c *gigahostProvider) request(method, path string, query url.Values, body, target any) error { - var reqBody io.Reader + var bodyJSON []byte if body != nil { j, err := json.Marshal(body) if err != nil { return err } - reqBody = bytes.NewBuffer(j) + bodyJSON = j } u := baseURL + path @@ -99,39 +101,67 @@ func (c *gigahostProvider) request(method, path string, query url.Values, body, u += "?" + query.Encode() } - req, err := http.NewRequest(method, u, reqBody) - if err != nil { - return err - } - req.Header.Set("Authorization", "Bearer "+c.apiKey) - req.Header.Set("Accept", "application/json") - if reqBody != nil { - req.Header.Set("Content-Type", "application/json") - } + // The API rate-limits aggressively enough that a normal push can trip it, + // so retry 429s with a backoff (honoring Retry-After when present). + const maxRetries = 5 + var resp *http.Response + var raw []byte + var env apiEnvelope + var status int + for attempt := 0; ; attempt++ { + var reqBody io.Reader + if bodyJSON != nil { + reqBody = bytes.NewReader(bodyJSON) + } + req, err := http.NewRequest(method, u, reqBody) + if err != nil { + return err + } + req.Header.Set("Authorization", "Bearer "+c.apiKey) + req.Header.Set("Accept", "application/json") + if reqBody != nil { + req.Header.Set("Content-Type", "application/json") + } - resp, err := httpClient.Do(req) - if err != nil { - return err - } - defer resp.Body.Close() + resp, err = httpClient.Do(req) + if err != nil { + return err + } + raw, err = io.ReadAll(resp.Body) + resp.Body.Close() + if err != nil { + return err + } - raw, err := io.ReadAll(resp.Body) - if err != nil { - return err - } + env = apiEnvelope{} + if len(raw) > 0 { + if err := json.Unmarshal(raw, &env); err != nil { + return fmt.Errorf("gigahost: could not decode response for %s %s (HTTP %d): %w", method, path, resp.StatusCode, err) + } + } - var env apiEnvelope - if len(raw) > 0 { - if err := json.Unmarshal(raw, &env); err != nil { - return fmt.Errorf("gigahost: could not decode response for %s %s (HTTP %d): %w", method, path, resp.StatusCode, err) + // Prefer the envelope's meta.status, falling back to the HTTP status code. + status = env.Meta.Status + if status == 0 { + status = resp.StatusCode } - } - // Prefer the envelope's meta.status, falling back to the HTTP status code. - status := env.Meta.Status - if status == 0 { - status = resp.StatusCode + if status != http.StatusTooManyRequests || attempt >= maxRetries { + break + } + wait := time.Duration(2< 180 { + return fmt.Errorf("gigahost: %s %s rate limited; Retry-After %ds too long", method, path, secs) + } + wait = time.Duration(secs+1) * time.Second + } + } + printer.Warnf("GIGAHOST: rate limited, retrying in %v\n", wait) + time.Sleep(wait) } + if status >= 400 { msg := env.Meta.Message if msg == "" { diff --git a/providers/gigahost/gigahostProvider.go b/providers/gigahost/gigahostProvider.go index 0074bbb58d..32de360d5c 100644 --- a/providers/gigahost/gigahostProvider.go +++ b/providers/gigahost/gigahostProvider.go @@ -6,15 +6,16 @@ import ( "fmt" "strings" - "github.com/DNSControl/dnscontrol/v4/models" - "github.com/DNSControl/dnscontrol/v4/pkg/diff2" - "github.com/DNSControl/dnscontrol/v4/pkg/printer" - "github.com/DNSControl/dnscontrol/v4/pkg/providers" - "github.com/DNSControl/dnscontrol/v4/pkg/rejectif" + dnsv2 "codeberg.org/miekg/dns" + "github.com/DNSControl/dnscontrol/v5/models" + "github.com/DNSControl/dnscontrol/v5/pkg/diff2" + "github.com/DNSControl/dnscontrol/v5/pkg/printer" + "github.com/DNSControl/dnscontrol/v5/pkg/providers" + "github.com/DNSControl/dnscontrol/v5/pkg/rejectif" + "github.com/DNSControl/dnscontrol/v5/pkg/txtutil" ) -// features describes the capabilities of the Gigahost provider. Start with -// zero optional capabilities; only A/AAAA/CNAME/MX/TXT/NS are handled. +// features describes the capabilities of the Gigahost provider. var features = providers.DocumentationNotes{ // The default for unlisted capabilities is 'Cannot'. // See providers/capabilities.go for the entire list of capabilities. @@ -67,12 +68,35 @@ func newGigahost(settings map[string]string, _ json.RawMessage) (providers.DNSSe // AuditRecords returns a list of errors corresponding to the records that // aren't supported by this provider. -func AuditRecords(records []*models.RecordConfig) []error { +func AuditRecords(records models.Records) []error { a := rejectif.Auditor{} + a.Add("MX", rejectif.MxNull) // The API rejects a "." target ("MX record value must be a valid mail server hostname"). a.Add("TXT", rejectif.TxtIsEmpty) + // The API cannot round-trip double quotes in TXT values: raw interior + // quotes are rejected by its zone parser, and if sent escaped + // (`"right\""`) the record is stored correctly but the read-back + // record_value is mangled (`right\`), breaking diffing and deletes. + a.Add("TXT", rejectif.TxtHasDoubleQuotes) + a.Add("TXT", rejectif.TxtStartsOrEndsWithSpaces) // The API trims leading/trailing whitespace on store. a.Add("CAA", rejectif.CaaTargetContainsWhitespace) a.Add("SRV", rejectif.SrvHasNullTarget) - return a.Audit(records) + errs := a.Audit(records) + + // The API silently replaces the entire NAPTR RRset on every create + // (POSTing a second NAPTR at a label deletes the first), so only one + // NAPTR per label can be represented. Verified against the live API + // 2026-07-27. + naptrSeen := map[string]bool{} + for _, rc := range records { + if rc.Type != "NAPTR" { + continue + } + if naptrSeen[rc.GetLabelFQDN()] { + errs = append(errs, fmt.Errorf("only one NAPTR record per label is supported (%s)", rc.GetLabelFQDN())) + } + naptrSeen[rc.GetLabelFQDN()] = true + } + return errs } // findZone resolves a domain name to its Gigahost zone, caching the zone list. @@ -145,7 +169,7 @@ func (c *gigahostProvider) GetZoneRecords(dc *models.DomainConfig) (models.Recor printer.Warnf("GIGAHOST: ignoring unsupported record type %s (%s)\n", t, recs[i].RecordName) continue } - rc, err := nativeToRecordConfig(dc.Name, &recs[i]) + rc, err := nativeToRecordConfig(dc, &recs[i]) if err != nil { return nil, err } @@ -201,7 +225,7 @@ func (c *gigahostProvider) GetZoneRecordsCorrections(dc *models.DomainConfig, ex corrections = append(corrections, &models.Correction{ Msg: inst.Msgs[0], F: func() error { - return c.deleteRecord(z.ZoneID, old.RecordID, old.RecordName, old.RecordType, old.RecordValue) + return c.deleteRecord(z.ZoneID, old.RecordID, old.RecordName, old.RecordType, deleteValue(old)) }, }) default: @@ -213,36 +237,42 @@ func (c *gigahostProvider) GetZoneRecordsCorrections(dc *models.DomainConfig, ex } // nativeToRecordConfig converts a Gigahost record into a RecordConfig. -func nativeToRecordConfig(domain string, r *record) (*models.RecordConfig, error) { - rc := &models.RecordConfig{ - Type: r.RecordType, - TTL: r.RecordTTL.Value, - Original: r, - } - rc.SetLabel(r.RecordName, domain) +func nativeToRecordConfig(dc *models.DomainConfig, r *record) (*models.RecordConfig, error) { + label := dc.LabelFromShort(r.RecordName) + ttl := r.RecordTTL.Value + var rc *models.RecordConfig var err error switch r.RecordType { case "MX": - err = rc.SetTargetMX(uint16(r.RecordPrio.Value), addDot(r.RecordValue)) + rc, err = dc.NewRecordConfig(label, ttl, r.RecordType, r.RecordPrio.Value, addDot(r.RecordValue)) case "CNAME", "NS", "ALIAS", "PTR", "DNAME": // Gigahost stores hostname targets inconsistently (some with a trailing // dot, some without); RecordConfig targets are always FQDNs. - err = rc.SetTarget(addDot(r.RecordValue)) + rc, err = dc.NewRecordConfig(label, ttl, r.RecordType, addDot(r.RecordValue)) case "TXT": - err = rc.SetTargetTXT(r.RecordValue) - case "CAA": - err = rc.SetTargetCAAString(r.RecordValue) - case "SRV": - err = rc.SetTargetSRVString(r.RecordValue) - case "NAPTR": - err = rc.SetTargetNAPTRString(r.RecordValue) + val := r.RecordValue + // The API returns >255-octet TXT values in the RFC1035 chunked form + // we sent (see recordConfigToRequest) with the outer quotes stripped, + // e.g. `aaa...aaa" "bbb`. A single TXT character-string cannot exceed + // 255 octets, so a longer record_value must be that form: re-wrap and + // decode to the raw joined text. Shorter values are stored and + // returned verbatim (kept as-is on decode failure). + if len(val) > 255 { + if decoded, derr := txtutil.ParseQuoted(`"` + val + `"`); derr == nil { + val = decoded + } + } + rc, err = dc.NewRecordConfig(label, ttl, r.RecordType, val) default: - err = rc.PopulateFromStringFunc(r.RecordType, r.RecordValue, domain, nil) + rc, err = dc.NewRecordConfigParse(label, ttl, r.RecordType, r.RecordValue) } if err != nil { return nil, fmt.Errorf("gigahost: unparsable %s record %q: %w", r.RecordType, r.RecordValue, err) } + + rc.Original = r + return rc, nil } @@ -253,26 +283,37 @@ func recordConfigToRequest(rc *models.RecordConfig) *recordRequest { RecordType: rc.Type, RecordTTL: rc.TTL, } - switch rc.Type { - case "MX": - pref := rc.MxPreference - r.RecordPrio = &pref - r.RecordValue = strings.TrimSuffix(rc.GetTargetField(), ".") - case "CNAME", "NS", "ALIAS", "PTR", "DNAME": - // Send hostname targets without a trailing dot; the API normalizes as - // needed and reads are re-dotted in nativeToRecordConfig. - r.RecordValue = strings.TrimSuffix(rc.GetTargetField(), ".") - case "TXT": - r.RecordValue = rc.GetTargetTXTJoined() - case "CAA", "SRV", "NAPTR": - // These are stored as full RFC1035 presentation strings in record_value. - r.RecordValue = rc.GetTargetCombined() + switch rc.TypeNum { + case dnsv2.TypeMX: + f := rc.AsMX() + r.RecordPrio = new(f.Preference) + r.RecordValue = strings.TrimSuffix(f.Mx, ".") + case dnsv2.TypeTXT: + txt := rc.GetTargetTXTJoined() + if len(txt) > 255 { + r.RecordValue = rc.AsTXT().String() + } else { + r.RecordValue = txt + } + default: - r.RecordValue = rc.GetTargetField() + r.RecordValue = rc.GetRDATA().String() } return r } +// deleteValue returns the value the DELETE endpoint matches against. For most +// types this is record_value exactly as the API returns it, but for MX the +// endpoint matches the internal RDATA presentation (" "), +// NOT the priority-less record_value it returns; sending record_value yields +// 404 "Record not found". Verified against the live API 2026-07-27. +func deleteValue(r *record) string { + if r.RecordType == "MX" { + return fmt.Sprintf("%d %s", r.RecordPrio.Value, addDot(r.RecordValue)) + } + return r.RecordValue +} + // addDot appends a trailing dot to a hostname if it lacks one. func addDot(s string) string { if s == "" || strings.HasSuffix(s, ".") { diff --git a/providers/gigahost/gigahostProvider_test.go b/providers/gigahost/gigahostProvider_test.go new file mode 100644 index 0000000000..6f4896d64e --- /dev/null +++ b/providers/gigahost/gigahostProvider_test.go @@ -0,0 +1,36 @@ +package gigahost + +import ( + "testing" + + "github.com/DNSControl/dnscontrol/v5/models" +) + +func TestNativeToRecordConfig(t *testing.T) { + dc, err := models.NewDomainConfig("example.com") + if err != nil { + t.Fatal(err) + } + tests := []struct { + name string + record record + wantTarget string + }{ + {"A", record{RecordName: "www", RecordType: "A", RecordValue: "192.0.2.1", RecordTTL: flexUint{Value: 300}}, "192.0.2.1"}, + {"MX", record{RecordName: "@", RecordType: "MX", RecordValue: "mail.example.net", RecordTTL: flexUint{Value: 300}, RecordPrio: flexUint{Value: 10}}, "10 mail.example.net."}, + {"TXT", record{RecordName: "@", RecordType: "TXT", RecordValue: "raw text", RecordTTL: flexUint{Value: 300}}, `"raw text"`}, + {"SRV", record{RecordName: "_sip._tcp", RecordType: "SRV", RecordValue: "1 2 5060 sip.example.net.", RecordTTL: flexUint{Value: 300}}, "1 2 5060 sip.example.net."}, + } + for _, tc := range tests { + t.Run(tc.name, func(t *testing.T) { + record := tc.record + rc, err := nativeToRecordConfig(dc, &record) + if err != nil { + t.Fatal(err) + } + if got := rc.GetRDATA().String(); got != tc.wantTarget { + t.Errorf("target = %q, want %q", got, tc.wantTarget) + } + }) + } +} diff --git a/providers/hedns/auditrecords.go b/providers/hedns/auditrecords.go index 211f27d55b..451e6795c3 100644 --- a/providers/hedns/auditrecords.go +++ b/providers/hedns/auditrecords.go @@ -3,8 +3,8 @@ package hedns import ( "fmt" - "github.com/DNSControl/dnscontrol/v4/models" - "github.com/DNSControl/dnscontrol/v4/pkg/rejectif" + "github.com/DNSControl/dnscontrol/v5/models" + "github.com/DNSControl/dnscontrol/v5/pkg/rejectif" ) // dynamicAllowedTypes lists the record types that support Dynamic DNS on HE DNS. @@ -17,7 +17,7 @@ var dynamicAllowedTypes = map[string]bool{ // 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 { +func AuditRecords(records models.Records) []error { a := rejectif.Auditor{} a.Add("MX", rejectif.MxNull) // Last verified 2020-12-28 diff --git a/providers/hedns/auditrecords_test.go b/providers/hedns/auditrecords_test.go index 76b3713d6d..0714645445 100644 --- a/providers/hedns/auditrecords_test.go +++ b/providers/hedns/auditrecords_test.go @@ -3,23 +3,18 @@ package hedns import ( "testing" - "github.com/DNSControl/dnscontrol/v4/models" + dnsv2 "codeberg.org/miekg/dns" + "github.com/DNSControl/dnscontrol/v5/models" ) func makeRC(rtype, label, target string) *models.RecordConfig { - rc := &models.RecordConfig{ - Type: rtype, - } - rc.SetLabel(label, "example.com") + dc := models.MustNewDomainConfig("example.com") switch rtype { - case "TXT": - rc.SetTargetTXT(target) case "MX": - rc.SetTargetMX(10, target) + return dc.MustNewRecordConfig(label, 0, dnsv2.TypeMX, uint16(10), target) default: - rc.SetTarget(target) + return dc.MustNewRecordConfig(label, 0, rtype, target) } - return rc } func withMeta(rc *models.RecordConfig, key, value string) *models.RecordConfig { @@ -33,82 +28,82 @@ func withMeta(rc *models.RecordConfig, key, value string) *models.RecordConfig { func TestAuditRecords(t *testing.T) { tests := []struct { name string - records []*models.RecordConfig + records models.Records wantCount int }{ { name: "empty records", - records: []*models.RecordConfig{}, + records: models.Records{}, wantCount: 0, }, // Allowed: A, AAAA, TXT with hedns_dynamic { name: "A with dynamic on", - records: []*models.RecordConfig{withMeta(makeRC("A", "dyn", "1.2.3.4"), metaDynamic, "on")}, + records: models.Records{withMeta(makeRC("A", "dyn", "1.2.3.4"), metaDynamic, "on")}, wantCount: 0, }, { name: "AAAA with dynamic on", - records: []*models.RecordConfig{withMeta(makeRC("AAAA", "dyn6", "::1"), metaDynamic, "on")}, + records: models.Records{withMeta(makeRC("AAAA", "dyn6", "::1"), metaDynamic, "on")}, wantCount: 0, }, { name: "TXT with dynamic on", - records: []*models.RecordConfig{withMeta(makeRC("TXT", "dyntxt", "val"), metaDynamic, "on")}, + records: models.Records{withMeta(makeRC("TXT", "dyntxt", "val"), metaDynamic, "on")}, wantCount: 0, }, { name: "A with dynamic off is allowed", - records: []*models.RecordConfig{withMeta(makeRC("A", "s", "1.2.3.4"), metaDynamic, "off")}, + records: models.Records{withMeta(makeRC("A", "s", "1.2.3.4"), metaDynamic, "off")}, wantCount: 0, }, // Allowed: A, AAAA with hedns_ddns_key { name: "A with ddns key", - records: []*models.RecordConfig{withMeta(makeRC("A", "k", "1.2.3.4"), metaDDNSKey, "tok")}, + records: models.Records{withMeta(makeRC("A", "k", "1.2.3.4"), metaDDNSKey, "tok")}, wantCount: 0, }, { name: "AAAA with ddns key", - records: []*models.RecordConfig{withMeta(makeRC("AAAA", "k6", "::1"), metaDDNSKey, "tok")}, + records: models.Records{withMeta(makeRC("AAAA", "k6", "::1"), metaDDNSKey, "tok")}, wantCount: 0, }, // Rejected: unsupported types with hedns_dynamic { name: "CNAME with dynamic on rejected", - records: []*models.RecordConfig{withMeta(makeRC("CNAME", "c", "example.com."), metaDynamic, "on")}, + records: models.Records{withMeta(makeRC("CNAME", "c", "example.com."), metaDynamic, "on")}, wantCount: 1, }, { name: "MX with dynamic on rejected", - records: []*models.RecordConfig{withMeta(makeRC("MX", "m", "mail.example.com."), metaDynamic, "on")}, + records: models.Records{withMeta(makeRC("MX", "m", "mail.example.com."), metaDynamic, "on")}, wantCount: 1, }, { name: "SRV with dynamic on rejected", - records: []*models.RecordConfig{withMeta(makeRC("CNAME", "srv", "example.com."), metaDynamic, "on")}, + records: models.Records{withMeta(makeRC("CNAME", "srv", "example.com."), metaDynamic, "on")}, wantCount: 1, }, // Rejected: unsupported types with hedns_ddns_key { name: "CNAME with ddns key rejected", - records: []*models.RecordConfig{withMeta(makeRC("CNAME", "c", "example.com."), metaDDNSKey, "tok")}, + records: models.Records{withMeta(makeRC("CNAME", "c", "example.com."), metaDDNSKey, "tok")}, wantCount: 1, }, // Non-dynamic metadata on unsupported types is fine { name: "CNAME with dynamic off is allowed", - records: []*models.RecordConfig{withMeta(makeRC("CNAME", "c", "example.com."), metaDynamic, "off")}, + records: models.Records{withMeta(makeRC("CNAME", "c", "example.com."), metaDynamic, "off")}, wantCount: 0, }, { name: "CNAME without metadata is allowed", - records: []*models.RecordConfig{makeRC("CNAME", "c", "example.com.")}, + records: models.Records{makeRC("CNAME", "c", "example.com.")}, wantCount: 0, }, } diff --git a/providers/hedns/convert_golden_test.go b/providers/hedns/convert_golden_test.go new file mode 100644 index 0000000000..98cefdf8e2 --- /dev/null +++ b/providers/hedns/convert_golden_test.go @@ -0,0 +1,16 @@ +package hedns + +import ( + "testing" + + "github.com/DNSControl/dnscontrol/v5/models" + "github.com/DNSControl/dnscontrol/v5/pkg/providergolden" +) + +func TestRecordToRCGolden(t *testing.T) { + providergolden.CheckToRC(t, "recordToRC", + func(dc *models.DomainConfig, native Record) (models.Records, error) { + rc, err := recordToRC(dc, native) + return models.Records{rc}, err + }) +} diff --git a/providers/hedns/convert_test.go b/providers/hedns/convert_test.go new file mode 100644 index 0000000000..37a80a253b --- /dev/null +++ b/providers/hedns/convert_test.go @@ -0,0 +1,37 @@ +package hedns + +import ( + "testing" + + dnsv2 "codeberg.org/miekg/dns" + "github.com/DNSControl/dnscontrol/v5/models" +) + +func TestRecordToRCUsesV3RecordConfig(t *testing.T) { + dc := models.MustNewDomainConfig("example.com") + tests := []struct { + name string + in Record + want *models.RecordConfig + }{ + {"A", Record{Name: "www.example.com", Type: "A", Data: "192.0.2.1", TTL: 300}, dc.MustNewRecordConfig("www", 300, dnsv2.TypeA, "192.0.2.1")}, + {"MX", Record{Name: "www.example.com", Type: "MX", Data: "mail.example.net", TTL: 300, Priority: 10}, dc.MustNewRecordConfig("www", 300, dnsv2.TypeMX, uint16(10), "mail.example.net.")}, + {"SRV", Record{Name: "www.example.com", Type: "SRV", Data: "2 443 service.example.net.", TTL: 300, Priority: 1}, dc.MustNewRecordConfig("www", 300, dnsv2.TypeSRV, uint16(1), uint16(2), uint16(443), "service.example.net.")}, + {"SPF becomes TXT", Record{Name: "www.example.com", Type: "SPF", Data: `"v=spf1 -all"`, TTL: 300}, dc.MustNewRecordConfig("www", 300, dnsv2.TypeTXT, "v=spf1 -all")}, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + got, err := recordToRC(dc, tt.in) + if err != nil { + t.Fatal(err) + } + if got.NameFQDN != tt.want.NameFQDN || got.TTL != tt.want.TTL || got.TypeNum != tt.want.TypeNum || got.GetRDATA().String() != tt.want.GetRDATA().String() { + t.Errorf("recordToRC() = %s %d IN %s %s, want %s %d IN %s %s", got.NameFQDN, got.TTL, got.Type, got.GetRDATA(), tt.want.NameFQDN, tt.want.TTL, tt.want.Type, tt.want.GetRDATA()) + } + if got.Original != tt.in { + t.Error("recordToRC() did not preserve the original HE.net record") + } + }) + } +} diff --git a/providers/hedns/hednsProvider.go b/providers/hedns/hednsProvider.go index f8d3a34e7c..9099972b02 100644 --- a/providers/hedns/hednsProvider.go +++ b/providers/hedns/hednsProvider.go @@ -16,14 +16,13 @@ import ( "strings" "time" - "github.com/DNSControl/dnscontrol/v4/models" - "github.com/DNSControl/dnscontrol/v4/pkg/diff2" - "github.com/DNSControl/dnscontrol/v4/pkg/domaintags" - "github.com/DNSControl/dnscontrol/v4/pkg/providers" - "github.com/DNSControl/dnscontrol/v4/pkg/rtypecontrol" - "github.com/DNSControl/dnscontrol/v4/pkg/rtypeinfo" - "github.com/DNSControl/dnscontrol/v4/pkg/txtutil" - "github.com/DNSControl/dnscontrol/v4/pkg/zonecache" + dnsv2 "codeberg.org/miekg/dns" + dnsrdatav2 "codeberg.org/miekg/dns/rdata" + "github.com/DNSControl/dnscontrol/v5/models" + "github.com/DNSControl/dnscontrol/v5/pkg/diff2" + "github.com/DNSControl/dnscontrol/v5/pkg/nrc" + "github.com/DNSControl/dnscontrol/v5/pkg/providers" + "github.com/DNSControl/dnscontrol/v5/pkg/zonecache" "github.com/PuerkitoBio/goquery" "github.com/pquerna/otp/totp" ) @@ -148,6 +147,7 @@ const ( // hednsProvider stores login credentials and represents and API connection. type hednsProvider struct { + observer providers.ConversionObserver Username string Password string TfaSecret string @@ -158,6 +158,10 @@ type hednsProvider struct { zoneCache zonecache.ZoneCache[uint64] } +func (c *hednsProvider) SetConversionObserver(observer providers.ConversionObserver) { + c.observer = observer +} + // Record stores the HEDNS specific zone and record IDs. type Record struct { ZoneID uint64 @@ -220,6 +224,7 @@ func (c *hednsProvider) ListZones() ([]string, error) { // EnsureZoneExists creates a zone if it does not exist. func (c *hednsProvider) EnsureZoneExists(dc *models.DomainConfig) error { domain := dc.Name + ok, err := c.zoneCache.HasZone(domain) if err != nil { return err @@ -418,7 +423,7 @@ func (c *hednsProvider) setDDNSKeyForNewRecord(zoneID uint64, _ string, record * func (c *hednsProvider) GetZoneRecords(dc *models.DomainConfig) (models.Records, error) { domain := dc.Name - var zoneRecords []*models.RecordConfig + var zoneRecords models.Records // Get Domain ID domainID, err := c.zoneCache.GetZone(domain) @@ -487,37 +492,13 @@ func (c *hednsProvider) GetZoneRecords(dc *models.DomainConfig) (models.Records, return true } - var rc *models.RecordConfig - if rtypeinfo.IsModernType(rec.Type) { - // FQDNs for NewRecordConfigFromString require trailing "." - rc, err = rtypecontrol.NewRecordConfigFromString( - rec.Name+".", rec.TTL, rec.Type, rec.Data, - domaintags.MakeDomainNameVarieties(domain), - ) - } else { - rc = &models.RecordConfig{Type: rec.Type, TTL: rec.TTL} - rc.SetLabelFromFQDN(rec.Name, domain) - switch rec.Type { - case "ALIAS": - err = rc.SetTarget(rec.Data) - case "MX": - // HEDNS omits the trailing "." on the hostnames for MX records - err = rc.SetTargetMX(rec.Priority, rec.Data+".") - case "SRV": - err = rc.SetTargetSRVPriorityString(rec.Priority, rec.Data) - case "SPF": - // Convert to TXT record as SPF is deprecated - rc.ChangeType("TXT", domain) - fallthrough - default: - err = rc.PopulateFromStringFunc(rec.Type, rec.Data, domain, txtutil.ParseQuoted) - } - } + before := providers.BeginToRC(c.observer, "recordToRC", rec) + rc, conversionErr := recordToRC(dc, rec) + providers.EndToRC(c.observer, "recordToRC", before, rec, models.Records{rc}, conversionErr) + err = conversionErr if err != nil { return false } - - rc.Original = rec rc.Metadata = map[string]string{ metaDynamic: "off", } @@ -533,6 +514,34 @@ func (c *hednsProvider) GetZoneRecords(dc *models.DomainConfig) (models.Records, return zoneRecords, err } +func recordToRC(dc *models.DomainConfig, rec Record) (*models.RecordConfig, error) { + label := dc.LabelFromFQDNNoDot(rec.Name) + ttl := rec.TTL + rtype := rec.Type + if rtype == "SPF" { + rtype = "TXT" + } + + var rc *models.RecordConfig + var err error + switch rtype { + case "MX": + rc, err = dc.NewRecordConfig(label, ttl, dnsv2.TypeMX, rec.Priority, rec.Data, + nrc.Flags{TargetIsFqdnNoDot: true}) + case "SRV": + rc, err = dc.NewRecordConfig(label, ttl, dnsv2.TypeSRV, rec.Priority, rec.Data, + nrc.Flags{SrvWeirdSplit: true, TargetIsFqdnNoDot: true}) + default: + rc, err = dc.NewRecordConfigParse(label, ttl, rtype, rec.Data, + nrc.Flags{TargetIsFqdnNoDot: true}) + } + if err != nil { + return nil, err + } + rc.Original = rec + return rc, nil +} + func (c *hednsProvider) authUsernameAndPassword() (document *goquery.Document, requiresTfa bool, err error) { // Login with username and password response, err := c.httpClient.PostForm(apiEndpoint, url.Values{ @@ -751,18 +760,18 @@ func (c *hednsProvider) editZoneRecord(zoneID uint64, recordID uint64, rc *model } // Work out the content - switch rc.Type { - case "MX": - values.Set("Priority", strconv.FormatUint(uint64(rc.MxPreference), 10)) - values.Set("Content", rc.GetTargetField()) - case "SRV": + switch f := rc.GetRDATA().(type) { + case dnsrdatav2.MX: + values.Set("Priority", strconv.FormatUint(uint64(f.Preference), 10)) + values.Set("Content", f.Mx) + case dnsrdatav2.SRV: values.Del("Content") - values.Set("Target", rc.GetTargetField()) - values.Set("Priority", strconv.FormatUint(uint64(rc.SrvPriority), 10)) - values.Set("Weight", strconv.FormatUint(uint64(rc.SrvWeight), 10)) - values.Set("Port", strconv.FormatUint(uint64(rc.SrvPort), 10)) + values.Set("Target", f.Target) + values.Set("Priority", strconv.FormatUint(uint64(f.Priority), 10)) + values.Set("Weight", strconv.FormatUint(uint64(f.Weight), 10)) + values.Set("Port", strconv.FormatUint(uint64(f.Port), 10)) default: - values.Set("Content", rc.GetTargetCombinedFunc(txtutil.EncodeQuoted)) + values.Set("Content", rc.GetRDATA().String()) } response, err := c.httpClient.PostForm(apiEndpoint, values) diff --git a/providers/hedns/test_data/expected_torc_output_recordToRC_dnscontrol.net.records b/providers/hedns/test_data/expected_torc_output_recordToRC_dnscontrol.net.records new file mode 100644 index 0000000000..3f4ba8b5b5 --- /dev/null +++ b/providers/hedns/test_data/expected_torc_output_recordToRC_dnscontrol.net.records @@ -0,0 +1,238 @@ +1 @ 172800 IN SOA ns1.he.net. hostmaster.he.net. 2026080899 86400 7200 3600000 172800 +2 @ 300 IN NS ns1.he.net. +3 @ 300 IN NS ns2.he.net. +4 @ 300 IN NS ns3.he.net. +5 @ 300 IN NS ns4.he.net. +6 @ 300 IN NS ns5.he.net. +7 testa 300 IN A 1.1.1.1 +8 testa 300 IN A 3.3.3.3 +9 @ 300 IN A 2.2.2.2 +10 @ 300 IN A 4.4.4.4 +11 testaaaa 300 IN AAAA 2607:f8b0:4006:820::2006 +12 testaaaa 300 IN AAAA 2607:f8b0:4006:820::2013 +13 testcname 300 IN CNAME www.google.com. +14 testcname 300 IN CNAME www.yahoo.com. +15 foo 300 IN A 1.2.3.4 +16 testcname 300 IN CNAME foo.dnscontrol.net. +17 @ 300 IN MX 5 bar.com. +18 @ 300 IN MX 5 foo.com. +19 testmx 300 IN MX 5 bar.com. +20 testmx 300 IN MX 5 foo.com. +21 testmx 300 IN MX 100 foo.com. +22 testmx 300 IN MX 5 foo.com. +23 foo 300 IN RP other.example.com. bar.com. +24 foo 300 IN RP other.example.com. example.com. +25 foo 300 IN RP user.example.com. bar.com. +26 foo 300 IN RP user.dnscontrol.net. server.dnscontrol.net. +27 foo 300 IN RP user2.dnscontrol.net. server.dnscontrol.net. +28 foo 300 IN RP user2.dnscontrol.net. waiter.dnscontrol.net. +29 testtxt 300 IN TXT "changed" +30 testtxt 300 IN TXT "simple" +31 www 300 IN A 1.1.1.1 +32 www 300 IN A 2.2.2.2 +33 www 300 IN A 3.3.3.3 +34 www 300 IN A 1.1.1.1 +35 www 300 IN A 2.2.2.2 +36 www 300 IN A 3.3.3.3 +37 testmx 300 IN MX 100 bar.com. +38 testmx 300 IN MX 5 foo.com. +39 www 300 IN A 1.1.1.1 +40 www 300 IN A 1.1.1.1 +41 testmx 300 IN MX 5 foo.com. +42 testmx 300 IN MX 100 bar.com. +43 testa 333 IN A 1.1.1.1 +44 testa 999 IN A 1.1.1.1 +45 @ 1000 IN A 8.8.8.8 +46 @ 500 IN A 8.8.8.8 +47 @ 666 IN A 8.8.8.8 +48 www 300 IN A 1.2.3.4 +49 www 300 IN A 2.2.2.2 +50 www 400 IN A 2.2.2.2 +51 www 300 IN A 5.6.7.8 +52 www 400 IN A 5.6.7.8 +53 www 400 IN A 5.6.7.8 +54 www 700 IN A 5.6.7.8 +55 www 700 IN A 1.2.3.4 +56 foo 300 IN A 1.2.3.4 +57 foo 300 IN MX 5 mx.google.com. +58 foo 300 IN A 4.5.6.7 +59 foo 300 IN CNAME google.com. +60 foo 300 IN A 1.2.3.4 +61 foo 300 IN CNAME google2.com. +62 @ 300 IN HTTPS 0 test.com. +63 @ 300 IN HTTPS 1 test.com. alpn="h2" port="99" +64 @ 300 IN HTTPS 1 test.com. port="80" +65 @ 300 IN HTTPS 1 test.com. port="99" +66 @ 300 IN HTTPS 3 example.com. alpn="h2,h3" port="999" +67 @ 300 IN SVCB 0 test.com. +68 @ 300 IN SVCB 1 test.com. alpn="h2" port="99" +69 @ 300 IN SVCB 1 test.com. port="80" +70 @ 300 IN SVCB 1 test.com. port="99" +71 @ 300 IN SVCB 3 example.com. alpn="h2,h3" port="999" +72 @ 300 IN A 1.2.3.4 +73 foo 300 IN CNAME dnscontrol.net. +74 @ 300 IN A 1.2.3.4 +75 foo 300 IN MX 8 dnscontrol.net. +76 nmx 300 IN A 1.2.3.3 +77 www 300 IN A 1.2.3.9 +78 nmx 300 IN MX 9 www.dnscontrol.net. +79 nmx 300 IN MX 3 nmx.dnscontrol.net. +80 @ 300 IN A 1.2.3.2 +81 www 300 IN A 1.2.3.8 +82 @ 300 IN MX 8 www.dnscontrol.net. +83 @ 300 IN MX 2 dnscontrol.net. +84 xyz 300 IN NS ns2.foo.com. +85 xyz 300 IN NS ns1.foo.com. +86 @ 300 IN A 1.2.3.4 +87 foo 300 IN NS dnscontrol.net. +88 @ 300 IN NS ns1.foo.com. +89 @ 300 IN NS ns2.foo.com. +90 foo0 300 IN TXT "" +91 foo254 300 IN TXT "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" +92 foo255 300 IN TXT "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" +93 foo256 300 IN TXT "CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC" "C" +94 foo509 300 IN TXT "DDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDD" "DDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDD" +95 foo510 300 IN TXT "EEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE" "EEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE" +96 foo511 300 IN TXT "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF" "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF" "F" +97 foo764 300 IN TXT "GGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGG" "GGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGG" "GGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGG" +98 foo765 300 IN TXT "HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH" "HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH" "HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH" +99 foo766 300 IN TXT "JJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJ" "JJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJ" "JJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJ" "J" +100 foosq 300 IN TXT "quo'te" +101 foobt 300 IN TXT "blah`blah" +102 foodq 300 IN TXT "in\"side" +103 foodqs 300 IN TXT "\"left" +104 foodqs 300 IN TXT "in\"ter\"ior" +105 foodqs 300 IN TXT "right\"" +106 foosc1 300 IN TXT "semi;colon" +107 foosc2 300 IN TXT "wssemi ; colon" +108 foosp 300 IN TXT "with spaces" +109 foows1 300 IN TXT "trailingws " +110 foo 300 IN TXT "v=spf1 ip4:99.99.99.99 -all" +111 fooosbs1 300 IN TXT "1back\\slash" +112 fooosbs2 300 IN TXT "2back\\\\slash" +113 fooosbs3 300 IN TXT "3back\\\\\\slash" +114 fooosbs4 300 IN TXT "4back\\\\\\\\slash" +115 bar 300 IN MX 5 bar.com. +116 decoy 300 IN A 1.1.1.1 +117 decoy 300 IN A 2.2.2.2 +118 decoy 300 IN A 3.3.3.3 +119 foo 300 IN A 1.2.3.4 +120 foo 300 IN A 2.3.4.5 +121 foo 300 IN A 3.4.5.6 +122 foo 300 IN A 3.4.5.6 +123 bar 300 IN A 1.2.3.4 +124 foo 300 IN A 2.3.4.5 +125 foo 300 IN A 3.4.5.6 +126 foo 300 IN A 8.8.8.8 +127 foo 300 IN MX 20 bar.dnscontrol.net. +128 foo 300 IN MX 10 foo.dnscontrol.net. +129 foo 300 IN A 8.8.8.8 +130 xn--ndaaa 300 IN A 1.2.3.4 +131 xn--ndaaa 300 IN A 2.2.2.2 +132 xn--fiq228c 300 IN A 1.2.3.4 +133 a 300 IN CNAME xn--ndaaa.com. +134 xn--o-0gab 300 IN CNAME xn--ndaaa.xn--vhquv. +135 @ 300 IN CAA 0 issue "letsencrypt.org; validationmethods=dns-01; accounturi=https://acme-v02.api.letsencrypt.org/acme/acct/1234" +136 @ 300 IN CAA 0 issue "letsencrypt.org" +137 @ 300 IN CAA 0 issuewild ";" +138 @ 300 IN CAA 0 issuewild "example.com" +139 @ 300 IN CAA 0 issuewild "letsencrypt.org" +140 @ 300 IN CAA 0 issue "letsencrypt.org" +141 @ 300 IN CAA 128 issue "letsencrypt.org" +142 @ 300 IN LOC 42 21 54.000 N 71 06 18.000 W -24.05m 30m 0.00m 0.00m +143 @ 300 IN LOC 42 21 54.000 N 71 06 18.000 W -24.06m 30m 10m 0.00m +144 @ 300 IN LOC 42 21 54.000 N 71 06 18.000 W -24m 30m 0.00m 0.00m +145 a 300 IN LOC 42 21 43.950 N 71 05 6.340 W -24.33m 1m 200m 10m +146 b 300 IN LOC 52 14 5.000 N 00 08 50.000 E 10.22m 0.00m 0.00m 0.00m +147 c 300 IN LOC 32 07 19.000 S 116 02 25.000 E 10m 0.00m 0.00m 0.00m +148 d 300 IN LOC 42 21 28.760 N 71 00 51.620 W -44m 2000m 0.00m 0.00m +149 test 300 IN NAPTR 100 10 "U" "E2U+sip" "!^.*$!sip:customer-service@example.com!" . +150 test 300 IN NAPTR 103 10 "U" "E2U+email" "!^.*$!mailto:information@example.com!" . +151 test 300 IN NAPTR 103 20 "A" "E2U+email" "!^.*$!mailto:information@example.com!" . +152 test 300 IN NAPTR 103 20 "A" "E2U+sip" "!^.*$!mailto:information@example.com!" . +153 test 300 IN NAPTR 103 20 "A" "E2U+sip" "!^.*$!sip:customer-service@example.com!" . +154 test 300 IN NAPTR 103 20 "A" "E2U+sip" "" example.foo.com. +155 test 300 IN NAPTR 103 20 "A" "E2U+sip" "" example2.foo.com. +156 test 300 IN NAPTR 103 20 "U" "E2U+email" "!^.*$!mailto:information@example.com!" . +157 test 300 IN NAPTR 102 10 "U" "E2U+email" "!^.*$!mailto:information@example.com!" . +158 4 300 IN PTR bar.com. +159 4 300 IN PTR foo.com. +160 _sip._tcp 300 IN SRV 5 6 7 foo.com. +161 _sip._tcp 300 IN SRV 52 6 7 foo.com. +162 _sip._tcp 300 IN SRV 52 62 7 foo.com. +163 _sip._tcp 300 IN SRV 52 62 72 foo.com. +164 _sip._tcp 300 IN SRV 5 60 70 foo2.com. +165 _sip._tcp 300 IN SRV 15 65 75 foo3.com. +166 _sip._tcp 300 IN SRV 15 65 75 foo4.com. +167 _sip._tcp 300 IN SRV 15 65 75 . +168 _sip._tcp 333 IN SRV 5 6 7 foo.com. +169 _sip._tcp 4400 IN SRV 5 6 7 foo.com. +170 @ 300 IN SSHFP 1 1 66C7D5540B7D75A1FB4C84FEBFA178AD99BDD67C +171 @ 300 IN SSHFP 2 1 66C7D5540B7D75A1FB4C84FEBFA178AD99BDD67C +172 @ 300 IN SSHFP 2 2 745A635BC46A397A5C4F21D437483005BCC40D7511FF15FBFAFE913A081559BC +173 @ 300 IN ALIAS foo.com. +174 @ 300 IN ALIAS foo2.com. +175 foo 300 IN A 1.2.3.4 +176 @ 300 IN ALIAS foo.dnscontrol.net. +177 test 300 IN ALIAS foo.com. +178 test 300 IN ALIAS foo2.com. +179 bar 300 IN A 5.5.5.5 +180 foo 300 IN A 1.2.3.4 +181 foo 300 IN A 2.3.4.5 +182 foo 300 IN TXT "simple" +183 mail 300 IN CNAME ghs.googlehosted.com. +184 @ 300 IN A 1.2.3.4 +185 @ 300 IN A 2.3.4.5 +186 @ 300 IN TXT "simple" +187 bar 300 IN A 5.5.5.5 +188 mail 300 IN CNAME ghs.googlehosted.com. +189 @ 300 IN A 2.2.2.2 +190 @ 300 IN TXT "asimple" +191 foo 300 IN A 1.2.3.4 +192 foo 300 IN TXT "simple" +193 bar.bat 300 IN A 5.5.5.5 +194 foo.bat 300 IN A 1.2.3.4 +195 foo.bat 300 IN A 2.3.4.5 +196 foo.bat 300 IN TXT "simple" +197 mail.bat 300 IN CNAME ghs.googlehosted.com. +198 foo 300 IN A 1.1.1.1 +199 foo 300 IN A 10.10.10.10 +200 foo 300 IN A 11.11.11.11 +201 foo 300 IN A 12.12.12.12 +202 foo 300 IN A 13.13.13.13 +203 foo 300 IN A 14.14.14.14 +204 foo 300 IN AAAA 2003:dd:d7ff::fe71:aaaa +205 foo 300 IN MX 10 aspmx.l.google.com. +206 foo 300 IN MX 20 alt1.aspmx.l.google.com. +207 zzz 300 IN A 3.3.3.3 +208 zzz 300 IN A 4.4.4.4 +209 zzz 300 IN AAAA 2003:dd:d7ff::fe71:cccc +210 bar 300 IN CNAME redact2.acm-validations.aws. +211 foo 300 IN CNAME redact1.acm-validations.aws. +212 dyndns-city1 300 IN A 91.42.1.1 +213 dyndns-city1 300 IN AAAA 2003:dd:d7ff::fe71:ce77 +214 dyndns-city2 300 IN A 91.42.1.2 +215 dyndns-city2 300 IN AAAA 2003:dd:d7ff::fe71:ce78 +216 testdefined 300 IN A 2.2.2.2 +217 testdefined 300 IN A 9.9.9.9 +218 testignore 300 IN A 8.8.8.8 +219 hdyn 300 IN A 1.2.3.4 +220 hdyn 300 IN A 10.0.0.1 +221 hdyn 300 IN A 5.6.7.8 +222 hdyn 300 IN A 5.6.7.8 +223 hstatic 300 IN A 2.2.2.2 +224 hdynv6 300 IN AAAA 2607:f8b0:4006:820::2006 +225 hdynv6 300 IN AAAA 2607:f8b0:4006:820::2013 +226 hdyntxt 300 IN TXT "dynamic-value" +227 hdyntxt 300 IN TXT "dynamic-value" +228 hkey 300 IN A 1.2.3.4 +229 hkey 300 IN A 5.6.7.8 +230 hkeyv6 300 IN AAAA 2607:f8b0:4006:820::2006 +231 hkeyv6 300 IN AAAA 2607:f8b0:4006:820::2013 +232 hdmix-dyn 300 IN A 1.1.1.1 +233 hdmix-static 300 IN A 2.2.2.2 +234 hdmix-static 300 IN A 3.3.3.3 +235 final 300 IN TXT "TestDNSProviders was successful!" +236 final 300 IN TXT "TestDNSProviders was successful!" +237 @ 300 IN NS ns1.example.com. +238 @ 300 IN NS ns2.example.com. diff --git a/providers/hedns/test_data/meta.json b/providers/hedns/test_data/meta.json new file mode 100644 index 0000000000..dda3bfa26f --- /dev/null +++ b/providers/hedns/test_data/meta.json @@ -0,0 +1,11 @@ +{ + "version": 1, + "recordings": [ + { + "domain": "dnscontrol.net", + "to_rc": [ + "recordToRC" + ] + } + ] +} diff --git a/providers/hedns/test_data/recorded_torc_input_recordToRC_dnscontrol.net.json b/providers/hedns/test_data/recorded_torc_input_recordToRC_dnscontrol.net.json new file mode 100644 index 0000000000..5bc4ac1e1d --- /dev/null +++ b/providers/hedns/test_data/recorded_torc_input_recordToRC_dnscontrol.net.json @@ -0,0 +1,3334 @@ +[ + { + "index": 1, + "value": { + "ZoneID": 1075212, + "ZoneName": "dnscontrol.net", + "ID": 4858238117, + "Type": "SOA", + "Name": "", + "Data": "ns1.he.net. hostmaster.he.net. 2026080899 86400 7200 3600000 172800", + "TTL": 172800, + "Priority": 0, + "DDNSEnabled": false + } + }, + { + "index": 2, + "value": { + "ZoneID": 1075212, + "ZoneName": "dnscontrol.net", + "ID": 9292749725, + "Type": "NS", + "Name": "dnscontrol.net", + "Data": "ns1.he.net.", + "TTL": 300, + "Priority": 0, + "DDNSEnabled": false + } + }, + { + "index": 3, + "value": { + "ZoneID": 1075212, + "ZoneName": "dnscontrol.net", + "ID": 9292749726, + "Type": "NS", + "Name": "dnscontrol.net", + "Data": "ns2.he.net.", + "TTL": 300, + "Priority": 0, + "DDNSEnabled": false + } + }, + { + "index": 4, + "value": { + "ZoneID": 1075212, + "ZoneName": "dnscontrol.net", + "ID": 9292749727, + "Type": "NS", + "Name": "dnscontrol.net", + "Data": "ns3.he.net.", + "TTL": 300, + "Priority": 0, + "DDNSEnabled": false + } + }, + { + "index": 5, + "value": { + "ZoneID": 1075212, + "ZoneName": "dnscontrol.net", + "ID": 9292749728, + "Type": "NS", + "Name": "dnscontrol.net", + "Data": "ns4.he.net.", + "TTL": 300, + "Priority": 0, + "DDNSEnabled": false + } + }, + { + "index": 6, + "value": { + "ZoneID": 1075212, + "ZoneName": "dnscontrol.net", + "ID": 9292749729, + "Type": "NS", + "Name": "dnscontrol.net", + "Data": "ns5.he.net.", + "TTL": 300, + "Priority": 0, + "DDNSEnabled": false + } + }, + { + "index": 7, + "value": { + "ZoneID": 1075212, + "ZoneName": "dnscontrol.net", + "ID": 9445082158, + "Type": "A", + "Name": "testa.dnscontrol.net", + "Data": "1.1.1.1", + "TTL": 300, + "Priority": 0, + "DDNSEnabled": false + } + }, + { + "index": 8, + "value": { + "ZoneID": 1075212, + "ZoneName": "dnscontrol.net", + "ID": 9445082158, + "Type": "A", + "Name": "testa.dnscontrol.net", + "Data": "3.3.3.3", + "TTL": 300, + "Priority": 0, + "DDNSEnabled": false + } + }, + { + "index": 9, + "value": { + "ZoneID": 1075212, + "ZoneName": "dnscontrol.net", + "ID": 9445082159, + "Type": "A", + "Name": "dnscontrol.net", + "Data": "2.2.2.2", + "TTL": 300, + "Priority": 0, + "DDNSEnabled": false + } + }, + { + "index": 10, + "value": { + "ZoneID": 1075212, + "ZoneName": "dnscontrol.net", + "ID": 9445082159, + "Type": "A", + "Name": "dnscontrol.net", + "Data": "4.4.4.4", + "TTL": 300, + "Priority": 0, + "DDNSEnabled": false + } + }, + { + "index": 11, + "value": { + "ZoneID": 1075212, + "ZoneName": "dnscontrol.net", + "ID": 9445082160, + "Type": "AAAA", + "Name": "testaaaa.dnscontrol.net", + "Data": "2607:f8b0:4006:820::2006", + "TTL": 300, + "Priority": 0, + "DDNSEnabled": false + } + }, + { + "index": 12, + "value": { + "ZoneID": 1075212, + "ZoneName": "dnscontrol.net", + "ID": 9445082160, + "Type": "AAAA", + "Name": "testaaaa.dnscontrol.net", + "Data": "2607:f8b0:4006:820::2013", + "TTL": 300, + "Priority": 0, + "DDNSEnabled": false + } + }, + { + "index": 13, + "value": { + "ZoneID": 1075212, + "ZoneName": "dnscontrol.net", + "ID": 9445082161, + "Type": "CNAME", + "Name": "testcname.dnscontrol.net", + "Data": "www.google.com.", + "TTL": 300, + "Priority": 0, + "DDNSEnabled": false + } + }, + { + "index": 14, + "value": { + "ZoneID": 1075212, + "ZoneName": "dnscontrol.net", + "ID": 9445082161, + "Type": "CNAME", + "Name": "testcname.dnscontrol.net", + "Data": "www.yahoo.com.", + "TTL": 300, + "Priority": 0, + "DDNSEnabled": false + } + }, + { + "index": 15, + "value": { + "ZoneID": 1075212, + "ZoneName": "dnscontrol.net", + "ID": 9445082162, + "Type": "A", + "Name": "foo.dnscontrol.net", + "Data": "1.2.3.4", + "TTL": 300, + "Priority": 0, + "DDNSEnabled": false + } + }, + { + "index": 16, + "value": { + "ZoneID": 1075212, + "ZoneName": "dnscontrol.net", + "ID": 9445082163, + "Type": "CNAME", + "Name": "testcname.dnscontrol.net", + "Data": "foo.dnscontrol.net.", + "TTL": 300, + "Priority": 0, + "DDNSEnabled": false + } + }, + { + "index": 17, + "value": { + "ZoneID": 1075212, + "ZoneName": "dnscontrol.net", + "ID": 9445082165, + "Type": "MX", + "Name": "dnscontrol.net", + "Data": "bar.com", + "TTL": 300, + "Priority": 5, + "DDNSEnabled": false + } + }, + { + "index": 18, + "value": { + "ZoneID": 1075212, + "ZoneName": "dnscontrol.net", + "ID": 9445082165, + "Type": "MX", + "Name": "dnscontrol.net", + "Data": "foo.com", + "TTL": 300, + "Priority": 5, + "DDNSEnabled": false + } + }, + { + "index": 19, + "value": { + "ZoneID": 1075212, + "ZoneName": "dnscontrol.net", + "ID": 9445082167, + "Type": "MX", + "Name": "testmx.dnscontrol.net", + "Data": "bar.com", + "TTL": 300, + "Priority": 5, + "DDNSEnabled": false + } + }, + { + "index": 20, + "value": { + "ZoneID": 1075212, + "ZoneName": "dnscontrol.net", + "ID": 9445082167, + "Type": "MX", + "Name": "testmx.dnscontrol.net", + "Data": "foo.com", + "TTL": 300, + "Priority": 5, + "DDNSEnabled": false + } + }, + { + "index": 21, + "value": { + "ZoneID": 1075212, + "ZoneName": "dnscontrol.net", + "ID": 9445082169, + "Type": "MX", + "Name": "testmx.dnscontrol.net", + "Data": "foo.com", + "TTL": 300, + "Priority": 100, + "DDNSEnabled": false + } + }, + { + "index": 22, + "value": { + "ZoneID": 1075212, + "ZoneName": "dnscontrol.net", + "ID": 9445082169, + "Type": "MX", + "Name": "testmx.dnscontrol.net", + "Data": "foo.com", + "TTL": 300, + "Priority": 5, + "DDNSEnabled": false + } + }, + { + "index": 23, + "value": { + "ZoneID": 1075212, + "ZoneName": "dnscontrol.net", + "ID": 9445082171, + "Type": "RP", + "Name": "foo.dnscontrol.net", + "Data": "other.example.com. bar.com.", + "TTL": 300, + "Priority": 0, + "DDNSEnabled": false + } + }, + { + "index": 24, + "value": { + "ZoneID": 1075212, + "ZoneName": "dnscontrol.net", + "ID": 9445082171, + "Type": "RP", + "Name": "foo.dnscontrol.net", + "Data": "other.example.com. example.com.", + "TTL": 300, + "Priority": 0, + "DDNSEnabled": false + } + }, + { + "index": 25, + "value": { + "ZoneID": 1075212, + "ZoneName": "dnscontrol.net", + "ID": 9445082171, + "Type": "RP", + "Name": "foo.dnscontrol.net", + "Data": "user.example.com. bar.com.", + "TTL": 300, + "Priority": 0, + "DDNSEnabled": false + } + }, + { + "index": 26, + "value": { + "ZoneID": 1075212, + "ZoneName": "dnscontrol.net", + "ID": 9445082172, + "Type": "RP", + "Name": "foo.dnscontrol.net", + "Data": "user.dnscontrol.net. server.dnscontrol.net.", + "TTL": 300, + "Priority": 0, + "DDNSEnabled": false + } + }, + { + "index": 27, + "value": { + "ZoneID": 1075212, + "ZoneName": "dnscontrol.net", + "ID": 9445082172, + "Type": "RP", + "Name": "foo.dnscontrol.net", + "Data": "user2.dnscontrol.net. server.dnscontrol.net.", + "TTL": 300, + "Priority": 0, + "DDNSEnabled": false + } + }, + { + "index": 28, + "value": { + "ZoneID": 1075212, + "ZoneName": "dnscontrol.net", + "ID": 9445082172, + "Type": "RP", + "Name": "foo.dnscontrol.net", + "Data": "user2.dnscontrol.net. waiter.dnscontrol.net.", + "TTL": 300, + "Priority": 0, + "DDNSEnabled": false + } + }, + { + "index": 29, + "value": { + "ZoneID": 1075212, + "ZoneName": "dnscontrol.net", + "ID": 9445082173, + "Type": "TXT", + "Name": "testtxt.dnscontrol.net", + "Data": "\"changed\"", + "TTL": 300, + "Priority": 0, + "DDNSEnabled": false + } + }, + { + "index": 30, + "value": { + "ZoneID": 1075212, + "ZoneName": "dnscontrol.net", + "ID": 9445082173, + "Type": "TXT", + "Name": "testtxt.dnscontrol.net", + "Data": "\"simple\"", + "TTL": 300, + "Priority": 0, + "DDNSEnabled": false + } + }, + { + "index": 31, + "value": { + "ZoneID": 1075212, + "ZoneName": "dnscontrol.net", + "ID": 9445082174, + "Type": "A", + "Name": "www.dnscontrol.net", + "Data": "1.1.1.1", + "TTL": 300, + "Priority": 0, + "DDNSEnabled": false + } + }, + { + "index": 32, + "value": { + "ZoneID": 1075212, + "ZoneName": "dnscontrol.net", + "ID": 9445082175, + "Type": "A", + "Name": "www.dnscontrol.net", + "Data": "2.2.2.2", + "TTL": 300, + "Priority": 0, + "DDNSEnabled": false + } + }, + { + "index": 33, + "value": { + "ZoneID": 1075212, + "ZoneName": "dnscontrol.net", + "ID": 9445082176, + "Type": "A", + "Name": "www.dnscontrol.net", + "Data": "3.3.3.3", + "TTL": 300, + "Priority": 0, + "DDNSEnabled": false + } + }, + { + "index": 34, + "value": { + "ZoneID": 1075212, + "ZoneName": "dnscontrol.net", + "ID": 9445082177, + "Type": "A", + "Name": "www.dnscontrol.net", + "Data": "1.1.1.1", + "TTL": 300, + "Priority": 0, + "DDNSEnabled": false + } + }, + { + "index": 35, + "value": { + "ZoneID": 1075212, + "ZoneName": "dnscontrol.net", + "ID": 9445082178, + "Type": "A", + "Name": "www.dnscontrol.net", + "Data": "2.2.2.2", + "TTL": 300, + "Priority": 0, + "DDNSEnabled": false + } + }, + { + "index": 36, + "value": { + "ZoneID": 1075212, + "ZoneName": "dnscontrol.net", + "ID": 9445082179, + "Type": "A", + "Name": "www.dnscontrol.net", + "Data": "3.3.3.3", + "TTL": 300, + "Priority": 0, + "DDNSEnabled": false + } + }, + { + "index": 37, + "value": { + "ZoneID": 1075212, + "ZoneName": "dnscontrol.net", + "ID": 9445082180, + "Type": "MX", + "Name": "testmx.dnscontrol.net", + "Data": "bar.com", + "TTL": 300, + "Priority": 100, + "DDNSEnabled": false + } + }, + { + "index": 38, + "value": { + "ZoneID": 1075212, + "ZoneName": "dnscontrol.net", + "ID": 9445082181, + "Type": "MX", + "Name": "testmx.dnscontrol.net", + "Data": "foo.com", + "TTL": 300, + "Priority": 5, + "DDNSEnabled": false + } + }, + { + "index": 39, + "value": { + "ZoneID": 1075212, + "ZoneName": "dnscontrol.net", + "ID": 9445082182, + "Type": "A", + "Name": "www.dnscontrol.net", + "Data": "1.1.1.1", + "TTL": 300, + "Priority": 0, + "DDNSEnabled": false + } + }, + { + "index": 40, + "value": { + "ZoneID": 1075212, + "ZoneName": "dnscontrol.net", + "ID": 9445082183, + "Type": "A", + "Name": "www.dnscontrol.net", + "Data": "1.1.1.1", + "TTL": 300, + "Priority": 0, + "DDNSEnabled": false + } + }, + { + "index": 41, + "value": { + "ZoneID": 1075212, + "ZoneName": "dnscontrol.net", + "ID": 9445082184, + "Type": "MX", + "Name": "testmx.dnscontrol.net", + "Data": "foo.com", + "TTL": 300, + "Priority": 5, + "DDNSEnabled": false + } + }, + { + "index": 42, + "value": { + "ZoneID": 1075212, + "ZoneName": "dnscontrol.net", + "ID": 9445082185, + "Type": "MX", + "Name": "testmx.dnscontrol.net", + "Data": "bar.com", + "TTL": 300, + "Priority": 100, + "DDNSEnabled": false + } + }, + { + "index": 43, + "value": { + "ZoneID": 1075212, + "ZoneName": "dnscontrol.net", + "ID": 9445082186, + "Type": "A", + "Name": "testa.dnscontrol.net", + "Data": "1.1.1.1", + "TTL": 333, + "Priority": 0, + "DDNSEnabled": false + } + }, + { + "index": 44, + "value": { + "ZoneID": 1075212, + "ZoneName": "dnscontrol.net", + "ID": 9445082186, + "Type": "A", + "Name": "testa.dnscontrol.net", + "Data": "1.1.1.1", + "TTL": 999, + "Priority": 0, + "DDNSEnabled": false + } + }, + { + "index": 45, + "value": { + "ZoneID": 1075212, + "ZoneName": "dnscontrol.net", + "ID": 9445082187, + "Type": "A", + "Name": "dnscontrol.net", + "Data": "8.8.8.8", + "TTL": 1000, + "Priority": 0, + "DDNSEnabled": false + } + }, + { + "index": 46, + "value": { + "ZoneID": 1075212, + "ZoneName": "dnscontrol.net", + "ID": 9445082187, + "Type": "A", + "Name": "dnscontrol.net", + "Data": "8.8.8.8", + "TTL": 500, + "Priority": 0, + "DDNSEnabled": false + } + }, + { + "index": 47, + "value": { + "ZoneID": 1075212, + "ZoneName": "dnscontrol.net", + "ID": 9445082187, + "Type": "A", + "Name": "dnscontrol.net", + "Data": "8.8.8.8", + "TTL": 666, + "Priority": 0, + "DDNSEnabled": false + } + }, + { + "index": 48, + "value": { + "ZoneID": 1075212, + "ZoneName": "dnscontrol.net", + "ID": 9445082188, + "Type": "A", + "Name": "www.dnscontrol.net", + "Data": "1.2.3.4", + "TTL": 300, + "Priority": 0, + "DDNSEnabled": false + } + }, + { + "index": 49, + "value": { + "ZoneID": 1075212, + "ZoneName": "dnscontrol.net", + "ID": 9445082188, + "Type": "A", + "Name": "www.dnscontrol.net", + "Data": "2.2.2.2", + "TTL": 300, + "Priority": 0, + "DDNSEnabled": false + } + }, + { + "index": 50, + "value": { + "ZoneID": 1075212, + "ZoneName": "dnscontrol.net", + "ID": 9445082188, + "Type": "A", + "Name": "www.dnscontrol.net", + "Data": "2.2.2.2", + "TTL": 400, + "Priority": 0, + "DDNSEnabled": false + } + }, + { + "index": 51, + "value": { + "ZoneID": 1075212, + "ZoneName": "dnscontrol.net", + "ID": 9445082189, + "Type": "A", + "Name": "www.dnscontrol.net", + "Data": "5.6.7.8", + "TTL": 300, + "Priority": 0, + "DDNSEnabled": false + } + }, + { + "index": 52, + "value": { + "ZoneID": 1075212, + "ZoneName": "dnscontrol.net", + "ID": 9445082189, + "Type": "A", + "Name": "www.dnscontrol.net", + "Data": "5.6.7.8", + "TTL": 400, + "Priority": 0, + "DDNSEnabled": false + } + }, + { + "index": 53, + "value": { + "ZoneID": 1075212, + "ZoneName": "dnscontrol.net", + "ID": 9445082190, + "Type": "A", + "Name": "www.dnscontrol.net", + "Data": "5.6.7.8", + "TTL": 400, + "Priority": 0, + "DDNSEnabled": false + } + }, + { + "index": 54, + "value": { + "ZoneID": 1075212, + "ZoneName": "dnscontrol.net", + "ID": 9445082190, + "Type": "A", + "Name": "www.dnscontrol.net", + "Data": "5.6.7.8", + "TTL": 700, + "Priority": 0, + "DDNSEnabled": false + } + }, + { + "index": 55, + "value": { + "ZoneID": 1075212, + "ZoneName": "dnscontrol.net", + "ID": 9445082191, + "Type": "A", + "Name": "www.dnscontrol.net", + "Data": "1.2.3.4", + "TTL": 700, + "Priority": 0, + "DDNSEnabled": false + } + }, + { + "index": 56, + "value": { + "ZoneID": 1075212, + "ZoneName": "dnscontrol.net", + "ID": 9445082192, + "Type": "A", + "Name": "foo.dnscontrol.net", + "Data": "1.2.3.4", + "TTL": 300, + "Priority": 0, + "DDNSEnabled": false + } + }, + { + "index": 57, + "value": { + "ZoneID": 1075212, + "ZoneName": "dnscontrol.net", + "ID": 9445082193, + "Type": "MX", + "Name": "foo.dnscontrol.net", + "Data": "mx.google.com", + "TTL": 300, + "Priority": 5, + "DDNSEnabled": false + } + }, + { + "index": 58, + "value": { + "ZoneID": 1075212, + "ZoneName": "dnscontrol.net", + "ID": 9445082194, + "Type": "A", + "Name": "foo.dnscontrol.net", + "Data": "4.5.6.7", + "TTL": 300, + "Priority": 0, + "DDNSEnabled": false + } + }, + { + "index": 59, + "value": { + "ZoneID": 1075212, + "ZoneName": "dnscontrol.net", + "ID": 9445082195, + "Type": "CNAME", + "Name": "foo.dnscontrol.net", + "Data": "google.com.", + "TTL": 300, + "Priority": 0, + "DDNSEnabled": false + } + }, + { + "index": 60, + "value": { + "ZoneID": 1075212, + "ZoneName": "dnscontrol.net", + "ID": 9445082196, + "Type": "A", + "Name": "foo.dnscontrol.net", + "Data": "1.2.3.4", + "TTL": 300, + "Priority": 0, + "DDNSEnabled": false + } + }, + { + "index": 61, + "value": { + "ZoneID": 1075212, + "ZoneName": "dnscontrol.net", + "ID": 9445082197, + "Type": "CNAME", + "Name": "foo.dnscontrol.net", + "Data": "google2.com.", + "TTL": 300, + "Priority": 0, + "DDNSEnabled": false + } + }, + { + "index": 62, + "value": { + "ZoneID": 1075212, + "ZoneName": "dnscontrol.net", + "ID": 9445082198, + "Type": "HTTPS", + "Name": "dnscontrol.net", + "Data": "0 test.com.", + "TTL": 300, + "Priority": 0, + "DDNSEnabled": false + } + }, + { + "index": 63, + "value": { + "ZoneID": 1075212, + "ZoneName": "dnscontrol.net", + "ID": 9445082198, + "Type": "HTTPS", + "Name": "dnscontrol.net", + "Data": "1 test.com. alpn=\"h2\" port=\"99\"", + "TTL": 300, + "Priority": 0, + "DDNSEnabled": false + } + }, + { + "index": 64, + "value": { + "ZoneID": 1075212, + "ZoneName": "dnscontrol.net", + "ID": 9445082198, + "Type": "HTTPS", + "Name": "dnscontrol.net", + "Data": "1 test.com. port=\"80\"", + "TTL": 300, + "Priority": 0, + "DDNSEnabled": false + } + }, + { + "index": 65, + "value": { + "ZoneID": 1075212, + "ZoneName": "dnscontrol.net", + "ID": 9445082198, + "Type": "HTTPS", + "Name": "dnscontrol.net", + "Data": "1 test.com. port=\"99\"", + "TTL": 300, + "Priority": 0, + "DDNSEnabled": false + } + }, + { + "index": 66, + "value": { + "ZoneID": 1075212, + "ZoneName": "dnscontrol.net", + "ID": 9445082198, + "Type": "HTTPS", + "Name": "dnscontrol.net", + "Data": "3 example.com. alpn=\"h2,h3\" port=\"999\"", + "TTL": 300, + "Priority": 0, + "DDNSEnabled": false + } + }, + { + "index": 67, + "value": { + "ZoneID": 1075212, + "ZoneName": "dnscontrol.net", + "ID": 9445082199, + "Type": "SVCB", + "Name": "dnscontrol.net", + "Data": "0 test.com.", + "TTL": 300, + "Priority": 0, + "DDNSEnabled": false + } + }, + { + "index": 68, + "value": { + "ZoneID": 1075212, + "ZoneName": "dnscontrol.net", + "ID": 9445082199, + "Type": "SVCB", + "Name": "dnscontrol.net", + "Data": "1 test.com. alpn=\"h2\" port=\"99\"", + "TTL": 300, + "Priority": 0, + "DDNSEnabled": false + } + }, + { + "index": 69, + "value": { + "ZoneID": 1075212, + "ZoneName": "dnscontrol.net", + "ID": 9445082199, + "Type": "SVCB", + "Name": "dnscontrol.net", + "Data": "1 test.com. port=\"80\"", + "TTL": 300, + "Priority": 0, + "DDNSEnabled": false + } + }, + { + "index": 70, + "value": { + "ZoneID": 1075212, + "ZoneName": "dnscontrol.net", + "ID": 9445082199, + "Type": "SVCB", + "Name": "dnscontrol.net", + "Data": "1 test.com. port=\"99\"", + "TTL": 300, + "Priority": 0, + "DDNSEnabled": false + } + }, + { + "index": 71, + "value": { + "ZoneID": 1075212, + "ZoneName": "dnscontrol.net", + "ID": 9445082199, + "Type": "SVCB", + "Name": "dnscontrol.net", + "Data": "3 example.com. alpn=\"h2,h3\" port=\"999\"", + "TTL": 300, + "Priority": 0, + "DDNSEnabled": false + } + }, + { + "index": 72, + "value": { + "ZoneID": 1075212, + "ZoneName": "dnscontrol.net", + "ID": 9445082200, + "Type": "A", + "Name": "dnscontrol.net", + "Data": "1.2.3.4", + "TTL": 300, + "Priority": 0, + "DDNSEnabled": false + } + }, + { + "index": 73, + "value": { + "ZoneID": 1075212, + "ZoneName": "dnscontrol.net", + "ID": 9445082201, + "Type": "CNAME", + "Name": "foo.dnscontrol.net", + "Data": "dnscontrol.net.", + "TTL": 300, + "Priority": 0, + "DDNSEnabled": false + } + }, + { + "index": 74, + "value": { + "ZoneID": 1075212, + "ZoneName": "dnscontrol.net", + "ID": 9445082202, + "Type": "A", + "Name": "dnscontrol.net", + "Data": "1.2.3.4", + "TTL": 300, + "Priority": 0, + "DDNSEnabled": false + } + }, + { + "index": 75, + "value": { + "ZoneID": 1075212, + "ZoneName": "dnscontrol.net", + "ID": 9445082203, + "Type": "MX", + "Name": "foo.dnscontrol.net", + "Data": "dnscontrol.net", + "TTL": 300, + "Priority": 8, + "DDNSEnabled": false + } + }, + { + "index": 76, + "value": { + "ZoneID": 1075212, + "ZoneName": "dnscontrol.net", + "ID": 9445082204, + "Type": "A", + "Name": "nmx.dnscontrol.net", + "Data": "1.2.3.3", + "TTL": 300, + "Priority": 0, + "DDNSEnabled": false + } + }, + { + "index": 77, + "value": { + "ZoneID": 1075212, + "ZoneName": "dnscontrol.net", + "ID": 9445082205, + "Type": "A", + "Name": "www.dnscontrol.net", + "Data": "1.2.3.9", + "TTL": 300, + "Priority": 0, + "DDNSEnabled": false + } + }, + { + "index": 78, + "value": { + "ZoneID": 1075212, + "ZoneName": "dnscontrol.net", + "ID": 9445082206, + "Type": "MX", + "Name": "nmx.dnscontrol.net", + "Data": "www.dnscontrol.net", + "TTL": 300, + "Priority": 9, + "DDNSEnabled": false + } + }, + { + "index": 79, + "value": { + "ZoneID": 1075212, + "ZoneName": "dnscontrol.net", + "ID": 9445082207, + "Type": "MX", + "Name": "nmx.dnscontrol.net", + "Data": "nmx.dnscontrol.net", + "TTL": 300, + "Priority": 3, + "DDNSEnabled": false + } + }, + { + "index": 80, + "value": { + "ZoneID": 1075212, + "ZoneName": "dnscontrol.net", + "ID": 9445082208, + "Type": "A", + "Name": "dnscontrol.net", + "Data": "1.2.3.2", + "TTL": 300, + "Priority": 0, + "DDNSEnabled": false + } + }, + { + "index": 81, + "value": { + "ZoneID": 1075212, + "ZoneName": "dnscontrol.net", + "ID": 9445082209, + "Type": "A", + "Name": "www.dnscontrol.net", + "Data": "1.2.3.8", + "TTL": 300, + "Priority": 0, + "DDNSEnabled": false + } + }, + { + "index": 82, + "value": { + "ZoneID": 1075212, + "ZoneName": "dnscontrol.net", + "ID": 9445082210, + "Type": "MX", + "Name": "dnscontrol.net", + "Data": "www.dnscontrol.net", + "TTL": 300, + "Priority": 8, + "DDNSEnabled": false + } + }, + { + "index": 83, + "value": { + "ZoneID": 1075212, + "ZoneName": "dnscontrol.net", + "ID": 9445082211, + "Type": "MX", + "Name": "dnscontrol.net", + "Data": "dnscontrol.net", + "TTL": 300, + "Priority": 2, + "DDNSEnabled": false + } + }, + { + "index": 84, + "value": { + "ZoneID": 1075212, + "ZoneName": "dnscontrol.net", + "ID": 9445082212, + "Type": "NS", + "Name": "xyz.dnscontrol.net", + "Data": "ns2.foo.com.", + "TTL": 300, + "Priority": 0, + "DDNSEnabled": false + } + }, + { + "index": 85, + "value": { + "ZoneID": 1075212, + "ZoneName": "dnscontrol.net", + "ID": 9445082213, + "Type": "NS", + "Name": "xyz.dnscontrol.net", + "Data": "ns1.foo.com.", + "TTL": 300, + "Priority": 0, + "DDNSEnabled": false + } + }, + { + "index": 86, + "value": { + "ZoneID": 1075212, + "ZoneName": "dnscontrol.net", + "ID": 9445082214, + "Type": "A", + "Name": "dnscontrol.net", + "Data": "1.2.3.4", + "TTL": 300, + "Priority": 0, + "DDNSEnabled": false + } + }, + { + "index": 87, + "value": { + "ZoneID": 1075212, + "ZoneName": "dnscontrol.net", + "ID": 9445082215, + "Type": "NS", + "Name": "foo.dnscontrol.net", + "Data": "dnscontrol.net.", + "TTL": 300, + "Priority": 0, + "DDNSEnabled": false + } + }, + { + "index": 88, + "value": { + "ZoneID": 1075212, + "ZoneName": "dnscontrol.net", + "ID": 9445082216, + "Type": "NS", + "Name": "dnscontrol.net", + "Data": "ns1.foo.com.", + "TTL": 300, + "Priority": 0, + "DDNSEnabled": false + } + }, + { + "index": 89, + "value": { + "ZoneID": 1075212, + "ZoneName": "dnscontrol.net", + "ID": 9445082217, + "Type": "NS", + "Name": "dnscontrol.net", + "Data": "ns2.foo.com.", + "TTL": 300, + "Priority": 0, + "DDNSEnabled": false + } + }, + { + "index": 90, + "value": { + "ZoneID": 1075212, + "ZoneName": "dnscontrol.net", + "ID": 9445082218, + "Type": "TXT", + "Name": "foo0.dnscontrol.net", + "Data": "", + "TTL": 300, + "Priority": 0, + "DDNSEnabled": false + } + }, + { + "index": 91, + "value": { + "ZoneID": 1075212, + "ZoneName": "dnscontrol.net", + "ID": 9445082219, + "Type": "TXT", + "Name": "foo254.dnscontrol.net", + "Data": "\"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\"", + "TTL": 300, + "Priority": 0, + "DDNSEnabled": false + } + }, + { + "index": 92, + "value": { + "ZoneID": 1075212, + "ZoneName": "dnscontrol.net", + "ID": 9445082220, + "Type": "TXT", + "Name": "foo255.dnscontrol.net", + "Data": "\"BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB\"", + "TTL": 300, + "Priority": 0, + "DDNSEnabled": false + } + }, + { + "index": 93, + "value": { + "ZoneID": 1075212, + "ZoneName": "dnscontrol.net", + "ID": 9445082221, + "Type": "TXT", + "Name": "foo256.dnscontrol.net", + "Data": "\"CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC\" \"C\"", + "TTL": 300, + "Priority": 0, + "DDNSEnabled": false + } + }, + { + "index": 94, + "value": { + "ZoneID": 1075212, + "ZoneName": "dnscontrol.net", + "ID": 9445082222, + "Type": "TXT", + "Name": "foo509.dnscontrol.net", + "Data": "\"DDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDD\" \"DDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDD\"", + "TTL": 300, + "Priority": 0, + "DDNSEnabled": false + } + }, + { + "index": 95, + "value": { + "ZoneID": 1075212, + "ZoneName": "dnscontrol.net", + "ID": 9445082223, + "Type": "TXT", + "Name": "foo510.dnscontrol.net", + "Data": "\"EEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE\" \"EEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE\"", + "TTL": 300, + "Priority": 0, + "DDNSEnabled": false + } + }, + { + "index": 96, + "value": { + "ZoneID": 1075212, + "ZoneName": "dnscontrol.net", + "ID": 9445082224, + "Type": "TXT", + "Name": "foo511.dnscontrol.net", + "Data": "\"FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF\" \"FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF\" \"F\"", + "TTL": 300, + "Priority": 0, + "DDNSEnabled": false + } + }, + { + "index": 97, + "value": { + "ZoneID": 1075212, + "ZoneName": "dnscontrol.net", + "ID": 9445082225, + "Type": "TXT", + "Name": "foo764.dnscontrol.net", + "Data": "\"GGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGG\" \"GGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGG\" \"GGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGG\"", + "TTL": 300, + "Priority": 0, + "DDNSEnabled": false + } + }, + { + "index": 98, + "value": { + "ZoneID": 1075212, + "ZoneName": "dnscontrol.net", + "ID": 9445082226, + "Type": "TXT", + "Name": "foo765.dnscontrol.net", + "Data": "\"HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH\" \"HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH\" \"HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH\"", + "TTL": 300, + "Priority": 0, + "DDNSEnabled": false + } + }, + { + "index": 99, + "value": { + "ZoneID": 1075212, + "ZoneName": "dnscontrol.net", + "ID": 9445082227, + "Type": "TXT", + "Name": "foo766.dnscontrol.net", + "Data": "\"JJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJ\" \"JJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJ\" \"JJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJ\" \"J\"", + "TTL": 300, + "Priority": 0, + "DDNSEnabled": false + } + }, + { + "index": 100, + "value": { + "ZoneID": 1075212, + "ZoneName": "dnscontrol.net", + "ID": 9445082228, + "Type": "TXT", + "Name": "foosq.dnscontrol.net", + "Data": "\"quo'te\"", + "TTL": 300, + "Priority": 0, + "DDNSEnabled": false + } + }, + { + "index": 101, + "value": { + "ZoneID": 1075212, + "ZoneName": "dnscontrol.net", + "ID": 9445082229, + "Type": "TXT", + "Name": "foobt.dnscontrol.net", + "Data": "\"blah`blah\"", + "TTL": 300, + "Priority": 0, + "DDNSEnabled": false + } + }, + { + "index": 102, + "value": { + "ZoneID": 1075212, + "ZoneName": "dnscontrol.net", + "ID": 9445082230, + "Type": "TXT", + "Name": "foodq.dnscontrol.net", + "Data": "\"in\\\"side\"", + "TTL": 300, + "Priority": 0, + "DDNSEnabled": false + } + }, + { + "index": 103, + "value": { + "ZoneID": 1075212, + "ZoneName": "dnscontrol.net", + "ID": 9445082231, + "Type": "TXT", + "Name": "foodqs.dnscontrol.net", + "Data": "\"\\\"left\"", + "TTL": 300, + "Priority": 0, + "DDNSEnabled": false + } + }, + { + "index": 104, + "value": { + "ZoneID": 1075212, + "ZoneName": "dnscontrol.net", + "ID": 9445082231, + "Type": "TXT", + "Name": "foodqs.dnscontrol.net", + "Data": "\"in\\\"ter\\\"ior\"", + "TTL": 300, + "Priority": 0, + "DDNSEnabled": false + } + }, + { + "index": 105, + "value": { + "ZoneID": 1075212, + "ZoneName": "dnscontrol.net", + "ID": 9445082231, + "Type": "TXT", + "Name": "foodqs.dnscontrol.net", + "Data": "\"right\\\"\"", + "TTL": 300, + "Priority": 0, + "DDNSEnabled": false + } + }, + { + "index": 106, + "value": { + "ZoneID": 1075212, + "ZoneName": "dnscontrol.net", + "ID": 9445082232, + "Type": "TXT", + "Name": "foosc1.dnscontrol.net", + "Data": "\"semi;colon\"", + "TTL": 300, + "Priority": 0, + "DDNSEnabled": false + } + }, + { + "index": 107, + "value": { + "ZoneID": 1075212, + "ZoneName": "dnscontrol.net", + "ID": 9445082233, + "Type": "TXT", + "Name": "foosc2.dnscontrol.net", + "Data": "\"wssemi ; colon\"", + "TTL": 300, + "Priority": 0, + "DDNSEnabled": false + } + }, + { + "index": 108, + "value": { + "ZoneID": 1075212, + "ZoneName": "dnscontrol.net", + "ID": 9445082234, + "Type": "TXT", + "Name": "foosp.dnscontrol.net", + "Data": "\"with spaces\"", + "TTL": 300, + "Priority": 0, + "DDNSEnabled": false + } + }, + { + "index": 109, + "value": { + "ZoneID": 1075212, + "ZoneName": "dnscontrol.net", + "ID": 9445082235, + "Type": "TXT", + "Name": "foows1.dnscontrol.net", + "Data": "\"trailingws \"", + "TTL": 300, + "Priority": 0, + "DDNSEnabled": false + } + }, + { + "index": 110, + "value": { + "ZoneID": 1075212, + "ZoneName": "dnscontrol.net", + "ID": 9445082236, + "Type": "TXT", + "Name": "foo.dnscontrol.net", + "Data": "\"v=spf1 ip4:99.99.99.99 -all\"", + "TTL": 300, + "Priority": 0, + "DDNSEnabled": false + } + }, + { + "index": 111, + "value": { + "ZoneID": 1075212, + "ZoneName": "dnscontrol.net", + "ID": 9445082237, + "Type": "TXT", + "Name": "fooosbs1.dnscontrol.net", + "Data": "\"1back\\\\slash\"", + "TTL": 300, + "Priority": 0, + "DDNSEnabled": false + } + }, + { + "index": 112, + "value": { + "ZoneID": 1075212, + "ZoneName": "dnscontrol.net", + "ID": 9445082238, + "Type": "TXT", + "Name": "fooosbs2.dnscontrol.net", + "Data": "\"2back\\\\\\\\slash\"", + "TTL": 300, + "Priority": 0, + "DDNSEnabled": false + } + }, + { + "index": 113, + "value": { + "ZoneID": 1075212, + "ZoneName": "dnscontrol.net", + "ID": 9445082239, + "Type": "TXT", + "Name": "fooosbs3.dnscontrol.net", + "Data": "\"3back\\\\\\\\\\\\slash\"", + "TTL": 300, + "Priority": 0, + "DDNSEnabled": false + } + }, + { + "index": 114, + "value": { + "ZoneID": 1075212, + "ZoneName": "dnscontrol.net", + "ID": 9445082240, + "Type": "TXT", + "Name": "fooosbs4.dnscontrol.net", + "Data": "\"4back\\\\\\\\\\\\\\\\slash\"", + "TTL": 300, + "Priority": 0, + "DDNSEnabled": false + } + }, + { + "index": 115, + "value": { + "ZoneID": 1075212, + "ZoneName": "dnscontrol.net", + "ID": 9445082241, + "Type": "MX", + "Name": "bar.dnscontrol.net", + "Data": "bar.com", + "TTL": 300, + "Priority": 5, + "DDNSEnabled": false + } + }, + { + "index": 116, + "value": { + "ZoneID": 1075212, + "ZoneName": "dnscontrol.net", + "ID": 9445082242, + "Type": "A", + "Name": "decoy.dnscontrol.net", + "Data": "1.1.1.1", + "TTL": 300, + "Priority": 0, + "DDNSEnabled": false + } + }, + { + "index": 117, + "value": { + "ZoneID": 1075212, + "ZoneName": "dnscontrol.net", + "ID": 9445082242, + "Type": "A", + "Name": "decoy.dnscontrol.net", + "Data": "2.2.2.2", + "TTL": 300, + "Priority": 0, + "DDNSEnabled": false + } + }, + { + "index": 118, + "value": { + "ZoneID": 1075212, + "ZoneName": "dnscontrol.net", + "ID": 9445082242, + "Type": "A", + "Name": "decoy.dnscontrol.net", + "Data": "3.3.3.3", + "TTL": 300, + "Priority": 0, + "DDNSEnabled": false + } + }, + { + "index": 119, + "value": { + "ZoneID": 1075212, + "ZoneName": "dnscontrol.net", + "ID": 9445082243, + "Type": "A", + "Name": "foo.dnscontrol.net", + "Data": "1.2.3.4", + "TTL": 300, + "Priority": 0, + "DDNSEnabled": false + } + }, + { + "index": 120, + "value": { + "ZoneID": 1075212, + "ZoneName": "dnscontrol.net", + "ID": 9445082244, + "Type": "A", + "Name": "foo.dnscontrol.net", + "Data": "2.3.4.5", + "TTL": 300, + "Priority": 0, + "DDNSEnabled": false + } + }, + { + "index": 121, + "value": { + "ZoneID": 1075212, + "ZoneName": "dnscontrol.net", + "ID": 9445082244, + "Type": "A", + "Name": "foo.dnscontrol.net", + "Data": "3.4.5.6", + "TTL": 300, + "Priority": 0, + "DDNSEnabled": false + } + }, + { + "index": 122, + "value": { + "ZoneID": 1075212, + "ZoneName": "dnscontrol.net", + "ID": 9445082245, + "Type": "A", + "Name": "foo.dnscontrol.net", + "Data": "3.4.5.6", + "TTL": 300, + "Priority": 0, + "DDNSEnabled": false + } + }, + { + "index": 123, + "value": { + "ZoneID": 1075212, + "ZoneName": "dnscontrol.net", + "ID": 9445082246, + "Type": "A", + "Name": "bar.dnscontrol.net", + "Data": "1.2.3.4", + "TTL": 300, + "Priority": 0, + "DDNSEnabled": false + } + }, + { + "index": 124, + "value": { + "ZoneID": 1075212, + "ZoneName": "dnscontrol.net", + "ID": 9445082247, + "Type": "A", + "Name": "foo.dnscontrol.net", + "Data": "2.3.4.5", + "TTL": 300, + "Priority": 0, + "DDNSEnabled": false + } + }, + { + "index": 125, + "value": { + "ZoneID": 1075212, + "ZoneName": "dnscontrol.net", + "ID": 9445082248, + "Type": "A", + "Name": "foo.dnscontrol.net", + "Data": "3.4.5.6", + "TTL": 300, + "Priority": 0, + "DDNSEnabled": false + } + }, + { + "index": 126, + "value": { + "ZoneID": 1075212, + "ZoneName": "dnscontrol.net", + "ID": 9445082248, + "Type": "A", + "Name": "foo.dnscontrol.net", + "Data": "8.8.8.8", + "TTL": 300, + "Priority": 0, + "DDNSEnabled": false + } + }, + { + "index": 127, + "value": { + "ZoneID": 1075212, + "ZoneName": "dnscontrol.net", + "ID": 9445082249, + "Type": "MX", + "Name": "foo.dnscontrol.net", + "Data": "bar.dnscontrol.net", + "TTL": 300, + "Priority": 20, + "DDNSEnabled": false + } + }, + { + "index": 128, + "value": { + "ZoneID": 1075212, + "ZoneName": "dnscontrol.net", + "ID": 9445082250, + "Type": "MX", + "Name": "foo.dnscontrol.net", + "Data": "foo.dnscontrol.net", + "TTL": 300, + "Priority": 10, + "DDNSEnabled": false + } + }, + { + "index": 129, + "value": { + "ZoneID": 1075212, + "ZoneName": "dnscontrol.net", + "ID": 9445082251, + "Type": "A", + "Name": "foo.dnscontrol.net", + "Data": "8.8.8.8", + "TTL": 300, + "Priority": 0, + "DDNSEnabled": false + } + }, + { + "index": 130, + "value": { + "ZoneID": 1075212, + "ZoneName": "dnscontrol.net", + "ID": 9445082252, + "Type": "A", + "Name": "xn--ndaaa.dnscontrol.net", + "Data": "1.2.3.4", + "TTL": 300, + "Priority": 0, + "DDNSEnabled": false + } + }, + { + "index": 131, + "value": { + "ZoneID": 1075212, + "ZoneName": "dnscontrol.net", + "ID": 9445082252, + "Type": "A", + "Name": "xn--ndaaa.dnscontrol.net", + "Data": "2.2.2.2", + "TTL": 300, + "Priority": 0, + "DDNSEnabled": false + } + }, + { + "index": 132, + "value": { + "ZoneID": 1075212, + "ZoneName": "dnscontrol.net", + "ID": 9445082259, + "Type": "A", + "Name": "xn--fiq228c.dnscontrol.net", + "Data": "1.2.3.4", + "TTL": 300, + "Priority": 0, + "DDNSEnabled": false + } + }, + { + "index": 133, + "value": { + "ZoneID": 1075212, + "ZoneName": "dnscontrol.net", + "ID": 9445082260, + "Type": "CNAME", + "Name": "a.dnscontrol.net", + "Data": "xn--ndaaa.com.", + "TTL": 300, + "Priority": 0, + "DDNSEnabled": false + } + }, + { + "index": 134, + "value": { + "ZoneID": 1075212, + "ZoneName": "dnscontrol.net", + "ID": 9445082261, + "Type": "CNAME", + "Name": "xn--o-0gab.dnscontrol.net", + "Data": "xn--ndaaa.xn--vhquv.", + "TTL": 300, + "Priority": 0, + "DDNSEnabled": false + } + }, + { + "index": 135, + "value": { + "ZoneID": 1075212, + "ZoneName": "dnscontrol.net", + "ID": 9445082262, + "Type": "CAA", + "Name": "dnscontrol.net", + "Data": "0 issue \"letsencrypt.org; validationmethods=dns-01; accounturi=https://acme-v02.api.letsencrypt.org/acme/acct/1234\"", + "TTL": 300, + "Priority": 0, + "DDNSEnabled": false + } + }, + { + "index": 136, + "value": { + "ZoneID": 1075212, + "ZoneName": "dnscontrol.net", + "ID": 9445082262, + "Type": "CAA", + "Name": "dnscontrol.net", + "Data": "0 issue \"letsencrypt.org\"", + "TTL": 300, + "Priority": 0, + "DDNSEnabled": false + } + }, + { + "index": 137, + "value": { + "ZoneID": 1075212, + "ZoneName": "dnscontrol.net", + "ID": 9445082262, + "Type": "CAA", + "Name": "dnscontrol.net", + "Data": "0 issuewild \";\"", + "TTL": 300, + "Priority": 0, + "DDNSEnabled": false + } + }, + { + "index": 138, + "value": { + "ZoneID": 1075212, + "ZoneName": "dnscontrol.net", + "ID": 9445082262, + "Type": "CAA", + "Name": "dnscontrol.net", + "Data": "0 issuewild \"example.com\"", + "TTL": 300, + "Priority": 0, + "DDNSEnabled": false + } + }, + { + "index": 139, + "value": { + "ZoneID": 1075212, + "ZoneName": "dnscontrol.net", + "ID": 9445082262, + "Type": "CAA", + "Name": "dnscontrol.net", + "Data": "0 issuewild \"letsencrypt.org\"", + "TTL": 300, + "Priority": 0, + "DDNSEnabled": false + } + }, + { + "index": 140, + "value": { + "ZoneID": 1075212, + "ZoneName": "dnscontrol.net", + "ID": 9445082263, + "Type": "CAA", + "Name": "dnscontrol.net", + "Data": "0 issue \"letsencrypt.org\"", + "TTL": 300, + "Priority": 0, + "DDNSEnabled": false + } + }, + { + "index": 141, + "value": { + "ZoneID": 1075212, + "ZoneName": "dnscontrol.net", + "ID": 9445082263, + "Type": "CAA", + "Name": "dnscontrol.net", + "Data": "128 issue \"letsencrypt.org\"", + "TTL": 300, + "Priority": 0, + "DDNSEnabled": false + } + }, + { + "index": 142, + "value": { + "ZoneID": 1075212, + "ZoneName": "dnscontrol.net", + "ID": 9445082264, + "Type": "LOC", + "Name": "dnscontrol.net", + "Data": "42 21 54.000 N 71 06 18.000 W -24.05m 30m 0.00m 0.00m", + "TTL": 300, + "Priority": 0, + "DDNSEnabled": false + } + }, + { + "index": 143, + "value": { + "ZoneID": 1075212, + "ZoneName": "dnscontrol.net", + "ID": 9445082264, + "Type": "LOC", + "Name": "dnscontrol.net", + "Data": "42 21 54.000 N 71 06 18.000 W -24.06m 30m 10m 0.00m", + "TTL": 300, + "Priority": 0, + "DDNSEnabled": false + } + }, + { + "index": 144, + "value": { + "ZoneID": 1075212, + "ZoneName": "dnscontrol.net", + "ID": 9445082264, + "Type": "LOC", + "Name": "dnscontrol.net", + "Data": "42 21 54.000 N 71 06 18.000 W -24m 30m 0.00m 0.00m", + "TTL": 300, + "Priority": 0, + "DDNSEnabled": false + } + }, + { + "index": 145, + "value": { + "ZoneID": 1075212, + "ZoneName": "dnscontrol.net", + "ID": 9445082265, + "Type": "LOC", + "Name": "a.dnscontrol.net", + "Data": "42 21 43.950 N 71 05 6.340 W -24.33m 1m 200m 10m", + "TTL": 300, + "Priority": 0, + "DDNSEnabled": false + } + }, + { + "index": 146, + "value": { + "ZoneID": 1075212, + "ZoneName": "dnscontrol.net", + "ID": 9445082266, + "Type": "LOC", + "Name": "b.dnscontrol.net", + "Data": "52 14 5.000 N 00 08 50.000 E 10.22m 0.00m 0.00m 0.00m", + "TTL": 300, + "Priority": 0, + "DDNSEnabled": false + } + }, + { + "index": 147, + "value": { + "ZoneID": 1075212, + "ZoneName": "dnscontrol.net", + "ID": 9445082267, + "Type": "LOC", + "Name": "c.dnscontrol.net", + "Data": "32 07 19.000 S 116 02 25.000 E 10m 0.00m 0.00m 0.00m", + "TTL": 300, + "Priority": 0, + "DDNSEnabled": false + } + }, + { + "index": 148, + "value": { + "ZoneID": 1075212, + "ZoneName": "dnscontrol.net", + "ID": 9445082269, + "Type": "LOC", + "Name": "d.dnscontrol.net", + "Data": "42 21 28.760 N 71 00 51.620 W -44m 2000m 0.00m 0.00m", + "TTL": 300, + "Priority": 0, + "DDNSEnabled": false + } + }, + { + "index": 149, + "value": { + "ZoneID": 1075212, + "ZoneName": "dnscontrol.net", + "ID": 9445082270, + "Type": "NAPTR", + "Name": "test.dnscontrol.net", + "Data": "100 10 \"U\" \"E2U+sip\" \"!^.*$!sip:customer-service@example.com!\" .", + "TTL": 300, + "Priority": 0, + "DDNSEnabled": false + } + }, + { + "index": 150, + "value": { + "ZoneID": 1075212, + "ZoneName": "dnscontrol.net", + "ID": 9445082270, + "Type": "NAPTR", + "Name": "test.dnscontrol.net", + "Data": "103 10 \"U\" \"E2U+email\" \"!^.*$!mailto:information@example.com!\" .", + "TTL": 300, + "Priority": 0, + "DDNSEnabled": false + } + }, + { + "index": 151, + "value": { + "ZoneID": 1075212, + "ZoneName": "dnscontrol.net", + "ID": 9445082270, + "Type": "NAPTR", + "Name": "test.dnscontrol.net", + "Data": "103 20 \"A\" \"E2U+email\" \"!^.*$!mailto:information@example.com!\" .", + "TTL": 300, + "Priority": 0, + "DDNSEnabled": false + } + }, + { + "index": 152, + "value": { + "ZoneID": 1075212, + "ZoneName": "dnscontrol.net", + "ID": 9445082270, + "Type": "NAPTR", + "Name": "test.dnscontrol.net", + "Data": "103 20 \"A\" \"E2U+sip\" \"!^.*$!mailto:information@example.com!\" .", + "TTL": 300, + "Priority": 0, + "DDNSEnabled": false + } + }, + { + "index": 153, + "value": { + "ZoneID": 1075212, + "ZoneName": "dnscontrol.net", + "ID": 9445082270, + "Type": "NAPTR", + "Name": "test.dnscontrol.net", + "Data": "103 20 \"A\" \"E2U+sip\" \"!^.*$!sip:customer-service@example.com!\" .", + "TTL": 300, + "Priority": 0, + "DDNSEnabled": false + } + }, + { + "index": 154, + "value": { + "ZoneID": 1075212, + "ZoneName": "dnscontrol.net", + "ID": 9445082270, + "Type": "NAPTR", + "Name": "test.dnscontrol.net", + "Data": "103 20 \"A\" \"E2U+sip\" \"\" example.foo.com.", + "TTL": 300, + "Priority": 0, + "DDNSEnabled": false + } + }, + { + "index": 155, + "value": { + "ZoneID": 1075212, + "ZoneName": "dnscontrol.net", + "ID": 9445082270, + "Type": "NAPTR", + "Name": "test.dnscontrol.net", + "Data": "103 20 \"A\" \"E2U+sip\" \"\" example2.foo.com.", + "TTL": 300, + "Priority": 0, + "DDNSEnabled": false + } + }, + { + "index": 156, + "value": { + "ZoneID": 1075212, + "ZoneName": "dnscontrol.net", + "ID": 9445082270, + "Type": "NAPTR", + "Name": "test.dnscontrol.net", + "Data": "103 20 \"U\" \"E2U+email\" \"!^.*$!mailto:information@example.com!\" .", + "TTL": 300, + "Priority": 0, + "DDNSEnabled": false + } + }, + { + "index": 157, + "value": { + "ZoneID": 1075212, + "ZoneName": "dnscontrol.net", + "ID": 9445082271, + "Type": "NAPTR", + "Name": "test.dnscontrol.net", + "Data": "102 10 \"U\" \"E2U+email\" \"!^.*$!mailto:information@example.com!\" .", + "TTL": 300, + "Priority": 0, + "DDNSEnabled": false + } + }, + { + "index": 158, + "value": { + "ZoneID": 1075212, + "ZoneName": "dnscontrol.net", + "ID": 9445082273, + "Type": "PTR", + "Name": "4.dnscontrol.net", + "Data": "bar.com.", + "TTL": 300, + "Priority": 0, + "DDNSEnabled": false + } + }, + { + "index": 159, + "value": { + "ZoneID": 1075212, + "ZoneName": "dnscontrol.net", + "ID": 9445082273, + "Type": "PTR", + "Name": "4.dnscontrol.net", + "Data": "foo.com.", + "TTL": 300, + "Priority": 0, + "DDNSEnabled": false + } + }, + { + "index": 160, + "value": { + "ZoneID": 1075212, + "ZoneName": "dnscontrol.net", + "ID": 9445082274, + "Type": "SRV", + "Name": "_sip._tcp.dnscontrol.net", + "Data": "6 7 foo.com.", + "TTL": 300, + "Priority": 5, + "DDNSEnabled": false + } + }, + { + "index": 161, + "value": { + "ZoneID": 1075212, + "ZoneName": "dnscontrol.net", + "ID": 9445082274, + "Type": "SRV", + "Name": "_sip._tcp.dnscontrol.net", + "Data": "6 7 foo.com.", + "TTL": 300, + "Priority": 52, + "DDNSEnabled": false + } + }, + { + "index": 162, + "value": { + "ZoneID": 1075212, + "ZoneName": "dnscontrol.net", + "ID": 9445082274, + "Type": "SRV", + "Name": "_sip._tcp.dnscontrol.net", + "Data": "62 7 foo.com.", + "TTL": 300, + "Priority": 52, + "DDNSEnabled": false + } + }, + { + "index": 163, + "value": { + "ZoneID": 1075212, + "ZoneName": "dnscontrol.net", + "ID": 9445082274, + "Type": "SRV", + "Name": "_sip._tcp.dnscontrol.net", + "Data": "62 72 foo.com.", + "TTL": 300, + "Priority": 52, + "DDNSEnabled": false + } + }, + { + "index": 164, + "value": { + "ZoneID": 1075212, + "ZoneName": "dnscontrol.net", + "ID": 9445082275, + "Type": "SRV", + "Name": "_sip._tcp.dnscontrol.net", + "Data": "60 70 foo2.com.", + "TTL": 300, + "Priority": 5, + "DDNSEnabled": false + } + }, + { + "index": 165, + "value": { + "ZoneID": 1075212, + "ZoneName": "dnscontrol.net", + "ID": 9445082276, + "Type": "SRV", + "Name": "_sip._tcp.dnscontrol.net", + "Data": "65 75 foo3.com.", + "TTL": 300, + "Priority": 15, + "DDNSEnabled": false + } + }, + { + "index": 166, + "value": { + "ZoneID": 1075212, + "ZoneName": "dnscontrol.net", + "ID": 9445082276, + "Type": "SRV", + "Name": "_sip._tcp.dnscontrol.net", + "Data": "65 75 foo4.com.", + "TTL": 300, + "Priority": 15, + "DDNSEnabled": false + } + }, + { + "index": 167, + "value": { + "ZoneID": 1075212, + "ZoneName": "dnscontrol.net", + "ID": 9445082278, + "Type": "SRV", + "Name": "_sip._tcp.dnscontrol.net", + "Data": "65 75 .", + "TTL": 300, + "Priority": 15, + "DDNSEnabled": false + } + }, + { + "index": 168, + "value": { + "ZoneID": 1075212, + "ZoneName": "dnscontrol.net", + "ID": 9445082279, + "Type": "SRV", + "Name": "_sip._tcp.dnscontrol.net", + "Data": "6 7 foo.com.", + "TTL": 333, + "Priority": 5, + "DDNSEnabled": false + } + }, + { + "index": 169, + "value": { + "ZoneID": 1075212, + "ZoneName": "dnscontrol.net", + "ID": 9445082279, + "Type": "SRV", + "Name": "_sip._tcp.dnscontrol.net", + "Data": "6 7 foo.com.", + "TTL": 4400, + "Priority": 5, + "DDNSEnabled": false + } + }, + { + "index": 170, + "value": { + "ZoneID": 1075212, + "ZoneName": "dnscontrol.net", + "ID": 9445082280, + "Type": "SSHFP", + "Name": "dnscontrol.net", + "Data": "1 1 66C7D5540B7D75A1FB4C84FEBFA178AD99BDD67C", + "TTL": 300, + "Priority": 0, + "DDNSEnabled": false + } + }, + { + "index": 171, + "value": { + "ZoneID": 1075212, + "ZoneName": "dnscontrol.net", + "ID": 9445082280, + "Type": "SSHFP", + "Name": "dnscontrol.net", + "Data": "2 1 66C7D5540B7D75A1FB4C84FEBFA178AD99BDD67C", + "TTL": 300, + "Priority": 0, + "DDNSEnabled": false + } + }, + { + "index": 172, + "value": { + "ZoneID": 1075212, + "ZoneName": "dnscontrol.net", + "ID": 9445082280, + "Type": "SSHFP", + "Name": "dnscontrol.net", + "Data": "2 2 745A635BC46A397A5C4F21D437483005BCC40D7511FF15FBFAFE913A081559BC", + "TTL": 300, + "Priority": 0, + "DDNSEnabled": false + } + }, + { + "index": 173, + "value": { + "ZoneID": 1075212, + "ZoneName": "dnscontrol.net", + "ID": 9445082281, + "Type": "ALIAS", + "Name": "dnscontrol.net", + "Data": "foo.com.", + "TTL": 300, + "Priority": 0, + "DDNSEnabled": false + } + }, + { + "index": 174, + "value": { + "ZoneID": 1075212, + "ZoneName": "dnscontrol.net", + "ID": 9445082281, + "Type": "ALIAS", + "Name": "dnscontrol.net", + "Data": "foo2.com.", + "TTL": 300, + "Priority": 0, + "DDNSEnabled": false + } + }, + { + "index": 175, + "value": { + "ZoneID": 1075212, + "ZoneName": "dnscontrol.net", + "ID": 9445082282, + "Type": "A", + "Name": "foo.dnscontrol.net", + "Data": "1.2.3.4", + "TTL": 300, + "Priority": 0, + "DDNSEnabled": false + } + }, + { + "index": 176, + "value": { + "ZoneID": 1075212, + "ZoneName": "dnscontrol.net", + "ID": 9445082283, + "Type": "ALIAS", + "Name": "dnscontrol.net", + "Data": "foo.dnscontrol.net.", + "TTL": 300, + "Priority": 0, + "DDNSEnabled": false + } + }, + { + "index": 177, + "value": { + "ZoneID": 1075212, + "ZoneName": "dnscontrol.net", + "ID": 9445082284, + "Type": "ALIAS", + "Name": "test.dnscontrol.net", + "Data": "foo.com.", + "TTL": 300, + "Priority": 0, + "DDNSEnabled": false + } + }, + { + "index": 178, + "value": { + "ZoneID": 1075212, + "ZoneName": "dnscontrol.net", + "ID": 9445082284, + "Type": "ALIAS", + "Name": "test.dnscontrol.net", + "Data": "foo2.com.", + "TTL": 300, + "Priority": 0, + "DDNSEnabled": false + } + }, + { + "index": 179, + "value": { + "ZoneID": 1075212, + "ZoneName": "dnscontrol.net", + "ID": 9445082285, + "Type": "A", + "Name": "bar.dnscontrol.net", + "Data": "5.5.5.5", + "TTL": 300, + "Priority": 0, + "DDNSEnabled": false + } + }, + { + "index": 180, + "value": { + "ZoneID": 1075212, + "ZoneName": "dnscontrol.net", + "ID": 9445082286, + "Type": "A", + "Name": "foo.dnscontrol.net", + "Data": "1.2.3.4", + "TTL": 300, + "Priority": 0, + "DDNSEnabled": false + } + }, + { + "index": 181, + "value": { + "ZoneID": 1075212, + "ZoneName": "dnscontrol.net", + "ID": 9445082287, + "Type": "A", + "Name": "foo.dnscontrol.net", + "Data": "2.3.4.5", + "TTL": 300, + "Priority": 0, + "DDNSEnabled": false + } + }, + { + "index": 182, + "value": { + "ZoneID": 1075212, + "ZoneName": "dnscontrol.net", + "ID": 9445098122, + "Type": "TXT", + "Name": "foo.dnscontrol.net", + "Data": "\"simple\"", + "TTL": 300, + "Priority": 0, + "DDNSEnabled": false + } + }, + { + "index": 183, + "value": { + "ZoneID": 1075212, + "ZoneName": "dnscontrol.net", + "ID": 9445098123, + "Type": "CNAME", + "Name": "mail.dnscontrol.net", + "Data": "ghs.googlehosted.com.", + "TTL": 300, + "Priority": 0, + "DDNSEnabled": false + } + }, + { + "index": 184, + "value": { + "ZoneID": 1075212, + "ZoneName": "dnscontrol.net", + "ID": 9445098124, + "Type": "A", + "Name": "dnscontrol.net", + "Data": "1.2.3.4", + "TTL": 300, + "Priority": 0, + "DDNSEnabled": false + } + }, + { + "index": 185, + "value": { + "ZoneID": 1075212, + "ZoneName": "dnscontrol.net", + "ID": 9445098125, + "Type": "A", + "Name": "dnscontrol.net", + "Data": "2.3.4.5", + "TTL": 300, + "Priority": 0, + "DDNSEnabled": false + } + }, + { + "index": 186, + "value": { + "ZoneID": 1075212, + "ZoneName": "dnscontrol.net", + "ID": 9445098126, + "Type": "TXT", + "Name": "dnscontrol.net", + "Data": "\"simple\"", + "TTL": 300, + "Priority": 0, + "DDNSEnabled": false + } + }, + { + "index": 187, + "value": { + "ZoneID": 1075212, + "ZoneName": "dnscontrol.net", + "ID": 9445098127, + "Type": "A", + "Name": "bar.dnscontrol.net", + "Data": "5.5.5.5", + "TTL": 300, + "Priority": 0, + "DDNSEnabled": false + } + }, + { + "index": 188, + "value": { + "ZoneID": 1075212, + "ZoneName": "dnscontrol.net", + "ID": 9445098128, + "Type": "CNAME", + "Name": "mail.dnscontrol.net", + "Data": "ghs.googlehosted.com.", + "TTL": 300, + "Priority": 0, + "DDNSEnabled": false + } + }, + { + "index": 189, + "value": { + "ZoneID": 1075212, + "ZoneName": "dnscontrol.net", + "ID": 9445098129, + "Type": "A", + "Name": "dnscontrol.net", + "Data": "2.2.2.2", + "TTL": 300, + "Priority": 0, + "DDNSEnabled": false + } + }, + { + "index": 190, + "value": { + "ZoneID": 1075212, + "ZoneName": "dnscontrol.net", + "ID": 9445098130, + "Type": "TXT", + "Name": "dnscontrol.net", + "Data": "\"asimple\"", + "TTL": 300, + "Priority": 0, + "DDNSEnabled": false + } + }, + { + "index": 191, + "value": { + "ZoneID": 1075212, + "ZoneName": "dnscontrol.net", + "ID": 9445098131, + "Type": "A", + "Name": "foo.dnscontrol.net", + "Data": "1.2.3.4", + "TTL": 300, + "Priority": 0, + "DDNSEnabled": false + } + }, + { + "index": 192, + "value": { + "ZoneID": 1075212, + "ZoneName": "dnscontrol.net", + "ID": 9445098132, + "Type": "TXT", + "Name": "foo.dnscontrol.net", + "Data": "\"simple\"", + "TTL": 300, + "Priority": 0, + "DDNSEnabled": false + } + }, + { + "index": 193, + "value": { + "ZoneID": 1075212, + "ZoneName": "dnscontrol.net", + "ID": 9445098133, + "Type": "A", + "Name": "bar.bat.dnscontrol.net", + "Data": "5.5.5.5", + "TTL": 300, + "Priority": 0, + "DDNSEnabled": false + } + }, + { + "index": 194, + "value": { + "ZoneID": 1075212, + "ZoneName": "dnscontrol.net", + "ID": 9445098134, + "Type": "A", + "Name": "foo.bat.dnscontrol.net", + "Data": "1.2.3.4", + "TTL": 300, + "Priority": 0, + "DDNSEnabled": false + } + }, + { + "index": 195, + "value": { + "ZoneID": 1075212, + "ZoneName": "dnscontrol.net", + "ID": 9445098135, + "Type": "A", + "Name": "foo.bat.dnscontrol.net", + "Data": "2.3.4.5", + "TTL": 300, + "Priority": 0, + "DDNSEnabled": false + } + }, + { + "index": 196, + "value": { + "ZoneID": 1075212, + "ZoneName": "dnscontrol.net", + "ID": 9445098136, + "Type": "TXT", + "Name": "foo.bat.dnscontrol.net", + "Data": "\"simple\"", + "TTL": 300, + "Priority": 0, + "DDNSEnabled": false + } + }, + { + "index": 197, + "value": { + "ZoneID": 1075212, + "ZoneName": "dnscontrol.net", + "ID": 9445098137, + "Type": "CNAME", + "Name": "mail.bat.dnscontrol.net", + "Data": "ghs.googlehosted.com.", + "TTL": 300, + "Priority": 0, + "DDNSEnabled": false + } + }, + { + "index": 198, + "value": { + "ZoneID": 1075212, + "ZoneName": "dnscontrol.net", + "ID": 9445098140, + "Type": "A", + "Name": "foo.dnscontrol.net", + "Data": "1.1.1.1", + "TTL": 300, + "Priority": 0, + "DDNSEnabled": false + } + }, + { + "index": 199, + "value": { + "ZoneID": 1075212, + "ZoneName": "dnscontrol.net", + "ID": 9445098200, + "Type": "A", + "Name": "foo.dnscontrol.net", + "Data": "10.10.10.10", + "TTL": 300, + "Priority": 0, + "DDNSEnabled": false + } + }, + { + "index": 200, + "value": { + "ZoneID": 1075212, + "ZoneName": "dnscontrol.net", + "ID": 9445098200, + "Type": "A", + "Name": "foo.dnscontrol.net", + "Data": "11.11.11.11", + "TTL": 300, + "Priority": 0, + "DDNSEnabled": false + } + }, + { + "index": 201, + "value": { + "ZoneID": 1075212, + "ZoneName": "dnscontrol.net", + "ID": 9445098200, + "Type": "A", + "Name": "foo.dnscontrol.net", + "Data": "12.12.12.12", + "TTL": 300, + "Priority": 0, + "DDNSEnabled": false + } + }, + { + "index": 202, + "value": { + "ZoneID": 1075212, + "ZoneName": "dnscontrol.net", + "ID": 9445098200, + "Type": "A", + "Name": "foo.dnscontrol.net", + "Data": "13.13.13.13", + "TTL": 300, + "Priority": 0, + "DDNSEnabled": false + } + }, + { + "index": 203, + "value": { + "ZoneID": 1075212, + "ZoneName": "dnscontrol.net", + "ID": 9445098200, + "Type": "A", + "Name": "foo.dnscontrol.net", + "Data": "14.14.14.14", + "TTL": 300, + "Priority": 0, + "DDNSEnabled": false + } + }, + { + "index": 204, + "value": { + "ZoneID": 1075212, + "ZoneName": "dnscontrol.net", + "ID": 9445098486, + "Type": "AAAA", + "Name": "foo.dnscontrol.net", + "Data": "2003:dd:d7ff::fe71:aaaa", + "TTL": 300, + "Priority": 0, + "DDNSEnabled": false + } + }, + { + "index": 205, + "value": { + "ZoneID": 1075212, + "ZoneName": "dnscontrol.net", + "ID": 9445098488, + "Type": "MX", + "Name": "foo.dnscontrol.net", + "Data": "aspmx.l.google.com", + "TTL": 300, + "Priority": 10, + "DDNSEnabled": false + } + }, + { + "index": 206, + "value": { + "ZoneID": 1075212, + "ZoneName": "dnscontrol.net", + "ID": 9445098489, + "Type": "MX", + "Name": "foo.dnscontrol.net", + "Data": "alt1.aspmx.l.google.com", + "TTL": 300, + "Priority": 20, + "DDNSEnabled": false + } + }, + { + "index": 207, + "value": { + "ZoneID": 1075212, + "ZoneName": "dnscontrol.net", + "ID": 9445098491, + "Type": "A", + "Name": "zzz.dnscontrol.net", + "Data": "3.3.3.3", + "TTL": 300, + "Priority": 0, + "DDNSEnabled": false + } + }, + { + "index": 208, + "value": { + "ZoneID": 1075212, + "ZoneName": "dnscontrol.net", + "ID": 9445098492, + "Type": "A", + "Name": "zzz.dnscontrol.net", + "Data": "4.4.4.4", + "TTL": 300, + "Priority": 0, + "DDNSEnabled": false + } + }, + { + "index": 209, + "value": { + "ZoneID": 1075212, + "ZoneName": "dnscontrol.net", + "ID": 9445098493, + "Type": "AAAA", + "Name": "zzz.dnscontrol.net", + "Data": "2003:dd:d7ff::fe71:cccc", + "TTL": 300, + "Priority": 0, + "DDNSEnabled": false + } + }, + { + "index": 210, + "value": { + "ZoneID": 1075212, + "ZoneName": "dnscontrol.net", + "ID": 9445104891, + "Type": "CNAME", + "Name": "bar.dnscontrol.net", + "Data": "redact2.acm-validations.aws.", + "TTL": 300, + "Priority": 0, + "DDNSEnabled": false + } + }, + { + "index": 211, + "value": { + "ZoneID": 1075212, + "ZoneName": "dnscontrol.net", + "ID": 9445104892, + "Type": "CNAME", + "Name": "foo.dnscontrol.net", + "Data": "redact1.acm-validations.aws.", + "TTL": 300, + "Priority": 0, + "DDNSEnabled": false + } + }, + { + "index": 212, + "value": { + "ZoneID": 1075212, + "ZoneName": "dnscontrol.net", + "ID": 9445104893, + "Type": "A", + "Name": "dyndns-city1.dnscontrol.net", + "Data": "91.42.1.1", + "TTL": 300, + "Priority": 0, + "DDNSEnabled": false + } + }, + { + "index": 213, + "value": { + "ZoneID": 1075212, + "ZoneName": "dnscontrol.net", + "ID": 9445104894, + "Type": "AAAA", + "Name": "dyndns-city1.dnscontrol.net", + "Data": "2003:dd:d7ff::fe71:ce77", + "TTL": 300, + "Priority": 0, + "DDNSEnabled": false + } + }, + { + "index": 214, + "value": { + "ZoneID": 1075212, + "ZoneName": "dnscontrol.net", + "ID": 9445104895, + "Type": "A", + "Name": "dyndns-city2.dnscontrol.net", + "Data": "91.42.1.2", + "TTL": 300, + "Priority": 0, + "DDNSEnabled": false + } + }, + { + "index": 215, + "value": { + "ZoneID": 1075212, + "ZoneName": "dnscontrol.net", + "ID": 9445104896, + "Type": "AAAA", + "Name": "dyndns-city2.dnscontrol.net", + "Data": "2003:dd:d7ff::fe71:ce78", + "TTL": 300, + "Priority": 0, + "DDNSEnabled": false + } + }, + { + "index": 216, + "value": { + "ZoneID": 1075212, + "ZoneName": "dnscontrol.net", + "ID": 9445104897, + "Type": "A", + "Name": "testdefined.dnscontrol.net", + "Data": "2.2.2.2", + "TTL": 300, + "Priority": 0, + "DDNSEnabled": false + } + }, + { + "index": 217, + "value": { + "ZoneID": 1075212, + "ZoneName": "dnscontrol.net", + "ID": 9445104897, + "Type": "A", + "Name": "testdefined.dnscontrol.net", + "Data": "9.9.9.9", + "TTL": 300, + "Priority": 0, + "DDNSEnabled": false + } + }, + { + "index": 218, + "value": { + "ZoneID": 1075212, + "ZoneName": "dnscontrol.net", + "ID": 9445104898, + "Type": "A", + "Name": "testignore.dnscontrol.net", + "Data": "8.8.8.8", + "TTL": 300, + "Priority": 0, + "DDNSEnabled": false + } + }, + { + "index": 219, + "value": { + "ZoneID": 1075212, + "ZoneName": "dnscontrol.net", + "ID": 9445104899, + "Type": "A", + "Name": "hdyn.dnscontrol.net", + "Data": "1.2.3.4", + "TTL": 300, + "Priority": 0, + "DDNSEnabled": true + } + }, + { + "index": 220, + "value": { + "ZoneID": 1075212, + "ZoneName": "dnscontrol.net", + "ID": 9445104899, + "Type": "A", + "Name": "hdyn.dnscontrol.net", + "Data": "10.0.0.1", + "TTL": 300, + "Priority": 0, + "DDNSEnabled": true + } + }, + { + "index": 221, + "value": { + "ZoneID": 1075212, + "ZoneName": "dnscontrol.net", + "ID": 9445104899, + "Type": "A", + "Name": "hdyn.dnscontrol.net", + "Data": "5.6.7.8", + "TTL": 300, + "Priority": 0, + "DDNSEnabled": false + } + }, + { + "index": 222, + "value": { + "ZoneID": 1075212, + "ZoneName": "dnscontrol.net", + "ID": 9445104899, + "Type": "A", + "Name": "hdyn.dnscontrol.net", + "Data": "5.6.7.8", + "TTL": 300, + "Priority": 0, + "DDNSEnabled": true + } + }, + { + "index": 223, + "value": { + "ZoneID": 1075212, + "ZoneName": "dnscontrol.net", + "ID": 9445104927, + "Type": "A", + "Name": "hstatic.dnscontrol.net", + "Data": "2.2.2.2", + "TTL": 300, + "Priority": 0, + "DDNSEnabled": false + } + }, + { + "index": 224, + "value": { + "ZoneID": 1075212, + "ZoneName": "dnscontrol.net", + "ID": 9445105968, + "Type": "AAAA", + "Name": "hdynv6.dnscontrol.net", + "Data": "2607:f8b0:4006:820::2006", + "TTL": 300, + "Priority": 0, + "DDNSEnabled": true + } + }, + { + "index": 225, + "value": { + "ZoneID": 1075212, + "ZoneName": "dnscontrol.net", + "ID": 9445105968, + "Type": "AAAA", + "Name": "hdynv6.dnscontrol.net", + "Data": "2607:f8b0:4006:820::2013", + "TTL": 300, + "Priority": 0, + "DDNSEnabled": true + } + }, + { + "index": 226, + "value": { + "ZoneID": 1075212, + "ZoneName": "dnscontrol.net", + "ID": 9445107039, + "Type": "TXT", + "Name": "hdyntxt.dnscontrol.net", + "Data": "\"dynamic-value\"", + "TTL": 300, + "Priority": 0, + "DDNSEnabled": false + } + }, + { + "index": 227, + "value": { + "ZoneID": 1075212, + "ZoneName": "dnscontrol.net", + "ID": 9445107039, + "Type": "TXT", + "Name": "hdyntxt.dnscontrol.net", + "Data": "\"dynamic-value\"", + "TTL": 300, + "Priority": 0, + "DDNSEnabled": true + } + }, + { + "index": 228, + "value": { + "ZoneID": 1075212, + "ZoneName": "dnscontrol.net", + "ID": 9445107063, + "Type": "A", + "Name": "hkey.dnscontrol.net", + "Data": "1.2.3.4", + "TTL": 300, + "Priority": 0, + "DDNSEnabled": true + } + }, + { + "index": 229, + "value": { + "ZoneID": 1075212, + "ZoneName": "dnscontrol.net", + "ID": 9445107063, + "Type": "A", + "Name": "hkey.dnscontrol.net", + "Data": "5.6.7.8", + "TTL": 300, + "Priority": 0, + "DDNSEnabled": true + } + }, + { + "index": 230, + "value": { + "ZoneID": 1075212, + "ZoneName": "dnscontrol.net", + "ID": 9445107064, + "Type": "AAAA", + "Name": "hkeyv6.dnscontrol.net", + "Data": "2607:f8b0:4006:820::2006", + "TTL": 300, + "Priority": 0, + "DDNSEnabled": true + } + }, + { + "index": 231, + "value": { + "ZoneID": 1075212, + "ZoneName": "dnscontrol.net", + "ID": 9445107064, + "Type": "AAAA", + "Name": "hkeyv6.dnscontrol.net", + "Data": "2607:f8b0:4006:820::2013", + "TTL": 300, + "Priority": 0, + "DDNSEnabled": true + } + }, + { + "index": 232, + "value": { + "ZoneID": 1075212, + "ZoneName": "dnscontrol.net", + "ID": 9445107065, + "Type": "A", + "Name": "hdmix-dyn.dnscontrol.net", + "Data": "1.1.1.1", + "TTL": 300, + "Priority": 0, + "DDNSEnabled": true + } + }, + { + "index": 233, + "value": { + "ZoneID": 1075212, + "ZoneName": "dnscontrol.net", + "ID": 9445107066, + "Type": "A", + "Name": "hdmix-static.dnscontrol.net", + "Data": "2.2.2.2", + "TTL": 300, + "Priority": 0, + "DDNSEnabled": false + } + }, + { + "index": 234, + "value": { + "ZoneID": 1075212, + "ZoneName": "dnscontrol.net", + "ID": 9445107066, + "Type": "A", + "Name": "hdmix-static.dnscontrol.net", + "Data": "3.3.3.3", + "TTL": 300, + "Priority": 0, + "DDNSEnabled": false + } + }, + { + "index": 235, + "value": { + "ZoneID": 1075212, + "ZoneName": "dnscontrol.net", + "ID": 9445107067, + "Type": "TXT", + "Name": "final.dnscontrol.net", + "Data": "\"TestDNSProviders was successful!\"", + "TTL": 300, + "Priority": 0, + "DDNSEnabled": false + } + }, + { + "index": 236, + "value": { + "ZoneID": 1075212, + "ZoneName": "dnscontrol.net", + "ID": 9445107068, + "Type": "TXT", + "Name": "final.dnscontrol.net", + "Data": "\"TestDNSProviders was successful!\"", + "TTL": 300, + "Priority": 0, + "DDNSEnabled": false + } + }, + { + "index": 237, + "value": { + "ZoneID": 1075212, + "ZoneName": "dnscontrol.net", + "ID": 9445107069, + "Type": "NS", + "Name": "dnscontrol.net", + "Data": "ns1.example.com.", + "TTL": 300, + "Priority": 0, + "DDNSEnabled": false + } + }, + { + "index": 238, + "value": { + "ZoneID": 1075212, + "ZoneName": "dnscontrol.net", + "ID": 9445107070, + "Type": "NS", + "Name": "dnscontrol.net", + "Data": "ns2.example.com.", + "TTL": 300, + "Priority": 0, + "DDNSEnabled": false + } + } +] diff --git a/providers/hetznerv2/auditrecords.go b/providers/hetznerv2/auditrecords.go index cdf5b386a2..8d7bd790aa 100644 --- a/providers/hetznerv2/auditrecords.go +++ b/providers/hetznerv2/auditrecords.go @@ -1,12 +1,12 @@ package hetznerv2 import ( - "github.com/DNSControl/dnscontrol/v4/models" + "github.com/DNSControl/dnscontrol/v5/models" ) // AuditRecords returns a list of errors corresponding to the records // that aren't supported by this provider. If all records are // supported, an empty list is returned. -func AuditRecords(_ []*models.RecordConfig) []error { +func AuditRecords(_ models.Records) []error { return nil } diff --git a/providers/hetznerv2/hetznerv2Provider.go b/providers/hetznerv2/hetznerv2Provider.go index 6cb39a8ec5..1700970a9b 100644 --- a/providers/hetznerv2/hetznerv2Provider.go +++ b/providers/hetznerv2/hetznerv2Provider.go @@ -8,12 +8,11 @@ import ( "github.com/hetznercloud/hcloud-go/v2/hcloud" "golang.org/x/net/idna" - "github.com/DNSControl/dnscontrol/v4/models" - "github.com/DNSControl/dnscontrol/v4/pkg/diff2" - "github.com/DNSControl/dnscontrol/v4/pkg/providers" - "github.com/DNSControl/dnscontrol/v4/pkg/txtutil" - "github.com/DNSControl/dnscontrol/v4/pkg/version" - "github.com/DNSControl/dnscontrol/v4/pkg/zonecache" + "github.com/DNSControl/dnscontrol/v5/models" + "github.com/DNSControl/dnscontrol/v5/pkg/diff2" + "github.com/DNSControl/dnscontrol/v5/pkg/providers" + "github.com/DNSControl/dnscontrol/v5/pkg/version" + "github.com/DNSControl/dnscontrol/v5/pkg/zonecache" ) var features = providers.DocumentationNotes{ @@ -54,7 +53,7 @@ func init() { DisplayName: "Hetzner DNS", Kind: providers.KindDNS, DocsURL: "https://docs.dnscontrol.org/provider/hetzner_v2", - PortalURL: "https://dns.hetzner.com/settings/api-token", // TODO: Verify + PortalURL: "https://console.hetzner.com/projects", Fields: []providers.CredsField{ { Key: "api_token", @@ -104,16 +103,11 @@ func (h *hetznerv2Provider) fetchAllZones() (map[string]*hcloud.Zone, error) { // EnsureZoneExists creates a zone if it does not exist. func (h *hetznerv2Provider) EnsureZoneExists(dc *models.DomainConfig) error { - domain := dc.Name - encoded, err := idna.ToASCII(domain) - if err != nil { - return err - } - if ok, err2 := h.zoneCache.HasZone(encoded); err2 != nil || ok { + if ok, err2 := h.zoneCache.HasZone(dc.Name); err2 != nil || ok { return err2 } result, _, err := h.client.Zone.Create(context.Background(), hcloud.ZoneCreateOpts{ - Name: encoded, + Name: dc.Name, Mode: hcloud.ZoneModePrimary, }) if err != nil { @@ -127,18 +121,13 @@ func (h *hetznerv2Provider) EnsureZoneExists(dc *models.DomainConfig) error { if err != nil { return err } - h.zoneCache.SetZone(encoded, z) + h.zoneCache.SetZone(dc.Name, z) return nil } // GetZoneRecordsCorrections returns a list of corrections that will turn existing records into dc.Records. func (h *hetznerv2Provider) GetZoneRecordsCorrections(dc *models.DomainConfig, existingRecords models.Records) ([]*models.Correction, int, error) { - encoded, err := idna.ToASCII(dc.Name) - if err != nil { - return nil, 0, err - } - - z, err := h.zoneCache.GetZone(encoded) + z, err := h.zoneCache.GetZone(dc.Name) if err != nil { return nil, 0, err } @@ -168,7 +157,7 @@ func (h *hetznerv2Provider) GetZoneRecordsCorrections(dc *models.DomainConfig, e } for _, r := range instruction.New { opts.Records = append(opts.Records, hcloud.ZoneRRSetRecord{ - Value: r.GetTargetCombinedFunc(txtutil.EncodeQuoted), + Value: r.GetRDATA().String(), }) } reports = append(reports, &models.Correction{ @@ -194,7 +183,7 @@ func (h *hetznerv2Provider) GetZoneRecordsCorrections(dc *models.DomainConfig, e opts := hcloud.ZoneRRSetSetRecordsOpts{} for _, r := range instruction.New { opts.Records = append(opts.Records, hcloud.ZoneRRSetRecord{ - Value: r.GetTargetCombinedFunc(txtutil.EncodeQuoted), + Value: r.GetRDATA().String(), }) } _, _, err2 := h.client.Zone.SetRRSetRecords(context.Background(), rrSet, opts) @@ -232,48 +221,50 @@ func (h *hetznerv2Provider) GetNameservers(domain string) ([]*models.Nameserver, // GetZoneRecords gets the records of a zone and returns them in RecordConfig format. func (h *hetznerv2Provider) GetZoneRecords(dc *models.DomainConfig) (models.Records, error) { - domain := dc.Name - - encoded, err := idna.ToASCII(domain) - if err != nil { - return nil, err - } - z, err := h.zoneCache.GetZone(encoded) + z, err := h.zoneCache.GetZone(dc.Name) if err != nil { return nil, err } - opts := hcloud.ZoneRRSetListOpts{} - opts.PerPage = 100 + opts := hcloud.ZoneRRSetListOpts{ + PerPage: 100} records, err := h.client.Zone.AllRRSetsWithOpts(context.Background(), z, opts) if err != nil { return nil, err } - existingRecords := make([]*models.RecordConfig, 0, len(records)) + existingRecords := make(models.Records, 0, len(records)) for _, rrSet := range records { - if rrSet.Type == hcloud.ZoneRRSetTypeSOA { - // SOA records are not available for editing, hide them. - continue - } - base := models.RecordConfig{ - Type: string(rrSet.Type), - Original: rrSet, - } - base.SetLabel(rrSet.Name, z.Name) - if rrSet.TTL != nil { - base.TTL = uint32(*rrSet.TTL) - } else { - base.TTL = uint32(z.TTL) + recs, err := nativeToRecords(dc, rrSet, uint32(z.TTL)) + if err != nil { + return nil, err } + existingRecords = append(existingRecords, recs...) + } + return existingRecords, nil +} - for _, r := range rrSet.Records { - rc := base - if err = rc.PopulateFromStringFunc(rc.Type, r.Value, z.Name, txtutil.ParseQuoted); err != nil { - return nil, err - } - existingRecords = append(existingRecords, &rc) +// nativeToRecords converts a Hetzner RRSet to RecordConfigs, one per value. +// zoneTTL is the TTL of the zone the RRSet belongs to, used when the RRSet does +// not carry one of its own. It returns nothing for SOA RRSets, which are hidden. +func nativeToRecords(dc *models.DomainConfig, rrSet *hcloud.ZoneRRSet, zoneTTL uint32) (models.Records, error) { + if rrSet.Type == hcloud.ZoneRRSetTypeSOA { + // SOA records are not available for editing, hide them. + return nil, nil + } + ttl := zoneTTL + if rrSet.TTL != nil { + ttl = uint32(*rrSet.TTL) + } + + recs := make(models.Records, 0, len(rrSet.Records)) + for _, r := range rrSet.Records { + rc, err := dc.NewRecordConfigParse(dc.LabelFromShort(rrSet.Name), ttl, string(rrSet.Type), r.Value) + if err != nil { + return nil, err } + rc.Original = rrSet + recs = append(recs, rc) } - return existingRecords, nil + return recs, nil } // ListZones lists the zones on this account. diff --git a/providers/hostingde/api.go b/providers/hostingde/api.go index e2f39a4007..359d255522 100644 --- a/providers/hostingde/api.go +++ b/providers/hostingde/api.go @@ -7,7 +7,7 @@ import ( "io" "net/http" - "github.com/DNSControl/dnscontrol/v4/pkg/diff" + "github.com/DNSControl/dnscontrol/v5/pkg/diff2" "golang.org/x/net/idna" ) @@ -127,24 +127,24 @@ func (hp *hostingdeProvider) updateNameservers(nss []string, domain string) func } } -func (hp *hostingdeProvider) updateZone(zc *zoneConfig, options *dnsSecOptions, create, del, mod diff.Changeset) error { +func (hp *hostingdeProvider) updateZone(zc *zoneConfig, options *dnsSecOptions, create, del, mod diff2.ChangeList) error { toAdd := []*record{} for _, c := range create { - r := recordToNative(c.Desired) + r := recordToNative(c.New[0]) toAdd = append(toAdd, r) } toDelete := []*record{} for _, d := range del { - r := recordToNative(d.Existing) - r.ID = d.Existing.Original.(record).ID + r := recordToNative(d.Old[0]) + r.ID = d.Old[0].Original.(record).ID toDelete = append(toDelete, r) } toModify := []*record{} for _, m := range mod { - r := recordToNative(m.Desired) - r.ID = m.Existing.Original.(record).ID + r := recordToNative(m.New[0]) + r.ID = m.Old[0].Original.(record).ID toModify = append(toModify, r) } diff --git a/providers/hostingde/auditrecords.go b/providers/hostingde/auditrecords.go index d7942964af..b914886658 100644 --- a/providers/hostingde/auditrecords.go +++ b/providers/hostingde/auditrecords.go @@ -1,14 +1,14 @@ package hostingde import ( - "github.com/DNSControl/dnscontrol/v4/models" - "github.com/DNSControl/dnscontrol/v4/pkg/rejectif" + "github.com/DNSControl/dnscontrol/v5/models" + "github.com/DNSControl/dnscontrol/v5/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 { +func AuditRecords(records models.Records) []error { a := rejectif.Auditor{} a.Add("SRV", rejectif.SrvHasNullTarget) // Last verified 2023-01-19 diff --git a/providers/hostingde/hostingdeProvider.go b/providers/hostingde/hostingdeProvider.go index 81068c1d39..8321ca9059 100644 --- a/providers/hostingde/hostingdeProvider.go +++ b/providers/hostingde/hostingdeProvider.go @@ -9,9 +9,10 @@ import ( "strings" "time" - "github.com/DNSControl/dnscontrol/v4/models" - "github.com/DNSControl/dnscontrol/v4/pkg/diff" - "github.com/DNSControl/dnscontrol/v4/pkg/providers" + dnsv2 "codeberg.org/miekg/dns" + "github.com/DNSControl/dnscontrol/v5/models" + "github.com/DNSControl/dnscontrol/v5/pkg/diff2" + "github.com/DNSControl/dnscontrol/v5/pkg/providers" ) var defaultNameservers = []string{"ns1.hosting.de", "ns2.hosting.de", "ns3.hosting.de"} @@ -122,16 +123,16 @@ func (hp *hostingdeProvider) GetZoneRecords(dc *models.DomainConfig) (models.Rec if err != nil { return nil, err } - return hp.APIRecordsToStandardRecordsModel(domain, zone.Records) + return hp.APIRecordsToStandardRecordsModel(dc, zone.Records) } -func (hp *hostingdeProvider) APIRecordsToStandardRecordsModel(domain string, src []record) (models.Records, error) { - records := []*models.RecordConfig{} +func (hp *hostingdeProvider) APIRecordsToStandardRecordsModel(dc *models.DomainConfig, src []record) (models.Records, error) { + records := models.Records{} for _, r := range src { if r.Type == "SOA" { continue } - newr, err := r.nativeToRecord(domain) + newr, err := r.nativeToRecord(dc) if err != nil { return nil, err } @@ -166,12 +167,27 @@ func (hp *hostingdeProvider) GetZoneRecordsCorrections(dc *models.DomainConfig, return nil, 0, err } - toReport, create, del, mod, actualChangeCount, err := diff.NewCompat(dc).IncrementalDiff(records) + changeset, actualChangeCount, err := diff2.ByRecord(records, dc, nil) if err != nil { return nil, 0, err } - // Start corrections with the reports - corrections := diff.GenerateMessageCorrections(toReport) + + var corrections []*models.Correction + var create, del, mod diff2.ChangeList + for _, change := range changeset { + switch change.Type { + case diff2.REPORT: + corrections = append(corrections, &models.Correction{Msg: change.MsgsJoined}) + case diff2.CREATE: + create = append(create, change) + case diff2.DELETE: + del = append(del, change) + case diff2.CHANGE: + mod = append(mod, change) + default: + panic(fmt.Sprintf("unhandled change.Type %s", change.Type)) + } + } // NOPURGE if dc.KeepUnknown { @@ -180,7 +196,7 @@ func (hp *hostingdeProvider) GetZoneRecordsCorrections(dc *models.DomainConfig, // remove SOA record from corrections as it is handled separately for i, r := range create { - if r.Desired.Type == "SOA" { + if r.New[0].Type == "SOA" { create = append(create[:i], create[i+1:]...) break } @@ -192,7 +208,7 @@ func (hp *hostingdeProvider) GetZoneRecordsCorrections(dc *models.DomainConfig, msg := []string{} for _, c := range append(del, append(create, mod...)...) { - msg = append(msg, c.String()) + msg = append(msg, c.MsgsJoined) } var desiredSoa *models.RecordConfig @@ -203,20 +219,18 @@ func (hp *hostingdeProvider) GetZoneRecordsCorrections(dc *models.DomainConfig, } } if desiredSoa == nil { - desiredSoa = &models.RecordConfig{} + desiredSoa = dc.MustNewRecordConfig("@", 0, dnsv2.TypeSOA, "ns", 1, 0, 0, 0, 0) } defaultSoa := &hp.defaultSoa - // Commented out because this can not happen: - // if defaultSoa == nil { - // defaultSoa = &soaValues{} - // } + + df := desiredSoa.AsSOA() newSOA := soaValues{ - Refresh: firstNonZero(desiredSoa.SoaRefresh, defaultSoa.Refresh, 86400), - Retry: firstNonZero(desiredSoa.SoaRetry, defaultSoa.Retry, 7200), - Expire: firstNonZero(desiredSoa.SoaExpire, defaultSoa.Expire, 3600000), - NegativeTTL: firstNonZero(desiredSoa.SoaMinttl, defaultSoa.NegativeTTL, 900), + Refresh: firstNonZero(df.Refresh, defaultSoa.Refresh, 86400), + Retry: firstNonZero(df.Retry, defaultSoa.Retry, 7200), + Expire: firstNonZero(df.Expire, defaultSoa.Expire, 3600000), + NegativeTTL: firstNonZero(df.Minttl, defaultSoa.NegativeTTL, 900), TTL: firstNonZero(desiredSoa.TTL, defaultSoa.TTL, 86400), } @@ -226,10 +240,10 @@ func (hp *hostingdeProvider) GetZoneRecordsCorrections(dc *models.DomainConfig, zoneChanged = true } - if desiredSoa.SoaMbox != "" { + if df.Mbox != "" { desiredMail := "" - if desiredSoa.SoaMbox[len(desiredSoa.SoaMbox)-1] != '.' { - desiredMail = desiredSoa.SoaMbox + "@" + dc.Name + if df.Mbox[len(df.Mbox)-1] != '.' { + desiredMail = df.Mbox + "@" + dc.Name } if desiredMail != "" && zone.ZoneConfig.EmailAddress != desiredMail { msg = append(msg, fmt.Sprintf("Changing SOA Mail from %s to %s", zone.ZoneConfig.EmailAddress, desiredMail)) diff --git a/providers/hostingde/types.go b/providers/hostingde/types.go index 882b37061c..03912963d9 100644 --- a/providers/hostingde/types.go +++ b/providers/hostingde/types.go @@ -3,11 +3,11 @@ package hostingde import ( "encoding/json" "fmt" - "log" "net" // Needed for communicating with provider API. "strings" - "github.com/DNSControl/dnscontrol/v4/models" + dnsv2 "codeberg.org/miekg/dns" + "github.com/DNSControl/dnscontrol/v5/models" "github.com/pkg/errors" ) @@ -136,7 +136,7 @@ type responseData struct { TotalPages uint `json:"totalPages"` } -func (r record) nativeToRecord(domain string) (*models.RecordConfig, error) { +func (r record) nativeToRecord(dc *models.DomainConfig) (*models.RecordConfig, error) { // normalize cname,mx,ns records with dots to be consistent with our config format. if r.Type == "ALIAS" || r.Type == "CNAME" || r.Type == "MX" || r.Type == "NS" || r.Type == "SRV" { if r.Content != "." { @@ -144,31 +144,28 @@ func (r record) nativeToRecord(domain string) (*models.RecordConfig, error) { } } - rc := &models.RecordConfig{ - Type: "", - TTL: r.TTL, - MxPreference: r.Priority, - SrvPriority: r.Priority, - Original: r, - } - rc.SetLabelFromFQDN(r.Name, domain) - + label := dc.ToShort(r.Name) + var rc *models.RecordConfig var err error + ttl := r.TTL switch r.Type { case "ALIAS": - rc.Type = r.Type - err = rc.SetTarget(r.Content) + rc, err = dc.NewRecordConfig(label, ttl, r.Type, r.Content) case "NULLMX": - err = rc.PopulateFromString("MX", "0 .", domain) + rc, err = dc.NewRecordConfig(label, ttl, "MX", 0, ".") case "MX": - err = rc.SetTargetMX(uint16(r.Priority), r.Content) + rc, err = dc.NewRecordConfig(label, ttl, r.Type, r.Priority, r.Content) case "PTR": - rc.Type = r.Type - err = rc.SetTarget(r.Content + ".") + rc, err = dc.NewRecordConfig(label, ttl, r.Type, r.Content+".") case "SRV": - err = rc.SetTargetSRVPriorityString(uint16(r.Priority), r.Content) + rc, err = dc.NewRecordConfigParse(label, ttl, r.Type, fmt.Sprintf("%d %s", r.Priority, r.Content)) + case "TXT": + rc, err = dc.NewRecordConfig(label, ttl, r.Type, r.Content) default: - err = rc.PopulateFromString(r.Type, r.Content, domain) + rc, err = dc.NewRecordConfigParse(label, ttl, r.Type, r.Content) + } + if err == nil { + rc.Original = r } return rc, err } @@ -177,14 +174,15 @@ func recordToNative(rc *models.RecordConfig) *record { record := &record{ Name: rc.NameFQDN, Type: rc.Type, - Content: strings.TrimSuffix(rc.GetTargetCombined(), "."), + Content: strings.TrimSuffix(rc.GetRDATA().String(), "."), TTL: rc.TTL, } - switch rc.Type { // #rtype_variations - case "A", "AAAA", "ALIAS", "CAA", "CNAME", "DNSKEY", "DS", "NS", "NSEC", "NSEC3", "NSEC3PARAM", "PTR", "RRSIG", "SSHFP", "TSLA": - // Nothing special. - case "TXT": + switch rc.TypeNum { + case dnsv2.TypeTXT: + // TODO(tlim): I think all of this can be replaced by: + // record.Content = rc.AsTXT().String() + // TODO(tlim): Move this to a function with unit tests. txtStrings := make([]string, rc.GetTargetTXTSegmentCount()) copy(txtStrings, rc.GetTargetTXTSegmented()) @@ -195,18 +193,20 @@ func recordToNative(rc *models.RecordConfig) *record { } record.Content = strings.Join(txtStrings, " ") - case "MX": - record.Priority = rc.MxPreference - record.Content = strings.TrimSuffix(rc.GetTargetField(), ".") + case dnsv2.TypeMX: + mx := rc.AsMX() + record.Priority = mx.Preference + record.Content = strings.TrimSuffix(mx.Mx, ".") if record.Content == "" { record.Type = "NULLMX" record.Priority = 10 } - case "SRV": - record.Priority = rc.SrvPriority - record.Content = fmt.Sprintf("%d %d %s", rc.SrvWeight, rc.SrvPort, strings.TrimSuffix(rc.GetTargetField(), ".")) + case dnsv2.TypeSRV: + srv := rc.AsSRV() + record.Priority = srv.Priority + record.Content = fmt.Sprintf("%d %d %s", srv.Weight, srv.Port, strings.TrimSuffix(srv.Target, ".")) default: - log.Printf("hosting.de rtype %v unimplemented", rc.Type) + // no-op } return record diff --git a/providers/huaweicloud/auditrecords.go b/providers/huaweicloud/auditrecords.go index 4af962eb46..622c634aa8 100644 --- a/providers/huaweicloud/auditrecords.go +++ b/providers/huaweicloud/auditrecords.go @@ -1,14 +1,14 @@ package huaweicloud import ( - "github.com/DNSControl/dnscontrol/v4/models" - "github.com/DNSControl/dnscontrol/v4/pkg/rejectif" + "github.com/DNSControl/dnscontrol/v5/models" + "github.com/DNSControl/dnscontrol/v5/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 { +func AuditRecords(records models.Records) []error { a := rejectif.Auditor{} // go test -v -run 'TestDNSProviders/.*/.*NullMX(Apex)?:(create|unnull|renull)$' -args -verbose -profile HUAWEICLOUD a.Add("MX", rejectif.MxNull) // Last verified 2026-05-18 diff --git a/providers/huaweicloud/convert.go b/providers/huaweicloud/convert.go index 6104401316..d0c5c86dc0 100644 --- a/providers/huaweicloud/convert.go +++ b/providers/huaweicloud/convert.go @@ -6,8 +6,8 @@ import ( "slices" "strconv" - "github.com/DNSControl/dnscontrol/v4/models" - "github.com/DNSControl/dnscontrol/v4/pkg/printer" + "github.com/DNSControl/dnscontrol/v5/models" + "github.com/DNSControl/dnscontrol/v5/pkg/printer" "github.com/huaweicloud/huaweicloud-sdk-go-v3/services/dns/v2/model" ) @@ -28,25 +28,26 @@ func getRRSetIDFromRecords(rcs models.Records) []string { return slices.Compact(ids) } -func nativeToRecords(n *model.ShowRecordSetByZoneResp, zoneName string) (models.Records, error) { +func nativeToRecords(n *model.ShowRecordSetByZoneResp, dc *models.DomainConfig) (models.Records, error) { if n.Name == nil || n.Type == nil || n.Records == nil || n.Ttl == nil { return nil, fmt.Errorf("missing required fields in Huaweicloud's RRset: %+v", n) } var rcs models.Records - recName := *n.Name + label := dc.ToShort(*n.Name) recType := *n.Type + ttl := uint32(*n.Ttl) // Split into records for _, value := range *n.Records { - rc := &models.RecordConfig{ - TTL: uint32(*n.Ttl), - Original: n, - Metadata: map[string]string{}, - } - rc.SetLabelFromFQDN(recName, zoneName) - if err := rc.PopulateFromString(recType, value, zoneName); err != nil { + var rc *models.RecordConfig + var err error + rc, err = dc.NewRecordConfigParse(label, ttl, recType, value) + if err != nil { return nil, fmt.Errorf("unparsable record received from Huaweicloud: %w", err) } + + rc.Original = n + if n.Line != nil { rc.Metadata[metaLine] = *n.Line } @@ -56,6 +57,7 @@ func nativeToRecords(n *model.ShowRecordSetByZoneResp, zoneName string) (models. if n.Description != nil { rc.Metadata[metaKey] = *n.Description } + rcs = append(rcs, rc) } @@ -113,11 +115,7 @@ func recordsToNative(rcs models.Records, expectedKey models.RecordKey) (*model.S if key != expectedKey { continue } - val := r.GetTargetCombined() - // special case for empty TXT records - if key.Type == "TXT" && len(val) == 0 { - val = "\"\"" - } + val := r.GetRDATA().String() resultVal = append(resultVal, val) if resultTTL == 0 { diff --git a/providers/huaweicloud/convert_test.go b/providers/huaweicloud/convert_test.go new file mode 100644 index 0000000000..36d83f7d47 --- /dev/null +++ b/providers/huaweicloud/convert_test.go @@ -0,0 +1,31 @@ +package huaweicloud + +import ( + "testing" + + "github.com/DNSControl/dnscontrol/v5/models" + "github.com/huaweicloud/huaweicloud-sdk-go-v3/services/dns/v2/model" +) + +func TestNativeToRecords(t *testing.T) { + dc, err := models.NewDomainConfig("example.com") + if err != nil { + t.Fatal(err) + } + name, rtype, ttl := "www.example.com.", "A", int32(300) + values := []string{"192.0.2.1", "192.0.2.2"} + records, err := nativeToRecords(&model.ShowRecordSetByZoneResp{ + Name: &name, Type: &rtype, Ttl: &ttl, Records: &values, + }, dc) + if err != nil { + t.Fatal(err) + } + if len(records) != 2 { + t.Fatalf("got %d records, want 2", len(records)) + } + for i, want := range values { + if got := records[i].GetRDATA().String(); got != want { + t.Errorf("record %d target = %q, want %q", i, got, want) + } + } +} diff --git a/providers/huaweicloud/dnssec.go b/providers/huaweicloud/dnssec.go index 917c6a848a..5b1330974a 100644 --- a/providers/huaweicloud/dnssec.go +++ b/providers/huaweicloud/dnssec.go @@ -1,7 +1,7 @@ package huaweicloud import ( - "github.com/DNSControl/dnscontrol/v4/models" + "github.com/DNSControl/dnscontrol/v5/models" "github.com/huaweicloud/huaweicloud-sdk-go-v3/services/dns/v2/model" ) diff --git a/providers/huaweicloud/huaweicloudProvider.go b/providers/huaweicloud/huaweicloudProvider.go index e0365166f3..8d3f623c93 100644 --- a/providers/huaweicloud/huaweicloudProvider.go +++ b/providers/huaweicloud/huaweicloudProvider.go @@ -5,9 +5,9 @@ import ( "strings" "time" - "github.com/DNSControl/dnscontrol/v4/models" - "github.com/DNSControl/dnscontrol/v4/pkg/printer" - "github.com/DNSControl/dnscontrol/v4/pkg/providers" + "github.com/DNSControl/dnscontrol/v5/models" + "github.com/DNSControl/dnscontrol/v5/pkg/printer" + "github.com/DNSControl/dnscontrol/v5/pkg/providers" "github.com/huaweicloud/huaweicloud-sdk-go-v3/core/auth/basic" "github.com/huaweicloud/huaweicloud-sdk-go-v3/core/region" dnssdk "github.com/huaweicloud/huaweicloud-sdk-go-v3/services/dns/v2" diff --git a/providers/huaweicloud/listzones.go b/providers/huaweicloud/listzones.go index 18b5b6353e..79e024050a 100644 --- a/providers/huaweicloud/listzones.go +++ b/providers/huaweicloud/listzones.go @@ -3,8 +3,8 @@ package huaweicloud import ( "strings" - "github.com/DNSControl/dnscontrol/v4/models" - "github.com/DNSControl/dnscontrol/v4/pkg/printer" + "github.com/DNSControl/dnscontrol/v5/models" + "github.com/DNSControl/dnscontrol/v5/pkg/printer" "github.com/huaweicloud/huaweicloud-sdk-go-v3/services/dns/v2/model" ) diff --git a/providers/huaweicloud/records.go b/providers/huaweicloud/records.go index 3ca8763d80..4ff4a8ba5c 100644 --- a/providers/huaweicloud/records.go +++ b/providers/huaweicloud/records.go @@ -5,8 +5,8 @@ import ( "net/url" "slices" - "github.com/DNSControl/dnscontrol/v4/models" - "github.com/DNSControl/dnscontrol/v4/pkg/diff2" + "github.com/DNSControl/dnscontrol/v5/models" + "github.com/DNSControl/dnscontrol/v5/pkg/diff2" "github.com/huaweicloud/huaweicloud-sdk-go-v3/services/dns/v2/model" ) @@ -27,12 +27,12 @@ func (c *huaweicloudProvider) GetZoneRecords(dc *models.DomainConfig) (models.Re } // Convert rrsets to DNSControl's RecordConfig - existingRecords := []*models.RecordConfig{} + existingRecords := models.Records{} for _, rec := range *records { if *rec.Type == "SOA" { continue } - nativeRecords, err := nativeToRecords(&rec, domain) + nativeRecords, err := nativeToRecords(&rec, dc) if err != nil { return nil, err } diff --git a/providers/infomaniak/auditrecords.go b/providers/infomaniak/auditrecords.go index e760f507ce..5b4d78e38e 100644 --- a/providers/infomaniak/auditrecords.go +++ b/providers/infomaniak/auditrecords.go @@ -1,15 +1,23 @@ package infomaniak import ( - "github.com/DNSControl/dnscontrol/v4/models" - "github.com/DNSControl/dnscontrol/v4/pkg/rejectif" + "github.com/DNSControl/dnscontrol/v5/models" + "github.com/DNSControl/dnscontrol/v5/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 { +func AuditRecords(records models.Records) []error { a := rejectif.Auditor{} + a.Add("MX", rejectif.MxNull) // Last verified 2026-07-26 + + a.Add("SRV", rejectif.SrvHasNullTarget) // Last verified 2026-07-26 + + a.Add("TXT", rejectif.TxtIsEmpty) // Last verified 2026-07-26 + + a.Add("TXT", rejectif.TxtHasDoubleQuotes) // Last verified 2026-08-26 + return a.Audit(records) } diff --git a/providers/infomaniak/infomaniakProvider.go b/providers/infomaniak/infomaniakProvider.go index a8bb60368a..2a21eb942c 100644 --- a/providers/infomaniak/infomaniakProvider.go +++ b/providers/infomaniak/infomaniakProvider.go @@ -6,10 +6,10 @@ import ( "fmt" "strings" - "github.com/DNSControl/dnscontrol/v4/models" - "github.com/DNSControl/dnscontrol/v4/pkg/diff2" - "github.com/DNSControl/dnscontrol/v4/pkg/providers" - "github.com/miekg/dns/dnsutil" + dnsv2 "codeberg.org/miekg/dns" + "github.com/DNSControl/dnscontrol/v5/models" + "github.com/DNSControl/dnscontrol/v5/pkg/diff2" + "github.com/DNSControl/dnscontrol/v5/pkg/providers" ) // infomaniakProvider is the handle for operations. @@ -71,101 +71,87 @@ func addTrailingDot(target string) string { } // toRecordConfig converts a DNS record from Infomaniak API to RecordConfig. -func toRecordConfig(domain string, r dnsRecord) (*models.RecordConfig, error) { - rc := &models.RecordConfig{ - TTL: uint32(r.TTL), - Original: r, - } - +func toRecordConfig(dc *models.DomainConfig, r dnsRecord) (*models.RecordConfig, error) { // Handle the source/label - Infomaniak uses empty string or "." for apex label := r.Source if label == "" || label == "." { label = "@" } - rc.SetLabel(label, domain) - // Parse the target based on record type rtype := r.Type target := r.Target + ttl := uint32(r.TTL) + var rc *models.RecordConfig var err error switch rtype { - case "A", "AAAA": - rc.Type = rtype - err = rc.SetTarget(target) + // case "A", "AAAA": + // rc, err = dc.NewRecordConfig(label, ttl, rtype, target) case "CNAME", "NS", "DNAME": - rc.Type = rtype - // Add trailing dot and use AddOrigin to properly qualify the target - err = rc.SetTarget(dnsutil.AddOrigin(addTrailingDot(target), domain)) + rc, err = dc.NewRecordConfig(label, ttl, rtype, addTrailingDot(target)) case "MX": // Infomaniak returns MX as "priority target" (e.g., "5 mta-gw.infomaniak.ch") - rc.Type = rtype - err = rc.SetTargetMXString(addTrailingDot(target)) + rc, err = dc.NewRecordConfigParse(label, ttl, rtype, addTrailingDot(target)) case "TXT": - rc.Type = rtype - // Infomaniak API returns TXT values wrapped in quotes, strip them - if len(target) >= 2 && strings.HasPrefix(target, "\"") && strings.HasSuffix(target, "\"") { - target = target[1 : len(target)-1] - } - err = rc.SetTargetTXT(target) + // Infomaniak returns TXT in RFC 1035 presentation format: one or more + // quoted character-strings. Values longer than 255 octets come back + // split into multiple `"..." "..."` strings, so parse them (naively + // stripping the outer quotes leaves the interior `" "` and breaks the + // round-trip). See issue #4748. + rc, err = dc.NewRecordConfigParse(label, ttl, rtype, target) case "SRV": // Infomaniak returns SRV as "priority weight port target" - rc.Type = rtype - err = rc.SetTargetSRVString(addTrailingDot(target)) + rc, err = dc.NewRecordConfigParse(label, ttl, rtype, addTrailingDot(target)) case "CAA": // Infomaniak returns CAA as "flags tag value" (e.g., "0 issue letsencrypt.org") - rc.Type = rtype - err = rc.SetTargetCAAString(target) + rc, err = dc.NewRecordConfigParse(label, ttl, rtype, target) case "DS": // Infomaniak returns DS as "keytag algorithm digesttype digest" // Note: Infomaniak may split long digest data with spaces, so we need to rejoin them - rc.Type = rtype parts := strings.Fields(target) if len(parts) >= 4 { // Rejoin all parts after the first 3 (keytag, algorithm, digesttype) as the digest digest := strings.Join(parts[3:], "") target = fmt.Sprintf("%s %s %s %s", parts[0], parts[1], parts[2], digest) } - err = rc.SetTargetDSString(target) + rc, err = dc.NewRecordConfigParse(label, ttl, rtype, target) case "SSHFP": // Infomaniak returns SSHFP as "algorithm fingerprint_type fingerprint" // Note: Infomaniak may split long fingerprint data with spaces, so we need to rejoin them - rc.Type = rtype parts := strings.Fields(target) if len(parts) >= 3 { // Rejoin all parts after the first 2 (algorithm, fingerprint_type) as the fingerprint fingerprint := strings.Join(parts[2:], "") target = fmt.Sprintf("%s %s %s", parts[0], parts[1], fingerprint) } - err = rc.SetTargetSSHFPString(target) + rc, err = dc.NewRecordConfigParse(label, ttl, rtype, target) case "TLSA": // Infomaniak returns TLSA as "usage selector matching_type certificate" // Note: Infomaniak may split long certificate data with spaces, so we need to rejoin them - rc.Type = rtype parts := strings.Fields(target) if len(parts) >= 4 { // Rejoin all parts after the first 3 (usage, selector, matching_type) as the certificate certificate := strings.Join(parts[3:], "") target = fmt.Sprintf("%s %s %s %s", parts[0], parts[1], parts[2], certificate) } - err = rc.SetTargetTLSAString(target) + rc, err = dc.NewRecordConfigParse(label, ttl, rtype, target) default: - rc.Type = rtype - err = rc.SetTarget(target) + rc, err = dc.NewRecordConfig(label, ttl, rtype, target) } if err != nil { return nil, fmt.Errorf("unparsable record type=%q target=%q received from Infomaniak: %w", rtype, target, err) } + rc.Original = r return rc, nil } @@ -180,43 +166,52 @@ func fromRecordConfig(rc *models.RecordConfig) *dnsRecordCreate { // Get the target in the format expected by Infomaniak API var target string - switch rc.Type { - case "A", "AAAA": - target = rc.GetTargetField() - - case "CNAME", "NS", "DNAME": - // Remove trailing dot for the API - target = strings.TrimSuffix(rc.GetTargetField(), ".") - - case "MX": + switch rc.TypeNum { + // case "A": + // target = rc.AsA().Addr.String() + // case "AAAA": + // target = rc.AsAAAA().Addr.String() + + case dnsv2.TypeCNAME: + target = strings.TrimSuffix(rc.AsCNAME().Target, ".") + case dnsv2.TypeNS: + target = strings.TrimSuffix(rc.AsNS().Ns, ".") + case dnsv2.TypeDNAME: + target = strings.TrimSuffix(rc.AsDNAME().Target, ".") + + case dnsv2.TypeMX: // Format: "priority target" (without trailing dot) - target = fmt.Sprintf("%d %s", rc.MxPreference, strings.TrimSuffix(rc.GetTargetField(), ".")) + f := rc.AsMX() + target = fmt.Sprintf("%d %s", f.Preference, strings.TrimSuffix(f.Mx, ".")) - case "TXT": - target = rc.GetTargetField() + case dnsv2.TypeTXT: + target = rc.AsTXT().String() - case "SRV": + case dnsv2.TypeSRV: // Format: "priority weight port target" (without trailing dot) - target = fmt.Sprintf("%d %d %d %s", rc.SrvPriority, rc.SrvWeight, rc.SrvPort, strings.TrimSuffix(rc.GetTargetField(), ".")) + f := rc.AsSRV() + target = fmt.Sprintf("%d %d %d %s", f.Priority, f.Weight, f.Port, strings.TrimSuffix(f.Target, ".")) - case "CAA": - // Format: "flags tag value" - target = fmt.Sprintf("%d %s %s", rc.CaaFlag, rc.CaaTag, rc.GetTargetField()) + // case "CAA": + // // Format: "flags tag value" + // target = rc.GetRDATA().String() - case "DS": - // Format: "keytag algorithm digesttype digest" - target = fmt.Sprintf("%d %d %d %s", rc.DsKeyTag, rc.DsAlgorithm, rc.DsDigestType, rc.DsDigest) + // case "DS": + // // Format: "keytag algorithm digesttype digest" + // target = rc.GetRDATA().String() - case "SSHFP": - // Format: "algorithm fingerprint_type fingerprint" - target = fmt.Sprintf("%d %d %s", rc.SshfpAlgorithm, rc.SshfpFingerprint, rc.GetTargetField()) + // case "SSHFP": + // // Format: "algorithm fingerprint_type fingerprint" + // target = rc.GetRDATA().String() - case "TLSA": - // Format: "usage selector matching_type certificate" - target = fmt.Sprintf("%d %d %d %s", rc.TlsaUsage, rc.TlsaSelector, rc.TlsaMatchingType, rc.GetTargetField()) + // case "TLSA": + // // Format: "usage selector matching_type certificate" + // target = rc.GetRDATA().String() + + // TODO(): If tests pass, removed the above comments. default: - target = rc.GetTargetField() + target = rc.GetRDATA().String() } return &dnsRecordCreate{ @@ -231,43 +226,57 @@ func fromRecordConfig(rc *models.RecordConfig) *dnsRecordCreate { func toRecordUpdate(rc *models.RecordConfig) *dnsRecordUpdate { // Get the target in the format expected by Infomaniak API var target string - switch rc.Type { - case "A", "AAAA": - target = rc.GetTargetField() + switch rc.TypeNum { + case dnsv2.TypeA: + target = rc.AsA().Addr.String() + case dnsv2.TypeAAAA: + target = rc.AsAAAA().Addr.String() - case "CNAME", "NS", "DNAME": + case dnsv2.TypeCNAME: // Remove trailing dot for the API - target = strings.TrimSuffix(rc.GetTargetField(), ".") + target = strings.TrimSuffix(rc.AsCNAME().Target, ".") + case dnsv2.TypeNS: + target = strings.TrimSuffix(rc.AsNS().Ns, ".") + case dnsv2.TypeDNAME: + target = strings.TrimSuffix(rc.AsDNAME().Target, ".") - case "MX": + case dnsv2.TypeMX: // Format: "priority target" (without trailing dot) - target = fmt.Sprintf("%d %s", rc.MxPreference, strings.TrimSuffix(rc.GetTargetField(), ".")) + f := rc.AsMX() + target = fmt.Sprintf("%d %s", f.Preference, strings.TrimSuffix(f.Mx, ".")) - case "TXT": - target = rc.GetTargetField() + case dnsv2.TypeTXT: + target = rc.GetTargetTXTJoined() - case "SRV": + case dnsv2.TypeSRV: // Format: "priority weight port target" (without trailing dot) - target = fmt.Sprintf("%d %d %d %s", rc.SrvPriority, rc.SrvWeight, rc.SrvPort, strings.TrimSuffix(rc.GetTargetField(), ".")) + f := rc.AsSRV() + target = fmt.Sprintf("%d %d %d %s", f.Priority, f.Weight, f.Port, strings.TrimSuffix(f.Target, ".")) - case "CAA": + case dnsv2.TypeCAA: // Format: "flags tag value" - target = fmt.Sprintf("%d %s %s", rc.CaaFlag, rc.CaaTag, rc.GetTargetField()) + f := rc.AsCAA() + target = fmt.Sprintf("%d %s %s", f.Flag, f.Tag, f.Value) - case "DS": + case dnsv2.TypeDS: // Format: "keytag algorithm digesttype digest" - target = fmt.Sprintf("%d %d %d %s", rc.DsKeyTag, rc.DsAlgorithm, rc.DsDigestType, rc.DsDigest) + f := rc.AsDS() + target = f.String() - case "SSHFP": + case dnsv2.TypeSSHFP: // Format: "algorithm fingerprint_type fingerprint" - target = fmt.Sprintf("%d %d %s", rc.SshfpAlgorithm, rc.SshfpFingerprint, rc.GetTargetField()) + f := rc.AsSSHFP() + target = f.String() + // If that doesn't work, try this: + //target = fmt.Sprintf("%d %d %s", f.Algorithm, f.Type, f.FingerPrint) - case "TLSA": + case dnsv2.TypeTLSA: // Format: "usage selector matching_type certificate" - target = fmt.Sprintf("%d %d %d %s", rc.TlsaUsage, rc.TlsaSelector, rc.TlsaMatchingType, rc.GetTargetField()) + f := rc.AsTLSA() + target = fmt.Sprintf("%d %d %d %s", f.Usage, f.Selector, f.MatchingType, f.Certificate) default: - target = rc.GetTargetField() + target = rc.GetRDATA().String() } return &dnsRecordUpdate{ @@ -287,7 +296,7 @@ func (p *infomaniakProvider) GetZoneRecords(dc *models.DomainConfig) (models.Rec cleanRecords := make(models.Records, 0, len(records)) for _, r := range records { - recConfig, err := toRecordConfig(domain, r) + recConfig, err := toRecordConfig(dc, r) if err != nil { return nil, err } diff --git a/providers/infomaniak/infomaniakProvider_test.go b/providers/infomaniak/infomaniakProvider_test.go new file mode 100644 index 0000000000..0fe78dfced --- /dev/null +++ b/providers/infomaniak/infomaniakProvider_test.go @@ -0,0 +1,44 @@ +package infomaniak + +import ( + "strings" + "testing" + + "github.com/DNSControl/dnscontrol/v5/models" +) + +func TestToRecordConfig(t *testing.T) { + dc, err := models.NewDomainConfig("example.com") + if err != nil { + t.Fatal(err) + } + // A 256-octet TXT is returned by Infomaniak in RFC 1035 presentation form, + // split into two quoted character-strings: `"<255>" "C"`. It must decode + // back to the single 256-octet value (whose canonical rendering is the same + // split form). Naively stripping only the outer quotes left the interior + // `" "` and broke the round-trip. See issue #4748. + txt256 := `"` + strings.Repeat("C", 255) + `" "C"` + tests := []struct { + name string + record dnsRecord + wantTarget string + }{ + {"A", dnsRecord{Source: "www", Type: "A", TTL: 300, Target: "192.0.2.1"}, "192.0.2.1"}, + {"MX", dnsRecord{Source: "", Type: "MX", TTL: 300, Target: "10 mail.example.net"}, "10 mail.example.net."}, + {"TXT", dnsRecord{Source: ".", Type: "TXT", TTL: 300, Target: `"raw text"`}, `"raw text"`}, + {"TXT-256-multichunk", dnsRecord{Source: "foo256", Type: "TXT", TTL: 300, Target: txt256}, txt256}, + {"TXT-interior-spaces", dnsRecord{Source: "sp", Type: "TXT", TTL: 300, Target: `"with spaces"`}, `"with spaces"`}, + {"SRV", dnsRecord{Source: "_sip._tcp", Type: "SRV", TTL: 300, Target: "1 2 5060 sip.example.net"}, "1 2 5060 sip.example.net."}, + } + for _, tc := range tests { + t.Run(tc.name, func(t *testing.T) { + rc, err := toRecordConfig(dc, tc.record) + if err != nil { + t.Fatal(err) + } + if got := rc.GetRDATA().String(); got != tc.wantTarget { + t.Errorf("target = %q, want %q", got, tc.wantTarget) + } + }) + } +} diff --git a/providers/internetbs/internetbsProvider.go b/providers/internetbs/internetbsProvider.go index 126dd79d6f..c85b05f6f4 100644 --- a/providers/internetbs/internetbsProvider.go +++ b/providers/internetbs/internetbsProvider.go @@ -6,8 +6,8 @@ import ( "sort" "strings" - "github.com/DNSControl/dnscontrol/v4/models" - "github.com/DNSControl/dnscontrol/v4/pkg/providers" + "github.com/DNSControl/dnscontrol/v5/models" + "github.com/DNSControl/dnscontrol/v5/pkg/providers" ) /* diff --git a/providers/inwx/auditrecords.go b/providers/inwx/auditrecords.go index 69a8de0e61..4f6e67b8e9 100644 --- a/providers/inwx/auditrecords.go +++ b/providers/inwx/auditrecords.go @@ -1,17 +1,18 @@ package inwx import ( - "github.com/DNSControl/dnscontrol/v4/models" - "github.com/DNSControl/dnscontrol/v4/pkg/rejectif" + "github.com/DNSControl/dnscontrol/v5/models" + "github.com/DNSControl/dnscontrol/v5/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 { +func AuditRecords(records models.Records) []error { a := rejectif.Auditor{} - a.Add("TXT", rejectif.TxtHasBackticks) // Last verified 2021-03-01 - a.Add("TXT", rejectif.TxtHasTrailingSpace) // Last verified 2021-03-01 - a.Add("TXT", rejectif.TxtIsEmpty) // Last verified 2021-03-01 + a.Add("TXT", rejectif.TxtHasBackticks) // Last verified 2026-07-30 + a.Add("TXT", rejectif.TxtHasTrailingSpace) // Last verified 2026-07-30 + a.Add("TXT", rejectif.TxtIsEmpty) // Last verified 2026-07-30 + a.Add("TXT", rejectif.TxtHasDoubleQuotes) // Last verified 2026-07-30 return a.Audit(records) } diff --git a/providers/inwx/inwxProvider.go b/providers/inwx/inwxProvider.go index 5b55c7e684..1b52a931fc 100644 --- a/providers/inwx/inwxProvider.go +++ b/providers/inwx/inwxProvider.go @@ -8,15 +8,17 @@ import ( "strings" "time" + dnsv2 "codeberg.org/miekg/dns" + "github.com/DNSControl/dnscontrol/v5/models" + "github.com/DNSControl/dnscontrol/v5/pkg/diff2" + "github.com/DNSControl/dnscontrol/v5/pkg/nrc" + "github.com/DNSControl/dnscontrol/v5/pkg/printer" + privatetypes "github.com/DNSControl/dnscontrol/v5/pkg/privatetypes" + "github.com/DNSControl/dnscontrol/v5/pkg/providers" "github.com/fatih/color" "github.com/nrdcg/goinwx" "github.com/pquerna/otp/totp" "golang.org/x/net/idna" - - "github.com/DNSControl/dnscontrol/v4/models" - "github.com/DNSControl/dnscontrol/v4/pkg/diff2" - "github.com/DNSControl/dnscontrol/v4/pkg/printer" - "github.com/DNSControl/dnscontrol/v4/pkg/providers" ) /* @@ -198,17 +200,15 @@ func newInwxDsp(m map[string]string, metadata json.RawMessage) (providers.DNSSer // makeNameserverRecordRequest is a helper function used to convert a RecordConfig to an INWX NS Record Request. func makeNameserverRecordRequest(domain string, rec *models.RecordConfig) *goinwx.NameserverRecordRequest { - content := rec.GetTargetField() req := &goinwx.NameserverRecordRequest{ - Domain: domain, - Type: rec.Type, - Content: content, - Name: rec.GetLabel(), - TTL: int(rec.TTL), + Domain: domain, + Type: rec.Type, + Name: rec.GetLabel(), + TTL: int(rec.TTL), } - switch rType := rec.Type; rType { + switch rType := rec.TypeNum; rType { /* INWX is a little bit special for CNAME, NS, MX and SRV records: The API will not accept any target with a final dot but will @@ -216,51 +216,72 @@ func makeNameserverRecordRequest(domain string, rec *models.RecordConfig) *goinw Records with empty targets (i.e., records with target ".") are allowed. */ - case "CNAME", "NS", "ALIAS": + case dnsv2.TypeCNAME: + f := rec.AsCNAME() + content := f.Target req.Content = content[:len(content)-1] - case "MX": - req.Priority = int(rec.MxPreference) + case dnsv2.TypeNS: + f := rec.AsNS() + content := f.Ns + req.Content = content[:len(content)-1] + case privatetypes.TypeALIAS: + f := rec.AsALIAS() + content := f.Target + req.Content = content[:len(content)-1] + case dnsv2.TypeMX: + f := rec.AsMX() + req.Priority = int(f.Preference) + content := f.Mx if content == "." { req.Content = content } else { req.Content = content[:len(content)-1] } - case "SRV": - req.Priority = int(rec.SrvPriority) + case dnsv2.TypeSRV: + f := rec.AsSRV() + req.Priority = int(f.Priority) + content := f.Target if content == "." { - req.Content = fmt.Sprintf("%d %d %v", rec.SrvWeight, rec.SrvPort, content) + req.Content = fmt.Sprintf("%d %d %v", f.Weight, f.Port, content) } else { - req.Content = fmt.Sprintf("%d %d %v", rec.SrvWeight, rec.SrvPort, content[:len(content)-1]) + req.Content = fmt.Sprintf("%d %d %v", f.Weight, f.Port, content[:len(content)-1]) } + case dnsv2.TypeTXT: + req.Content = rec.GetTargetTXTJoined() + default: - req.Content = rec.GetTargetCombined() + req.Content = rec.GetRDATA().String() } return req } -// createRecord is used by GetDomainCorrections to create a new record. +// createRecord is used by GetZoneRecordsCorrections to create a new record. func (api *inwxAPI) createRecord(domain string, rec *models.RecordConfig) error { req := makeNameserverRecordRequest(domain, rec) _, err := api.client.Nameservers.CreateRecord(req) return err } -// updateRecord is used by GetDomainCorrections to update an existing record. +// updateRecord is used by GetZoneRecordsCorrections to update an existing record. func (api *inwxAPI) updateRecord(RecordID string, rec *models.RecordConfig) error { req := makeNameserverRecordRequest("", rec) err := api.client.Nameservers.UpdateRecord(RecordID, req) return err } -// deleteRecord is used by GetDomainCorrections to delete a record. +// deleteRecord is used by GetZoneRecordsCorrections to delete a record. func (api *inwxAPI) deleteRecord(RecordID string) error { return api.client.Nameservers.DeleteRecord(RecordID) } // isNullMX checks if a record is a null MX record. func isNullMX(rec *models.RecordConfig) bool { - return rec.Type == "MX" && rec.MxPreference == 0 && rec.GetTargetField() == "." + if rec.TypeNum != dnsv2.TypeMX { + return false + } + f := rec.AsMX() + return f.Preference == 0 && f.Mx == "." } // AutoDnssecToggle enables and disables AutoDNSSEC for INWX domains. @@ -329,14 +350,14 @@ func (api *inwxAPI) GetZoneRecordsCorrections(dc *models.DomainConfig, foundReco // changing to or from a Null MX has to be deleted then create deletes = append(deletes, &models.Correction{ Msg: color.RedString("- DELETE %s %s %s ttl=%d", oldRec.GetLabelFQDN(), oldRec.Type, - oldRec.ToComparableNoTTL(), oldRec.TTL), + oldRec.ComparableV3, oldRec.TTL), F: func() error { return api.deleteRecord(oldRec.Original.(goinwx.NameserverRecord).ID) }, }) deferred = append(deferred, &models.Correction{ Msg: color.GreenString("+ CREATE %s %s %s ttl=%d", newRec.GetLabelFQDN(), newRec.Type, - newRec.ToComparableNoTTL(), newRec.TTL), + newRec.ComparableV3, newRec.TTL), F: func() error { return api.createRecord(dc.Name, newRec) }, @@ -397,60 +418,76 @@ func (api *inwxAPI) GetZoneRecords(dc *models.DomainConfig) (models.Records, err return nil, err } - records := []*models.RecordConfig{} + records := models.Records{} for _, record := range info.Records { - if record.Type == "SOA" { + rc, err := toRecordConfig(dc, record) + if err != nil { + return nil, err + } + if rc == nil { continue } - /* - INWX is a little bit special for CNAME,NS,MX and SRV records: - The API will not accept any target with a final dot but will - instead always add this final dot internally. - Records with empty targets (i.e. records with target ".") - are allowed. - */ - rtypeAddDot := map[string]bool{ - "ALIAS": true, - "CNAME": true, - "MX": true, - "NS": true, - "SRV": true, - "PTR": true, - } - if rtypeAddDot[record.Type] { - if record.Type == "MX" && record.Content == "." { - // null records don't need to be modified - } else if record.Type == "SRV" && strings.HasSuffix(record.Content, ".") { - // null targets don't need to be modified - } else { - record.Content = record.Content + "." - } - } + records = append(records, rc) + } - rc := &models.RecordConfig{ - TTL: uint32(record.TTL), - Original: record, - } - rc.SetLabelFromFQDN(record.Name, domain) + return records, nil +} - switch rType := record.Type; rType { - case "MX": - err = rc.SetTargetMX(uint16(record.Priority), record.Content) - case "SRV": - err = rc.SetTargetSRVPriorityString(uint16(record.Priority), record.Content) - default: - err = rc.PopulateFromString(rType, record.Content, domain) - } - if err != nil { - return nil, fmt.Errorf("INWX: unparsable record received: %w", err) +// toRecordConfig converts an INWX record to a RecordConfig. It returns nil for +// SOA records, which are not managed. +func toRecordConfig(dc *models.DomainConfig, record goinwx.NameserverRecord) (*models.RecordConfig, error) { + if record.Type == "SOA" { + return nil, nil + } + + /* + INWX is a little bit special for CNAME,NS,MX and SRV records: + The API will not accept any target with a final dot but will + instead always add this final dot internally. + Records with empty targets (i.e. records with target ".") + are allowed. + */ + rtypeAddDot := map[string]bool{ + "ALIAS": true, + "CNAME": true, + "MX": true, + "NS": true, + "SRV": true, + "PTR": true, + } + if rtypeAddDot[record.Type] { + if record.Type == "MX" && record.Content == "." { + // null records don't need to be modified + } else if record.Type == "SRV" && strings.HasSuffix(record.Content, ".") { + // null targets don't need to be modified + } else { + record.Content = record.Content + "." } + } - records = append(records, rc) + label := dc.ToShort(record.Name) + ttl := uint32(record.TTL) + + var rc *models.RecordConfig + var err error + switch rType := record.Type; rType { + case "MX": + rc, err = dc.NewRecordConfig(label, ttl, rType, record.Priority, record.Content) + case "SRV": + rc, err = dc.NewRecordConfig(label, ttl, rType, record.Priority, record.Content, + nrc.Flags{SrvWeirdSplit: true}) + default: + rc, err = dc.NewRecordConfigParse(label, ttl, rType, record.Content, + nrc.Flags{TxtDontParse: true}) } + if err != nil { + return nil, fmt.Errorf("INWX: unparsable record received: %w", err) + } + rc.Original = record - return records, nil + return rc, nil } // ListZones returns the zones configured in INWX. diff --git a/providers/inwx/test_data/meta.json b/providers/inwx/test_data/meta.json new file mode 100644 index 0000000000..e9c365f9a5 --- /dev/null +++ b/providers/inwx/test_data/meta.json @@ -0,0 +1,8 @@ +{ + "version": 1, + "recordings": [ + { + "domain": "dnscontrol-test-inwx.com" + } + ] +} diff --git a/providers/joker/auditrecords.go b/providers/joker/auditrecords.go index bd5ef90dfd..b145d9df41 100644 --- a/providers/joker/auditrecords.go +++ b/providers/joker/auditrecords.go @@ -3,8 +3,8 @@ package joker import ( "fmt" - "github.com/DNSControl/dnscontrol/v4/models" - "github.com/DNSControl/dnscontrol/v4/pkg/rejectif" + "github.com/DNSControl/dnscontrol/v5/models" + "github.com/DNSControl/dnscontrol/v5/pkg/rejectif" ) var supportedRTypes = map[string]struct{}{ @@ -22,7 +22,7 @@ var supportedRTypes = map[string]struct{}{ // 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 { +func AuditRecords(records models.Records) []error { a := rejectif.Auditor{} // Joker does not support custom NS records at apex (domain root) diff --git a/providers/joker/jokerProvider.go b/providers/joker/jokerProvider.go index 818e7062fa..31ff5e8876 100644 --- a/providers/joker/jokerProvider.go +++ b/providers/joker/jokerProvider.go @@ -7,7 +7,7 @@ import ( "net/http" "time" - "github.com/DNSControl/dnscontrol/v4/pkg/providers" + "github.com/DNSControl/dnscontrol/v5/pkg/providers" ) /* diff --git a/providers/joker/nameservers.go b/providers/joker/nameservers.go index 46e3c9dc08..64b003567b 100644 --- a/providers/joker/nameservers.go +++ b/providers/joker/nameservers.go @@ -1,6 +1,6 @@ package joker -import "github.com/DNSControl/dnscontrol/v4/models" +import "github.com/DNSControl/dnscontrol/v5/models" // GetNameservers returns the nameservers for a domain. func (api *jokerProvider) GetNameservers(domain string) ([]*models.Nameserver, error) { diff --git a/providers/joker/records.go b/providers/joker/records.go index aa59a3446b..38c524b061 100644 --- a/providers/joker/records.go +++ b/providers/joker/records.go @@ -6,8 +6,9 @@ import ( "strconv" "strings" - "github.com/DNSControl/dnscontrol/v4/models" - "github.com/DNSControl/dnscontrol/v4/pkg/diff2" + dnsv2 "codeberg.org/miekg/dns" + "github.com/DNSControl/dnscontrol/v5/models" + "github.com/DNSControl/dnscontrol/v5/pkg/diff2" ) // GetZoneRecords gets the records of a zone and returns them in RecordConfig format. @@ -79,6 +80,10 @@ func parseZoneLine(line string) []string { // parseZoneRecords parses Joker zone format into RecordConfig format. func (api *jokerProvider) parseZoneRecords(domain, zoneData string) (models.Records, error) { var records models.Records + dc, err := models.NewDomainConfig(domain) + if err != nil { + return nil, err + } lines := strings.SplitSeq(strings.TrimSpace(zoneData), "\n") for line := range lines { @@ -130,93 +135,50 @@ func (api *jokerProvider) parseZoneRecords(domain, zoneData string) (models.Reco } } - // Convert @ to empty string for root domain - if label == "@" { - label = "" - } - - rc := &models.RecordConfig{ - TTL: ttl, - } - - // Set the label and domain correctly - rc.SetLabel(label, domain) - // Handle different record types + var rc *models.RecordConfig + var err error switch recordType { case "A", "AAAA": - rc.Type = recordType - if err := rc.SetTarget(target); err != nil { - continue - } - case "CNAME": - rc.Type = recordType + rc, err = dc.NewRecordConfig(label, ttl, recordType, target) + case "CNAME", "NS": // Ensure CNAME targets are fully qualified if !strings.HasSuffix(target, ".") { target = target + "." } - if err := rc.SetTarget(target); err != nil { - continue - } - case "NS": - rc.Type = recordType - // Ensure NS targets are fully qualified - if !strings.HasSuffix(target, ".") { - target = target + "." - } - if err := rc.SetTarget(target); err != nil { - continue - } + rc, err = dc.NewRecordConfig(label, ttl, recordType, target) case "TXT": - rc.Type = recordType // TXT target is already extracted without quotes in the parsing above - if err := rc.SetTarget(target); err != nil { - continue - } + rc, err = dc.NewRecordConfig(label, ttl, recordType, target) case "MX": - rc.Type = recordType - if prio, err := strconv.ParseUint(priority, 10, 16); err == nil { - rc.MxPreference = uint16(prio) - } // Ensure MX targets are fully qualified if !strings.HasSuffix(target, ".") { target = target + "." } - if err := rc.SetTarget(target); err != nil { - continue - } + rc, err = dc.NewRecordConfig(label, ttl, recordType, priority, target) case "SRV": - rc.Type = recordType + var srvPriority, srvWeight, srvPort string // SRV format: priority/weight target:port if strings.Contains(priority, "/") { priorityParts := strings.Split(priority, "/") if len(priorityParts) == 2 { - if prio, err := strconv.ParseUint(priorityParts[0], 10, 16); err == nil { - rc.SrvPriority = uint16(prio) - } - if weight, err := strconv.ParseUint(priorityParts[1], 10, 16); err == nil { - rc.SrvWeight = uint16(weight) - } + srvPriority = priorityParts[0] + srvWeight = priorityParts[1] } } if strings.Contains(target, ":") { targetParts := strings.Split(target, ":") if len(targetParts) == 2 { - if port, err := strconv.ParseUint(targetParts[1], 10, 16); err == nil { - rc.SrvPort = uint16(port) - } + srvPort = targetParts[1] srvTarget := targetParts[0] // Ensure SRV targets are fully qualified if !strings.HasSuffix(srvTarget, ".") { srvTarget = srvTarget + "." } - if err := rc.SetTarget(srvTarget); err != nil { - continue - } + rc, err = dc.NewRecordConfig(label, ttl, recordType, srvPriority, srvWeight, srvPort, srvTarget) } } case "CAA": - rc.Type = recordType // CAA format: flags tag value [ttl] if len(parts) >= 4 { flags := priority // priority field contains flags for CAA @@ -226,39 +188,29 @@ func (api *jokerProvider) parseZoneRecords(domain, zoneData string) (models.Reco if len(parts) >= 5 { value = parts[4] // Remove surrounding quotes if present - if strings.HasPrefix(value, "\"") && strings.HasSuffix(value, "\"") && len(value) > 1 { + if len(value) > 1 && strings.HasPrefix(value, "\"") && strings.HasSuffix(value, "\"") { value = value[1 : len(value)-1] } // Parse TTL from the end if present (position 5) if len(parts) >= 6 { if ttlParsed, err := strconv.ParseUint(parts[5], 10, 32); err == nil { - rc.TTL = uint32(ttlParsed) + ttl = uint32(ttlParsed) } } } - - if flagsInt, err := strconv.ParseUint(flags, 10, 8); err == nil { - rc.CaaFlag = uint8(flagsInt) - } - rc.CaaTag = tag - if err := rc.SetTarget(value); err != nil { - continue - } + rc, err = dc.NewRecordConfig(label, ttl, recordType, flags, tag, value) } case "NAPTR": - rc.Type = recordType + var order, preference string + var flags, service, regexp string // NAPTR format for Joker: order/preference replacement ttl 0 0 "flags" "service" "regex" if len(parts) >= 9 { // Parse order/preference from priority field (parts[2]) if strings.Contains(priority, "/") { priorityParts := strings.Split(priority, "/") if len(priorityParts) == 2 { - if order, err := strconv.ParseUint(priorityParts[0], 10, 16); err == nil { - rc.NaptrOrder = uint16(order) - } - if pref, err := strconv.ParseUint(priorityParts[1], 10, 16); err == nil { - rc.NaptrPreference = uint16(pref) - } + order = priorityParts[0] + preference = priorityParts[1] } } // Replacement is in position 3 @@ -268,31 +220,32 @@ func (api *jokerProvider) parseZoneRecords(domain, zoneData string) (models.Reco // Parse TTL from position 4 if len(parts) >= 5 { if ttlParsed, err := strconv.ParseUint(parts[4], 10, 32); err == nil { - rc.TTL = uint32(ttlParsed) + ttl = uint32(ttlParsed) } } // Parse flags, service, and regex from positions 7, 8, 9 if len(parts) > 7 { - rc.NaptrFlags = strings.Trim(parts[7], "\"") + flags = strings.Trim(parts[7], "\"") } if len(parts) > 8 { - rc.NaptrService = strings.Trim(parts[8], "\"") + service = strings.Trim(parts[8], "\"") } if len(parts) > 9 { - rc.NaptrRegexp = strings.Trim(parts[9], "\"") + regexp = strings.Trim(parts[9], "\"") } // Ensure NAPTR targets are fully qualified if they're not empty or "." if target != "" && target != "." && !strings.HasSuffix(target, ".") { target = target + "." } - if err := rc.SetTarget(target); err != nil { - continue - } + rc, err = dc.NewRecordConfig(label, ttl, recordType, order, preference, flags, service, regexp, target) } default: // Skip unsupported record types continue } + if err != nil || rc == nil { + continue + } records = append(records, rc) } @@ -368,41 +321,54 @@ func (api *jokerProvider) recordsToZoneFormat(_ string, records models.Records) label = "@" } + // TODO(tlim): The can probably be generated by rc.GetRDATA().String(). + // Using that would simplify many of the cases. I've modified the easy ones. + // Joker format: