mirror of
https://github.com/StackExchange/dnscontrol.git
synced 2024-05-11 05:55:12 +00:00
Support ALIAS records with Cloudflare (#89)
* simple facility for registering provider capabilities * support for cloudflare. tests. * js and docs * docs * generate
This commit is contained in:
25
docs/_functions/domain/ALIAS.md
Normal file
25
docs/_functions/domain/ALIAS.md
Normal file
@ -0,0 +1,25 @@
|
||||
---
|
||||
name: ALIAS
|
||||
parameters:
|
||||
- name
|
||||
- target
|
||||
- modifiers...
|
||||
---
|
||||
|
||||
ALIAS is a virtual record type that points a record at another record. It is analagous to a CNAME, but is usually resolved at request-time and served as an A record. Unlike CNAMEs, ALIAS records can be used at the zone apex (`@`)
|
||||
|
||||
Different providers handle ALIAS records differently, and many do not support it at all. Attempting to use ALIAS records with a DNS provider type that does not support them will result in an error.
|
||||
|
||||
The name should be the relative label for the domain.
|
||||
|
||||
Target should be a string representing the target. If it is a single label we will assume it is a relative name on the current domain. If it contains *any* dots, it should be a fully qualified domain name, ending with a `.`.
|
||||
|
||||
{% include startExample.html %}
|
||||
{% highlight js %}
|
||||
|
||||
D("example.com", REGISTRAR, DnsProvider("CLOUDFLARE"),
|
||||
ALIAS("@", "google.com."), // example.com -> google.com
|
||||
);
|
||||
|
||||
{%endhighlight%}
|
||||
{% include endExample.html %}
|
25
docs/alias.md
Normal file
25
docs/alias.md
Normal file
@ -0,0 +1,25 @@
|
||||
---
|
||||
layout: default
|
||||
---
|
||||
|
||||
# ALIAS records
|
||||
|
||||
ALIAS records are not widely standardized across DNS providers. Some (Route 53, DNSimple) have a native ALIAS record type. Others (Cloudflare) implement transparent CNAME flattening.
|
||||
|
||||
DNSControl adds an ALIAS record type, and leaves it up to the provider implementation to handle it.
|
||||
|
||||
A few notes:
|
||||
|
||||
1. A provider must "opt-in" to supporting ALIAS records. When registering a provider, you specify which capabilities you support. Here is an example of how the
|
||||
cloudflare provider declares its support for aliases:
|
||||
|
||||
```
|
||||
func init() {
|
||||
providers.RegisterDomainServiceProviderType("CLOUDFLAREAPI", newCloudflare, providers.CanUseAlias)
|
||||
}
|
||||
```
|
||||
|
||||
2. If you try to use ALIAS records, **all** dns providers for the domain must support ALIAS records. We do not want to serve inconsistent records across providers.
|
||||
3. CNAMEs at `@` are disallowed, but ALIAS is allowed.
|
||||
4. Cloudflare does not have a native ALIAS type, but CNAMEs behave similarly. The Cloudflare provider "rewrites" ALIAS records to CNAME as it sees them. Other providers may not need this step.
|
||||
|
@ -23,3 +23,4 @@ Dnscontrol is a platform for seamlessly managing your dns configuration across a
|
||||
|
||||
- [Why CNAME/MX/NS targets require a trailing "dot"]({{site.github.url}}/why-the-dot)
|
||||
- [Writing Providers]({{site.github.url}}/writing-providers)
|
||||
- [ALIAS records in dnscontrol]({{site.github.url}}/alias)
|
||||
|
@ -97,6 +97,10 @@ func runTests(t *testing.T, prv providers.DNSServiceProvider, domainName string,
|
||||
break
|
||||
}
|
||||
t.Run(fmt.Sprintf("%d: %s", i, tst.Desc), func(t *testing.T) {
|
||||
if tst.SkipUnless != 0 && !providers.ProviderHasCabability(*providerToRun, tst.SkipUnless) {
|
||||
t.Log("Skipping because provider does not support test features")
|
||||
return
|
||||
}
|
||||
skipVal := false
|
||||
if knownFailures[i] {
|
||||
t.Log("SKIPPING VALIDATION FOR KNOWN FAILURE CASE")
|
||||
@ -188,6 +192,7 @@ func TestDualProviders(t *testing.T) {
|
||||
type TestCase struct {
|
||||
Desc string
|
||||
Records []*rec
|
||||
SkipUnless providers.Capability
|
||||
}
|
||||
|
||||
type rec models.RecordConfig
|
||||
@ -200,6 +205,10 @@ func cname(name, target string) *rec {
|
||||
return makeRec(name, target, "CNAME")
|
||||
}
|
||||
|
||||
func alias(name, target string) *rec {
|
||||
return makeRec(name, target, "ALIAS")
|
||||
}
|
||||
|
||||
func ns(name, target string) *rec {
|
||||
return makeRec(name, target, "NS")
|
||||
}
|
||||
@ -231,6 +240,11 @@ func tc(desc string, recs ...*rec) *TestCase {
|
||||
}
|
||||
}
|
||||
|
||||
func (tc *TestCase) IfHasCapability(c providers.Capability) *TestCase {
|
||||
tc.SkipUnless = c
|
||||
return tc
|
||||
}
|
||||
|
||||
//ALWAYS ADD TO BOTTOM OF LIST. Order and indexes matter.
|
||||
var tests = []*TestCase{
|
||||
// A
|
||||
@ -274,5 +288,12 @@ var tests = []*TestCase{
|
||||
tc("Change to other name", mx("@", 5, "foo2.com."), mx("mail", 15, "foo3.com.")),
|
||||
tc("Change Priority", mx("@", 7, "foo2.com."), mx("mail", 15, "foo3.com.")),
|
||||
|
||||
tc("IDN pre-punycoded", cname("xn--o-0gab", "xn--o-0gab.xn--o-0gab.")),
|
||||
//ALIAS
|
||||
tc("EMPTY"),
|
||||
tc("ALIAS at root", alias("@", "foo.com.")).IfHasCapability(providers.CanUseAlias),
|
||||
tc("change it", alias("@", "foo2.com.")).IfHasCapability(providers.CanUseAlias),
|
||||
tc("ALIAS at subdomain", alias("test", "foo.com.")).IfHasCapability(providers.CanUseAlias),
|
||||
|
||||
//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,7 +1,17 @@
|
||||
{
|
||||
"ACTIVEDIRECTORY_PS": {
|
||||
"knownFailures": "17,18,19,25,26,27,28,29,30",
|
||||
"domain": "$AD_DOMAIN",
|
||||
"ADServer": "$AD_SERVER"
|
||||
},
|
||||
"BIND": {
|
||||
"domain": "example.com"
|
||||
},
|
||||
"CLOUDFLAREAPI":{
|
||||
"domain": "$CF_DOMAIN",
|
||||
"apiuser": "$CF_USER",
|
||||
"apikey": "$CF_KEY"
|
||||
},
|
||||
"DNSIMPLE": {
|
||||
//16/17: no ns records managable. Not even for subdomains.
|
||||
"knownFailures": "17,18",
|
||||
@ -25,10 +35,5 @@
|
||||
"domain": "$R53_DOMAIN",
|
||||
"KeyId": "$R53_KEY_ID",
|
||||
"SecretKey": "$R53_KEY"
|
||||
},
|
||||
"ACTIVEDIRECTORY_PS":{
|
||||
"knownFailures": "17,18,19,25,26,27,28,29,30",
|
||||
"domain": "$AD_DOMAIN",
|
||||
"ADServer": "$AD_SERVER"
|
||||
}
|
||||
}
|
@ -1,4 +1,2 @@
|
||||
$TTL 300
|
||||
@ IN SOA DEFAULT_NOT_SET. DEFAULT_NOT_SET. 2017032394 3600 600 604800 1440
|
||||
IN MX 7 foo2.com.
|
||||
mail IN MX 15 foo3.com.
|
||||
@ IN SOA DEFAULT_NOT_SET. DEFAULT_NOT_SET. 2017041717 3600 600 604800 1440
|
||||
|
@ -123,6 +123,15 @@ function AAAA(name, ip) {
|
||||
}
|
||||
}
|
||||
|
||||
// ALIAS(name,target, recordModifiers...)
|
||||
function ALIAS(name, target) {
|
||||
var mods = getModifiers(arguments,2)
|
||||
return function(d) {
|
||||
addRecord(d,"ALIAS",name,target,mods)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// CNAME(name,target, recordModifiers...)
|
||||
function CNAME(name, target) {
|
||||
var mods = getModifiers(arguments,2)
|
||||
|
@ -30,7 +30,7 @@ func TestParsedFiles(t *testing.T) {
|
||||
if filepath.Ext(f.Name()) != ".js" || !unicode.IsNumber(rune(f.Name()[0])) {
|
||||
continue
|
||||
}
|
||||
t.Log(f.Name(), "------")
|
||||
t.Run(f.Name(), func(t *testing.T) {
|
||||
content, err := ioutil.ReadFile(filepath.Join(testDir, f.Name()))
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
@ -39,7 +39,7 @@ func TestParsedFiles(t *testing.T) {
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
actualJson, err := json.MarshalIndent(conf, "", " ")
|
||||
actualJSON, err := json.MarshalIndent(conf, "", " ")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
@ -49,20 +49,21 @@ func TestParsedFiles(t *testing.T) {
|
||||
t.Fatal(err)
|
||||
}
|
||||
conf = &models.DNSConfig{}
|
||||
//unmarshal and remarshal to not require manual formatting
|
||||
err = json.Unmarshal(expectedData, conf)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
expectedJson, err := json.MarshalIndent(conf, "", " ")
|
||||
expectedJSON, err := json.MarshalIndent(conf, "", " ")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if string(expectedJson) != string(actualJson) {
|
||||
if string(expectedJSON) != string(actualJSON) {
|
||||
t.Error("Expected and actual json don't match")
|
||||
t.Log("Expected:", string(expectedJson))
|
||||
t.Log("Actual:", string(actualJson))
|
||||
t.FailNow()
|
||||
t.Log("Expected:", string(expectedJSON))
|
||||
t.Log("Actual:", string(actualJSON))
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
|
3
js/parse_tests/010-alias.js
Normal file
3
js/parse_tests/010-alias.js
Normal file
@ -0,0 +1,3 @@
|
||||
D("foo.com","none",
|
||||
ALIAS("@","foo.com.")
|
||||
);
|
19
js/parse_tests/010-alias.json
Normal file
19
js/parse_tests/010-alias.json
Normal file
@ -0,0 +1,19 @@
|
||||
{
|
||||
"registrars": [],
|
||||
"dns_providers": [],
|
||||
"domains": [
|
||||
{
|
||||
"name": "foo.com",
|
||||
"registrar": "none",
|
||||
"dnsProviders": {},
|
||||
"records": [
|
||||
{
|
||||
"type": "ALIAS",
|
||||
"name": "@",
|
||||
"target": "foo.com."
|
||||
}
|
||||
],
|
||||
"keepunknown": false
|
||||
}
|
||||
]
|
||||
}
|
80
js/static.go
80
js/static.go
@ -190,48 +190,48 @@ var _escData = map[string]*_escFile{
|
||||
|
||||
"/helpers.js": {
|
||||
local: "js/helpers.js",
|
||||
size: 7563,
|
||||
size: 7758,
|
||||
modtime: 0,
|
||||
compressed: `
|
||||
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
|
||||
`,
|
||||
},
|
||||
|
||||
|
@ -6,6 +6,7 @@ import (
|
||||
"strings"
|
||||
|
||||
"github.com/StackExchange/dnscontrol/models"
|
||||
"github.com/StackExchange/dnscontrol/providers"
|
||||
"github.com/StackExchange/dnscontrol/transform"
|
||||
"github.com/miekg/dns"
|
||||
"github.com/miekg/dns/dnsutil"
|
||||
@ -52,6 +53,7 @@ func validateRecordTypes(rec *models.RecordConfig, domain string) error {
|
||||
"MX": true,
|
||||
"TXT": true,
|
||||
"NS": true,
|
||||
"ALIAS": false,
|
||||
}
|
||||
|
||||
if _, ok := validTypes[rec.Type]; !ok {
|
||||
@ -112,6 +114,9 @@ func checkTargets(rec *models.RecordConfig, domain string) (errs []error) {
|
||||
check(checkIPv6(target))
|
||||
case "CNAME":
|
||||
check(checkTarget(target))
|
||||
if label == "@" {
|
||||
check(fmt.Errorf("cannot create CNAME record for bare domain"))
|
||||
}
|
||||
case "MX":
|
||||
check(checkTarget(target))
|
||||
case "NS":
|
||||
@ -119,6 +124,8 @@ func checkTargets(rec *models.RecordConfig, domain string) (errs []error) {
|
||||
if label == "@" {
|
||||
check(fmt.Errorf("cannot create NS record for bare domain. Use NAMESERVER instead"))
|
||||
}
|
||||
case "ALIAS":
|
||||
check(checkTarget(target))
|
||||
case "TXT", "IMPORT_TRANSFORM":
|
||||
default:
|
||||
errs = append(errs, fmt.Errorf("Unimplemented record type (%v) domain=%v name=%v",
|
||||
@ -260,9 +267,20 @@ func NormalizeAndValidateConfig(config *models.DNSConfig) (errs []error) {
|
||||
errs = append(errs, err)
|
||||
}
|
||||
}
|
||||
|
||||
//Check that CNAMES don't have to co-exist with any other records
|
||||
for _, d := range config.Domains {
|
||||
errs = append(errs, checkCNAMEs(d)...)
|
||||
}
|
||||
|
||||
//Check that if any aliases are used in a domain, every provider for that domain supports them
|
||||
for _, d := range config.Domains {
|
||||
err := checkALIASes(d, config.DNSProviders)
|
||||
if err != nil {
|
||||
errs = append(errs, nil)
|
||||
}
|
||||
}
|
||||
|
||||
return errs
|
||||
}
|
||||
|
||||
@ -284,6 +302,30 @@ func checkCNAMEs(dc *models.DomainConfig) (errs []error) {
|
||||
return
|
||||
}
|
||||
|
||||
func checkALIASes(dc *models.DomainConfig, pList []*models.DNSProviderConfig) error {
|
||||
hasAlias := false
|
||||
for _, r := range dc.Records {
|
||||
if r.Type == "ALIAS" {
|
||||
hasAlias = true
|
||||
break
|
||||
}
|
||||
}
|
||||
if !hasAlias {
|
||||
return nil
|
||||
}
|
||||
for pName := range dc.DNSProviders {
|
||||
for _, p := range pList {
|
||||
if p.Name == pName {
|
||||
if !providers.ProviderHasCabability(p.Type, providers.CanUseAlias) {
|
||||
return fmt.Errorf("Domain %s uses ALIAS records, but DNS provider type %s does not support them", dc.Name, p.Type)
|
||||
}
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func applyRecordTransforms(domain *models.DomainConfig) error {
|
||||
for _, rec := range domain.Records {
|
||||
if rec.Type != "A" {
|
||||
|
@ -81,7 +81,6 @@ func (c *CloudflareApi) GetDomainCorrections(dc *models.DomainConfig) ([]*models
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
//for _, rec := range records {
|
||||
for i := len(records) - 1; i >= 0; i-- {
|
||||
rec := records[i]
|
||||
// Delete ignore labels
|
||||
@ -91,9 +90,11 @@ func (c *CloudflareApi) GetDomainCorrections(dc *models.DomainConfig) ([]*models
|
||||
}
|
||||
}
|
||||
for _, rec := range dc.Records {
|
||||
if rec.Type == "ALIAS" {
|
||||
rec.Type = "CNAME"
|
||||
}
|
||||
if labelMatches(rec.Name, c.ignoredLabels) {
|
||||
log.Fatalf("FATAL: dnsconfig contains label that matches ignored_labels: %#v is in %v)\n", rec.Name, c.ignoredLabels)
|
||||
// Since we log.Fatalf, we don't need to be clean here.
|
||||
}
|
||||
}
|
||||
checkNSModifications(dc)
|
||||
@ -166,9 +167,15 @@ func (c *CloudflareApi) preprocessConfig(dc *models.DomainConfig) error {
|
||||
// A and CNAMEs: Validate. If null, set to default.
|
||||
// else: Make sure it wasn't set. Set to default.
|
||||
for _, rec := range dc.Records {
|
||||
if rec.Metadata == nil {
|
||||
rec.Metadata = map[string]string{}
|
||||
}
|
||||
if rec.TTL == 0 || rec.TTL == 300 {
|
||||
rec.TTL = 1
|
||||
}
|
||||
if rec.TTL != 1 && rec.TTL < 120 {
|
||||
rec.TTL = 120
|
||||
}
|
||||
if rec.Type != "A" && rec.Type != "CNAME" && rec.Type != "AAAA" {
|
||||
if rec.Metadata[metaProxy] != "" {
|
||||
return fmt.Errorf("cloudflare_proxy set on %v record: %#v cloudflare_proxy=%#v", rec.Type, rec.Name, rec.Metadata[metaProxy])
|
||||
@ -243,7 +250,7 @@ func newCloudflare(m map[string]string, metadata json.RawMessage) (providers.DNS
|
||||
}
|
||||
|
||||
func init() {
|
||||
providers.RegisterDomainServiceProviderType("CLOUDFLAREAPI", newCloudflare)
|
||||
providers.RegisterDomainServiceProviderType("CLOUDFLAREAPI", newCloudflare, providers.CanUseAlias)
|
||||
}
|
||||
|
||||
// Used on the "existing" records.
|
||||
|
@ -34,6 +34,21 @@ var registrarTypes = map[string]RegistrarInitializer{}
|
||||
type DspInitializer func(map[string]string, json.RawMessage) (DNSServiceProvider, error)
|
||||
|
||||
var dspTypes = map[string]DspInitializer{}
|
||||
var dspCapabilities = map[string]Capability{}
|
||||
|
||||
//Capability is a bitmasked set of "features" that a provider supports. Only use constants from this package.
|
||||
type Capability uint32
|
||||
|
||||
const (
|
||||
// CanUseAlias indicates the provider support ALIAS records (or flattened CNAMES). Up to the provider to translate them to the appropriate record type.
|
||||
CanUseAlias Capability = 1 << iota
|
||||
// CanUsePTR indicates the provider can handle PTR records
|
||||
CanUsePTR
|
||||
)
|
||||
|
||||
func ProviderHasCabability(pType string, cap Capability) bool {
|
||||
return dspCapabilities[pType]&cap != 0
|
||||
}
|
||||
|
||||
//RegisterRegistrarType adds a registrar type to the registry by providing a suitable initialization function.
|
||||
func RegisterRegistrarType(name string, init RegistrarInitializer) {
|
||||
@ -44,11 +59,16 @@ func RegisterRegistrarType(name string, init RegistrarInitializer) {
|
||||
}
|
||||
|
||||
//RegisterDomainServiceProviderType adds a dsp to the registry with the given initialization function.
|
||||
func RegisterDomainServiceProviderType(name string, init DspInitializer) {
|
||||
func RegisterDomainServiceProviderType(name string, init DspInitializer, caps ...Capability) {
|
||||
if _, ok := dspTypes[name]; ok {
|
||||
log.Fatalf("Cannot register registrar type %s multiple times", name)
|
||||
}
|
||||
var abilities Capability
|
||||
for _, c := range caps {
|
||||
abilities |= c
|
||||
}
|
||||
dspTypes[name] = init
|
||||
dspCapabilities[name] = abilities
|
||||
}
|
||||
|
||||
func createRegistrar(rType string, config map[string]string) (Registrar, error) {
|
||||
|
Reference in New Issue
Block a user