github.com/philhug/dnscontrol@v0.2.4-0.20180625181521-921fa9849001/models/domain.go (about) 1 package models 2 3 import ( 4 "fmt" 5 6 "golang.org/x/net/idna" 7 ) 8 9 // DomainConfig describes a DNS domain (tecnically a DNS zone). 10 type DomainConfig struct { 11 Name string `json:"name"` // NO trailing "." 12 RegistrarName string `json:"registrar"` 13 DNSProviderNames map[string]int `json:"dnsProviders"` 14 15 Metadata map[string]string `json:"meta,omitempty"` 16 Records Records `json:"records"` 17 Nameservers []*Nameserver `json:"nameservers,omitempty"` 18 KeepUnknown bool `json:"keepunknown,omitempty"` 19 IgnoredLabels []string `json:"ignored_labels,omitempty"` 20 21 // These fields contain instantiated provider instances once everything is linked up. 22 // This linking is in two phases: 23 // 1. Metadata (name/type) is availible just from the dnsconfig. Validation can use that. 24 // 2. Final driver instances are loaded after we load credentials. Any actual provider interaction requires that. 25 RegistrarInstance *RegistrarInstance `json:"-"` 26 DNSProviderInstances []*DNSProviderInstance `json:"-"` 27 } 28 29 // Copy returns a deep copy of the DomainConfig. 30 func (dc *DomainConfig) Copy() (*DomainConfig, error) { 31 newDc := &DomainConfig{} 32 // provider instances are interfaces that gob hates if you don't register them. 33 // and the specific types are not gob encodable since nothing is exported. 34 // should find a better solution for this now. 35 // 36 // current strategy: remove everything, gob copy it. Then set both to stored copy. 37 reg := dc.RegistrarInstance 38 dnsps := dc.DNSProviderInstances 39 dc.RegistrarInstance = nil 40 dc.DNSProviderInstances = nil 41 err := copyObj(dc, newDc) 42 dc.RegistrarInstance = reg 43 newDc.RegistrarInstance = reg 44 dc.DNSProviderInstances = dnsps 45 newDc.DNSProviderInstances = dnsps 46 return newDc, err 47 } 48 49 // HasRecordTypeName returns True if there is a record with this rtype and name. 50 func (dc *DomainConfig) HasRecordTypeName(rtype, name string) bool { 51 for _, r := range dc.Records { 52 if r.Type == rtype && r.GetLabel() == name { 53 return true 54 } 55 } 56 return false 57 } 58 59 // Filter removes all records that don't match the filter f. 60 func (dc *DomainConfig) Filter(f func(r *RecordConfig) bool) { 61 recs := []*RecordConfig{} 62 for _, r := range dc.Records { 63 if f(r) { 64 recs = append(recs, r) 65 } 66 } 67 dc.Records = recs 68 } 69 70 // Punycode will convert all records to punycode format. 71 // It will encode: 72 // - Name 73 // - NameFQDN 74 // - Target (CNAME and MX only) 75 func (dc *DomainConfig) Punycode() error { 76 for _, rec := range dc.Records { 77 t, err := idna.ToASCII(rec.GetLabelFQDN()) 78 if err != nil { 79 return err 80 } 81 rec.SetLabelFromFQDN(t, dc.Name) 82 switch rec.Type { // #rtype_variations 83 case "ALIAS", "MX", "NS", "CNAME", "PTR", "SRV", "URL", "URL301", "FRAME", "R53_ALIAS": 84 // These rtypes are hostnames, therefore need to be converted (unlike, for example, an AAAA record) 85 t, err := idna.ToASCII(rec.GetTargetField()) 86 rec.SetTarget(t) 87 if err != nil { 88 return err 89 } 90 case "A", "AAAA", "CAA", "TXT", "TLSA": 91 // Nothing to do. 92 default: 93 msg := fmt.Sprintf("Punycode rtype %v unimplemented", rec.Type) 94 panic(msg) 95 // We panic so that we quickly find any switch statements 96 // that have not been updated for a new RR type. 97 } 98 } 99 return nil 100 }