Skip to content

Commit

Permalink
NEW RECORD TYPE: DNAME (StackExchange#2893)
Browse files Browse the repository at this point in the history
  • Loading branch information
imlonghao authored Apr 2, 2024
1 parent 293d5cb commit 42125b5
Show file tree
Hide file tree
Showing 19 changed files with 172 additions and 72 deletions.
6 changes: 6 additions & 0 deletions build/generate/featureMatrix.go
Original file line number Diff line number Diff line change
Expand Up @@ -89,6 +89,7 @@ func matrixData() *FeatureMatrix {
DomainModifierTlsa = "[`TLSA`](functions/domain/TLSA.md)"
DomainModifierDs = "[`DS`](functions/domain/DS.md)"
DomainModifierDhcid = "[`DHCID`](functions/domain/DHCID.md)"
DomainModifierDname = "[`DNAME`](functions/domain/DNAME.md)"
DualHost = "dual host"
CreateDomains = "create-domains"
GetZones = "get-zones"
Expand All @@ -113,6 +114,7 @@ func matrixData() *FeatureMatrix {
DomainModifierTlsa,
DomainModifierDs,
DomainModifierDhcid,
DomainModifierDname,
DualHost,
CreateDomains,
//NoPurge,
Expand Down Expand Up @@ -191,6 +193,10 @@ func matrixData() *FeatureMatrix {
DomainModifierDhcid,
providers.CanUseDHCID,
)
setCapability(
DomainModifierDname,
providers.CanUseDNAME,
)
setCapability(
DomainModifierDs,
providers.CanUseDS,
Expand Down
15 changes: 15 additions & 0 deletions commands/types/dnscontrol.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -820,6 +820,21 @@ declare const DISABLE_IGNORE_SAFETY_CHECK: DomainModifier;
*/
declare function DMARC_BUILDER(opts: { label?: string; version?: string; policy: 'none' | 'quarantine' | 'reject'; subdomainPolicy?: 'none' | 'quarantine' | 'reject'; alignmentSPF?: 'strict' | 's' | 'relaxed' | 'r'; alignmentDKIM?: 'strict' | 's' | 'relaxed' | 'r'; percent?: number; rua?: string[]; ruf?: string[]; failureOptions?: { SPF: boolean, DKIM: boolean } | string; failureFormat?: string; reportInterval?: Duration; ttl?: Duration }): DomainModifier;

/**
* DNAME adds a DNAME record to the domain.
*
* Target should be a string.
*
* ```javascript
* D("example.com", REG_MY_PROVIDER, DnsProvider(DSP_MY_PROVIDER),
* DNAME("sub", "example.net.")
* );
* ```
*
* @see https://docs.dnscontrol.org/language-reference/domain-modifiers/dname
*/
declare function DNAME(name: string, target: string, ...modifiers: RecordModifier[]): DomainModifier;

/**
* `DOMAIN_ELSEWHERE()` is a helper macro that lets you easily indicate that
* a domain's zones are managed elsewhere. That is, it permits you easily delegate
Expand Down
1 change: 1 addition & 0 deletions documentation/SUMMARY.md
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@
* [CAA_BUILDER](functions/domain/CAA_BUILDER.md)
* [CNAME](functions/domain/CNAME.md)
* [DHCID](functions/domain/DHCID.md)
* [DNAME](functions/domain/DNAME.md)
* [DISABLE_IGNORE_SAFETY_CHECK](functions/domain/DISABLE_IGNORE_SAFETY_CHECK.md)
* [DMARC_BUILDER](functions/domain/DMARC_BUILDER.md)
* [DS](functions/domain/DS.md)
Expand Down
23 changes: 23 additions & 0 deletions documentation/functions/domain/DNAME.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
---
name: DNAME
parameters:
- name
- target
- modifiers...
parameter_types:
name: string
target: string
"modifiers...": RecordModifier[]
---

DNAME adds a DNAME record to the domain.

Target should be a string.

{% code title="dnsconfig.js" %}
```javascript
D("example.com", REG_MY_PROVIDER, DnsProvider(DSP_MY_PROVIDER),
DNAME("sub", "example.net.")
);
```
{% endcode %}
104 changes: 52 additions & 52 deletions documentation/providers.md

Large diffs are not rendered by default.

11 changes: 11 additions & 0 deletions integrationTest/integration_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -512,6 +512,10 @@ func dhcid(name, target string) *models.RecordConfig {
return makeRec(name, target, "DHCID")
}

func dname(name, target string) *models.RecordConfig {
return makeRec(name, target, "DNAME")
}

func ds(name string, keyTag uint16, algorithm, digestType uint8, digest string) *models.RecordConfig {
r := makeRec(name, "", "DS")
r.SetTargetDS(keyTag, algorithm, digestType, digest)
Expand Down Expand Up @@ -1601,6 +1605,13 @@ func makeTests() []*TestGroup {
tc("Modify DHCID record", dhcid("test", "Test/AuCccgoJbsaxcQc9TUapptP69lOjxfNuVAA2kjEA=")),
),

testgroup("DNAME",
requires(providers.CanUseDNAME),
tc("Create DNAME record", dname("test", "example.com.")),
tc("Modify DNAME record", dname("test", "example.net.")),
tc("Create DNAME record in non-FQDN", dname("a", "b")),
),

//// Vendor-specific record types

// Narrative: DNSControl supports DNS records that don't exist!
Expand Down
2 changes: 2 additions & 0 deletions models/dnsrr.go
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,8 @@ func helperRRtoRC(rr dns.RR, origin string, fixBug bool) (RecordConfig, error) {
err = rc.SetTarget(v.Target)
case *dns.DHCID:
err = rc.SetTarget(v.Digest)
case *dns.DNAME:
err = rc.SetTarget(v.Target)
case *dns.DS:
err = rc.SetTargetDS(v.KeyTag, v.Algorithm, v.DigestType, v.Digest)
case *dns.LOC:
Expand Down
2 changes: 1 addition & 1 deletion models/domain.go
Original file line number Diff line number Diff line change
Expand Up @@ -132,7 +132,7 @@ func (dc *DomainConfig) Punycode() error {

// Set the target:
switch rec.Type { // #rtype_variations
case "ALIAS", "MX", "NS", "CNAME", "PTR", "SRV", "URL", "URL301", "FRAME", "R53_ALIAS", "NS1_URLFWD", "AKAMAICDN", "CLOUDNS_WR":
case "ALIAS", "MX", "NS", "CNAME", "DNAME", "PTR", "SRV", "URL", "URL301", "FRAME", "R53_ALIAS", "NS1_URLFWD", "AKAMAICDN", "CLOUDNS_WR":
// These rtypes are hostnames, therefore need to be converted (unlike, for example, an AAAA record)
t, err := idna.ToASCII(rec.GetTargetField())
if err != nil {
Expand Down
6 changes: 4 additions & 2 deletions models/record.go
Original file line number Diff line number Diff line change
Expand Up @@ -361,6 +361,8 @@ func (rc *RecordConfig) ToRR() dns.RR {
rr.(*dns.CNAME).Target = rc.GetTargetField()
case dns.TypeDHCID:
rr.(*dns.DHCID).Digest = rc.GetTargetField()
case dns.TypeDNAME:
rr.(*dns.DNAME).Target = rc.GetTargetField()
case dns.TypeDS:
rr.(*dns.DS).Algorithm = rc.DsAlgorithm
rr.(*dns.DS).DigestType = rc.DsDigestType
Expand Down Expand Up @@ -537,7 +539,7 @@ func Downcase(recs []*RecordConfig) {
r.Name = strings.ToLower(r.Name)
r.NameFQDN = strings.ToLower(r.NameFQDN)
switch r.Type { // #rtype_variations
case "AKAMAICDN", "ALIAS", "AAAA", "ANAME", "CNAME", "DS", "MX", "NS", "NAPTR", "PTR", "SRV", "TLSA":
case "AKAMAICDN", "ALIAS", "AAAA", "ANAME", "CNAME", "DNAME", "DS", "MX", "NS", "NAPTR", "PTR", "SRV", "TLSA":
// Target is case insensitive. Downcase it.
r.target = strings.ToLower(r.target)
// BUGFIX(tlim): isn't ALIAS in the wrong case statement?
Expand All @@ -562,7 +564,7 @@ func CanonicalizeTargets(recs []*RecordConfig, origin string) {

for _, r := range recs {
switch r.Type { // #rtype_variations
case "ALIAS", "ANAME", "CNAME", "DS", "MX", "NS", "NAPTR", "PTR", "SRV":
case "ALIAS", "ANAME", "CNAME", "DNAME", "DS", "MX", "NS", "NAPTR", "PTR", "SRV":
// Target is a hostname that might be a shortname. Turn it into a FQDN.
r.target = dnsutil.AddOrigin(r.target, originFQDN)
case "A", "AKAMAICDN", "CAA", "DHCID", "CF_REDIRECT", "CF_TEMP_REDIRECT", "CF_WORKER_ROUTE", "IMPORT_TRANSFORM", "LOC", "SSHFP", "TLSA", "TXT":
Expand Down
4 changes: 4 additions & 0 deletions models/t_parse.go
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,8 @@ func (rc *RecordConfig) PopulateFromStringFunc(rtype, contents, origin string, t
return rc.SetTargetDSString(contents)
case "DHCID":
return rc.SetTarget(contents)
case "DNAME":
return rc.SetTarget(contents)
case "LOC":
return rc.SetTargetLOCString(origin, contents)
case "MX":
Expand Down Expand Up @@ -164,6 +166,8 @@ func (rc *RecordConfig) PopulateFromString(rtype, contents, origin string) error
return rc.SetTargetDSString(contents)
case "DHCID":
return rc.SetTarget(contents)
case "DNAME":
return rc.SetTarget(contents)
case "LOC":
return rc.SetTargetLOCString(origin, contents)
case "MX":
Expand Down
3 changes: 3 additions & 0 deletions pkg/js/helpers.js
Original file line number Diff line number Diff line change
Expand Up @@ -427,6 +427,9 @@ var DS = recordBuilder('DS', {
// DHCID(name,target, recordModifiers...)
var DHCID = recordBuilder('DHCID');

// DNAME(name,target, recordModifiers...)
var DNAME = recordBuilder('DNAME');

// PTR(name,target, recordModifiers...)
var PTR = recordBuilder('PTR');

Expand Down
3 changes: 3 additions & 0 deletions pkg/js/parse_tests/047-DNAME.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
D("foo.com","none",
DNAME("@", "bar.com.")
);
18 changes: 18 additions & 0 deletions pkg/js/parse_tests/047-DNAME.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
{
"registrars": [],
"dns_providers": [],
"domains": [
{
"name": "foo.com",
"registrar": "none",
"dnsProviders": {},
"records": [
{
"type": "DNAME",
"name": "@",
"target": "bar.com."
}
]
}
]
}
4 changes: 4 additions & 0 deletions pkg/normalize/validate.go
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,7 @@ func validateRecordTypes(rec *models.RecordConfig, domain string, pTypes []strin
"CAA": true,
"CNAME": true,
"DHCID": true,
"DNAME": true,
"DS": true,
"IMPORT_TRANSFORM": false,
"LOC": true,
Expand Down Expand Up @@ -194,6 +195,8 @@ func checkTargets(rec *models.RecordConfig, domain string) (errs []error) {
if labelFQDN == targetFQDN {
check(fmt.Errorf("CNAME loop (target points at itself)"))
}
case "DNAME":
check(checkTarget(target))
case "LOC":
case "MX":
check(checkTarget(target))
Expand Down Expand Up @@ -679,6 +682,7 @@ var providerCapabilityChecks = []pairTypeCapability{
capabilityCheck("AZURE_ALIAS", providers.CanUseAzureAlias),
capabilityCheck("CAA", providers.CanUseCAA),
capabilityCheck("DHCID", providers.CanUseDHCID),
capabilityCheck("DNAME", providers.CanUseDNAME),
capabilityCheck("LOC", providers.CanUseLOC),
capabilityCheck("NAPTR", providers.CanUseNAPTR),
capabilityCheck("PTR", providers.CanUsePTR),
Expand Down
2 changes: 2 additions & 0 deletions pkg/prettyzone/prettyzone_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -338,6 +338,7 @@ func TestWriteZoneFileEach(t *testing.T) {
d = append(d, mustNewRR(`sub.bosun.org. 300 IN NS bosun.org.`)) // Must be a label with no other records.
d = append(d, mustNewRR(`x.bosun.org. 300 IN CNAME bosun.org.`)) // Must be a label with no other records.
d = append(d, mustNewRR(`bosun.org. 300 IN DHCID AAIBY2/AuCccgoJbsaxcQc9TUapptP69lOjxfNuVAA2kjEA=`))
d = append(d, mustNewRR(`dname.bosun.org. 300 IN DNAME example.com.`))
buf := &bytes.Buffer{}
writeZoneFileRR(buf, d, "bosun.org")
if buf.String() != testdataZFEach {
Expand All @@ -360,6 +361,7 @@ var testdataZFEach = `$TTL 300
_443._tcp IN TLSA 3 1 1 abcdef0
sub IN NS bosun.org.
x IN CNAME bosun.org.
dname IN DNAME example.com.
`

func TestWriteZoneFileSynth(t *testing.T) {
Expand Down
1 change: 1 addition & 0 deletions providers/bind/bindProvider.go
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ var features = providers.DocumentationNotes{
providers.CanConcur: providers.Cannot(),
providers.CanUseCAA: providers.Can(),
providers.CanUseDHCID: providers.Can(),
providers.CanUseDNAME: providers.Can(),
providers.CanUseDS: providers.Can(),
providers.CanUseLOC: providers.Can(),
providers.CanUseNAPTR: providers.Can(),
Expand Down
3 changes: 3 additions & 0 deletions providers/capabilities.go
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,9 @@ const (
// CanUseDHCID indicates the provider can handle DHCID records
CanUseDHCID

// CanUseDNAME indicates the provider can handle DNAME records
CanUseDNAME

// CanUseDS indicates that the provider can handle DS record types. This
// implies CanUseDSForChildren without specifying the latter explicitly.
CanUseDS
Expand Down
31 changes: 16 additions & 15 deletions providers/capability_string.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

5 changes: 3 additions & 2 deletions providers/cloudns/cloudnsProvider.go
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@ var features = providers.DocumentationNotes{
providers.CanConcur: providers.Cannot(),
providers.CanUseAlias: providers.Can(),
providers.CanUseCAA: providers.Can(),
providers.CanUseDNAME: providers.Can(),
providers.CanUseDSForChildren: providers.Can(),
providers.CanUseLOC: providers.Cannot(),
providers.CanUsePTR: providers.Can(),
Expand Down Expand Up @@ -268,7 +269,7 @@ func toRc(domain string, r *domainRecord) *models.RecordConfig {
switch rtype := r.Type; rtype { // #rtype_variations
case "TXT":
rc.SetTargetTXT(r.Target)
case "CNAME", "MX", "NS", "SRV", "ALIAS", "PTR":
case "CNAME", "DNAME", "MX", "NS", "SRV", "ALIAS", "PTR":
rc.SetTarget(dnsutil.AddOrigin(r.Target+".", domain))
case "CAA":
caaFlag, _ := strconv.ParseUint(r.CaaFlag, 10, 8)
Expand Down Expand Up @@ -323,7 +324,7 @@ func toReq(rc *models.RecordConfig) (requestParams, error) {
}

switch rc.Type { // #rtype_variations
case "A", "AAAA", "NS", "PTR", "TXT", "SOA", "ALIAS", "CNAME", "WR":
case "A", "AAAA", "NS", "PTR", "TXT", "SOA", "ALIAS", "CNAME", "WR", "DNAME":
// Nothing special.
case "CLOUDNS_WR":
req["record-type"] = "WR"
Expand Down

0 comments on commit 42125b5

Please sign in to comment.