mirror of
https://github.com/StackExchange/dnscontrol.git
synced 2024-12-25 09:12:31 +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
|
||||
}
|
||||
|
||||
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 {
|
||||
return &rec{
|
||||
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 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.
|
||||
//tc("IDN pre-punycoded", cname("xn--o-0gab", "xn--o-0gab.xn--o-0gab.")),
|
||||
}
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
$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 ns2.otherdomain.tld.
|
||||
|
|
|
@ -71,8 +71,10 @@ type RecordConfig struct {
|
|||
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"`
|
||||
|
||||
CombinedTarget bool `json:"omit"`
|
||||
CombinedTarget bool `json:"-"`
|
||||
|
||||
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)
|
||||
case "SOA":
|
||||
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:
|
||||
panic(fmt.Sprintf("rc.String rtype %v unimplemented", r.Type))
|
||||
}
|
||||
|
@ -138,6 +142,8 @@ func (r *RecordConfig) MergeToTarget() {
|
|||
r.SrvPriority = 0
|
||||
r.SrvWeight = 0
|
||||
r.SrvPort = 0
|
||||
r.CaaFlag = 0
|
||||
r.CaaTag = ""
|
||||
|
||||
r.CombinedTarget = true
|
||||
}
|
||||
|
@ -193,6 +199,10 @@ func (rc *RecordConfig) ToRR() dns.RR {
|
|||
rr.(*dns.SRV).Weight = rc.SrvWeight
|
||||
rr.(*dns.SRV).Port = rc.SrvPort
|
||||
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:
|
||||
rr.(*dns.TXT).Txt = []string{rc.Target}
|
||||
default:
|
||||
|
|
|
@ -36,4 +36,19 @@ func TestRR(t *testing.T) {
|
|||
if found != expected {
|
||||
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)
|
||||
|
@ -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...)
|
||||
function CNAME(name, target) {
|
||||
|
@ -303,6 +317,9 @@ function addRecord(d,type,name,target,mods) {
|
|||
var m = mods[i]
|
||||
if (_.isFunction(m)) {
|
||||
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)) {
|
||||
//convert transforms to strings
|
||||
if (m.transform && _.isArray(m.transform)){
|
||||
|
@ -312,6 +329,8 @@ function addRecord(d,type,name,target,mods) {
|
|||
_.extend(rec.meta,m);
|
||||
} else if (_.isNumber(m) && type == "MX") {
|
||||
rec.mxpreference = m;
|
||||
} else if (_.isNumber(m) && type == "CAA") {
|
||||
rec.caaflags |= m;
|
||||
} else {
|
||||
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": {
|
||||
local: "pkg/js/helpers.js",
|
||||
size: 11080,
|
||||
size: 11743,
|
||||
modtime: 0,
|
||||
compressed: `
|
||||
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
|
||||
`,
|
||||
},
|
||||
|
||||
|
|
|
@ -53,6 +53,7 @@ func validateRecordTypes(rec *models.RecordConfig, domain string, pTypes []strin
|
|||
"A": true,
|
||||
"AAAA": true,
|
||||
"CNAME": true,
|
||||
"CAA": true,
|
||||
"IMPORT_TRANSFORM": false,
|
||||
"MX": true,
|
||||
"SRV": true,
|
||||
|
@ -149,7 +150,7 @@ func checkTargets(rec *models.RecordConfig, domain string) (errs []error) {
|
|||
check(checkTarget(target))
|
||||
case "SRV":
|
||||
check(checkTarget(target))
|
||||
case "TXT", "IMPORT_TRANSFORM":
|
||||
case "TXT", "IMPORT_TRANSFORM", "CAA":
|
||||
default:
|
||||
if rec.Metadata["orig_custom_type"] != "" {
|
||||
//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.Target = transformCNAME(r.Target, srcDomain.Name, dstDomain.Name)
|
||||
dstDomain.Records = append(dstDomain.Records, r)
|
||||
case "MX", "NS", "SRV", "TXT":
|
||||
case "MX", "NS", "SRV", "TXT", "CAA":
|
||||
// Not imported.
|
||||
continue
|
||||
default:
|
||||
|
@ -281,6 +282,10 @@ func NormalizeAndValidateConfig(config *models.DNSConfig) (errs []error) {
|
|||
if rec.Name, err = transform.PtrNameMagic(rec.Name, domain.Name); err != nil {
|
||||
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:
|
||||
rec.NameFQDN = dnsutil.AddOrigin(rec.Name, domain.Name)
|
||||
|
@ -357,6 +362,7 @@ func checkProviderCapabilities(dc *models.DomainConfig, pList []*models.DNSProvi
|
|||
{"ALIAS", providers.CanUseAlias},
|
||||
{"PTR", providers.CanUsePTR},
|
||||
{"SRV", providers.CanUseSRV},
|
||||
{"CAA", providers.CanUseCAA},
|
||||
}
|
||||
for _, ty := range types {
|
||||
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() {
|
||||
providers.RegisterDomainServiceProviderType("BIND", initBind, providers.CanUsePTR, providers.CanUseSRV)
|
||||
providers.RegisterDomainServiceProviderType("BIND", initBind, providers.CanUsePTR, providers.CanUseSRV, providers.CanUseCAA)
|
||||
}
|
||||
|
||||
type SoaInfo struct {
|
||||
|
@ -93,6 +93,10 @@ func rrToRecord(rr dns.RR, origin string, replaceSerial uint32) (models.RecordCo
|
|||
rc.Target = v.A.String()
|
||||
case *dns.AAAA:
|
||||
rc.Target = v.AAAA.String()
|
||||
case *dns.CAA:
|
||||
rc.CaaTag = v.Tag
|
||||
rc.CaaFlag = v.Flag
|
||||
rc.Target = v.Value
|
||||
case *dns.CNAME:
|
||||
rc.Target = v.Target
|
||||
case *dns.MX:
|
||||
|
|
|
@ -67,6 +67,19 @@ func (z *zoneGenData) Less(i, j int) bool {
|
|||
if 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:
|
||||
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.
|
||||
`
|
||||
|
||||
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) {
|
||||
var records []dns.RR
|
||||
for i, td := range []string{
|
||||
|
|
|
@ -15,7 +15,7 @@ import (
|
|||
)
|
||||
|
||||
func init() {
|
||||
providers.RegisterDomainServiceProviderType("GCLOUD", New, providers.CanUsePTR, providers.CanUseSRV)
|
||||
providers.RegisterDomainServiceProviderType("GCLOUD", New, providers.CanUsePTR, providers.CanUseSRV, providers.CanUseCAA)
|
||||
}
|
||||
|
||||
type gcloud struct {
|
||||
|
|
|
@ -47,6 +47,8 @@ const (
|
|||
CanUsePTR
|
||||
// CanUseSRV indicates the provider can handle SRV records
|
||||
CanUseSRV
|
||||
// CanUseCAA indicates the provider can handle CAA records
|
||||
CanUseCAA
|
||||
)
|
||||
|
||||
func ProviderHasCabability(pType string, cap Capability) bool {
|
||||
|
|
Loading…
Reference in a new issue