mirror of
https://github.com/StackExchange/dnscontrol.git
synced 2024-05-11 05:55:12 +00:00
Refactor in preparation to unexport RecordConfig.{Name,NameFQDN,Target} (#337)
* Preparing for the unexport of Name/NameFQDN/Target * Cleanups
This commit is contained in:
@ -107,9 +107,11 @@ func runTests(t *testing.T, prv providers.DNSServiceProvider, domainName string,
|
|||||||
dom, _ := dc.Copy()
|
dom, _ := dc.Copy()
|
||||||
for _, r := range tst.Records {
|
for _, r := range tst.Records {
|
||||||
rc := models.RecordConfig(*r)
|
rc := models.RecordConfig(*r)
|
||||||
rc.NameFQDN = dnsutil.AddOrigin(rc.Name, domainName)
|
if strings.Contains(rc.GetTargetField(), "**current-domain**") {
|
||||||
if strings.Contains(rc.Target, "**current-domain**") {
|
rc.SetTarget(strings.Replace(rc.GetTargetField(), "**current-domain**", domainName, 1) + ".")
|
||||||
rc.Target = strings.Replace(rc.Target, "**current-domain**", domainName, 1) + "."
|
}
|
||||||
|
if strings.Contains(rc.GetLabelFQDN(), "**current-domain**") {
|
||||||
|
rc.SetLabelFromFQDN(strings.Replace(rc.GetLabelFQDN(), "**current-domain**", domainName, 1), domainName)
|
||||||
}
|
}
|
||||||
dom.Records = append(dom.Records, &rc)
|
dom.Records = append(dom.Records, &rc)
|
||||||
}
|
}
|
||||||
@ -205,6 +207,19 @@ type TestCase struct {
|
|||||||
|
|
||||||
type rec models.RecordConfig
|
type rec models.RecordConfig
|
||||||
|
|
||||||
|
func (r *rec) GetLabel() string {
|
||||||
|
return r.Name
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *rec) SetLabel(label, domain string) {
|
||||||
|
r.Name = label
|
||||||
|
r.NameFQDN = dnsutil.AddOrigin(label, "**current-domain**")
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *rec) SetTarget(target string) {
|
||||||
|
r.Target = target
|
||||||
|
}
|
||||||
|
|
||||||
func a(name, target string) *rec {
|
func a(name, target string) *rec {
|
||||||
return makeRec(name, target, "A")
|
return makeRec(name, target, "A")
|
||||||
}
|
}
|
||||||
@ -273,24 +288,25 @@ func tlsa(name string, usage, selector, matchingtype uint8, target string) *rec
|
|||||||
r.TlsaUsage = usage
|
r.TlsaUsage = usage
|
||||||
r.TlsaSelector = selector
|
r.TlsaSelector = selector
|
||||||
r.TlsaMatchingType = matchingtype
|
r.TlsaMatchingType = matchingtype
|
||||||
r.Target = target
|
|
||||||
return r
|
return r
|
||||||
}
|
}
|
||||||
|
|
||||||
func ignore(name string) *rec {
|
func ignore(name string) *rec {
|
||||||
return &rec{
|
r := &rec{
|
||||||
Name: name,
|
|
||||||
Type: "IGNORE",
|
Type: "IGNORE",
|
||||||
}
|
}
|
||||||
|
r.SetLabel(name, "**current-domain**")
|
||||||
|
return r
|
||||||
}
|
}
|
||||||
|
|
||||||
func makeRec(name, target, typ string) *rec {
|
func makeRec(name, target, typ string) *rec {
|
||||||
return &rec{
|
r := &rec{
|
||||||
Name: name,
|
|
||||||
Type: typ,
|
Type: typ,
|
||||||
Target: target,
|
|
||||||
TTL: 300,
|
TTL: 300,
|
||||||
}
|
}
|
||||||
|
r.SetLabel(name, "**current-domain**")
|
||||||
|
r.SetTarget(target)
|
||||||
|
return r
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *rec) ttl(t uint32) *rec {
|
func (r *rec) ttl(t uint32) *rec {
|
||||||
@ -303,7 +319,7 @@ func tc(desc string, recs ...*rec) *TestCase {
|
|||||||
var ignored []string
|
var ignored []string
|
||||||
for _, r := range recs {
|
for _, r := range recs {
|
||||||
if r.Type == "IGNORE" {
|
if r.Type == "IGNORE" {
|
||||||
ignored = append(ignored, r.Name)
|
ignored = append(ignored, r.GetLabel())
|
||||||
} else {
|
} else {
|
||||||
records = append(records, r)
|
records = append(records, r)
|
||||||
}
|
}
|
||||||
|
@ -26,9 +26,9 @@ func TestRR(t *testing.T) {
|
|||||||
experiment := RecordConfig{
|
experiment := RecordConfig{
|
||||||
Type: "A",
|
Type: "A",
|
||||||
Name: "foo",
|
Name: "foo",
|
||||||
|
NameFQDN: "foo.example.com",
|
||||||
Target: "1.2.3.4",
|
Target: "1.2.3.4",
|
||||||
TTL: 0,
|
TTL: 0,
|
||||||
NameFQDN: "foo.example.com",
|
|
||||||
MxPreference: 0,
|
MxPreference: 0,
|
||||||
}
|
}
|
||||||
expected := "foo.example.com.\t300\tIN\tA\t1.2.3.4"
|
expected := "foo.example.com.\t300\tIN\tA\t1.2.3.4"
|
||||||
@ -40,9 +40,9 @@ func TestRR(t *testing.T) {
|
|||||||
experiment = RecordConfig{
|
experiment = RecordConfig{
|
||||||
Type: "CAA",
|
Type: "CAA",
|
||||||
Name: "@",
|
Name: "@",
|
||||||
|
NameFQDN: "example.com",
|
||||||
Target: "mailto:test@example.com",
|
Target: "mailto:test@example.com",
|
||||||
TTL: 300,
|
TTL: 300,
|
||||||
NameFQDN: "example.com",
|
|
||||||
CaaTag: "iodef",
|
CaaTag: "iodef",
|
||||||
CaaFlag: 1,
|
CaaFlag: 1,
|
||||||
}
|
}
|
||||||
@ -55,9 +55,9 @@ func TestRR(t *testing.T) {
|
|||||||
experiment = RecordConfig{
|
experiment = RecordConfig{
|
||||||
Type: "TLSA",
|
Type: "TLSA",
|
||||||
Name: "@",
|
Name: "@",
|
||||||
|
NameFQDN: "_443._tcp.example.com",
|
||||||
Target: "abcdef0123456789",
|
Target: "abcdef0123456789",
|
||||||
TTL: 300,
|
TTL: 300,
|
||||||
NameFQDN: "_443._tcp.example.com",
|
|
||||||
TlsaUsage: 0,
|
TlsaUsage: 0,
|
||||||
TlsaSelector: 0,
|
TlsaSelector: 0,
|
||||||
TlsaMatchingType: 1,
|
TlsaMatchingType: 1,
|
||||||
@ -74,17 +74,17 @@ func TestDowncase(t *testing.T) {
|
|||||||
&RecordConfig{Type: "MX", Name: "lower", Target: "targetmx"},
|
&RecordConfig{Type: "MX", Name: "lower", Target: "targetmx"},
|
||||||
&RecordConfig{Type: "MX", Name: "UPPER", Target: "TARGETMX"},
|
&RecordConfig{Type: "MX", Name: "UPPER", Target: "TARGETMX"},
|
||||||
}}
|
}}
|
||||||
Downcase(dc.Records)
|
downcase(dc.Records)
|
||||||
if !dc.HasRecordTypeName("MX", "lower") {
|
if !dc.HasRecordTypeName("MX", "lower") {
|
||||||
t.Errorf("%v: expected (%v) got (%v)\n", dc.Records, false, true)
|
t.Errorf("%v: expected (%v) got (%v)\n", dc.Records, false, true)
|
||||||
}
|
}
|
||||||
if !dc.HasRecordTypeName("MX", "upper") {
|
if !dc.HasRecordTypeName("MX", "upper") {
|
||||||
t.Errorf("%v: expected (%v) got (%v)\n", dc.Records, false, true)
|
t.Errorf("%v: expected (%v) got (%v)\n", dc.Records, false, true)
|
||||||
}
|
}
|
||||||
if dc.Records[0].Target != "targetmx" {
|
if dc.Records[0].GetTargetField() != "targetmx" {
|
||||||
t.Errorf("%v: target0 expected (%v) got (%v)\n", dc.Records, "targetmx", dc.Records[0].Target)
|
t.Errorf("%v: target0 expected (%v) got (%v)\n", dc.Records, "targetmx", dc.Records[0].GetTargetField())
|
||||||
}
|
}
|
||||||
if dc.Records[1].Target != "targetmx" {
|
if dc.Records[1].GetTargetField() != "targetmx" {
|
||||||
t.Errorf("%v: target1 expected (%v) got (%v)\n", dc.Records, "targetmx", dc.Records[1].Target)
|
t.Errorf("%v: target1 expected (%v) got (%v)\n", dc.Records, "targetmx", dc.Records[1].GetTargetField())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -49,7 +49,7 @@ func (dc *DomainConfig) Copy() (*DomainConfig, error) {
|
|||||||
// HasRecordTypeName returns True if there is a record with this rtype and name.
|
// HasRecordTypeName returns True if there is a record with this rtype and name.
|
||||||
func (dc *DomainConfig) HasRecordTypeName(rtype, name string) bool {
|
func (dc *DomainConfig) HasRecordTypeName(rtype, name string) bool {
|
||||||
for _, r := range dc.Records {
|
for _, r := range dc.Records {
|
||||||
if r.Type == rtype && r.Name == name {
|
if r.Type == rtype && r.GetLabel() == name {
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -73,19 +73,17 @@ func (dc *DomainConfig) Filter(f func(r *RecordConfig) bool) {
|
|||||||
// - NameFQDN
|
// - NameFQDN
|
||||||
// - Target (CNAME and MX only)
|
// - Target (CNAME and MX only)
|
||||||
func (dc *DomainConfig) Punycode() error {
|
func (dc *DomainConfig) Punycode() error {
|
||||||
var err error
|
|
||||||
for _, rec := range dc.Records {
|
for _, rec := range dc.Records {
|
||||||
rec.Name, err = idna.ToASCII(rec.Name)
|
t, err := idna.ToASCII(rec.GetLabelFQDN())
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
rec.NameFQDN, err = idna.ToASCII(rec.NameFQDN)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
rec.SetLabelFromFQDN(t, dc.Name)
|
||||||
switch rec.Type { // #rtype_variations
|
switch rec.Type { // #rtype_variations
|
||||||
case "ALIAS", "MX", "NS", "CNAME", "PTR", "SRV", "URL", "URL301", "FRAME", "R53_ALIAS":
|
case "ALIAS", "MX", "NS", "CNAME", "PTR", "SRV", "URL", "URL301", "FRAME", "R53_ALIAS":
|
||||||
rec.Target, err = idna.ToASCII(rec.Target)
|
// These rtypes are hostnames, therefore need to be converted (unlike, for example, an AAAA record)
|
||||||
|
t, err := idna.ToASCII(rec.GetTargetField())
|
||||||
|
rec.SetTarget(t)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
@ -120,6 +120,14 @@ func (rc *RecordConfig) SetLabel(short, origin string) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// UnsafeSetLabelNull sets the label to "". Normally the FQDN is denoted by .Name being
|
||||||
|
// "@" however this can be used to violate that assertion. It should only be used
|
||||||
|
// on copies of a RecordConfig that is being used for non-standard things like
|
||||||
|
// Marshalling yaml.
|
||||||
|
func (rc *RecordConfig) UnsafeSetLabelNull() {
|
||||||
|
rc.Name = ""
|
||||||
|
}
|
||||||
|
|
||||||
// SetLabelFromFQDN sets the .Name/.NameFQDN fields given a FQDN and origin.
|
// SetLabelFromFQDN sets the .Name/.NameFQDN fields given a FQDN and origin.
|
||||||
// fqdn may have a trailing "." but it is not required.
|
// fqdn may have a trailing "." but it is not required.
|
||||||
// origin may not have a trailing dot.
|
// origin may not have a trailing dot.
|
||||||
@ -268,11 +276,11 @@ func (r Records) GroupedByLabel() ([]string, map[string]Records) {
|
|||||||
|
|
||||||
// PostProcessRecords does any post-processing of the downloaded DNS records.
|
// PostProcessRecords does any post-processing of the downloaded DNS records.
|
||||||
func PostProcessRecords(recs []*RecordConfig) {
|
func PostProcessRecords(recs []*RecordConfig) {
|
||||||
Downcase(recs)
|
downcase(recs)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Downcase converts all labels and targets to lowercase in a list of RecordConfig.
|
// Downcase converts all labels and targets to lowercase in a list of RecordConfig.
|
||||||
func Downcase(recs []*RecordConfig) {
|
func downcase(recs []*RecordConfig) {
|
||||||
for _, r := range recs {
|
for _, r := range recs {
|
||||||
r.Name = strings.ToLower(r.Name)
|
r.Name = strings.ToLower(r.Name)
|
||||||
r.NameFQDN = strings.ToLower(r.NameFQDN)
|
r.NameFQDN = strings.ToLower(r.NameFQDN)
|
||||||
|
@ -11,7 +11,7 @@ import (
|
|||||||
func (rc *RecordConfig) SetTargetCAA(flag uint8, tag string, target string) error {
|
func (rc *RecordConfig) SetTargetCAA(flag uint8, tag string, target string) error {
|
||||||
rc.CaaTag = tag
|
rc.CaaTag = tag
|
||||||
rc.CaaFlag = flag
|
rc.CaaFlag = flag
|
||||||
rc.Target = target
|
rc.SetTarget(target)
|
||||||
if rc.Type == "" {
|
if rc.Type == "" {
|
||||||
rc.Type = "CAA"
|
rc.Type = "CAA"
|
||||||
}
|
}
|
||||||
|
@ -10,7 +10,7 @@ import (
|
|||||||
// SetTargetMX sets the MX fields.
|
// SetTargetMX sets the MX fields.
|
||||||
func (rc *RecordConfig) SetTargetMX(pref uint16, target string) error {
|
func (rc *RecordConfig) SetTargetMX(pref uint16, target string) error {
|
||||||
rc.MxPreference = pref
|
rc.MxPreference = pref
|
||||||
rc.Target = target
|
rc.SetTarget(target)
|
||||||
if rc.Type == "" {
|
if rc.Type == "" {
|
||||||
rc.Type = "MX"
|
rc.Type = "MX"
|
||||||
}
|
}
|
||||||
|
@ -12,7 +12,7 @@ func (rc *RecordConfig) SetTargetSRV(priority, weight, port uint16, target strin
|
|||||||
rc.SrvPriority = priority
|
rc.SrvPriority = priority
|
||||||
rc.SrvWeight = weight
|
rc.SrvWeight = weight
|
||||||
rc.SrvPort = port
|
rc.SrvPort = port
|
||||||
rc.Target = target
|
rc.SetTarget(target)
|
||||||
if rc.Type == "" {
|
if rc.Type == "" {
|
||||||
rc.Type = "SRV"
|
rc.Type = "SRV"
|
||||||
}
|
}
|
||||||
|
@ -12,7 +12,7 @@ func (rc *RecordConfig) SetTargetTLSA(usage, selector, matchingtype uint8, targe
|
|||||||
rc.TlsaUsage = usage
|
rc.TlsaUsage = usage
|
||||||
rc.TlsaSelector = selector
|
rc.TlsaSelector = selector
|
||||||
rc.TlsaMatchingType = matchingtype
|
rc.TlsaMatchingType = matchingtype
|
||||||
rc.Target = target
|
rc.SetTarget(target)
|
||||||
if rc.Type == "" {
|
if rc.Type == "" {
|
||||||
rc.Type = "TLSA"
|
rc.Type = "TLSA"
|
||||||
}
|
}
|
||||||
|
@ -2,7 +2,7 @@ package models
|
|||||||
|
|
||||||
// SetTargetTXT sets the TXT fields when there is 1 string.
|
// SetTargetTXT sets the TXT fields when there is 1 string.
|
||||||
func (rc *RecordConfig) SetTargetTXT(s string) error {
|
func (rc *RecordConfig) SetTargetTXT(s string) error {
|
||||||
rc.Target = s
|
rc.SetTarget(s)
|
||||||
rc.TxtStrings = []string{s}
|
rc.TxtStrings = []string{s}
|
||||||
if rc.Type == "" {
|
if rc.Type == "" {
|
||||||
rc.Type = "TXT"
|
rc.Type = "TXT"
|
||||||
@ -15,7 +15,7 @@ func (rc *RecordConfig) SetTargetTXT(s string) error {
|
|||||||
|
|
||||||
// SetTargetTXTs sets the TXT fields when there are many strings.
|
// SetTargetTXTs sets the TXT fields when there are many strings.
|
||||||
func (rc *RecordConfig) SetTargetTXTs(s []string) error {
|
func (rc *RecordConfig) SetTargetTXTs(s []string) error {
|
||||||
rc.Target = s[0]
|
rc.SetTarget(s[0])
|
||||||
rc.TxtStrings = s
|
rc.TxtStrings = s
|
||||||
if rc.Type == "" {
|
if rc.Type == "" {
|
||||||
rc.Type = "TXT"
|
rc.Type = "TXT"
|
||||||
|
@ -109,11 +109,11 @@ func (rc *RecordConfig) SetTarget(target string) error {
|
|||||||
// SetTargetIP sets the target to an IP, verifying this is an appropriate rtype.
|
// SetTargetIP sets the target to an IP, verifying this is an appropriate rtype.
|
||||||
func (rc *RecordConfig) SetTargetIP(ip net.IP) error {
|
func (rc *RecordConfig) SetTargetIP(ip net.IP) error {
|
||||||
// TODO(tlim): Verify the rtype is appropriate for an IP.
|
// TODO(tlim): Verify the rtype is appropriate for an IP.
|
||||||
rc.Target = ip.String()
|
rc.SetTarget(ip.String())
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// // SetTargetFQDN sets the target to an IP, verifying this is an appropriate rtype.
|
// // SetTargetFQDN sets the target to a string, verifying this is an appropriate rtype.
|
||||||
// func (rc *RecordConfig) SetTargetFQDN(target string) error {
|
// func (rc *RecordConfig) SetTargetFQDN(target string) error {
|
||||||
// // TODO(tlim): Verify the rtype is appropriate for an hostname.
|
// // TODO(tlim): Verify the rtype is appropriate for an hostname.
|
||||||
// rc.Target = target
|
// rc.Target = target
|
||||||
|
@ -8,7 +8,6 @@ import (
|
|||||||
"strconv"
|
"strconv"
|
||||||
|
|
||||||
"github.com/StackExchange/dnscontrol/models"
|
"github.com/StackExchange/dnscontrol/models"
|
||||||
"github.com/miekg/dns/dnsutil"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
// DetermineNameservers will find all nameservers we should use for a domain. It follows the following rules:
|
// DetermineNameservers will find all nameservers we should use for a domain. It follows the following rules:
|
||||||
@ -52,15 +51,16 @@ func AddNSRecords(dc *models.DomainConfig) {
|
|||||||
for _, ns := range dc.Nameservers {
|
for _, ns := range dc.Nameservers {
|
||||||
rc := &models.RecordConfig{
|
rc := &models.RecordConfig{
|
||||||
Type: "NS",
|
Type: "NS",
|
||||||
Name: "@",
|
|
||||||
Target: ns.Name,
|
|
||||||
Metadata: map[string]string{},
|
Metadata: map[string]string{},
|
||||||
TTL: ttl,
|
TTL: ttl,
|
||||||
}
|
}
|
||||||
if !strings.HasSuffix(rc.Target, ".") {
|
rc.SetLabel("@", dc.Name)
|
||||||
rc.Target += "."
|
t := ns.Name
|
||||||
|
if !strings.HasSuffix(t, ".") {
|
||||||
|
rc.SetTarget(t + ".")
|
||||||
}
|
}
|
||||||
rc.NameFQDN = dnsutil.AddOrigin(rc.Name, dc.Name)
|
rc.SetTarget(t)
|
||||||
|
|
||||||
dc.Records = append(dc.Records, rc)
|
dc.Records = append(dc.Records, rc)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -3,7 +3,6 @@ package normalize
|
|||||||
import (
|
import (
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"github.com/miekg/dns/dnsutil"
|
|
||||||
"github.com/pkg/errors"
|
"github.com/pkg/errors"
|
||||||
|
|
||||||
"github.com/StackExchange/dnscontrol/models"
|
"github.com/StackExchange/dnscontrol/models"
|
||||||
@ -27,13 +26,13 @@ func flattenSPFs(cfg *models.DNSConfig) []error {
|
|||||||
return []error{err}
|
return []error{err}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
rec, err = spflib.Parse(txt.Target, cache)
|
rec, err = spflib.Parse(txt.GetTargetField(), cache)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
errs = append(errs, err)
|
errs = append(errs, err)
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if flatten, ok := txt.Metadata["flatten"]; ok && strings.HasPrefix(txt.Target, "v=spf1") {
|
if flatten, ok := txt.Metadata["flatten"]; ok && strings.HasPrefix(txt.GetTargetField(), "v=spf1") {
|
||||||
rec = rec.Flatten(flatten)
|
rec = rec.Flatten(flatten)
|
||||||
err = txt.SetTargetTXT(rec.TXT())
|
err = txt.SetTargetTXT(rec.TXT())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -44,7 +43,7 @@ func flattenSPFs(cfg *models.DNSConfig) []error {
|
|||||||
// now split if needed
|
// now split if needed
|
||||||
if split, ok := txt.Metadata["split"]; ok {
|
if split, ok := txt.Metadata["split"]; ok {
|
||||||
if !strings.Contains(split, "%d") {
|
if !strings.Contains(split, "%d") {
|
||||||
errs = append(errs, Warning{errors.Errorf("Split format `%s` in `%s` is not proper format (should have %%d in it)", split, txt.NameFQDN)})
|
errs = append(errs, Warning{errors.Errorf("Split format `%s` in `%s` is not proper format (should have %%d in it)", split, txt.GetLabelFQDN())})
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
recs := rec.TXTSplit(split + "." + domain.Name)
|
recs := rec.TXTSplit(split + "." + domain.Name)
|
||||||
@ -54,8 +53,7 @@ func flattenSPFs(cfg *models.DNSConfig) []error {
|
|||||||
} else {
|
} else {
|
||||||
cp, _ := txt.Copy()
|
cp, _ := txt.Copy()
|
||||||
cp.SetTargetTXT(v)
|
cp.SetTargetTXT(v)
|
||||||
cp.NameFQDN = k
|
cp.SetLabelFromFQDN(k, domain.Name)
|
||||||
cp.Name = dnsutil.TrimDomainName(k, domain.Name)
|
|
||||||
domain.Records = append(domain.Records, cp)
|
domain.Records = append(domain.Records, cp)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -6,6 +6,12 @@ import (
|
|||||||
"github.com/StackExchange/dnscontrol/models"
|
"github.com/StackExchange/dnscontrol/models"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
func makeRC(label, domain, target string, rc models.RecordConfig) *models.RecordConfig {
|
||||||
|
rc.SetLabel(label, domain)
|
||||||
|
rc.SetTarget(target)
|
||||||
|
return &rc
|
||||||
|
}
|
||||||
|
|
||||||
func TestImportTransform(t *testing.T) {
|
func TestImportTransform(t *testing.T) {
|
||||||
|
|
||||||
const transformDouble = "0.0.0.0~1.1.1.1~~9.0.0.0,10.0.0.0"
|
const transformDouble = "0.0.0.0~1.1.1.1~~9.0.0.0,10.0.0.0"
|
||||||
@ -13,15 +19,15 @@ func TestImportTransform(t *testing.T) {
|
|||||||
src := &models.DomainConfig{
|
src := &models.DomainConfig{
|
||||||
Name: "stackexchange.com",
|
Name: "stackexchange.com",
|
||||||
Records: []*models.RecordConfig{
|
Records: []*models.RecordConfig{
|
||||||
{Type: "A", Name: "*", NameFQDN: "*.stackexchange.com", Target: "0.0.2.2"},
|
makeRC("*", "stackexchange.com", "0.0.2.2", models.RecordConfig{Type: "A"}),
|
||||||
{Type: "A", Name: "www", NameFQDN: "www.stackexchange.com", Target: "0.0.1.1"},
|
makeRC("www", "stackexchange.com", "0.0.1.1", models.RecordConfig{Type: "A"}),
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
dst := &models.DomainConfig{
|
dst := &models.DomainConfig{
|
||||||
Name: "internal",
|
Name: "internal",
|
||||||
Records: []*models.RecordConfig{
|
Records: []*models.RecordConfig{
|
||||||
{Type: "A", Name: "*.stackexchange.com", NameFQDN: "*.stackexchange.com.internal", Target: "0.0.3.3", Metadata: map[string]string{"transform_table": transformSingle}},
|
makeRC("*.stackexchange.com", "*.stackexchange.com.internal", "0.0.3.3", models.RecordConfig{Type: "A", Metadata: map[string]string{"transform_table": transformSingle}}),
|
||||||
{Type: "IMPORT_TRANSFORM", Name: "@", NameFQDN: "internal", Target: "stackexchange.com", Metadata: map[string]string{"transform_table": transformDouble}},
|
makeRC("@", "internal", "stackexchange.com", models.RecordConfig{Type: "IMPORT_TRANSFORM", Metadata: map[string]string{"transform_table": transformDouble}}),
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
cfg := &models.DNSConfig{
|
cfg := &models.DNSConfig{
|
||||||
|
@ -66,7 +66,7 @@ func validateRecordTypes(rec *models.RecordConfig, domain string, pTypes []strin
|
|||||||
if !ok {
|
if !ok {
|
||||||
cType := providers.GetCustomRecordType(rec.Type)
|
cType := providers.GetCustomRecordType(rec.Type)
|
||||||
if cType == nil {
|
if cType == nil {
|
||||||
return errors.Errorf("Unsupported record type (%v) domain=%v name=%v", rec.Type, domain, rec.Name)
|
return errors.Errorf("Unsupported record type (%v) domain=%v name=%v", rec.Type, domain, rec.GetLabel())
|
||||||
}
|
}
|
||||||
for _, providerType := range pTypes {
|
for _, providerType := range pTypes {
|
||||||
if providerType != cType.Provider {
|
if providerType != cType.Provider {
|
||||||
@ -125,11 +125,11 @@ func checkLabel(label string, rType string, domain string, meta map[string]strin
|
|||||||
|
|
||||||
// checkTargets returns true if rec.Target is valid for the rec.Type.
|
// checkTargets returns true if rec.Target is valid for the rec.Type.
|
||||||
func checkTargets(rec *models.RecordConfig, domain string) (errs []error) {
|
func checkTargets(rec *models.RecordConfig, domain string) (errs []error) {
|
||||||
label := rec.Name
|
label := rec.GetLabel()
|
||||||
target := rec.Target
|
target := rec.GetTargetField()
|
||||||
check := func(e error) {
|
check := func(e error) {
|
||||||
if e != nil {
|
if e != nil {
|
||||||
err := errors.Errorf("In %s %s.%s: %s", rec.Type, rec.Name, domain, e.Error())
|
err := errors.Errorf("In %s %s.%s: %s", rec.Type, rec.GetLabel(), domain, e.Error())
|
||||||
if _, ok := e.(Warning); ok {
|
if _, ok := e.(Warning); ok {
|
||||||
err = Warning{err}
|
err = Warning{err}
|
||||||
}
|
}
|
||||||
@ -166,7 +166,7 @@ func checkTargets(rec *models.RecordConfig, domain string) (errs []error) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
errs = append(errs, errors.Errorf("checkTargets: Unimplemented record type (%v) domain=%v name=%v",
|
errs = append(errs, errors.Errorf("checkTargets: Unimplemented record type (%v) domain=%v name=%v",
|
||||||
rec.Type, domain, rec.Name))
|
rec.Type, domain, rec.GetLabel()))
|
||||||
}
|
}
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@ -189,13 +189,13 @@ func importTransform(srcDomain, dstDomain *models.DomainConfig, transforms []tra
|
|||||||
// 4. For As, change the target as described the transforms.
|
// 4. For As, change the target as described the transforms.
|
||||||
|
|
||||||
for _, rec := range srcDomain.Records {
|
for _, rec := range srcDomain.Records {
|
||||||
if dstDomain.HasRecordTypeName(rec.Type, rec.NameFQDN) {
|
if dstDomain.HasRecordTypeName(rec.Type, rec.GetLabelFQDN()) {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
newRec := func() *models.RecordConfig {
|
newRec := func() *models.RecordConfig {
|
||||||
rec2, _ := rec.Copy()
|
rec2, _ := rec.Copy()
|
||||||
rec2.Name = rec2.NameFQDN
|
newlabel := rec2.GetLabelFQDN()
|
||||||
rec2.NameFQDN = dnsutil.AddOrigin(rec2.Name, dstDomain.Name)
|
rec2.SetLabelFromFQDN(newlabel, dstDomain.Name)
|
||||||
if ttl != 0 {
|
if ttl != 0 {
|
||||||
rec2.TTL = ttl
|
rec2.TTL = ttl
|
||||||
}
|
}
|
||||||
@ -203,25 +203,25 @@ func importTransform(srcDomain, dstDomain *models.DomainConfig, transforms []tra
|
|||||||
}
|
}
|
||||||
switch rec.Type { // #rtype_variations
|
switch rec.Type { // #rtype_variations
|
||||||
case "A":
|
case "A":
|
||||||
trs, err := transform.TransformIPToList(net.ParseIP(rec.Target), transforms)
|
trs, err := transform.TransformIPToList(net.ParseIP(rec.GetTargetField()), transforms)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return errors.Errorf("import_transform: TransformIP(%v, %v) returned err=%s", rec.Target, transforms, err)
|
return errors.Errorf("import_transform: TransformIP(%v, %v) returned err=%s", rec.GetTargetField(), transforms, err)
|
||||||
}
|
}
|
||||||
for _, tr := range trs {
|
for _, tr := range trs {
|
||||||
r := newRec()
|
r := newRec()
|
||||||
r.Target = tr.String()
|
r.SetTarget(tr.String())
|
||||||
dstDomain.Records = append(dstDomain.Records, r)
|
dstDomain.Records = append(dstDomain.Records, r)
|
||||||
}
|
}
|
||||||
case "CNAME":
|
case "CNAME":
|
||||||
r := newRec()
|
r := newRec()
|
||||||
r.Target = transformCNAME(r.Target, srcDomain.Name, dstDomain.Name)
|
r.SetTarget(transformCNAME(r.GetTargetField(), srcDomain.Name, dstDomain.Name))
|
||||||
dstDomain.Records = append(dstDomain.Records, r)
|
dstDomain.Records = append(dstDomain.Records, r)
|
||||||
case "MX", "NS", "SRV", "TXT", "CAA", "TLSA":
|
case "MX", "NS", "SRV", "TXT", "CAA", "TLSA":
|
||||||
// Not imported.
|
// Not imported.
|
||||||
continue
|
continue
|
||||||
default:
|
default:
|
||||||
return errors.Errorf("import_transform: Unimplemented record type %v (%v)",
|
return errors.Errorf("import_transform: Unimplemented record type %v (%v)",
|
||||||
rec.Type, rec.Name)
|
rec.Type, rec.GetLabel())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
@ -276,7 +276,7 @@ func NormalizeAndValidateConfig(config *models.DNSConfig) (errs []error) {
|
|||||||
if err := validateRecordTypes(rec, domain.Name, pTypes); err != nil {
|
if err := validateRecordTypes(rec, domain.Name, pTypes); err != nil {
|
||||||
errs = append(errs, err)
|
errs = append(errs, err)
|
||||||
}
|
}
|
||||||
if err := checkLabel(rec.Name, rec.Type, domain.Name, rec.Metadata); err != nil {
|
if err := checkLabel(rec.GetLabel(), rec.Type, domain.Name, rec.Metadata); err != nil {
|
||||||
errs = append(errs, err)
|
errs = append(errs, err)
|
||||||
}
|
}
|
||||||
if errs2 := checkTargets(rec, domain.Name); errs2 != nil {
|
if errs2 := checkTargets(rec, domain.Name); errs2 != nil {
|
||||||
@ -285,14 +285,16 @@ func NormalizeAndValidateConfig(config *models.DNSConfig) (errs []error) {
|
|||||||
|
|
||||||
// Canonicalize Targets.
|
// Canonicalize Targets.
|
||||||
if rec.Type == "CNAME" || rec.Type == "MX" || rec.Type == "NS" {
|
if rec.Type == "CNAME" || rec.Type == "MX" || rec.Type == "NS" {
|
||||||
rec.Target = dnsutil.AddOrigin(rec.Target, domain.Name+".")
|
rec.SetTarget(dnsutil.AddOrigin(rec.GetTargetField(), domain.Name+"."))
|
||||||
} else if rec.Type == "A" || rec.Type == "AAAA" {
|
} else if rec.Type == "A" || rec.Type == "AAAA" {
|
||||||
rec.Target = net.ParseIP(rec.Target).String()
|
rec.SetTarget(net.ParseIP(rec.GetTargetField()).String())
|
||||||
} else if rec.Type == "PTR" {
|
} else if rec.Type == "PTR" {
|
||||||
var err error
|
var err error
|
||||||
if rec.Name, err = transform.PtrNameMagic(rec.Name, domain.Name); err != nil {
|
var name string
|
||||||
|
if name, err = transform.PtrNameMagic(rec.GetLabel(), domain.Name); err != nil {
|
||||||
errs = append(errs, err)
|
errs = append(errs, err)
|
||||||
}
|
}
|
||||||
|
rec.SetLabel(name, domain.Name)
|
||||||
} else if rec.Type == "CAA" {
|
} else if rec.Type == "CAA" {
|
||||||
if rec.CaaTag != "issue" && rec.CaaTag != "issuewild" && rec.CaaTag != "iodef" {
|
if rec.CaaTag != "issue" && rec.CaaTag != "issuewild" && rec.CaaTag != "iodef" {
|
||||||
errs = append(errs, errors.Errorf("CAA tag %s is invalid", rec.CaaTag))
|
errs = append(errs, errors.Errorf("CAA tag %s is invalid", rec.CaaTag))
|
||||||
@ -300,26 +302,26 @@ func NormalizeAndValidateConfig(config *models.DNSConfig) (errs []error) {
|
|||||||
} else if rec.Type == "TLSA" {
|
} else if rec.Type == "TLSA" {
|
||||||
if rec.TlsaUsage < 0 || rec.TlsaUsage > 3 {
|
if rec.TlsaUsage < 0 || rec.TlsaUsage > 3 {
|
||||||
errs = append(errs, errors.Errorf("TLSA Usage %d is invalid in record %s (domain %s)",
|
errs = append(errs, errors.Errorf("TLSA Usage %d is invalid in record %s (domain %s)",
|
||||||
rec.TlsaUsage, rec.Name, domain.Name))
|
rec.TlsaUsage, rec.GetLabel(), domain.Name))
|
||||||
}
|
}
|
||||||
if rec.TlsaSelector < 0 || rec.TlsaSelector > 1 {
|
if rec.TlsaSelector < 0 || rec.TlsaSelector > 1 {
|
||||||
errs = append(errs, errors.Errorf("TLSA Selector %d is invalid in record %s (domain %s)",
|
errs = append(errs, errors.Errorf("TLSA Selector %d is invalid in record %s (domain %s)",
|
||||||
rec.TlsaSelector, rec.Name, domain.Name))
|
rec.TlsaSelector, rec.GetLabel(), domain.Name))
|
||||||
}
|
}
|
||||||
if rec.TlsaMatchingType < 0 || rec.TlsaMatchingType > 2 {
|
if rec.TlsaMatchingType < 0 || rec.TlsaMatchingType > 2 {
|
||||||
errs = append(errs, errors.Errorf("TLSA MatchingType %d is invalid in record %s (domain %s)",
|
errs = append(errs, errors.Errorf("TLSA MatchingType %d is invalid in record %s (domain %s)",
|
||||||
rec.TlsaMatchingType, rec.Name, domain.Name))
|
rec.TlsaMatchingType, rec.GetLabel(), domain.Name))
|
||||||
}
|
}
|
||||||
} else if rec.Type == "TXT" && len(txtMultiDissenters) != 0 && len(rec.TxtStrings) > 1 {
|
} else if rec.Type == "TXT" && len(txtMultiDissenters) != 0 && len(rec.TxtStrings) > 1 {
|
||||||
// There are providers that don't support TXTMulti yet there is
|
// There are providers that don't support TXTMulti yet there is
|
||||||
// a TXT record with multiple strings:
|
// a TXT record with multiple strings:
|
||||||
errs = append(errs,
|
errs = append(errs,
|
||||||
errors.Errorf("TXT records with multiple strings (label %v domain: %v) not supported by %s",
|
errors.Errorf("TXT records with multiple strings (label %v domain: %v) not supported by %s",
|
||||||
rec.Name, domain.Name, strings.Join(txtMultiDissenters, ",")))
|
rec.GetLabel(), domain.Name, strings.Join(txtMultiDissenters, ",")))
|
||||||
}
|
}
|
||||||
|
|
||||||
// Populate FQDN:
|
// Populate FQDN:
|
||||||
rec.NameFQDN = dnsutil.AddOrigin(rec.Name, domain.Name)
|
//rec.NameFQDN = dnsutil.AddOrigin(rec.GetLabel(), domain.Name)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -337,7 +339,7 @@ func NormalizeAndValidateConfig(config *models.DNSConfig) (errs []error) {
|
|||||||
errs = append(errs, err)
|
errs = append(errs, err)
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
err = importTransform(config.FindDomain(rec.Target), domain, table, rec.TTL)
|
err = importTransform(config.FindDomain(rec.GetTargetField()), domain, table, rec.TTL)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
errs = append(errs, err)
|
errs = append(errs, err)
|
||||||
}
|
}
|
||||||
@ -375,15 +377,15 @@ func checkCNAMEs(dc *models.DomainConfig) (errs []error) {
|
|||||||
cnames := map[string]bool{}
|
cnames := map[string]bool{}
|
||||||
for _, r := range dc.Records {
|
for _, r := range dc.Records {
|
||||||
if r.Type == "CNAME" {
|
if r.Type == "CNAME" {
|
||||||
if cnames[r.Name] {
|
if cnames[r.GetLabel()] {
|
||||||
errs = append(errs, errors.Errorf("Cannot have multiple CNAMEs with same name: %s", r.NameFQDN))
|
errs = append(errs, errors.Errorf("Cannot have multiple CNAMEs with same name: %s", r.GetLabelFQDN()))
|
||||||
}
|
}
|
||||||
cnames[r.Name] = true
|
cnames[r.GetLabel()] = true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
for _, r := range dc.Records {
|
for _, r := range dc.Records {
|
||||||
if cnames[r.Name] && r.Type != "CNAME" {
|
if cnames[r.GetLabel()] && r.Type != "CNAME" {
|
||||||
errs = append(errs, errors.Errorf("Cannot have CNAME and %s record with same name: %s", r.Type, r.NameFQDN))
|
errs = append(errs, errors.Errorf("Cannot have CNAME and %s record with same name: %s", r.Type, r.GetLabelFQDN()))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return
|
return
|
||||||
@ -433,21 +435,21 @@ func applyRecordTransforms(domain *models.DomainConfig) error {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
ip := net.ParseIP(rec.Target) // ip already validated above
|
ip := net.ParseIP(rec.GetTargetField()) // ip already validated above
|
||||||
newIPs, err := transform.TransformIPToList(net.ParseIP(rec.Target), table)
|
newIPs, err := transform.TransformIPToList(net.ParseIP(rec.GetTargetField()), table)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
for i, newIP := range newIPs {
|
for i, newIP := range newIPs {
|
||||||
if i == 0 && !newIP.Equal(ip) {
|
if i == 0 && !newIP.Equal(ip) {
|
||||||
rec.Target = newIP.String() // replace target of first record if different
|
rec.SetTarget(newIP.String()) // replace target of first record if different
|
||||||
} else if i > 0 {
|
} else if i > 0 {
|
||||||
// any additional ips need identical records with the alternate ip added to the domain
|
// any additional ips need identical records with the alternate ip added to the domain
|
||||||
copy, err := rec.Copy()
|
copy, err := rec.Copy()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
copy.Target = newIP.String()
|
copy.SetTarget(newIP.String())
|
||||||
domain.Records = append(domain.Records, copy)
|
domain.Records = append(domain.Records, copy)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -113,12 +113,14 @@ func Test_transform_cname(t *testing.T) {
|
|||||||
|
|
||||||
func TestNSAtRoot(t *testing.T) {
|
func TestNSAtRoot(t *testing.T) {
|
||||||
// do not allow ns records for @
|
// do not allow ns records for @
|
||||||
rec := &models.RecordConfig{Name: "test", Type: "NS", Target: "ns1.name.com."}
|
rec := &models.RecordConfig{Type: "NS"}
|
||||||
|
rec.SetLabel("test", "foo.com")
|
||||||
|
rec.SetTarget("ns1.name.com.")
|
||||||
errs := checkTargets(rec, "foo.com")
|
errs := checkTargets(rec, "foo.com")
|
||||||
if len(errs) > 0 {
|
if len(errs) > 0 {
|
||||||
t.Error("Expect no error with ns record on subdomain")
|
t.Error("Expect no error with ns record on subdomain")
|
||||||
}
|
}
|
||||||
rec.Name = "@"
|
rec.SetLabel("@", "foo.com")
|
||||||
errs = checkTargets(rec, "foo.com")
|
errs = checkTargets(rec, "foo.com")
|
||||||
if len(errs) != 1 {
|
if len(errs) != 1 {
|
||||||
t.Error("Expect error with ns record on @")
|
t.Error("Expect error with ns record on @")
|
||||||
@ -138,7 +140,7 @@ func TestTransforms(t *testing.T) {
|
|||||||
for i, test := range tests {
|
for i, test := range tests {
|
||||||
dc := &models.DomainConfig{
|
dc := &models.DomainConfig{
|
||||||
Records: []*models.RecordConfig{
|
Records: []*models.RecordConfig{
|
||||||
{Type: "A", Target: test.givenIP, Metadata: map[string]string{"transform": transform}},
|
makeRC("f", "example.tld", test.givenIP, models.RecordConfig{Type: "A", Metadata: map[string]string{"transform": transform}}),
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
err := applyRecordTransforms(dc)
|
err := applyRecordTransforms(dc)
|
||||||
@ -151,8 +153,8 @@ func TestTransforms(t *testing.T) {
|
|||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
for r, rec := range dc.Records {
|
for r, rec := range dc.Records {
|
||||||
if rec.Target != test.expectedRecords[r] {
|
if rec.GetTargetField() != test.expectedRecords[r] {
|
||||||
t.Errorf("test %d at index %d: records don't match. Expect %s but found %s.", i, r, test.expectedRecords[r], rec.Target)
|
t.Errorf("test %d at index %d: records don't match. Expect %s but found %s.", i, r, test.expectedRecords[r], rec.GetTargetField())
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -160,7 +162,9 @@ func TestTransforms(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func TestCNAMEMutex(t *testing.T) {
|
func TestCNAMEMutex(t *testing.T) {
|
||||||
var recA = &models.RecordConfig{Type: "CNAME", Name: "foo", NameFQDN: "foo.example.com", Target: "example.com."}
|
var recA = &models.RecordConfig{Type: "CNAME"}
|
||||||
|
recA.SetLabel("foo", "foo.example.com")
|
||||||
|
recA.SetTarget("example.com.")
|
||||||
tests := []struct {
|
tests := []struct {
|
||||||
rType string
|
rType string
|
||||||
name string
|
name string
|
||||||
@ -173,7 +177,9 @@ func TestCNAMEMutex(t *testing.T) {
|
|||||||
}
|
}
|
||||||
for _, tst := range tests {
|
for _, tst := range tests {
|
||||||
t.Run(fmt.Sprintf("%s %s", tst.rType, tst.name), func(t *testing.T) {
|
t.Run(fmt.Sprintf("%s %s", tst.rType, tst.name), func(t *testing.T) {
|
||||||
var recB = &models.RecordConfig{Type: tst.rType, Name: tst.name, NameFQDN: tst.name + ".example.com", Target: "example2.com."}
|
var recB = &models.RecordConfig{Type: tst.rType}
|
||||||
|
recB.SetLabel(tst.name, "example.com")
|
||||||
|
recB.SetTarget("example2.com.")
|
||||||
dc := &models.DomainConfig{
|
dc := &models.DomainConfig{
|
||||||
Name: "example.com",
|
Name: "example.com",
|
||||||
Records: []*models.RecordConfig{recA, recB},
|
Records: []*models.RecordConfig{recA, recB},
|
||||||
@ -196,7 +202,7 @@ func TestCAAValidation(t *testing.T) {
|
|||||||
Name: "example.com",
|
Name: "example.com",
|
||||||
RegistrarName: "BIND",
|
RegistrarName: "BIND",
|
||||||
Records: []*models.RecordConfig{
|
Records: []*models.RecordConfig{
|
||||||
{Name: "@", NameFQDN: "example.com", Type: "CAA", CaaTag: "invalid", Target: "example.com"},
|
makeRC("@", "example.com", "example.com", models.RecordConfig{Type: "CAA", CaaTag: "invalid"}),
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
@ -214,7 +220,8 @@ func TestTLSAValidation(t *testing.T) {
|
|||||||
Name: "_443._tcp.example.com",
|
Name: "_443._tcp.example.com",
|
||||||
RegistrarName: "BIND",
|
RegistrarName: "BIND",
|
||||||
Records: []*models.RecordConfig{
|
Records: []*models.RecordConfig{
|
||||||
{Name: "_443._tcp", NameFQDN: "_443._tcp._443._tcp.example.com", Type: "TLSA", TlsaUsage: 4, TlsaSelector: 1, TlsaMatchingType: 1, Target: "abcdef0"},
|
makeRC("_443._tcp", "_443._tcp.example.com", "abcdef0", models.RecordConfig{
|
||||||
|
Type: "TLSA", TlsaUsage: 4, TlsaSelector: 1, TlsaMatchingType: 1}),
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
@ -11,7 +11,6 @@ import (
|
|||||||
"github.com/StackExchange/dnscontrol/models"
|
"github.com/StackExchange/dnscontrol/models"
|
||||||
"github.com/StackExchange/dnscontrol/providers/diff"
|
"github.com/StackExchange/dnscontrol/providers/diff"
|
||||||
"github.com/TomOnTime/utfutil"
|
"github.com/TomOnTime/utfutil"
|
||||||
"github.com/miekg/dns/dnsutil"
|
|
||||||
"github.com/pkg/errors"
|
"github.com/pkg/errors"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -35,7 +34,7 @@ func (c *adProvider) GetDomainCorrections(dc *models.DomainConfig) ([]*models.Co
|
|||||||
|
|
||||||
dc.Filter(func(r *models.RecordConfig) bool {
|
dc.Filter(func(r *models.RecordConfig) bool {
|
||||||
if r.Type != "A" && r.Type != "CNAME" {
|
if r.Type != "A" && r.Type != "CNAME" {
|
||||||
log.Printf("WARNING: Active Directory only manages A and CNAME records. Won't consider %s %s", r.Type, r.NameFQDN)
|
log.Printf("WARNING: Active Directory only manages A and CNAME records. Won't consider %s %s", r.Type, r.GetLabelFQDN())
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
return true
|
return true
|
||||||
@ -162,18 +161,16 @@ func (c *adProvider) getExistingRecords(domainname string) ([]*models.RecordConf
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (r *RecordConfigJson) unpackRecord(origin string) *models.RecordConfig {
|
func (r *RecordConfigJson) unpackRecord(origin string) *models.RecordConfig {
|
||||||
rc := models.RecordConfig{}
|
rc := models.RecordConfig{
|
||||||
|
Type: r.Type,
|
||||||
rc.Name = strings.ToLower(r.Name)
|
TTL: r.TTL,
|
||||||
rc.NameFQDN = dnsutil.AddOrigin(rc.Name, origin)
|
}
|
||||||
rc.Type = r.Type
|
rc.SetLabel(r.Name, origin)
|
||||||
rc.TTL = r.TTL
|
switch rtype := rc.Type; rtype { // #rtype_variations
|
||||||
|
case "A", "AAAA":
|
||||||
switch rc.Type { // #rtype_variations
|
rc.SetTarget(r.Data)
|
||||||
case "A":
|
|
||||||
rc.Target = r.Data
|
|
||||||
case "CNAME":
|
case "CNAME":
|
||||||
rc.Target = strings.ToLower(r.Data)
|
rc.SetTarget(strings.ToLower(r.Data))
|
||||||
case "NS", "SOA":
|
case "NS", "SOA":
|
||||||
return nil
|
return nil
|
||||||
default:
|
default:
|
||||||
@ -197,12 +194,12 @@ Get-DnsServerResourceRecord -ComputerName REPLACE_WITH_COMPUTER_NAME -ZoneName $
|
|||||||
|
|
||||||
// generatePowerShellCreate generates PowerShell commands to ADD a record.
|
// generatePowerShellCreate generates PowerShell commands to ADD a record.
|
||||||
func (c *adProvider) generatePowerShellCreate(domainname string, rec *models.RecordConfig) string {
|
func (c *adProvider) generatePowerShellCreate(domainname string, rec *models.RecordConfig) string {
|
||||||
content := rec.Target
|
content := rec.GetTargetField()
|
||||||
text := "\r\n" // Skip a line.
|
text := "\r\n" // Skip a line.
|
||||||
text += fmt.Sprintf("Add-DnsServerResourceRecord%s", rec.Type)
|
text += fmt.Sprintf("Add-DnsServerResourceRecord%s", rec.Type)
|
||||||
text += fmt.Sprintf(` -ComputerName "%s"`, c.adServer)
|
text += fmt.Sprintf(` -ComputerName "%s"`, c.adServer)
|
||||||
text += fmt.Sprintf(` -ZoneName "%s"`, domainname)
|
text += fmt.Sprintf(` -ZoneName "%s"`, domainname)
|
||||||
text += fmt.Sprintf(` -Name "%s"`, rec.Name)
|
text += fmt.Sprintf(` -Name "%s"`, rec.GetLabel())
|
||||||
text += fmt.Sprintf(` -TimeToLive $(New-TimeSpan -Seconds %d)`, rec.TTL)
|
text += fmt.Sprintf(` -TimeToLive $(New-TimeSpan -Seconds %d)`, rec.TTL)
|
||||||
switch rec.Type { // #rtype_variations
|
switch rec.Type { // #rtype_variations
|
||||||
case "CNAME":
|
case "CNAME":
|
||||||
@ -210,9 +207,10 @@ func (c *adProvider) generatePowerShellCreate(domainname string, rec *models.Rec
|
|||||||
case "A":
|
case "A":
|
||||||
text += fmt.Sprintf(` -IPv4Address "%s"`, content)
|
text += fmt.Sprintf(` -IPv4Address "%s"`, content)
|
||||||
case "NS":
|
case "NS":
|
||||||
text = fmt.Sprintf("\r\n"+`echo "Skipping NS update (%v %v)"`+"\r\n", rec.Name, rec.Target)
|
text = fmt.Sprintf("\r\n"+`echo "Skipping NS update (%v %v)"`+"\r\n", rec.GetLabel(), rec.GetTargetDebug())
|
||||||
default:
|
default:
|
||||||
panic(errors.Errorf("generatePowerShellCreate() does not yet handle recType=%s recName=%#v content=%#v)", rec.Type, rec.Name, content))
|
panic(errors.Errorf("generatePowerShellCreate() does not yet handle recType=%s recName=%#v content=%#v)",
|
||||||
|
rec.Type, rec.GetLabel(), content))
|
||||||
// We panic so that we quickly find any switch statements
|
// We panic so that we quickly find any switch statements
|
||||||
// that have not been updated for a new RR type.
|
// that have not been updated for a new RR type.
|
||||||
}
|
}
|
||||||
@ -286,7 +284,7 @@ func (c *adProvider) generatePowerShellDelete(domainname, recName, recType, cont
|
|||||||
func (c *adProvider) createRec(domainname string, rec *models.RecordConfig) []*models.Correction {
|
func (c *adProvider) createRec(domainname string, rec *models.RecordConfig) []*models.Correction {
|
||||||
arr := []*models.Correction{
|
arr := []*models.Correction{
|
||||||
{
|
{
|
||||||
Msg: fmt.Sprintf("CREATE record: %s %s ttl(%d) %s", rec.Name, rec.Type, rec.TTL, rec.Target),
|
Msg: fmt.Sprintf("CREATE record: %s %s ttl(%d) %s", rec.GetLabel(), rec.Type, rec.TTL, rec.GetTargetField()),
|
||||||
F: func() error {
|
F: func() error {
|
||||||
return c.powerShellDoCommand(c.generatePowerShellCreate(domainname, rec), true)
|
return c.powerShellDoCommand(c.generatePowerShellCreate(domainname, rec), true)
|
||||||
}},
|
}},
|
||||||
@ -299,16 +297,16 @@ func (c *adProvider) modifyRec(domainname string, m diff.Correlation) *models.Co
|
|||||||
return &models.Correction{
|
return &models.Correction{
|
||||||
Msg: m.String(),
|
Msg: m.String(),
|
||||||
F: func() error {
|
F: func() error {
|
||||||
return c.powerShellDoCommand(c.generatePowerShellModify(domainname, rec.Name, rec.Type, old.Target, rec.Target, old.TTL, rec.TTL), true)
|
return c.powerShellDoCommand(c.generatePowerShellModify(domainname, rec.GetLabel(), rec.Type, old.GetTargetField(), rec.GetTargetField(), old.TTL, rec.TTL), true)
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *adProvider) deleteRec(domainname string, rec *models.RecordConfig) *models.Correction {
|
func (c *adProvider) deleteRec(domainname string, rec *models.RecordConfig) *models.Correction {
|
||||||
return &models.Correction{
|
return &models.Correction{
|
||||||
Msg: fmt.Sprintf("DELETE record: %s %s ttl(%d) %s", rec.Name, rec.Type, rec.TTL, rec.Target),
|
Msg: fmt.Sprintf("DELETE record: %s %s ttl(%d) %s", rec.GetLabel(), rec.Type, rec.TTL, rec.GetTargetField()),
|
||||||
F: func() error {
|
F: func() error {
|
||||||
return c.powerShellDoCommand(c.generatePowerShellDelete(domainname, rec.Name, rec.Type, rec.Target), true)
|
return c.powerShellDoCommand(c.generatePowerShellDelete(domainname, rec.GetLabel(), rec.Type, rec.GetTargetField()), true)
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -7,6 +7,12 @@ import (
|
|||||||
"github.com/StackExchange/dnscontrol/models"
|
"github.com/StackExchange/dnscontrol/models"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
func makeRC(label, domain, target string, rc models.RecordConfig) *models.RecordConfig {
|
||||||
|
rc.SetLabel(label, domain)
|
||||||
|
rc.SetTarget(target)
|
||||||
|
return &rc
|
||||||
|
}
|
||||||
|
|
||||||
func TestGetExistingRecords(t *testing.T) {
|
func TestGetExistingRecords(t *testing.T) {
|
||||||
|
|
||||||
cf := &adProvider{}
|
cf := &adProvider{}
|
||||||
@ -17,11 +23,11 @@ func TestGetExistingRecords(t *testing.T) {
|
|||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
expected := []*models.RecordConfig{
|
expected := []*models.RecordConfig{
|
||||||
{Name: "@", NameFQDN: "test2", Type: "A", TTL: 600, Target: "10.166.2.11"},
|
makeRC("@", "test2", "10.166.2.11", models.RecordConfig{Type: "A", TTL: 600}),
|
||||||
//{Name: "_msdcs", NameFQDN: "_msdcs.test2", Type: "NS", TTL: 300, Target: "other_record"}, // Will be filtered.
|
//makeRC("_msdcs", "test2", "other_record", models.RecordConfig{Type: "NS", TTL: 300}), // Will be filtered.
|
||||||
{Name: "co-devsearch02", NameFQDN: "co-devsearch02.test2", Type: "A", TTL: 3600, Target: "10.8.2.64"},
|
makeRC("co-devsearch02", "test2", "10.8.2.64", models.RecordConfig{Type: "A", TTL: 3600}),
|
||||||
{Name: "co-devservice01", NameFQDN: "co-devservice01.test2", Type: "A", TTL: 1200, Target: "10.8.2.48"}, // Downcased.
|
makeRC("co-devservice01", "test2", "10.8.2.48", models.RecordConfig{Type: "A", TTL: 1200}), // Downcased.
|
||||||
{Name: "yum", NameFQDN: "yum.test2", Type: "A", TTL: 3600, Target: "10.8.0.59"},
|
makeRC("yum", "test2", "10.8.0.59", models.RecordConfig{Type: "A", TTL: 3600}),
|
||||||
}
|
}
|
||||||
|
|
||||||
actualS := ""
|
actualS := ""
|
||||||
|
@ -127,7 +127,7 @@ func rrToRecord(rr dns.RR, origin string, replaceSerial uint32) (models.RecordCo
|
|||||||
}
|
}
|
||||||
newSerial = v.Serial
|
newSerial = v.Serial
|
||||||
//if (dnsutil.TrimDomainName(rc.Name, origin+".") == "@") && replaceSerial != 0 {
|
//if (dnsutil.TrimDomainName(rc.Name, origin+".") == "@") && replaceSerial != 0 {
|
||||||
if rc.Name == "@" && replaceSerial != 0 {
|
if rc.GetLabel() == "@" && replaceSerial != 0 {
|
||||||
newSerial = replaceSerial
|
newSerial = replaceSerial
|
||||||
}
|
}
|
||||||
panicInvalid(rc.SetTarget(
|
panicInvalid(rc.SetTarget(
|
||||||
|
@ -16,14 +16,25 @@ func newDomainConfig() *models.DomainConfig {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func makeRCmeta(meta map[string]string) *models.RecordConfig {
|
||||||
|
rc := models.RecordConfig{
|
||||||
|
Type: "A",
|
||||||
|
Metadata: meta,
|
||||||
|
}
|
||||||
|
rc.SetLabel("foo", "example.tld")
|
||||||
|
rc.SetTarget("1.2.3.4")
|
||||||
|
return &rc
|
||||||
|
}
|
||||||
|
|
||||||
func TestPreprocess_BoolValidation(t *testing.T) {
|
func TestPreprocess_BoolValidation(t *testing.T) {
|
||||||
cf := &CloudflareApi{}
|
cf := &CloudflareApi{}
|
||||||
|
|
||||||
domain := newDomainConfig()
|
domain := newDomainConfig()
|
||||||
domain.Records = append(domain.Records, &models.RecordConfig{Type: "A", Target: "1.2.3.4", Metadata: map[string]string{metaProxy: "on"}})
|
domain.Records = append(domain.Records, makeRCmeta(map[string]string{metaProxy: "on"}))
|
||||||
domain.Records = append(domain.Records, &models.RecordConfig{Type: "A", Target: "1.2.3.4", Metadata: map[string]string{metaProxy: "fUll"}})
|
domain.Records = append(domain.Records, makeRCmeta(map[string]string{metaProxy: "fUll"}))
|
||||||
domain.Records = append(domain.Records, &models.RecordConfig{Type: "A", Target: "1.2.3.4", Metadata: map[string]string{}})
|
domain.Records = append(domain.Records, makeRCmeta(map[string]string{}))
|
||||||
domain.Records = append(domain.Records, &models.RecordConfig{Type: "A", Target: "1.2.3.4", Metadata: map[string]string{metaProxy: "Off"}})
|
domain.Records = append(domain.Records, makeRCmeta(map[string]string{metaProxy: "Off"}))
|
||||||
domain.Records = append(domain.Records, &models.RecordConfig{Type: "A", Target: "1.2.3.4", Metadata: map[string]string{metaProxy: "off"}})
|
domain.Records = append(domain.Records, makeRCmeta(map[string]string{metaProxy: "off"}))
|
||||||
err := cf.preprocessConfig(domain)
|
err := cf.preprocessConfig(domain)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
@ -51,9 +62,9 @@ func TestPreprocess_DefaultProxy(t *testing.T) {
|
|||||||
cf := &CloudflareApi{}
|
cf := &CloudflareApi{}
|
||||||
domain := newDomainConfig()
|
domain := newDomainConfig()
|
||||||
domain.Metadata[metaProxyDefault] = "full"
|
domain.Metadata[metaProxyDefault] = "full"
|
||||||
domain.Records = append(domain.Records, &models.RecordConfig{Type: "A", Target: "1.2.3.4", Metadata: map[string]string{metaProxy: "on"}})
|
domain.Records = append(domain.Records, makeRCmeta(map[string]string{metaProxy: "on"}))
|
||||||
domain.Records = append(domain.Records, &models.RecordConfig{Type: "A", Target: "1.2.3.4", Metadata: map[string]string{metaProxy: "off"}})
|
domain.Records = append(domain.Records, makeRCmeta(map[string]string{metaProxy: "off"}))
|
||||||
domain.Records = append(domain.Records, &models.RecordConfig{Type: "A", Target: "1.2.3.4", Metadata: map[string]string{}})
|
domain.Records = append(domain.Records, makeRCmeta(map[string]string{}))
|
||||||
err := cf.preprocessConfig(domain)
|
err := cf.preprocessConfig(domain)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
@ -97,7 +108,8 @@ func TestIpRewriting(t *testing.T) {
|
|||||||
NewBases: []net.IP{net.ParseIP("255.255.255.0")},
|
NewBases: []net.IP{net.ParseIP("255.255.255.0")},
|
||||||
NewIPs: nil}}
|
NewIPs: nil}}
|
||||||
for _, tst := range tests {
|
for _, tst := range tests {
|
||||||
rec := &models.RecordConfig{Type: "A", Target: tst.Given, Metadata: map[string]string{metaProxy: tst.Proxy}}
|
rec := &models.RecordConfig{Type: "A", Metadata: map[string]string{metaProxy: tst.Proxy}}
|
||||||
|
rec.SetTarget(tst.Given)
|
||||||
domain.Records = append(domain.Records, rec)
|
domain.Records = append(domain.Records, rec)
|
||||||
}
|
}
|
||||||
err := cf.preprocessConfig(domain)
|
err := cf.preprocessConfig(domain)
|
||||||
@ -106,8 +118,8 @@ func TestIpRewriting(t *testing.T) {
|
|||||||
}
|
}
|
||||||
for i, tst := range tests {
|
for i, tst := range tests {
|
||||||
rec := domain.Records[i]
|
rec := domain.Records[i]
|
||||||
if rec.Target != tst.Expected {
|
if rec.GetTargetField() != tst.Expected {
|
||||||
t.Fatalf("At index %d, expected target of %s, but found %s.", i, tst.Expected, rec.Target)
|
t.Fatalf("At index %d, expected target of %s, but found %s.", i, tst.Expected, rec.GetTargetField())
|
||||||
}
|
}
|
||||||
if tst.Proxy == "full" && tst.Given != tst.Expected && rec.Metadata[metaOriginalIP] != tst.Given {
|
if tst.Proxy == "full" && tst.Given != tst.Expected && rec.Metadata[metaOriginalIP] != tst.Given {
|
||||||
t.Fatalf("At index %d, expected original_ip to be set", i)
|
t.Fatalf("At index %d, expected original_ip to be set", i)
|
||||||
|
@ -77,7 +77,7 @@ func (d *differ) IncrementalDiff(existing []*models.RecordConfig) (unchanged, cr
|
|||||||
if d.matchIgnored(e.GetLabel()) {
|
if d.matchIgnored(e.GetLabel()) {
|
||||||
log.Printf("Ignoring record %s %s due to IGNORE", e.GetLabel(), e.Type)
|
log.Printf("Ignoring record %s %s due to IGNORE", e.GetLabel(), e.Type)
|
||||||
} else {
|
} else {
|
||||||
k := key{e.NameFQDN, e.Type}
|
k := key{e.GetLabelFQDN(), e.Type}
|
||||||
existingByNameAndType[k] = append(existingByNameAndType[k], e)
|
existingByNameAndType[k] = append(existingByNameAndType[k], e)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -85,7 +85,7 @@ func (d *differ) IncrementalDiff(existing []*models.RecordConfig) (unchanged, cr
|
|||||||
if d.matchIgnored(dr.GetLabel()) {
|
if d.matchIgnored(dr.GetLabel()) {
|
||||||
panic(fmt.Sprintf("Trying to update/add IGNOREd record: %s %s", dr.GetLabel(), dr.Type))
|
panic(fmt.Sprintf("Trying to update/add IGNOREd record: %s %s", dr.GetLabel(), dr.Type))
|
||||||
} else {
|
} else {
|
||||||
k := key{dr.NameFQDN, dr.Type}
|
k := key{dr.GetLabelFQDN(), dr.Type}
|
||||||
desiredByNameAndType[k] = append(desiredByNameAndType[k], dr)
|
desiredByNameAndType[k] = append(desiredByNameAndType[k], dr)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -106,7 +106,7 @@ func (d *differ) IncrementalDiff(existing []*models.RecordConfig) (unchanged, cr
|
|||||||
for i := len(existingRecords) - 1; i >= 0; i-- {
|
for i := len(existingRecords) - 1; i >= 0; i-- {
|
||||||
ex := existingRecords[i]
|
ex := existingRecords[i]
|
||||||
for j, de := range desiredRecords {
|
for j, de := range desiredRecords {
|
||||||
if de.Target == ex.Target {
|
if de.GetTargetField() == ex.GetTargetField() {
|
||||||
// they're either identical or should be a modification of each other (ttl or metadata changes)
|
// they're either identical or should be a modification of each other (ttl or metadata changes)
|
||||||
if d.content(de) == d.content(ex) {
|
if d.content(de) == d.content(ex) {
|
||||||
unchanged = append(unchanged, Correlation{d, ex, de})
|
unchanged = append(unchanged, Correlation{d, ex, de})
|
||||||
@ -197,12 +197,12 @@ func (d *differ) ChangedGroups(existing []*models.RecordConfig) map[models.Recor
|
|||||||
|
|
||||||
func (c Correlation) String() string {
|
func (c Correlation) String() string {
|
||||||
if c.Existing == nil {
|
if c.Existing == nil {
|
||||||
return fmt.Sprintf("CREATE %s %s %s", c.Desired.Type, c.Desired.NameFQDN, c.d.content(c.Desired))
|
return fmt.Sprintf("CREATE %s %s %s", c.Desired.Type, c.Desired.GetLabelFQDN(), c.d.content(c.Desired))
|
||||||
}
|
}
|
||||||
if c.Desired == nil {
|
if c.Desired == nil {
|
||||||
return fmt.Sprintf("DELETE %s %s %s", c.Existing.Type, c.Existing.NameFQDN, c.d.content(c.Existing))
|
return fmt.Sprintf("DELETE %s %s %s", c.Existing.Type, c.Existing.GetLabelFQDN(), c.d.content(c.Existing))
|
||||||
}
|
}
|
||||||
return fmt.Sprintf("MODIFY %s %s: (%s) -> (%s)", c.Existing.Type, c.Existing.NameFQDN, c.d.content(c.Existing), c.d.content(c.Desired))
|
return fmt.Sprintf("MODIFY %s %s: (%s) -> (%s)", c.Existing.Type, c.Existing.GetLabelFQDN(), c.d.content(c.Existing), c.d.content(c.Desired))
|
||||||
}
|
}
|
||||||
|
|
||||||
func sortedKeys(m map[string]*models.RecordConfig) []string {
|
func sortedKeys(m map[string]*models.RecordConfig) []string {
|
||||||
|
@ -7,20 +7,19 @@ import (
|
|||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"github.com/StackExchange/dnscontrol/models"
|
"github.com/StackExchange/dnscontrol/models"
|
||||||
"github.com/miekg/dns/dnsutil"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
func myRecord(s string) *models.RecordConfig {
|
func myRecord(s string) *models.RecordConfig {
|
||||||
parts := strings.Split(s, " ")
|
parts := strings.Split(s, " ")
|
||||||
ttl, _ := strconv.ParseUint(parts[2], 10, 32)
|
ttl, _ := strconv.ParseUint(parts[2], 10, 32)
|
||||||
return &models.RecordConfig{
|
r := &models.RecordConfig{
|
||||||
Name: parts[0],
|
|
||||||
NameFQDN: dnsutil.AddOrigin(parts[0], "example.com"),
|
|
||||||
Type: parts[1],
|
Type: parts[1],
|
||||||
TTL: uint32(ttl),
|
TTL: uint32(ttl),
|
||||||
Target: parts[3],
|
|
||||||
Metadata: map[string]string{},
|
Metadata: map[string]string{},
|
||||||
}
|
}
|
||||||
|
r.SetLabel(parts[0], "example.com")
|
||||||
|
r.SetTarget(parts[3])
|
||||||
|
return r
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestAdditionsOnly(t *testing.T) {
|
func TestAdditionsOnly(t *testing.T) {
|
||||||
|
@ -203,7 +203,6 @@ func toRc(dc *models.DomainConfig, r *godo.DomainRecord) *models.RecordConfig {
|
|||||||
|
|
||||||
t := &models.RecordConfig{
|
t := &models.RecordConfig{
|
||||||
Type: r.Type,
|
Type: r.Type,
|
||||||
Target: target,
|
|
||||||
TTL: uint32(r.TTL),
|
TTL: uint32(r.TTL),
|
||||||
MxPreference: uint16(r.Priority),
|
MxPreference: uint16(r.Priority),
|
||||||
SrvPriority: uint16(r.Priority),
|
SrvPriority: uint16(r.Priority),
|
||||||
@ -212,6 +211,7 @@ func toRc(dc *models.DomainConfig, r *godo.DomainRecord) *models.RecordConfig {
|
|||||||
Original: r,
|
Original: r,
|
||||||
}
|
}
|
||||||
t.SetLabelFromFQDN(name, dc.Name)
|
t.SetLabelFromFQDN(name, dc.Name)
|
||||||
|
t.SetTarget(target)
|
||||||
switch rtype := r.Type; rtype {
|
switch rtype := r.Type; rtype {
|
||||||
case "TXT":
|
case "TXT":
|
||||||
t.SetTargetTXTString(target)
|
t.SetTargetTXTString(target)
|
||||||
|
@ -10,7 +10,6 @@ import (
|
|||||||
"github.com/StackExchange/dnscontrol/models"
|
"github.com/StackExchange/dnscontrol/models"
|
||||||
"github.com/StackExchange/dnscontrol/providers"
|
"github.com/StackExchange/dnscontrol/providers"
|
||||||
"github.com/StackExchange/dnscontrol/providers/diff"
|
"github.com/StackExchange/dnscontrol/providers/diff"
|
||||||
"github.com/miekg/dns/dnsutil"
|
|
||||||
"github.com/pkg/errors"
|
"github.com/pkg/errors"
|
||||||
|
|
||||||
dnsimpleapi "github.com/dnsimple/dnsimple-go/dnsimple"
|
dnsimpleapi "github.com/dnsimple/dnsimple-go/dnsimple"
|
||||||
@ -281,7 +280,7 @@ func (c *DnsimpleApi) createRecordFunc(rc *models.RecordConfig, domainName strin
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
record := dnsimpleapi.ZoneRecord{
|
record := dnsimpleapi.ZoneRecord{
|
||||||
Name: dnsutil.TrimDomainName(rc.NameFQDN, domainName),
|
Name: rc.GetLabel(),
|
||||||
Type: rc.Type,
|
Type: rc.Type,
|
||||||
Content: rc.GetTargetCombined(),
|
Content: rc.GetTargetCombined(),
|
||||||
TTL: int(rc.TTL),
|
TTL: int(rc.TTL),
|
||||||
@ -327,7 +326,7 @@ func (c *DnsimpleApi) updateRecordFunc(old *dnsimpleapi.ZoneRecord, rc *models.R
|
|||||||
}
|
}
|
||||||
|
|
||||||
record := dnsimpleapi.ZoneRecord{
|
record := dnsimpleapi.ZoneRecord{
|
||||||
Name: dnsutil.TrimDomainName(rc.NameFQDN, domainName),
|
Name: rc.GetLabel(),
|
||||||
Type: rc.Type,
|
Type: rc.Type,
|
||||||
Content: rc.GetTargetCombined(),
|
Content: rc.GetTargetCombined(),
|
||||||
TTL: int(rc.TTL),
|
TTL: int(rc.TTL),
|
||||||
@ -374,7 +373,7 @@ func removeOtherNS(dc *models.DomainConfig) {
|
|||||||
for _, rec := range dc.Records {
|
for _, rec := range dc.Records {
|
||||||
if rec.Type == "NS" {
|
if rec.Type == "NS" {
|
||||||
// apex NS inside dnsimple are expected.
|
// apex NS inside dnsimple are expected.
|
||||||
if rec.NameFQDN == dc.Name && strings.HasSuffix(rec.GetTargetField(), ".dnsimple.com.") {
|
if rec.GetLabelFQDN() == dc.Name && strings.HasSuffix(rec.GetTargetField(), ".dnsimple.com.") {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
fmt.Printf("Warning: dnsimple.com does not allow NS records to be modified. %s will not be added.\n", rec.GetTargetField())
|
fmt.Printf("Warning: dnsimple.com does not allow NS records to be modified. %s will not be added.\n", rec.GetTargetField())
|
||||||
|
@ -99,11 +99,11 @@ func (c *GandiApi) GetDomainCorrections(dc *models.DomainConfig) ([]*models.Corr
|
|||||||
return nil, errors.Errorf("ERROR: Gandi does not support TTLs > 30 days (TTL=%d)", rec.TTL)
|
return nil, errors.Errorf("ERROR: Gandi does not support TTLs > 30 days (TTL=%d)", rec.TTL)
|
||||||
}
|
}
|
||||||
if rec.Type == "TXT" {
|
if rec.Type == "TXT" {
|
||||||
rec.Target = "\"" + rec.Target + "\"" // FIXME(tlim): Should do proper quoting.
|
rec.SetTarget("\"" + rec.GetTargetField() + "\"") // FIXME(tlim): Should do proper quoting.
|
||||||
}
|
}
|
||||||
if rec.Type == "NS" && rec.GetLabel() == "@" {
|
if rec.Type == "NS" && rec.GetLabel() == "@" {
|
||||||
if !strings.HasSuffix(rec.Target, ".gandi.net.") {
|
if !strings.HasSuffix(rec.GetTargetField(), ".gandi.net.") {
|
||||||
log.Printf("WARNING: Gandi does not support changing apex NS records. %s will not be added.", rec.Target)
|
log.Printf("WARNING: Gandi does not support changing apex NS records. %s will not be added.", rec.GetTargetField())
|
||||||
}
|
}
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
@ -223,31 +223,31 @@ func (c *liveClient) recordsToInfo(records models.Records) (models.Records, []*g
|
|||||||
|
|
||||||
for _, rec := range records {
|
for _, rec := range records {
|
||||||
if rec.TTL < 300 {
|
if rec.TTL < 300 {
|
||||||
log.Printf("WARNING: Gandi does not support ttls < 300. %s will not be set to %d.", rec.NameFQDN, rec.TTL)
|
log.Printf("WARNING: Gandi does not support ttls < 300. %s will not be set to %d.", rec.GetLabelFQDN(), rec.TTL)
|
||||||
rec.TTL = 300
|
rec.TTL = 300
|
||||||
}
|
}
|
||||||
if rec.TTL > 2592000 {
|
if rec.TTL > 2592000 {
|
||||||
return nil, nil, errors.Errorf("ERROR: Gandi does not support TTLs > 30 days (TTL=%d)", rec.TTL)
|
return nil, nil, errors.Errorf("ERROR: Gandi does not support TTLs > 30 days (TTL=%d)", rec.TTL)
|
||||||
}
|
}
|
||||||
if rec.Type == "NS" && rec.Name == "@" {
|
if rec.Type == "NS" && rec.GetLabel() == "@" {
|
||||||
if !strings.HasSuffix(rec.Target, ".gandi.net.") {
|
if !strings.HasSuffix(rec.GetTargetField(), ".gandi.net.") {
|
||||||
log.Printf("WARNING: Gandi does not support changing apex NS records. %s will not be added.", rec.Target)
|
log.Printf("WARNING: Gandi does not support changing apex NS records. %s will not be added.", rec.GetTargetField())
|
||||||
}
|
}
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
r, ok := recordSets[rec.Name][rec.Type]
|
r, ok := recordSets[rec.GetLabel()][rec.Type]
|
||||||
if !ok {
|
if !ok {
|
||||||
_, ok := recordSets[rec.Name]
|
_, ok := recordSets[rec.GetLabel()]
|
||||||
if !ok {
|
if !ok {
|
||||||
recordSets[rec.Name] = map[string]*gandiliverecord.Info{}
|
recordSets[rec.GetLabel()] = map[string]*gandiliverecord.Info{}
|
||||||
}
|
}
|
||||||
r = &gandiliverecord.Info{
|
r = &gandiliverecord.Info{
|
||||||
Type: rec.Type,
|
Type: rec.Type,
|
||||||
Name: rec.Name,
|
Name: rec.GetLabel(),
|
||||||
TTL: int64(rec.TTL),
|
TTL: int64(rec.TTL),
|
||||||
}
|
}
|
||||||
recordInfos = append(recordInfos, r)
|
recordInfos = append(recordInfos, r)
|
||||||
recordSets[rec.Name][rec.Type] = r
|
recordSets[rec.GetLabel()][rec.Type] = r
|
||||||
} else {
|
} else {
|
||||||
if r.TTL != int64(rec.TTL) {
|
if r.TTL != int64(rec.TTL) {
|
||||||
log.Printf(
|
log.Printf(
|
||||||
|
@ -8,6 +8,11 @@ import (
|
|||||||
"github.com/stretchr/testify/assert"
|
"github.com/stretchr/testify/assert"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
func makeRC(label, domain, target string, rc models.RecordConfig) *models.RecordConfig {
|
||||||
|
rc.SetLabel(label, domain)
|
||||||
|
rc.SetTarget(target)
|
||||||
|
return &rc
|
||||||
|
}
|
||||||
func TestRecordConfigFromInfo(t *testing.T) {
|
func TestRecordConfigFromInfo(t *testing.T) {
|
||||||
|
|
||||||
for _, data := range []struct {
|
for _, data := range []struct {
|
||||||
@ -22,20 +27,14 @@ func TestRecordConfigFromInfo(t *testing.T) {
|
|||||||
Values: []string{"127.0.0.1", "127.1.0.1"},
|
Values: []string{"127.0.0.1", "127.1.0.1"},
|
||||||
},
|
},
|
||||||
[]*models.RecordConfig{
|
[]*models.RecordConfig{
|
||||||
{
|
makeRC("www", "example.com", "127.0.0.1", models.RecordConfig{
|
||||||
NameFQDN: "www.example.com",
|
|
||||||
Name: "www",
|
|
||||||
Type: "A",
|
Type: "A",
|
||||||
Target: "127.0.0.1",
|
|
||||||
TTL: 500,
|
TTL: 500,
|
||||||
},
|
}),
|
||||||
{
|
makeRC("www", "example.com", "127.1.0.1", models.RecordConfig{
|
||||||
NameFQDN: "www.example.com",
|
|
||||||
Name: "www",
|
|
||||||
Type: "A",
|
Type: "A",
|
||||||
Target: "127.1.0.1",
|
|
||||||
TTL: 500,
|
TTL: 500,
|
||||||
},
|
}),
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@ -46,14 +45,11 @@ func TestRecordConfigFromInfo(t *testing.T) {
|
|||||||
Values: []string{"\"test 2\"", "\"test message test message test message\""},
|
Values: []string{"\"test 2\"", "\"test message test message test message\""},
|
||||||
},
|
},
|
||||||
[]*models.RecordConfig{
|
[]*models.RecordConfig{
|
||||||
{
|
makeRC("www", "example.com", "test 2", models.RecordConfig{
|
||||||
NameFQDN: "www.example.com",
|
|
||||||
Name: "www",
|
|
||||||
Type: "TXT",
|
Type: "TXT",
|
||||||
Target: "test 2",
|
|
||||||
TxtStrings: []string{"test 2", "test message test message test message"},
|
TxtStrings: []string{"test 2", "test message test message test message"},
|
||||||
TTL: 500,
|
TTL: 500,
|
||||||
},
|
}),
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@ -65,24 +61,18 @@ func TestRecordConfigFromInfo(t *testing.T) {
|
|||||||
Values: []string{"0 issue \"www.certinomis.com\"", "0 issuewild \"buypass.com\""},
|
Values: []string{"0 issue \"www.certinomis.com\"", "0 issuewild \"buypass.com\""},
|
||||||
},
|
},
|
||||||
[]*models.RecordConfig{
|
[]*models.RecordConfig{
|
||||||
{
|
makeRC("www", "example.com", "www.certinomis.com", models.RecordConfig{
|
||||||
NameFQDN: "www.example.com",
|
|
||||||
Name: "www",
|
|
||||||
Type: "CAA",
|
Type: "CAA",
|
||||||
Target: "www.certinomis.com",
|
|
||||||
CaaFlag: 0,
|
CaaFlag: 0,
|
||||||
CaaTag: "issue",
|
CaaTag: "issue",
|
||||||
TTL: 500,
|
TTL: 500,
|
||||||
},
|
}),
|
||||||
{
|
makeRC("www", "example.com", "buypass.com", models.RecordConfig{
|
||||||
NameFQDN: "www.example.com",
|
|
||||||
Name: "www",
|
|
||||||
Type: "CAA",
|
Type: "CAA",
|
||||||
Target: "buypass.com",
|
|
||||||
CaaFlag: 0,
|
CaaFlag: 0,
|
||||||
CaaTag: "issuewild",
|
CaaTag: "issuewild",
|
||||||
TTL: 500,
|
TTL: 500,
|
||||||
},
|
}),
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@ -93,16 +83,13 @@ func TestRecordConfigFromInfo(t *testing.T) {
|
|||||||
Values: []string{"20 0 5060 backupbox.example.com."},
|
Values: []string{"20 0 5060 backupbox.example.com."},
|
||||||
},
|
},
|
||||||
[]*models.RecordConfig{
|
[]*models.RecordConfig{
|
||||||
{
|
makeRC("test", "example.com", "backupbox.example.com.", models.RecordConfig{
|
||||||
NameFQDN: "test.example.com",
|
|
||||||
Name: "test",
|
|
||||||
Type: "SRV",
|
Type: "SRV",
|
||||||
Target: "backupbox.example.com.",
|
|
||||||
SrvPriority: 20,
|
SrvPriority: 20,
|
||||||
SrvWeight: 0,
|
SrvWeight: 0,
|
||||||
SrvPort: 5060,
|
SrvPort: 5060,
|
||||||
TTL: 500,
|
TTL: 500,
|
||||||
},
|
}),
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@ -113,22 +100,16 @@ func TestRecordConfigFromInfo(t *testing.T) {
|
|||||||
Values: []string{"50 fb.mail.gandi.net.", "10 spool.mail.gandi.net."},
|
Values: []string{"50 fb.mail.gandi.net.", "10 spool.mail.gandi.net."},
|
||||||
},
|
},
|
||||||
[]*models.RecordConfig{
|
[]*models.RecordConfig{
|
||||||
{
|
makeRC("mail", "example.com", "fb.mail.gandi.net.", models.RecordConfig{
|
||||||
NameFQDN: "mail.example.com",
|
|
||||||
Name: "mail",
|
|
||||||
Type: "MX",
|
Type: "MX",
|
||||||
MxPreference: 50,
|
MxPreference: 50,
|
||||||
Target: "fb.mail.gandi.net.",
|
|
||||||
TTL: 500,
|
TTL: 500,
|
||||||
},
|
}),
|
||||||
{
|
makeRC("mail", "example.com", "spool.mail.gandi.net.", models.RecordConfig{
|
||||||
NameFQDN: "mail.example.com",
|
|
||||||
Name: "mail",
|
|
||||||
Type: "MX",
|
Type: "MX",
|
||||||
MxPreference: 10,
|
MxPreference: 10,
|
||||||
Target: "spool.mail.gandi.net.",
|
|
||||||
TTL: 500,
|
TTL: 500,
|
||||||
},
|
}),
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
} {
|
} {
|
||||||
|
@ -104,7 +104,7 @@ func keyFor(r *gdns.ResourceRecordSet) key {
|
|||||||
return key{Type: r.Type, Name: r.Name}
|
return key{Type: r.Type, Name: r.Name}
|
||||||
}
|
}
|
||||||
func keyForRec(r *models.RecordConfig) key {
|
func keyForRec(r *models.RecordConfig) key {
|
||||||
return key{Type: r.Type, Name: r.NameFQDN + "."}
|
return key{Type: r.Type, Name: r.GetLabelFQDN() + "."}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (g *gcloud) GetDomainCorrections(dc *models.DomainConfig) ([]*models.Correction, error) {
|
func (g *gcloud) GetDomainCorrections(dc *models.DomainConfig) ([]*models.Correction, error) {
|
||||||
|
@ -136,10 +136,10 @@ func (api *LinodeApi) GetDomainCorrections(dc *models.DomainConfig) ([]*models.C
|
|||||||
// https://github.com/linode/manager/blob/edd99dc4e1be5ab8190f243c3dbf8b830716255e/src/constants.js#L184
|
// https://github.com/linode/manager/blob/edd99dc4e1be5ab8190f243c3dbf8b830716255e/src/constants.js#L184
|
||||||
for _, name := range defaultNameServerNames {
|
for _, name := range defaultNameServerNames {
|
||||||
rc := &models.RecordConfig{
|
rc := &models.RecordConfig{
|
||||||
NameFQDN: dc.Name,
|
|
||||||
Type: "NS",
|
Type: "NS",
|
||||||
Original: &domainRecord{},
|
Original: &domainRecord{},
|
||||||
}
|
}
|
||||||
|
rc.SetLabelFromFQDN(dc.Name, dc.Name)
|
||||||
rc.SetTarget(name)
|
rc.SetTarget(name)
|
||||||
|
|
||||||
existingRecords = append(existingRecords, rc)
|
existingRecords = append(existingRecords, rc)
|
||||||
@ -249,7 +249,7 @@ func toRc(dc *models.DomainConfig, r *domainRecord) *models.RecordConfig {
|
|||||||
func toReq(dc *models.DomainConfig, rc *models.RecordConfig) (*recordEditRequest, error) {
|
func toReq(dc *models.DomainConfig, rc *models.RecordConfig) (*recordEditRequest, error) {
|
||||||
req := &recordEditRequest{
|
req := &recordEditRequest{
|
||||||
Type: rc.Type,
|
Type: rc.Type,
|
||||||
Name: dnsutil.TrimDomainName(rc.NameFQDN, dc.Name),
|
Name: rc.GetLabel(),
|
||||||
Target: rc.GetTargetField(),
|
Target: rc.GetTargetField(),
|
||||||
TTL: int(rc.TTL),
|
TTL: int(rc.TTL),
|
||||||
Priority: 0,
|
Priority: 0,
|
||||||
|
@ -14,7 +14,6 @@ import (
|
|||||||
"github.com/StackExchange/dnscontrol/providers"
|
"github.com/StackExchange/dnscontrol/providers"
|
||||||
"github.com/StackExchange/dnscontrol/providers/diff"
|
"github.com/StackExchange/dnscontrol/providers/diff"
|
||||||
nc "github.com/billputer/go-namecheap"
|
nc "github.com/billputer/go-namecheap"
|
||||||
"github.com/miekg/dns/dnsutil"
|
|
||||||
"github.com/pkg/errors"
|
"github.com/pkg/errors"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -125,9 +124,9 @@ func (n *Namecheap) GetDomainCorrections(dc *models.DomainConfig) ([]*models.Cor
|
|||||||
|
|
||||||
// namecheap does not allow setting @ NS with basic DNS
|
// namecheap does not allow setting @ NS with basic DNS
|
||||||
dc.Filter(func(r *models.RecordConfig) bool {
|
dc.Filter(func(r *models.RecordConfig) bool {
|
||||||
if r.Type == "NS" && r.Name == "@" {
|
if r.Type == "NS" && r.GetLabel() == "@" {
|
||||||
if !strings.HasSuffix(r.Target, "registrar-servers.com.") {
|
if !strings.HasSuffix(r.GetTargetField(), "registrar-servers.com.") {
|
||||||
fmt.Println("\n", r.Target, "Namecheap does not support changing apex NS records. Skipping.")
|
fmt.Println("\n", r.GetTargetField(), "Namecheap does not support changing apex NS records. Skipping.")
|
||||||
}
|
}
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
@ -150,13 +149,13 @@ func (n *Namecheap) GetDomainCorrections(dc *models.DomainConfig) ([]*models.Cor
|
|||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
rec := &models.RecordConfig{
|
rec := &models.RecordConfig{
|
||||||
NameFQDN: dnsutil.AddOrigin(r.Name, dc.Name),
|
|
||||||
Type: r.Type,
|
Type: r.Type,
|
||||||
Target: r.Address,
|
|
||||||
TTL: uint32(r.TTL),
|
TTL: uint32(r.TTL),
|
||||||
MxPreference: uint16(r.MXPref),
|
MxPreference: uint16(r.MXPref),
|
||||||
Original: r,
|
Original: r,
|
||||||
}
|
}
|
||||||
|
rec.SetLabel(r.Name, dc.Name)
|
||||||
|
rec.SetTarget(r.Address)
|
||||||
actual = append(actual, rec)
|
actual = append(actual, rec)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -204,12 +203,11 @@ func (n *Namecheap) generateRecords(dc *models.DomainConfig) error {
|
|||||||
|
|
||||||
id := 1
|
id := 1
|
||||||
for _, r := range dc.Records {
|
for _, r := range dc.Records {
|
||||||
name := dnsutil.TrimDomainName(r.NameFQDN, dc.Name)
|
|
||||||
rec := nc.DomainDNSHost{
|
rec := nc.DomainDNSHost{
|
||||||
ID: id,
|
ID: id,
|
||||||
Name: name,
|
Name: r.GetLabel(),
|
||||||
Type: r.Type,
|
Type: r.Type,
|
||||||
Address: r.Target,
|
Address: r.GetTargetField(),
|
||||||
MXPref: int(r.MxPreference),
|
MXPref: int(r.MxPreference),
|
||||||
TTL: int(r.TTL),
|
TTL: int(r.TTL),
|
||||||
}
|
}
|
||||||
|
@ -8,8 +8,6 @@ import (
|
|||||||
"github.com/namedotcom/go/namecom"
|
"github.com/namedotcom/go/namecom"
|
||||||
"github.com/pkg/errors"
|
"github.com/pkg/errors"
|
||||||
|
|
||||||
"github.com/miekg/dns/dnsutil"
|
|
||||||
|
|
||||||
"github.com/StackExchange/dnscontrol/models"
|
"github.com/StackExchange/dnscontrol/models"
|
||||||
"github.com/StackExchange/dnscontrol/providers/diff"
|
"github.com/StackExchange/dnscontrol/providers/diff"
|
||||||
)
|
)
|
||||||
@ -76,7 +74,7 @@ func (n *NameCom) GetDomainCorrections(dc *models.DomainConfig) ([]*models.Corre
|
|||||||
func checkNSModifications(dc *models.DomainConfig) {
|
func checkNSModifications(dc *models.DomainConfig) {
|
||||||
newList := make([]*models.RecordConfig, 0, len(dc.Records))
|
newList := make([]*models.RecordConfig, 0, len(dc.Records))
|
||||||
for _, rec := range dc.Records {
|
for _, rec := range dc.Records {
|
||||||
if rec.Type == "NS" && rec.NameFQDN == dc.Name {
|
if rec.Type == "NS" && rec.GetLabel() == "@" {
|
||||||
continue // Apex NS records are automatically created for the domain's nameservers and cannot be managed otherwise via the name.com API.
|
continue // Apex NS records are automatically created for the domain's nameservers and cannot be managed otherwise via the name.com API.
|
||||||
}
|
}
|
||||||
newList = append(newList, rec)
|
newList = append(newList, rec)
|
||||||
@ -147,9 +145,9 @@ func (n *NameCom) getRecords(domain string) ([]*namecom.Record, error) {
|
|||||||
func (n *NameCom) createRecord(rc *models.RecordConfig, domain string) error {
|
func (n *NameCom) createRecord(rc *models.RecordConfig, domain string) error {
|
||||||
record := &namecom.Record{
|
record := &namecom.Record{
|
||||||
DomainName: domain,
|
DomainName: domain,
|
||||||
Host: dnsutil.TrimDomainName(rc.NameFQDN, domain),
|
Host: rc.GetLabel(),
|
||||||
Type: rc.Type,
|
Type: rc.Type,
|
||||||
Answer: rc.Target,
|
Answer: rc.GetTargetField(),
|
||||||
TTL: rc.TTL,
|
TTL: rc.TTL,
|
||||||
Priority: uint32(rc.MxPreference),
|
Priority: uint32(rc.MxPreference),
|
||||||
}
|
}
|
||||||
@ -159,7 +157,7 @@ func (n *NameCom) createRecord(rc *models.RecordConfig, domain string) error {
|
|||||||
case "TXT":
|
case "TXT":
|
||||||
record.Answer = encodeTxt(rc.TxtStrings)
|
record.Answer = encodeTxt(rc.TxtStrings)
|
||||||
case "SRV":
|
case "SRV":
|
||||||
record.Answer = fmt.Sprintf("%d %d %v", rc.SrvWeight, rc.SrvPort, rc.Target)
|
record.Answer = fmt.Sprintf("%d %d %v", rc.SrvWeight, rc.SrvPort, rc.GetTargetField())
|
||||||
record.Priority = uint32(rc.SrvPriority)
|
record.Priority = uint32(rc.SrvPriority)
|
||||||
default:
|
default:
|
||||||
panic(fmt.Sprintf("createRecord rtype %v unimplemented", rc.Type))
|
panic(fmt.Sprintf("createRecord rtype %v unimplemented", rc.Type))
|
||||||
|
@ -178,7 +178,7 @@ func parseLeaf(results models.Records, k string, v interface{}, origin string) (
|
|||||||
case "port": // SRV
|
case "port": // SRV
|
||||||
newRc.SrvPort = uint16(v4.(int))
|
newRc.SrvPort = uint16(v4.(int))
|
||||||
case "value": // MX
|
case "value": // MX
|
||||||
newRc.Target = v4.(string)
|
newRc.SetTarget(v4.(string))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
//fmt.Printf("parseLeaf: append %v\n", newRc)
|
//fmt.Printf("parseLeaf: append %v\n", newRc)
|
||||||
|
@ -56,7 +56,9 @@ func TestYamlWrite(t *testing.T) {
|
|||||||
m.AddFunc("json", minjson.Minify)
|
m.AddFunc("json", minjson.Minify)
|
||||||
|
|
||||||
t.Run(f.Name(), func(t *testing.T) {
|
t.Run(f.Name(), func(t *testing.T) {
|
||||||
content, err := ioutil.ReadFile(filepath.Join(testDir, f.Name()))
|
fname := filepath.Join(testDir, f.Name())
|
||||||
|
fmt.Printf("Filename: %v\n", fname)
|
||||||
|
content, err := ioutil.ReadFile(fname)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
|
@ -48,14 +48,14 @@ func (z *genYamlData) Less(i, j int) bool {
|
|||||||
case "NS", "TXT", "TLSA":
|
case "NS", "TXT", "TLSA":
|
||||||
// pass through.
|
// pass through.
|
||||||
case "A":
|
case "A":
|
||||||
ta2, tb2 := net.ParseIP(a.Target), net.ParseIP(b.Target)
|
ta2, tb2 := net.ParseIP(a.GetTargetField()), net.ParseIP(b.GetTargetField())
|
||||||
ipa, ipb := ta2.To4(), tb2.To4()
|
ipa, ipb := ta2.To4(), tb2.To4()
|
||||||
if ipa == nil || ipb == nil {
|
if ipa == nil || ipb == nil {
|
||||||
log.Fatalf("should not happen: IPs are not 4 bytes: %#v %#v", ta2, tb2)
|
log.Fatalf("should not happen: IPs are not 4 bytes: %#v %#v", ta2, tb2)
|
||||||
}
|
}
|
||||||
return bytes.Compare(ipa, ipb) == -1
|
return bytes.Compare(ipa, ipb) == -1
|
||||||
case "AAAA":
|
case "AAAA":
|
||||||
ta2, tb2 := net.ParseIP(a.Target), net.ParseIP(b.Target)
|
ta2, tb2 := net.ParseIP(a.GetTargetField()), net.ParseIP(b.GetTargetField())
|
||||||
ipa, ipb := ta2.To16(), tb2.To16()
|
ipa, ipb := ta2.To16(), tb2.To16()
|
||||||
return bytes.Compare(ipa, ipb) == -1
|
return bytes.Compare(ipa, ipb) == -1
|
||||||
case "MX":
|
case "MX":
|
||||||
@ -75,7 +75,7 @@ func (z *genYamlData) Less(i, j int) bool {
|
|||||||
return pa < pb
|
return pa < pb
|
||||||
}
|
}
|
||||||
case "PTR":
|
case "PTR":
|
||||||
pa, pb := a.Target, b.Target
|
pa, pb := a.GetTargetField(), b.GetTargetField()
|
||||||
if pa != pb {
|
if pa != pb {
|
||||||
return pa < pb
|
return pa < pb
|
||||||
}
|
}
|
||||||
|
@ -28,8 +28,9 @@ func WriteYaml(w io.Writer, records models.Records, origin string) error {
|
|||||||
recsCopy = append(recsCopy, r)
|
recsCopy = append(recsCopy, r)
|
||||||
}
|
}
|
||||||
for _, r := range recsCopy {
|
for _, r := range recsCopy {
|
||||||
if r.Name == "@" {
|
if r.GetLabel() == "@" {
|
||||||
r.Name = ""
|
//r.Name = ""
|
||||||
|
r.UnsafeSetLabelNull()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -156,7 +157,7 @@ func sameType(records models.Records) bool {
|
|||||||
func oneLabel(records models.Records) yaml.MapItem {
|
func oneLabel(records models.Records) yaml.MapItem {
|
||||||
item := yaml.MapItem{
|
item := yaml.MapItem{
|
||||||
// a yaml.MapItem is a YAML map that retains the key order.
|
// a yaml.MapItem is a YAML map that retains the key order.
|
||||||
Key: records[0].Name,
|
Key: records[0].GetLabel(),
|
||||||
}
|
}
|
||||||
// Special case labels with a single record:
|
// Special case labels with a single record:
|
||||||
if len(records) == 1 {
|
if len(records) == 1 {
|
||||||
|
@ -112,7 +112,7 @@ func (c *ovhProvider) deleteRecordFunc(id int64, fqdn string) func() error {
|
|||||||
func (c *ovhProvider) createRecordFunc(rc *models.RecordConfig, fqdn string) func() error {
|
func (c *ovhProvider) createRecordFunc(rc *models.RecordConfig, fqdn string) func() error {
|
||||||
return func() error {
|
return func() error {
|
||||||
record := Record{
|
record := Record{
|
||||||
SubDomain: dnsutil.TrimDomainName(rc.NameFQDN, fqdn),
|
SubDomain: dnsutil.TrimDomainName(rc.GetLabelFQDN(), fqdn),
|
||||||
FieldType: rc.Type,
|
FieldType: rc.Type,
|
||||||
Target: rc.GetTargetCombined(),
|
Target: rc.GetTargetCombined(),
|
||||||
TTL: rc.TTL,
|
TTL: rc.TTL,
|
||||||
@ -130,7 +130,7 @@ func (c *ovhProvider) createRecordFunc(rc *models.RecordConfig, fqdn string) fun
|
|||||||
func (c *ovhProvider) updateRecordFunc(old *Record, rc *models.RecordConfig, fqdn string) func() error {
|
func (c *ovhProvider) updateRecordFunc(old *Record, rc *models.RecordConfig, fqdn string) func() error {
|
||||||
return func() error {
|
return func() error {
|
||||||
record := Record{
|
record := Record{
|
||||||
SubDomain: dnsutil.TrimDomainName(rc.NameFQDN, fqdn),
|
SubDomain: rc.GetLabel(),
|
||||||
FieldType: rc.Type,
|
FieldType: rc.Type,
|
||||||
Target: rc.GetTargetCombined(),
|
Target: rc.GetTargetCombined(),
|
||||||
TTL: rc.TTL,
|
TTL: rc.TTL,
|
||||||
|
@ -9,7 +9,6 @@ import (
|
|||||||
"github.com/StackExchange/dnscontrol/models"
|
"github.com/StackExchange/dnscontrol/models"
|
||||||
"github.com/StackExchange/dnscontrol/providers"
|
"github.com/StackExchange/dnscontrol/providers"
|
||||||
"github.com/StackExchange/dnscontrol/providers/diff"
|
"github.com/StackExchange/dnscontrol/providers/diff"
|
||||||
"github.com/miekg/dns/dnsutil"
|
|
||||||
"github.com/pkg/errors"
|
"github.com/pkg/errors"
|
||||||
|
|
||||||
"github.com/softlayer/softlayer-go/datatypes"
|
"github.com/softlayer/softlayer-go/datatypes"
|
||||||
@ -129,10 +128,10 @@ func (s *SoftLayer) getExistingRecords(domain *datatypes.Dns_Domain) ([]*models.
|
|||||||
|
|
||||||
recConfig := &models.RecordConfig{
|
recConfig := &models.RecordConfig{
|
||||||
Type: recType,
|
Type: recType,
|
||||||
Target: *record.Data,
|
|
||||||
TTL: uint32(*record.Ttl),
|
TTL: uint32(*record.Ttl),
|
||||||
Original: record,
|
Original: record,
|
||||||
}
|
}
|
||||||
|
recConfig.SetTarget(*record.Data)
|
||||||
|
|
||||||
switch recType {
|
switch recType {
|
||||||
case "SRV":
|
case "SRV":
|
||||||
@ -153,21 +152,16 @@ func (s *SoftLayer) getExistingRecords(domain *datatypes.Dns_Domain) ([]*models.
|
|||||||
if record.Service != nil {
|
if record.Service != nil {
|
||||||
service = *record.Service
|
service = *record.Service
|
||||||
}
|
}
|
||||||
|
recConfig.SetLabel(fmt.Sprintf("%s.%s", service, strings.ToLower(protocol)), *domain.Name)
|
||||||
recConfig.Name = fmt.Sprintf("%s.%s", service, strings.ToLower(protocol))
|
|
||||||
|
|
||||||
case "MX":
|
case "MX":
|
||||||
if record.MxPriority != nil {
|
if record.MxPriority != nil {
|
||||||
recConfig.MxPreference = uint16(*record.MxPriority)
|
recConfig.MxPreference = uint16(*record.MxPriority)
|
||||||
}
|
}
|
||||||
|
|
||||||
fallthrough
|
fallthrough
|
||||||
|
|
||||||
default:
|
default:
|
||||||
recConfig.Name = *record.Host
|
recConfig.SetLabel(*record.Host, *domain.Name)
|
||||||
}
|
}
|
||||||
|
|
||||||
recConfig.NameFQDN = dnsutil.AddOrigin(recConfig.Name, *domain.Name)
|
|
||||||
actual = append(actual, recConfig)
|
actual = append(actual, recConfig)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -180,7 +174,7 @@ func (s *SoftLayer) getExistingRecords(domain *datatypes.Dns_Domain) ([]*models.
|
|||||||
func (s *SoftLayer) createRecordFunc(desired *models.RecordConfig, domain *datatypes.Dns_Domain) func() error {
|
func (s *SoftLayer) createRecordFunc(desired *models.RecordConfig, domain *datatypes.Dns_Domain) func() error {
|
||||||
var ttl, preference, domainID int = int(desired.TTL), int(desired.MxPreference), *domain.Id
|
var ttl, preference, domainID int = int(desired.TTL), int(desired.MxPreference), *domain.Id
|
||||||
var weight, priority, port int = int(desired.SrvWeight), int(desired.SrvPriority), int(desired.SrvPort)
|
var weight, priority, port int = int(desired.SrvWeight), int(desired.SrvPriority), int(desired.SrvPort)
|
||||||
var host, data, newType string = desired.Name, desired.Target, desired.Type
|
var host, data, newType string = desired.GetLabel(), desired.GetTargetField(), desired.Type
|
||||||
var err error
|
var err error
|
||||||
|
|
||||||
srvRegexp := regexp.MustCompile(`^_(?P<Service>\w+)\.\_(?P<Protocol>\w+)$`)
|
srvRegexp := regexp.MustCompile(`^_(?P<Service>\w+)\.\_(?P<Protocol>\w+)$`)
|
||||||
@ -260,13 +254,15 @@ func (s *SoftLayer) updateRecordFunc(existing *datatypes.Dns_Domain_ResourceReco
|
|||||||
service := services.GetDnsDomainResourceRecordMxTypeService(s.Session)
|
service := services.GetDnsDomainResourceRecordMxTypeService(s.Session)
|
||||||
updated := datatypes.Dns_Domain_ResourceRecord_MxType{}
|
updated := datatypes.Dns_Domain_ResourceRecord_MxType{}
|
||||||
|
|
||||||
if desired.Name != *existing.Host {
|
label := desired.GetLabel()
|
||||||
updated.Host = &desired.Name
|
if label != *existing.Host {
|
||||||
|
updated.Host = &label
|
||||||
changes = true
|
changes = true
|
||||||
}
|
}
|
||||||
|
|
||||||
if desired.Target != *existing.Data {
|
target := desired.GetTargetField()
|
||||||
updated.Data = &desired.Target
|
if target != *existing.Data {
|
||||||
|
updated.Data = &target
|
||||||
changes = true
|
changes = true
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -290,13 +286,15 @@ func (s *SoftLayer) updateRecordFunc(existing *datatypes.Dns_Domain_ResourceReco
|
|||||||
service := services.GetDnsDomainResourceRecordSrvTypeService(s.Session)
|
service := services.GetDnsDomainResourceRecordSrvTypeService(s.Session)
|
||||||
updated := datatypes.Dns_Domain_ResourceRecord_SrvType{}
|
updated := datatypes.Dns_Domain_ResourceRecord_SrvType{}
|
||||||
|
|
||||||
if desired.Name != *existing.Host {
|
label := desired.GetLabel()
|
||||||
updated.Host = &desired.Name
|
if label != *existing.Host {
|
||||||
|
updated.Host = &label
|
||||||
changes = true
|
changes = true
|
||||||
}
|
}
|
||||||
|
|
||||||
if desired.Target != *existing.Data {
|
target := desired.GetTargetField()
|
||||||
updated.Data = &desired.Target
|
if target != *existing.Data {
|
||||||
|
updated.Data = &target
|
||||||
changes = true
|
changes = true
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -333,13 +331,15 @@ func (s *SoftLayer) updateRecordFunc(existing *datatypes.Dns_Domain_ResourceReco
|
|||||||
service := services.GetDnsDomainResourceRecordService(s.Session)
|
service := services.GetDnsDomainResourceRecordService(s.Session)
|
||||||
updated := datatypes.Dns_Domain_ResourceRecord{}
|
updated := datatypes.Dns_Domain_ResourceRecord{}
|
||||||
|
|
||||||
if desired.Name != *existing.Host {
|
label := desired.GetLabel()
|
||||||
updated.Host = &desired.Name
|
if label != *existing.Host {
|
||||||
|
updated.Host = &label
|
||||||
changes = true
|
changes = true
|
||||||
}
|
}
|
||||||
|
|
||||||
if desired.Target != *existing.Data {
|
target := desired.GetTargetField()
|
||||||
updated.Data = &desired.Target
|
if target != *existing.Data {
|
||||||
|
updated.Data = &target
|
||||||
changes = true
|
changes = true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -234,7 +234,7 @@ func toRecordConfig(dc *models.DomainConfig, r *vultr.DNSRecord) (*models.Record
|
|||||||
|
|
||||||
// toVultrRecord converts a RecordConfig converted by toRecordConfig back to a Vultr DNSRecord #rtype_variations
|
// toVultrRecord converts a RecordConfig converted by toRecordConfig back to a Vultr DNSRecord #rtype_variations
|
||||||
func toVultrRecord(dc *models.DomainConfig, rc *models.RecordConfig) *vultr.DNSRecord {
|
func toVultrRecord(dc *models.DomainConfig, rc *models.RecordConfig) *vultr.DNSRecord {
|
||||||
name := dnsutil.TrimDomainName(rc.NameFQDN, dc.Name)
|
name := rc.GetLabel()
|
||||||
// Vultr uses a blank string to represent the apex domain
|
// Vultr uses a blank string to represent the apex domain
|
||||||
if name == "@" {
|
if name == "@" {
|
||||||
name = ""
|
name = ""
|
||||||
@ -267,17 +267,16 @@ func toVultrRecord(dc *models.DomainConfig, rc *models.RecordConfig) *vultr.DNSR
|
|||||||
TTL: int(rc.TTL),
|
TTL: int(rc.TTL),
|
||||||
Priority: priority,
|
Priority: priority,
|
||||||
}
|
}
|
||||||
|
switch rtype := rc.Type; rtype { // #rtype_variations
|
||||||
if rc.Type == "SRV" {
|
case "SRV":
|
||||||
target := rc.Target
|
target := rc.GetTargetField()
|
||||||
if strings.HasSuffix(target, ".") {
|
if strings.HasSuffix(target, ".") {
|
||||||
target = target[:len(target)-1]
|
target = target[:len(target)-1]
|
||||||
}
|
}
|
||||||
r.Data = fmt.Sprintf("%v %v %s", rc.SrvWeight, rc.SrvPort, target)
|
r.Data = fmt.Sprintf("%v %v %s", rc.SrvWeight, rc.SrvPort, target)
|
||||||
}
|
case "CAA":
|
||||||
|
|
||||||
if rc.Type == "CAA" {
|
|
||||||
r.Data = fmt.Sprintf(`%v %s "%s"`, rc.CaaFlag, rc.CaaTag, rc.GetTargetField())
|
r.Data = fmt.Sprintf(`%v %s "%s"`, rc.CaaFlag, rc.CaaTag, rc.GetTargetField())
|
||||||
|
default:
|
||||||
}
|
}
|
||||||
|
|
||||||
return r
|
return r
|
||||||
|
Reference in New Issue
Block a user