mirror of
https://github.com/StackExchange/dnscontrol.git
synced 2024-05-11 05:55:12 +00:00
@@ -54,6 +54,7 @@ func validateRecordTypes(rec *models.RecordConfig, domain string, pTypes []strin
|
||||
"AAAA": true,
|
||||
"CNAME": true,
|
||||
"CAA": true,
|
||||
"TLSA": true,
|
||||
"IMPORT_TRANSFORM": false,
|
||||
"MX": true,
|
||||
"SRV": true,
|
||||
@@ -84,7 +85,10 @@ func validateRecordTypes(rec *models.RecordConfig, domain string, pTypes []strin
|
||||
|
||||
// underscores in names are often used erroneously. They are valid for dns records, but invalid for urls.
|
||||
// here we list common records expected to have underscores. Anything else containing an underscore will print a warning.
|
||||
var expectedUnderscores = []string{"_domainkey", "_dmarc", "_amazonses"}
|
||||
var labelUnderscores = []string{"_domainkey", "_dmarc", "_amazonses"}
|
||||
|
||||
//these record types may contain underscores
|
||||
var rTypeUnderscores = []string{"SRV", "TLSA", "TXT"}
|
||||
|
||||
func checkLabel(label string, rType string, domain string) error {
|
||||
if label == "@" {
|
||||
@@ -96,20 +100,19 @@ func checkLabel(label string, rType string, domain string) error {
|
||||
if label[len(label)-1] == '.' {
|
||||
return fmt.Errorf("label %s.%s ends with a (.)", label, domain)
|
||||
}
|
||||
|
||||
for _, ex := range rTypeUnderscores {
|
||||
if rType == ex {
|
||||
return nil
|
||||
}
|
||||
}
|
||||
for _, ex := range labelUnderscores {
|
||||
if strings.Contains(label, ex) {
|
||||
return nil
|
||||
}
|
||||
}
|
||||
//underscores are warnings
|
||||
if rType != "SRV" && strings.ContainsRune(label, '_') {
|
||||
//unless it is in our exclusion list
|
||||
ok := false
|
||||
for _, ex := range expectedUnderscores {
|
||||
if strings.Contains(label, ex) {
|
||||
ok = true
|
||||
break
|
||||
}
|
||||
}
|
||||
if !ok {
|
||||
return Warning{fmt.Errorf("label %s.%s contains an underscore", label, domain)}
|
||||
}
|
||||
if strings.ContainsRune(label, '_') {
|
||||
return Warning{fmt.Errorf("label %s.%s contains an underscore", label, domain)}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
@@ -150,7 +153,7 @@ func checkTargets(rec *models.RecordConfig, domain string) (errs []error) {
|
||||
check(checkTarget(target))
|
||||
case "SRV":
|
||||
check(checkTarget(target))
|
||||
case "TXT", "IMPORT_TRANSFORM", "CAA":
|
||||
case "TXT", "IMPORT_TRANSFORM", "CAA", "TLSA":
|
||||
default:
|
||||
if rec.Metadata["orig_custom_type"] != "" {
|
||||
//it is a valid custom type. We perform no validation on target
|
||||
@@ -207,7 +210,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", "CAA":
|
||||
case "MX", "NS", "SRV", "TXT", "CAA", "TLSA":
|
||||
// Not imported.
|
||||
continue
|
||||
default:
|
||||
@@ -291,7 +294,21 @@ func NormalizeAndValidateConfig(config *models.DNSConfig) (errs []error) {
|
||||
if rec.CaaTag != "issue" && rec.CaaTag != "issuewild" && rec.CaaTag != "iodef" {
|
||||
errs = append(errs, fmt.Errorf("CAA tag %s is invalid", rec.CaaTag))
|
||||
}
|
||||
} else if rec.Type == "TLSA" {
|
||||
if rec.TlsaUsage < 0 || rec.TlsaUsage > 3 {
|
||||
errs = append(errs, fmt.Errorf("TLSA Usage %d is invalid in record %s (domain %s)",
|
||||
rec.TlsaUsage, rec.Name, domain.Name))
|
||||
}
|
||||
if rec.TlsaSelector < 0 || rec.TlsaSelector > 1 {
|
||||
errs = append(errs, fmt.Errorf("TLSA Selector %d is invalid in record %s (domain %s)",
|
||||
rec.TlsaSelector, rec.Name, domain.Name))
|
||||
}
|
||||
if rec.TlsaMatchingType < 0 || rec.TlsaMatchingType > 2 {
|
||||
errs = append(errs, fmt.Errorf("TLSA MatchingType %d is invalid in record %s (domain %s)",
|
||||
rec.TlsaMatchingType, rec.Name, domain.Name))
|
||||
}
|
||||
}
|
||||
|
||||
// Populate FQDN:
|
||||
rec.NameFQDN = dnsutil.AddOrigin(rec.Name, domain.Name)
|
||||
}
|
||||
@@ -368,6 +385,7 @@ func checkProviderCapabilities(dc *models.DomainConfig, pList []*models.DNSProvi
|
||||
{"PTR", providers.CanUsePTR},
|
||||
{"SRV", providers.CanUseSRV},
|
||||
{"CAA", providers.CanUseCAA},
|
||||
{"TLSA", providers.CanUseTLSA},
|
||||
}
|
||||
for _, ty := range types {
|
||||
hasAny := false
|
||||
|
||||
@@ -10,21 +10,24 @@ import (
|
||||
|
||||
func TestCheckLabel(t *testing.T) {
|
||||
var tests = []struct {
|
||||
experiment string
|
||||
isError bool
|
||||
label string
|
||||
rType string
|
||||
target string
|
||||
isError bool
|
||||
}{
|
||||
{"@", false},
|
||||
{"foo", false},
|
||||
{"foo.bar", false},
|
||||
{"foo.", true},
|
||||
{"foo.bar.", true},
|
||||
{"foo_bar", true},
|
||||
{"_domainkey", false},
|
||||
{"@", "A", "0.0.0.0", false},
|
||||
{"@", "A", "foo.tld", true},
|
||||
{"foo.bar", "A", "0.0.0.0", false},
|
||||
{"_foo", "SRV", "foo.tld", false},
|
||||
{"_foo", "TLSA", "foo.tld", false},
|
||||
{"_foo", "TXT", "foo.tld", false},
|
||||
}
|
||||
|
||||
for _, test := range tests {
|
||||
err := checkLabel(test.experiment, "A", "foo.com")
|
||||
checkError(t, err, test.isError, test.experiment)
|
||||
err := checkLabel(test.label, test.rType, test.target)
|
||||
if err != nil && test.isError {
|
||||
t.Errorf("%v: Expected error but got none \n", "TestCheckLabel")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -191,3 +194,21 @@ func TestCAAValidation(t *testing.T) {
|
||||
t.Error("Expect error on invalid CAA but got none")
|
||||
}
|
||||
}
|
||||
|
||||
func TestTLSAValidation(t *testing.T) {
|
||||
config := &models.DNSConfig{
|
||||
Domains: []*models.DomainConfig{
|
||||
{
|
||||
Name: "_443._tcp.example.com",
|
||||
Registrar: "BIND",
|
||||
Records: []*models.RecordConfig{
|
||||
{Name: "_443._tcp", Type: "TLSA", TlsaUsage: 4, TlsaSelector: 1, TlsaMatchingType: 1, Target: "abcdef0"},
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
errs := NormalizeAndValidateConfig(config)
|
||||
if len(errs) != 1 {
|
||||
t.Error("Expect error on invalid TLSA but got none")
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user