mirror of
https://github.com/StackExchange/dnscontrol.git
synced 2024-12-26 01:31:16 +08:00
Add CAA support (#161)
* Added CAA support * Fixed bind parsing of CAA records * Added CAA parsing test * Renamed CAA json fields * Added CAA tag validation * Updated CAA docs to clarify on the value field * parse_tests: Fixed typo in caaflags * Added integration test * Small cleanups
This commit is contained in:
parent
1a84edbe9c
commit
2f0f5330fc
16 changed files with 283 additions and 58 deletions
36
docs/_functions/domain/CAA.md
Normal file
36
docs/_functions/domain/CAA.md
Normal file
|
@ -0,0 +1,36 @@
|
||||||
|
---
|
||||||
|
name: CAA
|
||||||
|
parameters:
|
||||||
|
- name
|
||||||
|
- tag
|
||||||
|
- value
|
||||||
|
- modifiers...
|
||||||
|
---
|
||||||
|
|
||||||
|
CAA adds a CAA record to a domain. The name should be the relative label for the record. Use `@` for the domain apex.
|
||||||
|
|
||||||
|
Tag can be one of "issue", "issuewild" or "iodef".
|
||||||
|
|
||||||
|
Value is a string. The format of the contents is different depending on the tag. DNSControl will handle any escaping or quoting required, similer to TXT records. For example use `CAA("@", "issue", "letsencrypt.org")` rather than `CAA("@", "issue", "\"letsencrypt.org\"")`.
|
||||||
|
|
||||||
|
Flags are controlled by modifier.:
|
||||||
|
|
||||||
|
- CAA_CRITICAL: Issuer critical flag. CA that does not understand this tag will refuse to issue certificate for this domain.
|
||||||
|
|
||||||
|
CAA record is supported only by BIND and Google Cloud DNS. Some certificate authorities may not support this record until the mandatory date of September 2017.
|
||||||
|
|
||||||
|
{% include startExample.html %}
|
||||||
|
{% highlight js %}
|
||||||
|
|
||||||
|
D("example.com", REGISTRAR, DnsProvider("GCLOUD"),
|
||||||
|
// Allow letsencrypt to issue certificate for this domain
|
||||||
|
CAA("@", "issue", "letsencrypt.org"),
|
||||||
|
// Allow no CA to issue wildcard certificate for this domain
|
||||||
|
CAA("@", "issuewild", ";"),
|
||||||
|
// Report all violation to test@example.com. If CA does not support
|
||||||
|
// this record then refuse to issue any certificate
|
||||||
|
CAA("@", "iodef", "mailto:test@example.com", CAA_CRITICAL)
|
||||||
|
);
|
||||||
|
|
||||||
|
{%endhighlight%}
|
||||||
|
{% include endExample.html %}
|
|
@ -236,6 +236,13 @@ func srv(name string, priority, weight, port uint16, target string) *rec {
|
||||||
return r
|
return r
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func caa(name string, tag string, flag uint8, target string) *rec {
|
||||||
|
r := makeRec(name, target, "CAA")
|
||||||
|
r.CaaFlag = flag
|
||||||
|
r.CaaTag = tag
|
||||||
|
return r
|
||||||
|
}
|
||||||
|
|
||||||
func makeRec(name, target, typ string) *rec {
|
func makeRec(name, target, typ string) *rec {
|
||||||
return &rec{
|
return &rec{
|
||||||
Name: name,
|
Name: name,
|
||||||
|
@ -327,6 +334,15 @@ var tests = []*TestCase{
|
||||||
tc("Change Weight", srv("@", 52, 62, 7, "foo.com."), srv("@", 15, 65, 75, "foo4.com.")).IfHasCapability(providers.CanUseSRV),
|
tc("Change Weight", srv("@", 52, 62, 7, "foo.com."), srv("@", 15, 65, 75, "foo4.com.")).IfHasCapability(providers.CanUseSRV),
|
||||||
tc("Change Port", srv("@", 52, 62, 72, "foo.com."), srv("@", 15, 65, 75, "foo4.com.")).IfHasCapability(providers.CanUseSRV),
|
tc("Change Port", srv("@", 52, 62, 72, "foo.com."), srv("@", 15, 65, 75, "foo4.com.")).IfHasCapability(providers.CanUseSRV),
|
||||||
|
|
||||||
|
//CAA
|
||||||
|
tc("Empty").IfHasCapability(providers.CanUseCAA),
|
||||||
|
tc("CAA record", caa("@", "issue", 0, "letsencrypt.org")).IfHasCapability(providers.CanUseCAA),
|
||||||
|
tc("CAA change tag", caa("@", "issuewild", 0, "letsencrypt.org")).IfHasCapability(providers.CanUseCAA),
|
||||||
|
tc("CAA change target", caa("@", "issuewild", 0, "example.com")).IfHasCapability(providers.CanUseCAA),
|
||||||
|
tc("CAA change flag", caa("@", "issuewild", 1, "example.com")).IfHasCapability(providers.CanUseCAA),
|
||||||
|
tc("CAA many records", caa("@", "issue", 0, "letsencrypt.org"), caa("@", "issuewild", 0, ";"), caa("@", "iodef", 1, "mailto:test@example.com")).IfHasCapability(providers.CanUseCAA),
|
||||||
|
tc("CAA delete", caa("@", "issue", 0, "letsencrypt.org")).IfHasCapability(providers.CanUseCAA),
|
||||||
|
|
||||||
//TODO: in validation, check that everything is given in unicode. This case hurts too much.
|
//TODO: in validation, check that everything is given in unicode. This case hurts too much.
|
||||||
//tc("IDN pre-punycoded", cname("xn--o-0gab", "xn--o-0gab.xn--o-0gab.")),
|
//tc("IDN pre-punycoded", cname("xn--o-0gab", "xn--o-0gab.xn--o-0gab.")),
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
$TTL 300
|
$TTL 300
|
||||||
@ IN SOA DEFAULT_NOT_SET. DEFAULT_NOT_SET. 2017071990 3600 600 604800 1440
|
@ IN SOA DEFAULT_NOT_SET. DEFAULT_NOT_SET. 2017072603 3600 600 604800 1440
|
||||||
IN NS ns1.otherdomain.tld.
|
IN NS ns1.otherdomain.tld.
|
||||||
IN NS ns2.otherdomain.tld.
|
IN NS ns2.otherdomain.tld.
|
||||||
|
|
|
@ -71,8 +71,10 @@ type RecordConfig struct {
|
||||||
SrvPriority uint16 `json:"srvpriority,omitempty"`
|
SrvPriority uint16 `json:"srvpriority,omitempty"`
|
||||||
SrvWeight uint16 `json:"srvweight,omitempty"`
|
SrvWeight uint16 `json:"srvweight,omitempty"`
|
||||||
SrvPort uint16 `json:"srvport,omitempty"`
|
SrvPort uint16 `json:"srvport,omitempty"`
|
||||||
|
CaaTag string `json:"caatag,omitempty"`
|
||||||
|
CaaFlag uint8 `json:"caaflag,omitempty"`
|
||||||
|
|
||||||
CombinedTarget bool `json:"omit"`
|
CombinedTarget bool `json:"-"`
|
||||||
|
|
||||||
Original interface{} `json:"-"` // Store pointer to provider-specific record object. Used in diffing.
|
Original interface{} `json:"-"` // Store pointer to provider-specific record object. Used in diffing.
|
||||||
}
|
}
|
||||||
|
@ -90,6 +92,8 @@ func (r *RecordConfig) String() (content string) {
|
||||||
content += fmt.Sprintf(" priority=%d", r.MxPreference)
|
content += fmt.Sprintf(" priority=%d", r.MxPreference)
|
||||||
case "SOA":
|
case "SOA":
|
||||||
content = fmt.Sprintf("%s %s %s %d", r.Type, r.Name, r.Target, r.TTL)
|
content = fmt.Sprintf("%s %s %s %d", r.Type, r.Name, r.Target, r.TTL)
|
||||||
|
case "CAA":
|
||||||
|
content += fmt.Sprintf(" caatag=%s caaflag=%d", r.CaaTag, r.CaaFlag)
|
||||||
default:
|
default:
|
||||||
panic(fmt.Sprintf("rc.String rtype %v unimplemented", r.Type))
|
panic(fmt.Sprintf("rc.String rtype %v unimplemented", r.Type))
|
||||||
}
|
}
|
||||||
|
@ -138,6 +142,8 @@ func (r *RecordConfig) MergeToTarget() {
|
||||||
r.SrvPriority = 0
|
r.SrvPriority = 0
|
||||||
r.SrvWeight = 0
|
r.SrvWeight = 0
|
||||||
r.SrvPort = 0
|
r.SrvPort = 0
|
||||||
|
r.CaaFlag = 0
|
||||||
|
r.CaaTag = ""
|
||||||
|
|
||||||
r.CombinedTarget = true
|
r.CombinedTarget = true
|
||||||
}
|
}
|
||||||
|
@ -193,6 +199,10 @@ func (rc *RecordConfig) ToRR() dns.RR {
|
||||||
rr.(*dns.SRV).Weight = rc.SrvWeight
|
rr.(*dns.SRV).Weight = rc.SrvWeight
|
||||||
rr.(*dns.SRV).Port = rc.SrvPort
|
rr.(*dns.SRV).Port = rc.SrvPort
|
||||||
rr.(*dns.SRV).Target = rc.Target
|
rr.(*dns.SRV).Target = rc.Target
|
||||||
|
case dns.TypeCAA:
|
||||||
|
rr.(*dns.CAA).Flag = rc.CaaFlag
|
||||||
|
rr.(*dns.CAA).Tag = rc.CaaTag
|
||||||
|
rr.(*dns.CAA).Value = rc.Target
|
||||||
case dns.TypeTXT:
|
case dns.TypeTXT:
|
||||||
rr.(*dns.TXT).Txt = []string{rc.Target}
|
rr.(*dns.TXT).Txt = []string{rc.Target}
|
||||||
default:
|
default:
|
||||||
|
|
|
@ -36,4 +36,19 @@ func TestRR(t *testing.T) {
|
||||||
if found != expected {
|
if found != expected {
|
||||||
t.Errorf("RR expected (%#v) got (%#v)\n", expected, found)
|
t.Errorf("RR expected (%#v) got (%#v)\n", expected, found)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
experiment = RecordConfig{
|
||||||
|
Type: "CAA",
|
||||||
|
Name: "@",
|
||||||
|
Target: "mailto:test@example.com",
|
||||||
|
TTL: 300,
|
||||||
|
NameFQDN: "example.com",
|
||||||
|
CaaTag: "iodef",
|
||||||
|
CaaFlags: 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)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -118,6 +118,8 @@ function DefaultTTL(v) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// CAA_CRITICAL: Critical CAA flag
|
||||||
|
var CAA_CRITICAL = 1<<0;
|
||||||
|
|
||||||
|
|
||||||
// DnsProvider("providerName", 0)
|
// DnsProvider("providerName", 0)
|
||||||
|
@ -156,6 +158,18 @@ function ALIAS(name, target) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// CAA(name,tag,value, recordModifiers...)
|
||||||
|
function CAA(name, tag, value){
|
||||||
|
checkArgs([_.isString, _.isString, _.isString], arguments, "CAA expects (name, tag, value) plus optional flag as a meta argument")
|
||||||
|
|
||||||
|
var mods = getModifiers(arguments,3)
|
||||||
|
mods.push({caatag: tag});
|
||||||
|
|
||||||
|
return function(d) {
|
||||||
|
addRecord(d,"CAA",name,value,mods)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
// CNAME(name,target, recordModifiers...)
|
// CNAME(name,target, recordModifiers...)
|
||||||
function CNAME(name, target) {
|
function CNAME(name, target) {
|
||||||
|
@ -303,6 +317,9 @@ function addRecord(d,type,name,target,mods) {
|
||||||
var m = mods[i]
|
var m = mods[i]
|
||||||
if (_.isFunction(m)) {
|
if (_.isFunction(m)) {
|
||||||
m(rec);
|
m(rec);
|
||||||
|
} else if (_.isObject(m) && m.caatag) {
|
||||||
|
// caatag is a top level object, not in meta
|
||||||
|
rec.caatag = m.caatag;
|
||||||
} else if (_.isObject(m)) {
|
} else if (_.isObject(m)) {
|
||||||
//convert transforms to strings
|
//convert transforms to strings
|
||||||
if (m.transform && _.isArray(m.transform)){
|
if (m.transform && _.isArray(m.transform)){
|
||||||
|
@ -312,6 +329,8 @@ function addRecord(d,type,name,target,mods) {
|
||||||
_.extend(rec.meta,m);
|
_.extend(rec.meta,m);
|
||||||
} else if (_.isNumber(m) && type == "MX") {
|
} else if (_.isNumber(m) && type == "MX") {
|
||||||
rec.mxpreference = m;
|
rec.mxpreference = m;
|
||||||
|
} else if (_.isNumber(m) && type == "CAA") {
|
||||||
|
rec.caaflags |= m;
|
||||||
} else {
|
} else {
|
||||||
console.log("WARNING: Modifier type unsupported:", typeof m, "(Skipping!)");
|
console.log("WARNING: Modifier type unsupported:", typeof m, "(Skipping!)");
|
||||||
}
|
}
|
||||||
|
|
13
pkg/js/parse_tests/014-caa.js
Normal file
13
pkg/js/parse_tests/014-caa.js
Normal file
|
@ -0,0 +1,13 @@
|
||||||
|
D("foo.com","none",
|
||||||
|
// Allow letsencrypt to issue certificate for this domain
|
||||||
|
CAA("@","issue","letsencrypt.org"),
|
||||||
|
// Allow no CA to issue wildcard certificate for this domain
|
||||||
|
CAA("@","issuewild",";"),
|
||||||
|
// Report all violation to test@example.com. If CA does not support
|
||||||
|
// this record then refuse to issue any certificate
|
||||||
|
CAA("@", "iodef", "mailto:test@example.com", CAA_CRITICAL),
|
||||||
|
// Optionally report violation to http://example.com
|
||||||
|
CAA("@", "iodef", "http://example.com"),
|
||||||
|
// Report violation to https://example.com
|
||||||
|
CAA("@", "iodef", "https://example.com", CAA_CRITICAL)
|
||||||
|
);
|
43
pkg/js/parse_tests/014-caa.json
Normal file
43
pkg/js/parse_tests/014-caa.json
Normal file
|
@ -0,0 +1,43 @@
|
||||||
|
{
|
||||||
|
"registrars":[],
|
||||||
|
"dns_providers":[],
|
||||||
|
"domains":[
|
||||||
|
{
|
||||||
|
"name":"foo.com",
|
||||||
|
"registrar":"none",
|
||||||
|
"dnsProviders":{},
|
||||||
|
"records":[
|
||||||
|
{
|
||||||
|
"type":"CAA",
|
||||||
|
"name":"@",
|
||||||
|
"target":"letsencrypt.org",
|
||||||
|
"caatag":"issue"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type":"CAA",
|
||||||
|
"name":"@",
|
||||||
|
"target":";",
|
||||||
|
"caatag":"issuewild"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type":"CAA",
|
||||||
|
"name":"@",
|
||||||
|
"target":"mailto:test@example.com",
|
||||||
|
"caatag":"iodef"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type":"CAA",
|
||||||
|
"name":"@",
|
||||||
|
"target":"http://example.com",
|
||||||
|
"caatag":"iodef"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type":"CAA",
|
||||||
|
"name":"@",
|
||||||
|
"target":"https://example.com",
|
||||||
|
"caatag":"iodef"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
107
pkg/js/static.go
107
pkg/js/static.go
|
@ -190,60 +190,63 @@ var _escData = map[string]*_escFile{
|
||||||
|
|
||||||
"/helpers.js": {
|
"/helpers.js": {
|
||||||
local: "pkg/js/helpers.js",
|
local: "pkg/js/helpers.js",
|
||||||
size: 11080,
|
size: 11743,
|
||||||
modtime: 0,
|
modtime: 0,
|
||||||
compressed: `
|
compressed: `
|
||||||
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
|
||||||
`,
|
`,
|
||||||
},
|
},
|
||||||
|
|
||||||
|
|
|
@ -53,6 +53,7 @@ func validateRecordTypes(rec *models.RecordConfig, domain string, pTypes []strin
|
||||||
"A": true,
|
"A": true,
|
||||||
"AAAA": true,
|
"AAAA": true,
|
||||||
"CNAME": true,
|
"CNAME": true,
|
||||||
|
"CAA": true,
|
||||||
"IMPORT_TRANSFORM": false,
|
"IMPORT_TRANSFORM": false,
|
||||||
"MX": true,
|
"MX": true,
|
||||||
"SRV": true,
|
"SRV": true,
|
||||||
|
@ -149,7 +150,7 @@ func checkTargets(rec *models.RecordConfig, domain string) (errs []error) {
|
||||||
check(checkTarget(target))
|
check(checkTarget(target))
|
||||||
case "SRV":
|
case "SRV":
|
||||||
check(checkTarget(target))
|
check(checkTarget(target))
|
||||||
case "TXT", "IMPORT_TRANSFORM":
|
case "TXT", "IMPORT_TRANSFORM", "CAA":
|
||||||
default:
|
default:
|
||||||
if rec.Metadata["orig_custom_type"] != "" {
|
if rec.Metadata["orig_custom_type"] != "" {
|
||||||
//it is a valid custom type. We perform no validation on target
|
//it is a valid custom type. We perform no validation on target
|
||||||
|
@ -206,7 +207,7 @@ func importTransform(srcDomain, dstDomain *models.DomainConfig, transforms []tra
|
||||||
r := newRec()
|
r := newRec()
|
||||||
r.Target = transformCNAME(r.Target, srcDomain.Name, dstDomain.Name)
|
r.Target = transformCNAME(r.Target, srcDomain.Name, dstDomain.Name)
|
||||||
dstDomain.Records = append(dstDomain.Records, r)
|
dstDomain.Records = append(dstDomain.Records, r)
|
||||||
case "MX", "NS", "SRV", "TXT":
|
case "MX", "NS", "SRV", "TXT", "CAA":
|
||||||
// Not imported.
|
// Not imported.
|
||||||
continue
|
continue
|
||||||
default:
|
default:
|
||||||
|
@ -281,6 +282,10 @@ func NormalizeAndValidateConfig(config *models.DNSConfig) (errs []error) {
|
||||||
if rec.Name, err = transform.PtrNameMagic(rec.Name, domain.Name); err != nil {
|
if rec.Name, err = transform.PtrNameMagic(rec.Name, domain.Name); err != nil {
|
||||||
errs = append(errs, err)
|
errs = append(errs, err)
|
||||||
}
|
}
|
||||||
|
} else if rec.Type == "CAA" {
|
||||||
|
if rec.CaaTag != "issue" && rec.CaaTag != "issuewild" && rec.CaaTag != "iodef" {
|
||||||
|
errs = append(errs, fmt.Errorf("CAA tag %s is invalid", rec.CaaTag))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
// Populate FQDN:
|
// Populate FQDN:
|
||||||
rec.NameFQDN = dnsutil.AddOrigin(rec.Name, domain.Name)
|
rec.NameFQDN = dnsutil.AddOrigin(rec.Name, domain.Name)
|
||||||
|
@ -357,6 +362,7 @@ func checkProviderCapabilities(dc *models.DomainConfig, pList []*models.DNSProvi
|
||||||
{"ALIAS", providers.CanUseAlias},
|
{"ALIAS", providers.CanUseAlias},
|
||||||
{"PTR", providers.CanUsePTR},
|
{"PTR", providers.CanUsePTR},
|
||||||
{"SRV", providers.CanUseSRV},
|
{"SRV", providers.CanUseSRV},
|
||||||
|
{"CAA", providers.CanUseCAA},
|
||||||
}
|
}
|
||||||
for _, ty := range types {
|
for _, ty := range types {
|
||||||
hasAny := false
|
hasAny := false
|
||||||
|
|
|
@ -173,3 +173,21 @@ func TestCNAMEMutex(t *testing.T) {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestCAAValidation(t *testing.T) {
|
||||||
|
config := &models.DNSConfig{
|
||||||
|
Domains: []*models.DomainConfig{
|
||||||
|
{
|
||||||
|
Name: "example.com",
|
||||||
|
Registrar: "BIND",
|
||||||
|
Records: []*models.RecordConfig{
|
||||||
|
{Name: "@", Type: "CAA", CaaTag: "invalid", Target: "example.com"},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
errs := NormalizeAndValidateConfig(config)
|
||||||
|
if len(errs) != 1 {
|
||||||
|
t.Error("Expect error on invalid CAA but got none")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -47,7 +47,7 @@ func initBind(config map[string]string, providermeta json.RawMessage) (providers
|
||||||
}
|
}
|
||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
providers.RegisterDomainServiceProviderType("BIND", initBind, providers.CanUsePTR, providers.CanUseSRV)
|
providers.RegisterDomainServiceProviderType("BIND", initBind, providers.CanUsePTR, providers.CanUseSRV, providers.CanUseCAA)
|
||||||
}
|
}
|
||||||
|
|
||||||
type SoaInfo struct {
|
type SoaInfo struct {
|
||||||
|
@ -93,6 +93,10 @@ func rrToRecord(rr dns.RR, origin string, replaceSerial uint32) (models.RecordCo
|
||||||
rc.Target = v.A.String()
|
rc.Target = v.A.String()
|
||||||
case *dns.AAAA:
|
case *dns.AAAA:
|
||||||
rc.Target = v.AAAA.String()
|
rc.Target = v.AAAA.String()
|
||||||
|
case *dns.CAA:
|
||||||
|
rc.CaaTag = v.Tag
|
||||||
|
rc.CaaFlag = v.Flag
|
||||||
|
rc.Target = v.Value
|
||||||
case *dns.CNAME:
|
case *dns.CNAME:
|
||||||
rc.Target = v.Target
|
rc.Target = v.Target
|
||||||
case *dns.MX:
|
case *dns.MX:
|
||||||
|
|
|
@ -67,6 +67,19 @@ func (z *zoneGenData) Less(i, j int) bool {
|
||||||
if pa != pb {
|
if pa != pb {
|
||||||
return pa < pb
|
return pa < pb
|
||||||
}
|
}
|
||||||
|
case dns.TypeCAA:
|
||||||
|
ta2, tb2 := a.(*dns.CAA), b.(*dns.CAA)
|
||||||
|
// sort by tag
|
||||||
|
pa, pb := ta2.Tag, tb2.Tag
|
||||||
|
if pa != pb {
|
||||||
|
return pa < pb
|
||||||
|
}
|
||||||
|
// then flag
|
||||||
|
fa, fb := ta2.Flag, tb2.Flag
|
||||||
|
if fa != fb {
|
||||||
|
// flag set goes before ones without flag set
|
||||||
|
return fa > fb
|
||||||
|
}
|
||||||
default:
|
default:
|
||||||
panic(fmt.Sprintf("zoneGenData Less: unimplemented rtype %v", dns.TypeToString[rrtypeA]))
|
panic(fmt.Sprintf("zoneGenData Less: unimplemented rtype %v", dns.TypeToString[rrtypeA]))
|
||||||
}
|
}
|
||||||
|
|
|
@ -181,6 +181,33 @@ var testdataZFSRV = `$TTL 300
|
||||||
IN SRV 10 10 9999 foo.com.
|
IN SRV 10 10 9999 foo.com.
|
||||||
`
|
`
|
||||||
|
|
||||||
|
func TestWriteZoneFileCaa(t *testing.T) {
|
||||||
|
//exhibits explicit ttls and long name
|
||||||
|
r1, _ := dns.NewRR(`bosun.org. 300 IN CAA 0 issuewild ";"`)
|
||||||
|
r2, _ := dns.NewRR(`bosun.org. 300 IN CAA 0 issue "letsencrypt.org"`)
|
||||||
|
r3, _ := dns.NewRR(`bosun.org. 300 IN CAA 1 iodef "http://example.com"`)
|
||||||
|
r4, _ := dns.NewRR(`bosun.org. 300 IN CAA 0 iodef "https://example.com"`)
|
||||||
|
r5, _ := dns.NewRR(`bosun.org. 300 IN CAA 0 iodef "https://example.net"`)
|
||||||
|
r6, _ := dns.NewRR(`bosun.org. 300 IN CAA 1 iodef "mailto:example.com"`)
|
||||||
|
buf := &bytes.Buffer{}
|
||||||
|
WriteZoneFile(buf, []dns.RR{r1, r2, r3, r4, r5, r6}, "bosun.org")
|
||||||
|
if buf.String() != testdataZFCAA {
|
||||||
|
t.Log(buf.String())
|
||||||
|
t.Log(testdataZFCAA)
|
||||||
|
t.Fatalf("Zone file does not match.")
|
||||||
|
}
|
||||||
|
parseAndRegen(t, buf, testdataZFCAA)
|
||||||
|
}
|
||||||
|
|
||||||
|
var testdataZFCAA = `$TTL 300
|
||||||
|
@ IN CAA 1 iodef "http://example.com"
|
||||||
|
IN CAA 1 iodef "mailto:example.com"
|
||||||
|
IN CAA 0 iodef "https://example.com"
|
||||||
|
IN CAA 0 iodef "https://example.net"
|
||||||
|
IN CAA 0 issue "letsencrypt.org"
|
||||||
|
IN CAA 0 issuewild ";"
|
||||||
|
`
|
||||||
|
|
||||||
func TestWriteZoneFileOrder(t *testing.T) {
|
func TestWriteZoneFileOrder(t *testing.T) {
|
||||||
var records []dns.RR
|
var records []dns.RR
|
||||||
for i, td := range []string{
|
for i, td := range []string{
|
||||||
|
|
|
@ -15,7 +15,7 @@ import (
|
||||||
)
|
)
|
||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
providers.RegisterDomainServiceProviderType("GCLOUD", New, providers.CanUsePTR, providers.CanUseSRV)
|
providers.RegisterDomainServiceProviderType("GCLOUD", New, providers.CanUsePTR, providers.CanUseSRV, providers.CanUseCAA)
|
||||||
}
|
}
|
||||||
|
|
||||||
type gcloud struct {
|
type gcloud struct {
|
||||||
|
|
|
@ -47,6 +47,8 @@ const (
|
||||||
CanUsePTR
|
CanUsePTR
|
||||||
// CanUseSRV indicates the provider can handle SRV records
|
// CanUseSRV indicates the provider can handle SRV records
|
||||||
CanUseSRV
|
CanUseSRV
|
||||||
|
// CanUseCAA indicates the provider can handle CAA records
|
||||||
|
CanUseCAA
|
||||||
)
|
)
|
||||||
|
|
||||||
func ProviderHasCabability(pType string, cap Capability) bool {
|
func ProviderHasCabability(pType string, cap Capability) bool {
|
||||||
|
|
Loading…
Reference in a new issue