fix .NameFQDN* and other nits

This commit is contained in:
Thomas Limoncelli 2025-12-03 21:46:00 -05:00
parent 691764ee29
commit 4a9233d0b6
No known key found for this signature in database
8 changed files with 228 additions and 145 deletions

View file

@ -536,16 +536,10 @@ func (rc *RecordConfig) GetSVCBValue() []dns.SVCBKeyValue {
return nil
}
// IsModernType returns true if this RecordConfig uses the new "F" field to store its rdata.
// Once all record types have been migrated to use "F", this function can be removed.
func (rc *RecordConfig) IsModernType() bool {
//fmt.Printf("DEBUG: IsModernType rtype=%s\n", rc.Type)
return rc.F != nil
// switch rc.Type {
// case "CLOUDFLAREAPI_SINGLE_REDIRECT", "RP":
// return true
// }
// return false
}
// Records is a list of *RecordConfig.

View file

@ -59,9 +59,7 @@ func (rc *RecordConfig) PopulateFromStringFunc(rtype, contents, origin string, t
return fmt.Errorf("assertion failed: rtype already set (%s) (%s)", rtype, rc.Type)
}
rc.Type = rtype
switch rtype { // #rtype_variations
switch rc.Type = rtype; rtype { // #rtype_variations
case "A":
ip := net.ParseIP(contents)
if ip == nil || ip.To4() == nil {

View file

@ -48,19 +48,3 @@ func (handle *RP) CopyToLegacyFields(rec *models.RecordConfig) {
rp := rec.F.(*RP)
_ = rec.SetTarget(rp.Mbox + " " + rp.Txt)
}
// func (handle *RP) TestData() {
// return []itest.TestGroup[
// itest.Testgroup("RP",
// itest.tc("Create RP", rp("foo", "user.example.com.", "bar.com.")),
// itest.tc("Create RP", rp("foo", "other.example.com.", "bar.com.")),
// itest.tc("Create RP", rp("foo", "other.example.com.", "example.com.")),
// ),
// itest.Testgroup("RP-apex",
// itest.tc("Create RP", rp("@", "user.example.com.", "bar.com.")),
// itest.tc("Create RP", rp("@", "other.example.com.", "bar.com.")),
// itest.tc("Create RP", rp("@", "other.example.com.", "example.com.")),
// ),
// ]
// }

View file

@ -2,11 +2,11 @@ package rtypecontrol
import (
"fmt"
"strings"
"github.com/StackExchange/dnscontrol/v4/models"
"github.com/StackExchange/dnscontrol/v4/pkg/domaintags"
"github.com/miekg/dns"
"github.com/miekg/dns/dnsutil"
)
// ImportRawRecords imports the RawRecordConfigs into RecordConfigs.
@ -16,10 +16,10 @@ func ImportRawRecords(domains []*models.DomainConfig) error {
for _, rawRec := range dc.RawRecords {
rec, err := NewRecordConfigFromRaw(rawRec.Type, rawRec.TTL, rawRec.Args, dc)
rec.FilePos = models.FixPosition(rawRec.FilePos)
if err != nil {
return fmt.Errorf("%s: %w", rec.FilePos, err)
return err
}
rec.FilePos = models.FixPosition(rawRec.FilePos)
// Free memeory:
clear(rawRec.Args)
@ -106,31 +106,39 @@ func setRecordNames(rec *models.RecordConfig, dc *models.DomainConfig, n string)
rec.Name = "@"
rec.NameRaw = "@"
rec.NameUnicode = "@"
} else {
rec.Name = domaintags.EfficientToASCII(n)
rec.NameRaw = n
rec.NameUnicode = domaintags.EfficientToUnicode(n)
}
rec.NameFQDN = dc.Name
rec.NameFQDNRaw = dc.NameRaw
rec.NameFQDNUnicode = dc.NameUnicode
rec.NameFQDN = dc.Name
rec.NameFQDNRaw = dc.NameRaw
rec.NameFQDNUnicode = dc.NameUnicode
} else {
// _EXTEND() mode:
// FIXME(tlim): Not implemented.
rec.Name = strings.ToLower(domaintags.EfficientToASCII(n))
rec.NameRaw = n
rec.NameUnicode = domaintags.EfficientToUnicode(n)
rec.NameFQDN = rec.Name + "." + dc.Name
rec.NameFQDNRaw = rec.NameRaw + "." + dc.NameRaw
rec.NameFQDNUnicode = rec.NameUnicode + "." + dc.NameUnicode
}
} else {
// D_EXTEND() mode:
sdRaw := rec.SubDomain
sdIDN := domaintags.EfficientToASCII(rec.SubDomain)
sdUnicode := domaintags.EfficientToUnicode(rec.SubDomain)
sdASCII := strings.ToLower(domaintags.EfficientToASCII(rec.SubDomain))
sdUnicode := domaintags.EfficientToUnicode(sdASCII)
if n == "@" {
rec.Name = sdIDN
rec.Name = sdASCII
rec.NameRaw = sdRaw
rec.NameUnicode = sdUnicode
rec.NameFQDN = rec.Name + "." + dc.Name
rec.NameFQDNRaw = rec.NameRaw + "." + dc.NameRaw
rec.NameFQDNUnicode = rec.NameUnicode + "." + dc.NameUnicode
} else {
rec.Name = domaintags.EfficientToASCII(n + "." + sdIDN)
rec.Name = domaintags.EfficientToASCII(n) + "." + sdASCII
rec.NameRaw = n + "." + sdRaw
rec.NameUnicode = domaintags.EfficientToUnicode(n + "." + sdUnicode)
rec.NameUnicode = domaintags.EfficientToUnicode(rec.Name)
rec.NameFQDN = rec.Name + "." + dc.Name
rec.NameFQDNRaw = rec.NameRaw + "." + dc.NameRaw
rec.NameFQDNUnicode = rec.NameUnicode + "." + dc.NameUnicode
}
rec.NameFQDN = dnsutil.AddOrigin(rec.Name, dc.Name)
rec.NameFQDNRaw = dnsutil.AddOrigin(rec.NameRaw, dc.NameRaw)
rec.NameFQDNUnicode = dnsutil.AddOrigin(rec.NameUnicode, dc.NameUnicode)
}
}

View file

@ -0,0 +1,199 @@
package rtypecontrol
import (
"testing"
"github.com/StackExchange/dnscontrol/v4/models"
)
func TestSetRecordNames(t *testing.T) {
dc := &models.DomainConfig{
Name: "example.com",
NameRaw: "example.com",
NameUnicode: "example.com",
}
dcIDN := &models.DomainConfig{
Name: "xn--bcher-kva.com",
NameRaw: "bücher.com",
NameUnicode: "bücher.com",
}
tests := []struct {
name string
rec *models.RecordConfig
dc *models.DomainConfig
n string
expectedRec *models.RecordConfig
}{
{
name: "normal_at",
rec: &models.RecordConfig{},
dc: dc,
n: "@",
expectedRec: &models.RecordConfig{
Name: "@",
NameRaw: "@",
NameUnicode: "@",
NameFQDN: "example.com",
NameFQDNRaw: "example.com",
NameFQDNUnicode: "example.com",
},
},
{
name: "normal_label",
rec: &models.RecordConfig{},
dc: dc,
n: "www",
expectedRec: &models.RecordConfig{
Name: "www",
NameRaw: "www",
NameUnicode: "www",
NameFQDN: "www.example.com",
NameFQDNRaw: "www.example.com",
NameFQDNUnicode: "www.example.com",
},
},
{
name: "normal_idn_label",
rec: &models.RecordConfig{},
dc: dc,
n: "bücher",
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: "normal_idn_domain",
rec: &models.RecordConfig{},
dc: dcIDN,
n: "www",
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: "extend_at",
rec: &models.RecordConfig{SubDomain: "sub"},
dc: dc,
n: "@",
expectedRec: &models.RecordConfig{
SubDomain: "sub",
Name: "sub",
NameRaw: "sub",
NameUnicode: "sub",
NameFQDN: "sub.example.com",
NameFQDNRaw: "sub.example.com",
NameFQDNUnicode: "sub.example.com",
},
},
{
name: "extend_label",
rec: &models.RecordConfig{SubDomain: "sub"},
dc: dc,
n: "www",
expectedRec: &models.RecordConfig{
SubDomain: "sub",
Name: "www.sub",
NameRaw: "www.sub",
NameUnicode: "www.sub",
NameFQDN: "www.sub.example.com",
NameFQDNRaw: "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",
Name: "www.xn--bcher-kva",
NameRaw: "www.bücher",
NameUnicode: "www.bücher",
NameFQDN: "www.xn--bcher-kva.example.com",
NameFQDNRaw: "www.bücher.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",
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: "extend_idn_subdomain_and_label",
rec: &models.RecordConfig{SubDomain: "bücher"},
dc: dc,
n: "könig",
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: "extend_idn_domain_and_subdomain",
rec: &models.RecordConfig{SubDomain: "bücher"},
dc: dcIDN,
n: "www",
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) {
setRecordNames(tt.rec, tt.dc, tt.n)
if tt.rec.Name != tt.expectedRec.Name {
t.Errorf("Name: got %q, want %q", tt.rec.Name, tt.expectedRec.Name)
}
if tt.rec.NameRaw != tt.expectedRec.NameRaw {
t.Errorf("NameRaw: got %q, want %q", tt.rec.NameRaw, tt.expectedRec.NameRaw)
}
if tt.rec.NameUnicode != tt.expectedRec.NameUnicode {
t.Errorf("NameUnicode: got %q, want %q", tt.rec.NameUnicode, tt.expectedRec.NameUnicode)
}
if tt.rec.NameFQDN != tt.expectedRec.NameFQDN {
t.Errorf("NameFQDN: got %q, want %q", tt.rec.NameFQDN, tt.expectedRec.NameFQDN)
}
if tt.rec.NameFQDNRaw != tt.expectedRec.NameFQDNRaw {
t.Errorf("NameFQDNRaw: got %q, want %q", tt.rec.NameFQDNRaw, tt.expectedRec.NameFQDNRaw)
}
if tt.rec.NameFQDNUnicode != tt.expectedRec.NameFQDNUnicode {
t.Errorf("NameFQDNUnicode: got %q, want %q", tt.rec.NameFQDNUnicode, tt.expectedRec.NameFQDNUnicode)
}
})
}
}

View file

@ -222,7 +222,6 @@ func ParseZoneContents(content string, zoneName string, zonefileName string) (mo
}
rec = *prec
rec.TTL = rr.Header().Ttl
fmt.Printf("DEBUG: RP record parsed as %+v\n", rec)
default:
// Legacy types:
rec, err = models.RRtoRCTxtBug(rr, zoneName)

View file

@ -73,14 +73,8 @@ func init() {
RecordAuditor: AuditRecords,
}
providers.RegisterDomainServiceProviderType(providerName, fns, features)
//providers.RegisterCustomRecordType("CF_REDIRECT", providerName, "")
//providers.RegisterCustomRecordType("CF_TEMP_REDIRECT", providerName, "")
providers.RegisterCustomRecordType("CF_WORKER_ROUTE", providerName, "")
providers.RegisterMaintainer(providerName, providerMaintainer)
// providers.SupportedRecordTypes(provderName,
// "CLOUDFLAREAPI_SINGLE_REDIRECT",
// )
}
// cloudflareProvider is the handle for API calls.
@ -455,7 +449,6 @@ 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
//prPriority := 0
for i := len(dc.Records) - 1; i >= 0; i-- {
rec := dc.Records[i]
if rec.Metadata == nil {
@ -605,7 +598,6 @@ func newCloudflare(m map[string]string, metadata json.RawMessage) (providers.DNS
parsedMeta := &struct {
IPConversions string `json:"ip_conversions"`
IgnoredLabels []string `json:"ignored_labels"`
//ManageRedirects bool `json:"manage_redirects"` // Old-style PAGE_RULE-based redirects
ManageWorkers bool `json:"manage_workers"`
//
ManageSingleRedirects bool `json:"manage_single_redirects"` // New-style Dynamic "Single Redirects"
@ -616,7 +608,6 @@ func newCloudflare(m map[string]string, metadata json.RawMessage) (providers.DNS
return nil, err
}
api.manageSingleRedirects = parsedMeta.ManageSingleRedirects
//api.manageRedirects = parsedMeta.ManageRedirects
api.tcLogFilename = parsedMeta.TranscodeLogFilename
api.manageWorkers = parsedMeta.ManageWorkers
// ignored_labels:

View file

@ -1,90 +0,0 @@
package cfsingleredirect
// // MakePageRule updates a RecordConfig to be a PAGE_RULE using PAGE_RULE data.
// func MakePageRule(rc *models.RecordConfig, priority int, code uint16, when, then string) error {
// if rc == nil {
// return errors.New("RecordConfig cannot be nil")
// }
// if when == "" || then == "" {
// return errors.New("when and then parameters cannot be empty")
// }
// display := mkPageRuleBlob(priority, code, when, then)
// rc.Type = "PAGE_RULE"
// rc.TTL = 1
// rc.CloudflareRedirect = &models.CloudflareSingleRedirectConfig{
// Code: code,
// //
// PRWhen: when,
// PRThen: then,
// PRPriority: priority,
// PRDisplay: display,
// }
// return rc.SetTarget(display)
// }
// // mkPageRuleBlob creates the 1,301,when,then string used in displays.
// func mkPageRuleBlob(priority int, code uint16, when, then string) string {
// return fmt.Sprintf("%03d,%03d,%s,%s", priority, code, when, then)
// }
// func MakeSingleRedirectFromAPI(rc *models.RecordConfig, code uint16, name, when, then string) error {
// return rtypecontrol.Func["CLOUDFLAREAPI_SINGLE_REDIRECT"].FromArgs(rc, []any{name, code, when, then})
// }
// // MakeSingleRedirectFromAPI updatese a RecordConfig to be a SINGLEREDIRECT using data downloaded via the API.
// func MakeSingleRedirectFromAPI(rc *models.RecordConfig, code uint16, name, when, then string) error {
// // The target is the same as the name. It is the responsibility of the record creator to name it something diffable.
// target := targetFromAPIData(name, code, when, then)
// rc.CloudflareRedirect = &CloudflareSingleRedirectConfig{
// Code: code,
// //
// PRWhen: "UNKNOWABLE",
// PRThen: "UNKNOWABLE",
// PRPriority: 0,
// PRDisplay: "UNKNOWABLE",
// //
// SRName: name,
// SRWhen: when,
// SRThen: then,
// SRDisplay: target,
// }
// return rc.SetTarget(rc.CloudflareRedirect.SRDisplay)
// }
// // targetFromAPIData creates the display text used for a Redirect as received from Cloudflare's API.
// func targetFromAPIData(name string, code uint16, when, then string) string {
// return fmt.Sprintf("%s code=(%03d) when=(%s) then=(%s)",
// name,
// code,
// when,
// then,
// )
// }
// // makeSingleRedirectFromConvert updates a RecordConfig to be a SINGLEREDIRECT using data from a PAGE_RULE conversion.
// func makeSingleRedirectFromConvert(rc *models.RecordConfig,
// priority int,
// prWhen, prThen string,
// code uint16,
// srName, srWhen, srThen string,
// ) error {
// srDisplay := targetFromConverted(priority, code, prWhen, prThen, srWhen, srThen)
// sr := rc.CloudflareRedirect
// sr.Code = code
// sr.SRName = srName
// sr.SRWhen = srWhen
// sr.SRThen = srThen
// sr.SRDisplay = srDisplay
// return rc.SetTarget(rc.CloudflareRedirect.SRDisplay)
// }
// // targetFromConverted makes the display text used when a redirect was the result of converting a PAGE_RULE.
// func targetFromConverted(prPriority int, code uint16, prWhen, prThen, srWhen, srThen string) string {
// return fmt.Sprintf("%03d,%03d,%s,%s code=(%03d) when=(%s) then=(%s)", prPriority, code, prWhen, prThen, code, srWhen, srThen)
// }