1
0
mirror of https://github.com/StackExchange/dnscontrol.git synced 2024-05-11 05:55:12 +00:00

Add SRV Record Type (#136)

* Add support for SRV records for NAMEDOTCOM and ROUTE53.
* Improve docs
* Rename RR() to ToRR().
* Rename RecordConfig Priority to MxPreference (affects json IR data)
This commit is contained in:
Tom Limoncelli
2017-07-19 15:53:40 -04:00
committed by GitHub
parent 032750743c
commit d55b20ecdb
23 changed files with 351 additions and 161 deletions

View File

@ -119,7 +119,12 @@ func runTests(t *testing.T, prv providers.DNSServiceProvider, domainName string,
t.Fatal(err)
}
if !skipVal && i != *startIdx && len(corrections) == 0 {
t.Fatalf("Expect changes for all tests, but got none")
if tst.Desc != "Empty" {
// There are "no corrections" if the last test was programatically
// skipped. We detect this (possibly inaccurately) by checking to
// see if .Desc is "Empty".
t.Fatalf("Expect changes for all tests, but got none")
}
}
for _, c := range corrections {
if *verbose {
@ -215,7 +220,7 @@ func ns(name, target string) *rec {
func mx(name string, prio uint16, target string) *rec {
r := makeRec(name, target, "MX")
r.Priority = prio
r.MxPreference = prio
return r
}
@ -223,6 +228,14 @@ func ptr(name, target string) *rec {
return makeRec(name, target, "PTR")
}
func srv(name string, priority, weight, port uint16, target string) *rec {
r := makeRec(name, target, "SRV")
r.SrvPriority = priority
r.SrvWeight = weight
r.SrvPort = port
return r
}
func makeRec(name, target, typ string) *rec {
return &rec{
Name: name,
@ -257,8 +270,8 @@ var tests = []*TestCase{
tc("Change it", a("@", "1.2.3.4")),
tc("Add another", a("@", "1.2.3.4"), a("www", "1.2.3.4")),
tc("Add another(same name)", a("@", "1.2.3.4"), a("www", "1.2.3.4"), a("www", "5.6.7.8")),
tc("Change a ttl", a("@", "1.2.3.4").ttl(100), a("www", "1.2.3.4"), a("www", "5.6.7.8")),
tc("Change single target from set", a("@", "1.2.3.4").ttl(100), a("www", "2.2.2.2"), a("www", "5.6.7.8")),
tc("Change a ttl", a("@", "1.2.3.4").ttl(1000), a("www", "1.2.3.4"), a("www", "5.6.7.8")),
tc("Change single target from set", a("@", "1.2.3.4").ttl(1000), a("www", "2.2.2.2"), a("www", "5.6.7.8")),
tc("Change all ttls", a("@", "1.2.3.4").ttl(500), a("www", "2.2.2.2").ttl(400), a("www", "5.6.7.8").ttl(400)),
tc("Delete one", a("@", "1.2.3.4").ttl(500), a("www", "5.6.7.8").ttl(400)),
tc("Add back and change ttl", a("www", "5.6.7.8").ttl(700), a("www", "1.2.3.4").ttl(700)),
@ -290,7 +303,7 @@ var tests = []*TestCase{
tc("3 MX", mx("@", 5, "foo.com."), mx("@", 5, "foo2.com."), mx("@", 15, "foo3.com.")),
tc("Delete one", mx("@", 5, "foo2.com."), mx("@", 15, "foo3.com.")),
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("Change Preference", mx("@", 7, "foo2.com."), mx("mail", 15, "foo3.com.")),
//PTR
tc("Empty"),
@ -298,11 +311,22 @@ var tests = []*TestCase{
tc("Modify PTR record", ptr("4", "bar.com.")),
//ALIAS
tc("EMPTY"),
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),
//SRV
tc("Empty"),
tc("SRV record", srv("@", 5, 6, 7, "foo.com.")),
tc("Second SRV record, same prio", srv("@", 5, 6, 7, "foo.com."), srv("@", 5, 60, 70, "foo2.com.")),
tc("3 SRV", srv("@", 5, 6, 7, "foo.com."), srv("@", 5, 60, 70, "foo2.com."), srv("@", 15, 65, 75, "foo3.com.")),
tc("Delete one", srv("@", 5, 6, 7, "foo.com."), srv("@", 15, 65, 75, "foo3.com.")),
tc("Change Target", srv("@", 5, 6, 7, "foo.com."), srv("@", 15, 65, 75, "foo4.com.")),
tc("Change Priority", srv("@", 52, 6, 7, "foo.com."), srv("@", 15, 65, 75, "foo4.com.")),
tc("Change Weight", srv("@", 52, 62, 7, "foo.com."), srv("@", 15, 65, 75, "foo4.com.")),
tc("Change Port", srv("@", 52, 62, 72, "foo.com."), srv("@", 15, 65, 75, "foo4.com.")),
//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.")),
}

View File

@ -20,7 +20,7 @@
"token": "$DNSIMPLE_TOKEN"
},
"GANDI": {
"COMMENT": "5: gandi does not accept ttls less than 300",
"COMMENT": "5: gandi does not accept TTLs less than 300",
"apikey": "$GANDI_KEY",
"domain": "$GANDI_DOMAIN",
"knownFailures": "5"

View File

@ -1,4 +1,4 @@
$TTL 300
@ IN SOA DEFAULT_NOT_SET. DEFAULT_NOT_SET. 2017070632 3600 600 604800 1440
@ IN SOA DEFAULT_NOT_SET. DEFAULT_NOT_SET. 2017071945 3600 600 604800 1440
IN NS ns1.otherdomain.tld.
IN NS ns2.otherdomain.tld.

View File

@ -9,6 +9,7 @@ import (
"net"
"reflect"
"strconv"
"strings"
"github.com/StackExchange/dnscontrol/pkg/transform"
"github.com/miekg/dns"
@ -60,21 +61,30 @@ type DNSProviderConfig struct {
// This is the FQDN version of Name.
// It should never have a trailiing ".".
type RecordConfig struct {
Type string `json:"type"`
Name string `json:"name"` // The short name. See below.
Target string `json:"target"` // If a name, must end with "."
TTL uint32 `json:"ttl,omitempty"`
Metadata map[string]string `json:"meta,omitempty"`
NameFQDN string `json:"-"` // Must end with ".$origin". See below.
Priority uint16 `json:"priority,omitempty"`
Type string `json:"type"`
Name string `json:"name"` // The short name. See below.
Target string `json:"target"` // If a name, must end with "."
TTL uint32 `json:"ttl,omitempty"`
Metadata map[string]string `json:"meta,omitempty"`
NameFQDN string `json:"-"` // Must end with ".$origin". See below.
MxPreference uint16 `json:"mxpreference,omitempty"` // FIXME(tlim): Rename to MxPreference
SrvPriority uint16 `json:"srvpriority,omitempty"`
SrvWeight uint16 `json:"srvweight,omitempty"`
SrvPort uint16 `json:"srvport,omitempty"`
Original interface{} `json:"-"` // Store pointer to provider-specific record object. Used in diffing.
}
func (r *RecordConfig) String() string {
content := fmt.Sprintf("%s %s %s %d", r.Type, r.NameFQDN, r.Target, r.TTL)
if r.Type == "MX" {
content += fmt.Sprintf(" priority=%d", r.Priority)
func (r *RecordConfig) String() (content string) {
switch r.Type {
case "A", "AAAA", "PTR":
content = fmt.Sprintf("%s %s %s %d", r.Type, r.NameFQDN, r.Target, r.TTL)
case "MX":
content = fmt.Sprintf(" priority=%d", r.MxPreference)
case "SOA":
content = fmt.Sprintf("%s %s %s %d", r.Type, r.Name, r.Target, r.TTL)
default:
panic(fmt.Sprintf("rc.String rtype %v unimplemented", r.Type))
}
for k, v := range r.Metadata {
content += fmt.Sprintf(" %s=%s", k, v)
@ -82,52 +92,103 @@ func (r *RecordConfig) String() string {
return content
}
// Content combines Target and other fields into one string.
func (r *RecordConfig) Content() string {
// If this is a pseudo record, just return the target.
if _, ok := dns.StringToType[r.Type]; !ok {
return r.Target
}
// We cheat by converting to a dns.RR and use the String() function.
// Sadly that function always includes a header, which we must strip out.
// TODO(tlim): Request the dns project add a function that returns
// the string without the header.
rr := r.ToRR()
header := rr.Header().String()
full := rr.String()
if !strings.HasPrefix(full, header) {
panic("dns.Hdr.String() not acting as we expect")
}
return full[len(header):]
}
// MergeToTarget combines "extra" fields into .Target, and zeros the merged fields.
func (r *RecordConfig) MergeToTarget() {
// Merge "extra" fields into the Target.
r.Target = r.Content()
// Zap any fields that may have been merged.
r.MxPreference = 0
r.SrvPriority = 0
r.SrvWeight = 0
r.SrvPort = 0
}
/// Convert RecordConfig -> dns.RR.
func (r *RecordConfig) ToRR() dns.RR {
func (rc *RecordConfig) ToRR() dns.RR {
// Note: The label is a FQDN ending in a ".". It will not put "@" in the Name field.
// NB(tlim): An alternative way to do this would be
// to create the rr via: rr := TypeToRR[x]()
// then set the parameters. A benchmark may find that
// faster. This was faster to implement.
rdtype, ok := dns.StringToType[r.Type]
// Don't call this on fake types.
rdtype, ok := dns.StringToType[rc.Type]
if !ok {
log.Fatalf("No such DNS type as (%#v)\n", r.Type)
log.Fatalf("No such DNS type as (%#v)\n", rc.Type)
}
hdr := dns.RR_Header{
Name: r.NameFQDN + ".",
Rrtype: rdtype,
Class: dns.ClassINET,
Ttl: r.TTL,
// Magicallly create an RR of the correct type.
rr := dns.TypeToRR[rdtype]()
// Fill in the header.
rr.Header().Name = rc.NameFQDN + "."
rr.Header().Rrtype = rdtype
rr.Header().Class = dns.ClassINET
rr.Header().Ttl = rc.TTL
if rc.TTL == 0 {
rr.Header().Ttl = DefaultTTL
}
// Handle some special cases:
// Fill in the data.
switch rdtype {
case dns.TypeA:
rr.(*dns.A).A = net.ParseIP(rc.Target)
case dns.TypeCNAME:
rr.(*dns.CNAME).Target = rc.Target
case dns.TypePTR:
rr.(*dns.PTR).Ptr = rc.Target
case dns.TypeMX:
// Has a Priority field.
return &dns.MX{Hdr: hdr, Preference: r.Priority, Mx: r.Target}
rr.(*dns.MX).Preference = rc.MxPreference
rr.(*dns.MX).Mx = rc.Target
case dns.TypeNS:
rr.(*dns.NS).Ns = rc.Target
case dns.TypeSOA:
t := strings.Replace(rc.Target, `\ `, ` `, -1)
parts := strings.Fields(t)
rr.(*dns.SOA).Ns = parts[0]
rr.(*dns.SOA).Mbox = parts[1]
rr.(*dns.SOA).Serial = atou32(parts[2])
rr.(*dns.SOA).Refresh = atou32(parts[3])
rr.(*dns.SOA).Retry = atou32(parts[4])
rr.(*dns.SOA).Expire = atou32(parts[5])
rr.(*dns.SOA).Minttl = atou32(parts[6])
case dns.TypeSRV:
rr.(*dns.SRV).Priority = rc.SrvPriority
rr.(*dns.SRV).Weight = rc.SrvWeight
rr.(*dns.SRV).Port = rc.SrvPort
rr.(*dns.SRV).Target = rc.Target
case dns.TypeTXT:
// Assure no problems due to quoting/unquoting:
return &dns.TXT{Hdr: hdr, Txt: []string{r.Target}}
rr.(*dns.TXT).Txt = []string{rc.Target}
default:
panic(fmt.Sprintf("ToRR: Unimplemented rtype %v", rc.Type))
}
var ttl string
if r.TTL == 0 {
ttl = strconv.FormatUint(uint64(DefaultTTL), 10)
} else {
ttl = strconv.FormatUint(uint64(r.TTL), 10)
}
return rr
}
s := fmt.Sprintf("%s %s IN %s %s", r.NameFQDN, ttl, r.Type, r.Target)
rc, err := dns.NewRR(s)
func atou32(s string) uint32 {
i64, err := strconv.ParseInt(s, 10, 32)
if err != nil {
log.Fatalf("NewRR rejected RecordConfig: %#v (t=%#v)\n%v\n", s, r.Target, err)
panic(fmt.Sprintf("atou32 failed (%v) (err=%v", s, err))
}
return rc
return uint32(i64)
}
type Nameserver struct {
@ -196,8 +257,8 @@ func (dc *DomainConfig) Punycode() error {
func (dc *DomainConfig) CombineMXs() {
for _, rec := range dc.Records {
if rec.Type == "MX" {
rec.Target = fmt.Sprintf("%d %s", rec.Priority, rec.Target)
rec.Priority = 0
rec.Target = fmt.Sprintf("%d %s", rec.MxPreference, rec.Target)
rec.MxPreference = 0
}
}
}

View File

@ -24,12 +24,12 @@ func TestHasRecordTypeName(t *testing.T) {
func TestRR(t *testing.T) {
experiment := RecordConfig{
Type: "A",
Name: "foo",
Target: "1.2.3.4",
TTL: 0,
NameFQDN: "foo.example.com",
Priority: 0,
Type: "A",
Name: "foo",
Target: "1.2.3.4",
TTL: 0,
NameFQDN: "foo.example.com",
MxPreference: 0,
}
expected := "foo.example.com.\t300\tIN\tA\t1.2.3.4"
found := experiment.ToRR().String()

View File

@ -173,6 +173,15 @@ function PTR(name, target) {
}
}
// SRV(name,priority,weight,port,target, recordModifiers...)
function SRV(name, priority, weight, port, target) {
checkArgs([_.isString, _.isNumber, _.isNumber, _.isNumber, _.isString], arguments, "SRV expects (name, priority, weight, port, target)")
var mods = getModifiers(arguments,5)
return function(d) {
addRecordSRV(d, "SRV", name, priority, weight, port, target, mods)
}
}
// TXT(name,target, recordModifiers...)
function TXT(name, target) {
var mods = getModifiers(arguments,2)
@ -312,6 +321,33 @@ function addRecord(d,type,name,target,mods) {
return rec;
}
function addRecordSRV(d,type,name,srvpriority,srvweight,srvport,target,mods) {
var rec = {type: type, name: name, srvpriority: srvpriority, srvweight: srvweight, srvport: srvport, target: target, ttl:d.defaultTTL, meta:{}};
// for each modifier, decide based on type:
// - Function: call is with the record as the argument
// - Object: merge it into the metadata
// FIXME(tlim): Factor this code out to its own function.
if (mods) {
for (var i = 0; i< mods.length; i++) {
var m = mods[i]
if (_.isFunction(m)) {
m(rec);
} else if (_.isObject(m)) {
//convert transforms to strings
if (m.transform && _.isArray(m.transform)){
m.transform = format_tt(m.transform)
}
_.extend(rec.meta,m);
_.extend(rec.meta,m);
} else {
console.log("WARNING: Modifier type unsupported:", typeof m, "(Skipping!)");
}
}
}
d.records.push(rec);
return rec;
}
//ip conversion functions from http://stackoverflow.com/a/8105740/121660
// via http://javascript.about.com/library/blipconvert.htm
function IP(dot)

View File

@ -190,57 +190,60 @@ var _escData = map[string]*_escFile{
"/helpers.js": {
local: "pkg/js/helpers.js",
size: 9590,
size: 11076,
modtime: 0,
compressed: `
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
kDbVHw+Gt787GzSUesQQ/woAAP//mqS3P0QrAAA=
`,
},

View File

@ -55,6 +55,7 @@ func validateRecordTypes(rec *models.RecordConfig, domain string, pTypes []strin
"CNAME": true,
"IMPORT_TRANSFORM": false,
"MX": true,
"SRV": true,
"TXT": true,
"NS": true,
"PTR": true,
@ -96,7 +97,7 @@ func checkLabel(label string, rType string, domain string) error {
}
//underscores are warnings
if strings.ContainsRune(label, '_') {
if rType != "SRV" && strings.ContainsRune(label, '_') {
//unless it is in our exclusion list
ok := false
for _, ex := range expectedUnderscores {
@ -146,6 +147,8 @@ func checkTargets(rec *models.RecordConfig, domain string) (errs []error) {
check(checkTarget(target))
case "ALIAS":
check(checkTarget(target))
case "SRV":
check(checkTarget(target))
case "TXT", "IMPORT_TRANSFORM":
default:
if rec.Metadata["orig_custom_type"] != "" {
@ -203,7 +206,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", "TXT":
case "MX", "NS", "SRV", "TXT":
// Not imported.
continue
default:

View File

@ -97,7 +97,7 @@ func rrToRecord(rr dns.RR, origin string, replaceSerial uint32) (models.RecordCo
rc.Target = v.Target
case *dns.MX:
rc.Target = v.Mx
rc.Priority = v.Preference
rc.MxPreference = v.Preference
case *dns.NS:
rc.Target = v.Ns
case *dns.PTR:
@ -114,10 +114,15 @@ func rrToRecord(rr dns.RR, origin string, replaceSerial uint32) (models.RecordCo
}
rc.Target = fmt.Sprintf("%v %v %v %v %v %v %v",
v.Ns, v.Mbox, new_serial, v.Refresh, v.Retry, v.Expire, v.Minttl)
case *dns.SRV:
rc.Target = v.Target
rc.SrvPort = v.Port
rc.SrvWeight = v.Weight
rc.SrvPriority = v.Priority
case *dns.TXT:
rc.Target = strings.Join(v.Txt, " ")
default:
log.Fatalf("Unimplemented zone record type=%s (%v)\n", rc.Type, rr)
log.Fatalf("rrToRecord: Unimplemented zone record type=%s (%v)\n", rc.Type, rr)
}
return rc, old_serial
}
@ -129,12 +134,11 @@ func makeDefaultSOA(info SoaInfo, origin string) *models.RecordConfig {
Name: "@",
}
soaRec.NameFQDN = dnsutil.AddOrigin(soaRec.Name, origin)
//TODO(cpeterson): are these sane defaults?
if len(info.Ns) == 0 {
info.Ns = "DEFAULT_NOT_SET"
info.Ns = "DEFAULT_NOT_SET."
}
if len(info.Mbox) == 0 {
info.Mbox = "DEFAULT_NOT_SET"
info.Mbox = "DEFAULT_NOT_SET."
}
if info.Serial == 0 {
info.Serial = 1

View File

@ -39,18 +39,36 @@ func (z *zoneGenData) Less(i, j int) bool {
if rrtypeA != rrtypeB {
return zoneRrtypeLess(rrtypeA, rrtypeB)
}
if rrtypeA == dns.TypeA {
switch rrtypeA {
case dns.TypeNS, dns.TypeTXT:
// pass through.
case dns.TypeA:
ta2, tb2 := a.(*dns.A), b.(*dns.A)
ipa, ipb := ta2.A.To4(), tb2.A.To4()
if ipa == nil || ipb == nil {
log.Fatalf("should not happen: IPs are not 4 bytes: %#v %#v", ta2, tb2)
}
return bytes.Compare(ipa, ipb) == -1
}
if rrtypeA == dns.TypeMX {
case dns.TypeMX:
ta2, tb2 := a.(*dns.MX), b.(*dns.MX)
pa, pb := ta2.Preference, tb2.Preference
return pa < pb
case dns.TypeSRV:
ta2, tb2 := a.(*dns.SRV), b.(*dns.SRV)
pa, pb := ta2.Port, tb2.Port
if pa != pb {
return pa < pb
}
pa, pb = ta2.Priority, tb2.Priority
if pa != pb {
return pa < pb
}
pa, pb = ta2.Weight, tb2.Weight
if pa != pb {
return pa < pb
}
default:
panic(fmt.Sprintf("zoneGenData Less: unimplemented rtype %v", dns.TypeToString[rrtypeA]))
}
return a.String() < b.String()
}
@ -92,6 +110,7 @@ func WriteZoneFile(w io.Writer, records []dns.RR, origin string) error {
// be easy to read and pleasant to the eye.
// * Within a label, SOA and NS records are listed first.
// * MX records are sorted numericly by preference value.
// * SRV records are sorted numericly by port, then priority, then weight.
// * A records are sorted by IP address, not lexicographically.
// * Repeated labels are removed.
// * $TTL is used to eliminate clutter. The most common TTL value is used.
@ -148,7 +167,7 @@ func (z *zoneGenData) generateZoneFileHelper(w io.Writer) error {
// items[2]: class
if hdr.Class != dns.ClassINET {
log.Fatalf("Unimplemented class=%v", items[2])
log.Fatalf("generateZoneFileHelper: Unimplemented class=%v", items[2])
}
// items[3]: type

View File

@ -156,6 +156,31 @@ _domainkey IN TXT "vvvv"
google._domainkey IN TXT "\"foo\""
`
func TestWriteZoneFileSrv(t *testing.T) {
//exhibits explicit ttls and long name
r1, _ := dns.NewRR(`bosun.org. 300 IN SRV 10 10 9999 foo.com.`)
r2, _ := dns.NewRR(`bosun.org. 300 IN SRV 10 20 5050 foo.com.`)
r3, _ := dns.NewRR(`bosun.org. 300 IN SRV 10 10 5050 foo.com.`)
r4, _ := dns.NewRR(`bosun.org. 300 IN SRV 20 10 5050 foo.com.`)
r5, _ := dns.NewRR(`bosun.org. 300 IN SRV 10 10 5050 foo.com.`)
buf := &bytes.Buffer{}
WriteZoneFile(buf, []dns.RR{r1, r2, r3, r4, r5}, "bosun.org")
if buf.String() != testdataZFSRV {
t.Log(buf.String())
t.Log(testdataZFSRV)
t.Fatalf("Zone file does not match.")
}
parseAndRegen(t, buf, testdataZFSRV)
}
var testdataZFSRV = `$TTL 300
@ IN SRV 10 10 5050 foo.com.
IN SRV 10 10 5050 foo.com.
IN SRV 10 20 5050 foo.com.
IN SRV 20 10 5050 foo.com.
IN SRV 10 10 9999 foo.com.
`
func TestWriteZoneFileOrder(t *testing.T) {
var records []dns.RR
for i, td := range []string{

View File

@ -344,12 +344,12 @@ func (c *cfRecord) toRecord(domain string) *models.RecordConfig {
c.Content = dnsutil.AddOrigin(c.Content+".", domain)
}
return &models.RecordConfig{
NameFQDN: c.Name,
Type: c.Type,
Target: c.Content,
Priority: c.Priority,
TTL: c.TTL,
Original: c,
NameFQDN: c.Name,
Type: c.Type,
Target: c.Content,
MxPreference: c.Priority,
TTL: c.TTL,
Original: c,
}
}

View File

@ -131,7 +131,7 @@ func (c *CloudflareApi) createRec(rec *models.RecordConfig, domainID string) []*
}
prio := ""
if rec.Type == "MX" {
prio = fmt.Sprintf(" %d ", rec.Priority)
prio = fmt.Sprintf(" %d ", rec.MxPreference)
}
arr := []*models.Correction{{
Msg: fmt.Sprintf("CREATE record: %s %s %d%s %s", rec.Name, rec.Type, rec.TTL, prio, content),
@ -142,7 +142,7 @@ func (c *CloudflareApi) createRec(rec *models.RecordConfig, domainID string) []*
Type: rec.Type,
TTL: rec.TTL,
Content: content,
Priority: rec.Priority,
Priority: rec.MxPreference,
}
endpoint := fmt.Sprintf(recordsURL, domainID)
buf := &bytes.Buffer{}
@ -181,7 +181,7 @@ func (c *CloudflareApi) modifyRecord(domainID, recID string, proxied bool, rec *
Priority uint16 `json:"priority"`
TTL uint32 `json:"ttl"`
}
r := record{recID, proxied, rec.Name, rec.Type, rec.Target, rec.Priority, rec.TTL}
r := record{recID, proxied, rec.Name, rec.Type, rec.Target, rec.MxPreference, rec.TTL}
endpoint := fmt.Sprintf(singleRecordURL, domainID, recID)
buf := &bytes.Buffer{}
encoder := json.NewEncoder(buf)

View File

@ -33,11 +33,7 @@ type differ struct {
// get normalized content for record. target, ttl, mxprio, and specified metadata
func (d *differ) content(r *models.RecordConfig) string {
content := fmt.Sprintf("%s %d", r.Target, r.TTL)
if r.Type == "MX" {
content += fmt.Sprintf(" priority=%d", r.Priority)
}
content := fmt.Sprintf("%v ttl=%d", r.Content(), r.TTL)
for _, f := range d.extraValues {
for k, v := range f(r) {
content += fmt.Sprintf(" %s=%s", k, v)

View File

@ -94,8 +94,8 @@ func TestMxPrio(t *testing.T) {
desired := []*models.RecordConfig{
myRecord("www MX 1 1.1.1.1"),
}
existing[0].Priority = 10
desired[0].Priority = 20
existing[0].MxPreference = 10
desired[0].MxPreference = 20
checkLengths(t, existing, desired, 0, 0, 0, 1)
}

View File

@ -54,12 +54,12 @@ func (c *DnsimpleApi) GetDomainCorrections(dc *models.DomainConfig) ([]*models.C
r.Content += "."
}
rec := &models.RecordConfig{
NameFQDN: dnsutil.AddOrigin(r.Name, dc.Name),
Type: r.Type,
Target: r.Content,
TTL: uint32(r.TTL),
Priority: uint16(r.Priority),
Original: r,
NameFQDN: dnsutil.AddOrigin(r.Name, dc.Name),
Type: r.Type,
Target: r.Content,
TTL: uint32(r.TTL),
MxPreference: uint16(r.Priority),
Original: r,
}
actual = append(actual, rec)
}
@ -230,7 +230,7 @@ func (c *DnsimpleApi) createRecordFunc(rc *models.RecordConfig, domainName strin
Type: rc.Type,
Content: rc.Target,
TTL: int(rc.TTL),
Priority: int(rc.Priority),
Priority: int(rc.MxPreference),
}
_, err = client.Zones.CreateRecord(accountId, domainName, record)
@ -277,7 +277,7 @@ func (c *DnsimpleApi) updateRecordFunc(old *dnsimpleapi.ZoneRecord, rc *models.R
Type: rc.Type,
Content: rc.Target,
TTL: int(rc.TTL),
Priority: int(rc.Priority),
Priority: int(rc.MxPreference),
}
_, err = client.Zones.UpdateRecord(accountId, domainName, old.ID, record)

View File

@ -146,5 +146,5 @@ func newGandi(m map[string]string, metadata json.RawMessage) (providers.DNSServi
}
func init() {
providers.RegisterDomainServiceProviderType("GANDI", newGandi)
providers.RegisterDomainServiceProviderType("GANDI", newGandi, providers.CanUsePTR)
}

View File

@ -126,13 +126,7 @@ func (g *gcloud) GetDomainCorrections(dc *models.DomainConfig) ([]*models.Correc
}
for _, want := range dc.Records {
if want.Type == "MX" {
want.Target = fmt.Sprintf("%d %s", want.Priority, want.Target)
want.Priority = 0
} else if want.Type == "TXT" {
//add quotes to txts
want.Target = fmt.Sprintf(`"%s"`, want.Target)
}
want.MergeToTarget()
}
// first collect keys that have changed

View File

@ -41,7 +41,8 @@ func newProvider(conf map[string]string) (*nameDotCom, error) {
func init() {
providers.RegisterRegistrarType("NAMEDOTCOM", newReg)
providers.RegisterDomainServiceProviderType("NAMEDOTCOM", newDsp, providers.CanUseAlias)
providers.RegisterDomainServiceProviderType("NAMEDOTCOM", newDsp, providers.CanUseSRV)
// PTR records are not supported https://www.name.com/support/articles/205188508-Reverse-DNS-records (2017-05-08)
}
///

View File

@ -3,6 +3,7 @@ package namedotcom
import (
"fmt"
"strconv"
"strings"
"github.com/miekg/dns/dnsutil"
@ -97,14 +98,31 @@ func checkNSModifications(dc *models.DomainConfig) {
func (r *nameComRecord) toRecord() *models.RecordConfig {
ttl, _ := strconv.ParseUint(r.TTL, 10, 32)
prio, _ := strconv.ParseUint(r.Priority, 10, 16)
return &models.RecordConfig{
rc := &models.RecordConfig{
NameFQDN: r.Name,
Type: r.Type,
Target: r.Content,
TTL: uint32(ttl),
Priority: uint16(prio),
Original: r,
}
switch r.Type {
case "A", "AAAA", "CNAME", "NS", "TXT":
// nothing additional.
case "MX":
rc.MxPreference = uint16(prio)
case "SRV":
parts := strings.Split(r.Content, " ")
weight, _ := strconv.ParseInt(parts[0], 10, 32)
port, _ := strconv.ParseInt(parts[1], 10, 32)
rc.SrvWeight = uint16(weight)
rc.SrvPort = uint16(port)
rc.SrvPriority = uint16(prio)
rc.MxPreference = 0
rc.Target = parts[2] + "."
default:
panic(fmt.Sprintf("toRecord unimplemented rtype %v", r.Type))
}
return rc
}
type listRecordsResponse struct {
@ -150,11 +168,20 @@ func (n *nameDotCom) createRecord(rc *models.RecordConfig, domain string) error
Type: rc.Type,
Content: target,
TTL: rc.TTL,
Priority: rc.Priority,
Priority: rc.MxPreference,
}
if dat.Hostname == "@" {
dat.Hostname = ""
}
switch rc.Type {
case "A", "AAAA", "CNAME", "MX", "NS", "TXT":
// nothing
case "SRV":
dat.Content = fmt.Sprintf("%d %d %v", rc.SrvWeight, rc.SrvPort, rc.Target)
dat.Priority = rc.SrvPriority
default:
panic(fmt.Sprintf("createRecord rtype %v unimplemented", rc.Type))
}
resp, err := n.post(n.apiCreateRecord(domain), dat)
if err != nil {
return err

View File

@ -44,6 +44,8 @@ const (
CanUseAlias Capability = 1 << iota
// CanUsePTR indicates the provider can handle PTR records
CanUsePTR
// CanUseSRV indicates the provider can handle SRV records
CanUseSRV
)
func ProviderHasCabability(pType string, cap Capability) bool {

View File

@ -42,7 +42,7 @@ func newRoute53(m map[string]string, metadata json.RawMessage) (providers.DNSSer
}
func init() {
providers.RegisterDomainServiceProviderType("ROUTE53", newRoute53, providers.CanUsePTR)
providers.RegisterDomainServiceProviderType("ROUTE53", newRoute53, providers.CanUsePTR, providers.CanUseSRV)
}
func sPtr(s string) *string {
return &s
@ -142,12 +142,7 @@ func (r *route53Provider) GetDomainCorrections(dc *models.DomainConfig) ([]*mode
}
}
for _, want := range dc.Records {
if want.Type == "MX" {
want.Target = fmt.Sprintf("%d %s", want.Priority, want.Target)
want.Priority = 0
} else if want.Type == "TXT" {
want.Target = fmt.Sprintf(`"%s"`, want.Target) //FIXME: better escaping/quoting
}
want.MergeToTarget()
}
//diff