traefik/vendor/github.com/akamai/AkamaiOPEN-edgegrid-golang/configdns-v1/zone.go
Ludovic Fernandez 2b2cfdfb32 Updates of Lego.
2019-02-13 17:26:04 +01:00

1567 lines
39 KiB
Go

package dns
import (
"errors"
"fmt"
"reflect"
"strings"
"sync"
"time"
"github.com/akamai/AkamaiOPEN-edgegrid-golang/client-v1"
)
type name struct {
recordType string
name string
}
var (
cnameNames []name
nonCnameNames []name
zoneWriteLock sync.Mutex
)
// Zone represents a DNS zone
type Zone struct {
Token string `json:"token"`
Zone struct {
Name string `json:"name,omitempty"`
A []*ARecord `json:"a,omitempty"`
Aaaa []*AaaaRecord `json:"aaaa,omitempty"`
Afsdb []*AfsdbRecord `json:"afsdb,omitempty"`
Cname []*CnameRecord `json:"cname,omitempty"`
Dnskey []*DnskeyRecord `json:"dnskey,omitempty"`
Ds []*DsRecord `json:"ds,omitempty"`
Hinfo []*HinfoRecord `json:"hinfo,omitempty"`
Loc []*LocRecord `json:"loc,omitempty"`
Mx []*MxRecord `json:"mx,omitempty"`
Naptr []*NaptrRecord `json:"naptr,omitempty"`
Ns []*NsRecord `json:"ns,omitempty"`
Nsec3 []*Nsec3Record `json:"nsec3,omitempty"`
Nsec3param []*Nsec3paramRecord `json:"nsec3param,omitempty"`
Ptr []*PtrRecord `json:"ptr,omitempty"`
Rp []*RpRecord `json:"rp,omitempty"`
Rrsig []*RrsigRecord `json:"rrsig,omitempty"`
Soa *SoaRecord `json:"soa,omitempty"`
Spf []*SpfRecord `json:"spf,omitempty"`
Srv []*SrvRecord `json:"srv,omitempty"`
Sshfp []*SshfpRecord `json:"sshfp,omitempty"`
Txt []*TxtRecord `json:"txt,omitempty"`
} `json:"zone"`
}
// NewZone creates a new Zone
func NewZone(hostname string) *Zone {
zone := &Zone{Token: "new"}
zone.Zone.Soa = NewSoaRecord()
zone.Zone.Name = hostname
return zone
}
// GetZone retrieves a DNS Zone for a given hostname
func GetZone(hostname string) (*Zone, error) {
zone := NewZone(hostname)
req, err := client.NewRequest(
Config,
"GET",
"/config-dns/v1/zones/"+hostname,
nil,
)
if err != nil {
return nil, err
}
res, err := client.Do(Config, req)
if err != nil {
return nil, err
}
if client.IsError(res) && res.StatusCode != 404 {
return nil, client.NewAPIError(res)
} else if res.StatusCode == 404 {
return nil, &ZoneError{zoneName: hostname}
} else {
err = client.BodyJSON(res, zone)
if err != nil {
return nil, err
}
return zone, nil
}
}
// Save updates the Zone
func (zone *Zone) Save() error {
// This lock will restrict the concurrency of API calls
// to 1 save request at a time. This is needed for the Soa.Serial value which
// is required to be incremented for every subsequent update to a zone
// so we have to save just one request at a time to ensure this is always
// incremented properly
zoneWriteLock.Lock()
defer zoneWriteLock.Unlock()
valid, f := zone.validateCnames()
if valid == false {
var msg string
for _, v := range f {
msg = msg + fmt.Sprintf("\n%s Record '%s' conflicts with CNAME", v.recordType, v.name)
}
return &ZoneError{
zoneName: zone.Zone.Name,
apiErrorMessage: "All CNAMEs must be unique in the zone" + msg,
}
}
req, err := client.NewJSONRequest(
Config,
"POST",
"/config-dns/v1/zones/"+zone.Zone.Name,
zone,
)
if err != nil {
return err
}
res, err := client.Do(Config, req)
// Network error
if err != nil {
return &ZoneError{
zoneName: zone.Zone.Name,
httpErrorMessage: err.Error(),
err: err,
}
}
// API error
if client.IsError(res) {
err := client.NewAPIError(res)
return &ZoneError{zoneName: zone.Zone.Name, apiErrorMessage: err.Detail, err: err}
}
for {
updatedZone, err := GetZone(zone.Zone.Name)
if err != nil {
return err
}
if updatedZone.Token != zone.Token {
*zone = *updatedZone
break
}
time.Sleep(time.Second)
}
return nil
}
func (zone *Zone) Delete() error {
// remove all the records except for SOA
// which is required and save the zone
zone.Zone.A = nil
zone.Zone.Aaaa = nil
zone.Zone.Afsdb = nil
zone.Zone.Cname = nil
zone.Zone.Dnskey = nil
zone.Zone.Ds = nil
zone.Zone.Hinfo = nil
zone.Zone.Loc = nil
zone.Zone.Mx = nil
zone.Zone.Naptr = nil
zone.Zone.Ns = nil
zone.Zone.Nsec3 = nil
zone.Zone.Nsec3param = nil
zone.Zone.Ptr = nil
zone.Zone.Rp = nil
zone.Zone.Rrsig = nil
zone.Zone.Spf = nil
zone.Zone.Srv = nil
zone.Zone.Sshfp = nil
zone.Zone.Txt = nil
return zone.Save()
}
func (zone *Zone) AddRecord(recordPtr interface{}) error {
switch recordPtr.(type) {
case *ARecord:
zone.addARecord(recordPtr.(*ARecord))
case *AaaaRecord:
zone.addAaaaRecord(recordPtr.(*AaaaRecord))
case *AfsdbRecord:
zone.addAfsdbRecord(recordPtr.(*AfsdbRecord))
case *CnameRecord:
zone.addCnameRecord(recordPtr.(*CnameRecord))
case *DnskeyRecord:
zone.addDnskeyRecord(recordPtr.(*DnskeyRecord))
case *DsRecord:
zone.addDsRecord(recordPtr.(*DsRecord))
case *HinfoRecord:
zone.addHinfoRecord(recordPtr.(*HinfoRecord))
case *LocRecord:
zone.addLocRecord(recordPtr.(*LocRecord))
case *MxRecord:
zone.addMxRecord(recordPtr.(*MxRecord))
case *NaptrRecord:
zone.addNaptrRecord(recordPtr.(*NaptrRecord))
case *NsRecord:
zone.addNsRecord(recordPtr.(*NsRecord))
case *Nsec3Record:
zone.addNsec3Record(recordPtr.(*Nsec3Record))
case *Nsec3paramRecord:
zone.addNsec3paramRecord(recordPtr.(*Nsec3paramRecord))
case *PtrRecord:
zone.addPtrRecord(recordPtr.(*PtrRecord))
case *RpRecord:
zone.addRpRecord(recordPtr.(*RpRecord))
case *RrsigRecord:
zone.addRrsigRecord(recordPtr.(*RrsigRecord))
case *SoaRecord:
zone.addSoaRecord(recordPtr.(*SoaRecord))
case *SpfRecord:
zone.addSpfRecord(recordPtr.(*SpfRecord))
case *SrvRecord:
zone.addSrvRecord(recordPtr.(*SrvRecord))
case *SshfpRecord:
zone.addSshfpRecord(recordPtr.(*SshfpRecord))
case *TxtRecord:
zone.addTxtRecord(recordPtr.(*TxtRecord))
}
return nil
}
func (zone *Zone) RemoveRecord(recordPtr interface{}) error {
switch recordPtr.(type) {
case *ARecord:
return zone.removeARecord(recordPtr.(*ARecord))
case *AaaaRecord:
return zone.removeAaaaRecord(recordPtr.(*AaaaRecord))
case *AfsdbRecord:
return zone.removeAfsdbRecord(recordPtr.(*AfsdbRecord))
case *CnameRecord:
return zone.removeCnameRecord(recordPtr.(*CnameRecord))
case *DnskeyRecord:
return zone.removeDnskeyRecord(recordPtr.(*DnskeyRecord))
case *DsRecord:
return zone.removeDsRecord(recordPtr.(*DsRecord))
case *HinfoRecord:
return zone.removeHinfoRecord(recordPtr.(*HinfoRecord))
case *LocRecord:
return zone.removeLocRecord(recordPtr.(*LocRecord))
case *MxRecord:
return zone.removeMxRecord(recordPtr.(*MxRecord))
case *NaptrRecord:
return zone.removeNaptrRecord(recordPtr.(*NaptrRecord))
case *NsRecord:
return zone.removeNsRecord(recordPtr.(*NsRecord))
case *Nsec3Record:
return zone.removeNsec3Record(recordPtr.(*Nsec3Record))
case *Nsec3paramRecord:
return zone.removeNsec3paramRecord(recordPtr.(*Nsec3paramRecord))
case *PtrRecord:
return zone.removePtrRecord(recordPtr.(*PtrRecord))
case *RpRecord:
return zone.removeRpRecord(recordPtr.(*RpRecord))
case *RrsigRecord:
return zone.removeRrsigRecord(recordPtr.(*RrsigRecord))
case *SoaRecord:
return zone.removeSoaRecord(recordPtr.(*SoaRecord))
case *SpfRecord:
return zone.removeSpfRecord(recordPtr.(*SpfRecord))
case *SrvRecord:
return zone.removeSrvRecord(recordPtr.(*SrvRecord))
case *SshfpRecord:
return zone.removeSshfpRecord(recordPtr.(*SshfpRecord))
case *TxtRecord:
return zone.removeTxtRecord(recordPtr.(*TxtRecord))
}
return nil
}
func (zone *Zone) addARecord(record *ARecord) {
zone.Zone.A = append(zone.Zone.A, record)
nonCnameNames = append(nonCnameNames, name{recordType: "A", name: record.Name})
}
func (zone *Zone) addAaaaRecord(record *AaaaRecord) {
zone.Zone.Aaaa = append(zone.Zone.Aaaa, record)
nonCnameNames = append(nonCnameNames, name{recordType: "AAAA", name: record.Name})
}
func (zone *Zone) addAfsdbRecord(record *AfsdbRecord) {
zone.Zone.Afsdb = append(zone.Zone.Afsdb, record)
nonCnameNames = append(nonCnameNames, name{recordType: "AFSDB", name: record.Name})
}
func (zone *Zone) addCnameRecord(record *CnameRecord) {
zone.Zone.Cname = append(zone.Zone.Cname, record)
cnameNames = append(cnameNames, name{recordType: "CNAME", name: record.Name})
}
func (zone *Zone) addDnskeyRecord(record *DnskeyRecord) {
zone.Zone.Dnskey = append(zone.Zone.Dnskey, record)
nonCnameNames = append(nonCnameNames, name{recordType: "DNSKEY", name: record.Name})
}
func (zone *Zone) addDsRecord(record *DsRecord) {
zone.Zone.Ds = append(zone.Zone.Ds, record)
nonCnameNames = append(nonCnameNames, name{recordType: "DS", name: record.Name})
}
func (zone *Zone) addHinfoRecord(record *HinfoRecord) {
zone.Zone.Hinfo = append(zone.Zone.Hinfo, record)
nonCnameNames = append(nonCnameNames, name{recordType: "HINFO", name: record.Name})
}
func (zone *Zone) addLocRecord(record *LocRecord) {
zone.Zone.Loc = append(zone.Zone.Loc, record)
nonCnameNames = append(nonCnameNames, name{recordType: "LOC", name: record.Name})
}
func (zone *Zone) addMxRecord(record *MxRecord) {
zone.Zone.Mx = append(zone.Zone.Mx, record)
nonCnameNames = append(nonCnameNames, name{recordType: "MX", name: record.Name})
}
func (zone *Zone) addNaptrRecord(record *NaptrRecord) {
zone.Zone.Naptr = append(zone.Zone.Naptr, record)
nonCnameNames = append(nonCnameNames, name{recordType: "NAPTR", name: record.Name})
}
func (zone *Zone) addNsRecord(record *NsRecord) {
zone.Zone.Ns = append(zone.Zone.Ns, record)
nonCnameNames = append(nonCnameNames, name{recordType: "NS", name: record.Name})
}
func (zone *Zone) addNsec3Record(record *Nsec3Record) {
zone.Zone.Nsec3 = append(zone.Zone.Nsec3, record)
nonCnameNames = append(nonCnameNames, name{recordType: "NSEC3", name: record.Name})
}
func (zone *Zone) addNsec3paramRecord(record *Nsec3paramRecord) {
zone.Zone.Nsec3param = append(zone.Zone.Nsec3param, record)
nonCnameNames = append(nonCnameNames, name{recordType: "NSEC3PARAM", name: record.Name})
}
func (zone *Zone) addPtrRecord(record *PtrRecord) {
zone.Zone.Ptr = append(zone.Zone.Ptr, record)
nonCnameNames = append(nonCnameNames, name{recordType: "PTR", name: record.Name})
}
func (zone *Zone) addRpRecord(record *RpRecord) {
zone.Zone.Rp = append(zone.Zone.Rp, record)
nonCnameNames = append(nonCnameNames, name{recordType: "RP", name: record.Name})
}
func (zone *Zone) addRrsigRecord(record *RrsigRecord) {
zone.Zone.Rrsig = append(zone.Zone.Rrsig, record)
nonCnameNames = append(nonCnameNames, name{recordType: "RRSIG", name: record.Name})
}
func (zone *Zone) addSoaRecord(record *SoaRecord) {
// Only one SOA records is allowed
zone.Zone.Soa = record
}
func (zone *Zone) addSpfRecord(record *SpfRecord) {
zone.Zone.Spf = append(zone.Zone.Spf, record)
nonCnameNames = append(nonCnameNames, name{recordType: "SPF", name: record.Name})
}
func (zone *Zone) addSrvRecord(record *SrvRecord) {
zone.Zone.Srv = append(zone.Zone.Srv, record)
nonCnameNames = append(nonCnameNames, name{recordType: "SRV", name: record.Name})
}
func (zone *Zone) addSshfpRecord(record *SshfpRecord) {
zone.Zone.Sshfp = append(zone.Zone.Sshfp, record)
nonCnameNames = append(nonCnameNames, name{recordType: "SSHFP", name: record.Name})
}
func (zone *Zone) addTxtRecord(record *TxtRecord) {
zone.Zone.Txt = append(zone.Zone.Txt, record)
nonCnameNames = append(nonCnameNames, name{recordType: "TXT", name: record.Name})
}
func (zone *Zone) removeARecord(record *ARecord) error {
for key, r := range zone.Zone.A {
if reflect.DeepEqual(r, record) {
records := zone.Zone.A[:key]
if len(zone.Zone.A) > key {
if len(zone.Zone.A) > key {
zone.Zone.A = append(records, zone.Zone.A[key+1:]...)
} else {
zone.Zone.A = records
}
}
zone.removeNonCnameName(record.Name)
return nil
}
}
return errors.New("A Record not found")
}
func (zone *Zone) removeAaaaRecord(record *AaaaRecord) error {
for key, r := range zone.Zone.Aaaa {
if reflect.DeepEqual(r, record) {
records := zone.Zone.Aaaa[:key]
if len(zone.Zone.Aaaa) > key {
zone.Zone.Aaaa = append(records, zone.Zone.Aaaa[key+1:]...)
} else {
zone.Zone.Aaaa = records
}
zone.removeNonCnameName(record.Name)
return nil
}
}
return errors.New("AAAA Record not found")
}
func (zone *Zone) removeAfsdbRecord(record *AfsdbRecord) error {
for key, r := range zone.Zone.Afsdb {
if reflect.DeepEqual(r, record) {
records := zone.Zone.Afsdb[:key]
if len(zone.Zone.Afsdb) > key {
zone.Zone.Afsdb = append(records, zone.Zone.Afsdb[key+1:]...)
} else {
zone.Zone.Afsdb = records
}
zone.removeNonCnameName(record.Name)
return nil
}
}
return errors.New("Afsdb Record not found")
}
func (zone *Zone) removeCnameRecord(record *CnameRecord) error {
for key, r := range zone.Zone.Cname {
if reflect.DeepEqual(r, record) {
records := zone.Zone.Cname[:key]
if len(zone.Zone.Cname) > key {
zone.Zone.Cname = append(records, zone.Zone.Cname[key+1:]...)
} else {
zone.Zone.Cname = records
}
zone.removeNonCnameName(record.Name)
return nil
}
}
return errors.New("Cname Record not found")
zone.removeCnameName(record.Name)
return nil
}
func (zone *Zone) removeDnskeyRecord(record *DnskeyRecord) error {
for key, r := range zone.Zone.Dnskey {
if reflect.DeepEqual(r, record) {
records := zone.Zone.Dnskey[:key]
if len(zone.Zone.Dnskey) > key {
zone.Zone.Dnskey = append(records, zone.Zone.Dnskey[key+1:]...)
} else {
zone.Zone.Dnskey = records
}
zone.removeNonCnameName(record.Name)
return nil
}
}
return errors.New("Dnskey Record not found")
}
func (zone *Zone) removeDsRecord(record *DsRecord) error {
for key, r := range zone.Zone.Ds {
if reflect.DeepEqual(r, record) {
records := zone.Zone.Ds[:key]
if len(zone.Zone.Ds) > key {
zone.Zone.Ds = append(records, zone.Zone.Ds[key+1:]...)
} else {
zone.Zone.Ds = records
}
zone.removeNonCnameName(record.Name)
return nil
}
}
return errors.New("Ds Record not found")
}
func (zone *Zone) removeHinfoRecord(record *HinfoRecord) error {
for key, r := range zone.Zone.Hinfo {
if reflect.DeepEqual(r, record) {
records := zone.Zone.Hinfo[:key]
if len(zone.Zone.Hinfo) > key {
zone.Zone.Hinfo = append(records, zone.Zone.Hinfo[key+1:]...)
} else {
zone.Zone.Hinfo = records
}
zone.removeNonCnameName(record.Name)
return nil
}
}
return errors.New("Hinfo Record not found")
}
func (zone *Zone) removeLocRecord(record *LocRecord) error {
for key, r := range zone.Zone.Loc {
if reflect.DeepEqual(r, record) {
records := zone.Zone.Loc[:key]
if len(zone.Zone.Loc) > key {
zone.Zone.Loc = append(records, zone.Zone.Loc[key+1:]...)
} else {
zone.Zone.Loc = records
}
zone.removeNonCnameName(record.Name)
return nil
}
}
return errors.New("Loc Record not found")
}
func (zone *Zone) removeMxRecord(record *MxRecord) error {
for key, r := range zone.Zone.Mx {
if reflect.DeepEqual(r, record) {
records := zone.Zone.Mx[:key]
if len(zone.Zone.Mx) > key {
zone.Zone.Mx = append(records, zone.Zone.Mx[key+1:]...)
} else {
zone.Zone.Mx = records
}
zone.removeNonCnameName(record.Name)
return nil
}
}
return errors.New("Mx Record not found")
}
func (zone *Zone) removeNaptrRecord(record *NaptrRecord) error {
for key, r := range zone.Zone.Naptr {
if reflect.DeepEqual(r, record) {
records := zone.Zone.Naptr[:key]
if len(zone.Zone.Naptr) > key {
zone.Zone.Naptr = append(records, zone.Zone.Naptr[key+1:]...)
} else {
zone.Zone.Naptr = records
}
zone.removeNonCnameName(record.Name)
return nil
}
}
return errors.New("Naptr Record not found")
}
func (zone *Zone) removeNsRecord(record *NsRecord) error {
for key, r := range zone.Zone.Ns {
if reflect.DeepEqual(r, record) {
records := zone.Zone.Ns[:key]
if len(zone.Zone.Ns) > key {
zone.Zone.Ns = append(records, zone.Zone.Ns[key+1:]...)
} else {
zone.Zone.Ns = records
}
zone.removeNonCnameName(record.Name)
return nil
}
}
return errors.New("Ns Record not found")
}
func (zone *Zone) removeNsec3Record(record *Nsec3Record) error {
for key, r := range zone.Zone.Nsec3 {
if reflect.DeepEqual(r, record) {
records := zone.Zone.Nsec3[:key]
if len(zone.Zone.Nsec3) > key {
zone.Zone.Nsec3 = append(records, zone.Zone.Nsec3[key+1:]...)
} else {
zone.Zone.Nsec3 = records
}
zone.removeNonCnameName(record.Name)
return nil
}
}
return errors.New("Nsec3 Record not found")
}
func (zone *Zone) removeNsec3paramRecord(record *Nsec3paramRecord) error {
for key, r := range zone.Zone.Nsec3param {
if reflect.DeepEqual(r, record) {
records := zone.Zone.Nsec3param[:key]
if len(zone.Zone.Nsec3param) > key {
zone.Zone.Nsec3param = append(records, zone.Zone.Nsec3param[key+1:]...)
} else {
zone.Zone.Nsec3param = records
}
zone.removeNonCnameName(record.Name)
return nil
}
}
return errors.New("Nsec3param Record not found")
}
func (zone *Zone) removePtrRecord(record *PtrRecord) error {
for key, r := range zone.Zone.Ptr {
if reflect.DeepEqual(r, record) {
records := zone.Zone.Ptr[:key]
if len(zone.Zone.Ptr) > key {
zone.Zone.Ptr = append(records, zone.Zone.Ptr[key+1:]...)
} else {
zone.Zone.Ptr = records
}
zone.removeNonCnameName(record.Name)
return nil
}
}
return errors.New("Ptr Record not found")
}
func (zone *Zone) removeRpRecord(record *RpRecord) error {
for key, r := range zone.Zone.Rp {
if reflect.DeepEqual(r, record) {
records := zone.Zone.Rp[:key]
if len(zone.Zone.Rp) > key {
zone.Zone.Rp = append(records, zone.Zone.Rp[key+1:]...)
} else {
zone.Zone.Rp = records
}
zone.removeNonCnameName(record.Name)
return nil
}
}
return errors.New("Rp Record not found")
}
func (zone *Zone) removeRrsigRecord(record *RrsigRecord) error {
for key, r := range zone.Zone.Rrsig {
if reflect.DeepEqual(r, record) {
records := zone.Zone.Rrsig[:key]
if len(zone.Zone.Rrsig) > key {
zone.Zone.Rrsig = append(records, zone.Zone.Rrsig[key+1:]...)
} else {
zone.Zone.Rrsig = records
}
zone.removeNonCnameName(record.Name)
return nil
}
}
return errors.New("Rrsig Record not found")
}
func (zone *Zone) removeSoaRecord(record *SoaRecord) error {
if reflect.DeepEqual(zone.Zone.Soa, record) {
zone.Zone.Soa = nil
return nil
}
return errors.New("SOA Record does not match")
}
func (zone *Zone) removeSpfRecord(record *SpfRecord) error {
for key, r := range zone.Zone.Spf {
if reflect.DeepEqual(r, record) {
records := zone.Zone.Spf[:key]
if len(zone.Zone.Spf) > key {
zone.Zone.Spf = append(records, zone.Zone.Spf[key+1:]...)
} else {
zone.Zone.Spf = records
}
zone.removeNonCnameName(record.Name)
return nil
}
}
return errors.New("Spf Record not found")
}
func (zone *Zone) removeSrvRecord(record *SrvRecord) error {
for key, r := range zone.Zone.Srv {
if reflect.DeepEqual(r, record) {
records := zone.Zone.Srv[:key]
if len(zone.Zone.Srv) > key {
zone.Zone.Srv = append(records, zone.Zone.Srv[key+1:]...)
} else {
zone.Zone.Srv = records
}
zone.removeNonCnameName(record.Name)
return nil
}
}
return errors.New("Srv Record not found")
}
func (zone *Zone) removeSshfpRecord(record *SshfpRecord) error {
for key, r := range zone.Zone.Sshfp {
if reflect.DeepEqual(r, record) {
records := zone.Zone.Sshfp[:key]
if len(zone.Zone.Sshfp) > key {
zone.Zone.Sshfp = append(records, zone.Zone.Sshfp[key+1:]...)
} else {
zone.Zone.Sshfp = records
}
zone.removeNonCnameName(record.Name)
return nil
}
}
return errors.New("Sshfp Record not found")
}
func (zone *Zone) removeTxtRecord(record *TxtRecord) error {
for key, r := range zone.Zone.Txt {
if reflect.DeepEqual(r, record) {
records := zone.Zone.Txt[:key]
if len(zone.Zone.Txt) > key {
zone.Zone.Txt = append(records, zone.Zone.Txt[key+1:]...)
} else {
zone.Zone.Txt = records
}
zone.removeNonCnameName(record.Name)
return nil
}
}
return errors.New("Txt Record not found")
}
func (zone *Zone) PostUnmarshalJSON() error {
if zone.Zone.Soa.Serial > 0 {
zone.Zone.Soa.originalSerial = zone.Zone.Soa.Serial
}
return nil
}
func (zone *Zone) PreMarshalJSON() error {
if zone.Zone.Soa.Serial == 0 {
zone.Zone.Soa.Serial = uint(time.Now().Unix())
} else if zone.Zone.Soa.Serial == zone.Zone.Soa.originalSerial {
zone.Zone.Soa.Serial = zone.Zone.Soa.Serial + 1
}
return nil
}
func (zone *Zone) validateCnames() (bool, []name) {
var valid bool = true
var failedRecords []name
for _, v := range cnameNames {
for _, vv := range nonCnameNames {
if v.name == vv.name {
valid = false
failedRecords = append(failedRecords, vv)
}
}
}
return valid, failedRecords
}
func (zone *Zone) removeCnameName(host string) {
var ncn []name
for _, v := range cnameNames {
if v.name != host {
ncn =append(ncn, v)
}
}
cnameNames = ncn
}
func (zone *Zone) removeNonCnameName(host string) {
var ncn []name
for _, v := range nonCnameNames {
if v.name != host {
ncn =append(ncn, v)
}
}
nonCnameNames = ncn
}
func (zone *Zone) FindRecords(recordType string, options map[string]interface{}) []DNSRecord {
switch strings.ToUpper(recordType) {
case "A":
return zone.findARecord(options)
case "AAAA":
return zone.findAaaaRecord(options)
case "AFSDB":
return zone.findAfsdbRecord(options)
case "CNAME":
return zone.findCnameRecord(options)
case "DNSKEY":
return zone.findDnskeyRecord(options)
case "DS":
return zone.findDsRecord(options)
case "HINFO":
return zone.findHinfoRecord(options)
case "LOC":
return zone.findLocRecord(options)
case "MX":
return zone.findMxRecord(options)
case "NAPTR":
return zone.findNaptrRecord(options)
case "NS":
return zone.findNsRecord(options)
case "NSEC3":
return zone.findNsec3Record(options)
case "NSEC3PARAM":
return zone.findNsec3paramRecord(options)
case "PTR":
return zone.findPtrRecord(options)
case "RP":
return zone.findRpRecord(options)
case "RRSIG":
return zone.findRrsigRecord(options)
case "SPF":
return zone.findSpfRecord(options)
case "SRV":
return zone.findSrvRecord(options)
case "SSHFP":
return zone.findSshfpRecord(options)
case "TXT":
return zone.findTxtRecord(options)
}
return make([]DNSRecord, 0)
}
func (zone *Zone) findARecord(options map[string]interface{}) []DNSRecord {
found := make([]DNSRecord, 0)
matchesNeeded := len(options)
for _, record := range zone.Zone.A {
matchCounter := 0
if name, ok := options["name"]; ok && record.Name == name.(string) {
matchCounter++
}
if target, ok := options["target"]; ok && record.Target == target.(string) {
matchCounter++
}
if active, ok := options["active"]; ok && record.Active == active.(bool) {
matchCounter++
}
if ttl, ok := options["ttl"]; ok && record.TTL == ttl.(int) {
matchCounter++
}
if matchCounter >= matchesNeeded {
found = append(found, record)
}
}
return found
}
func (zone *Zone) findAaaaRecord(options map[string]interface{}) []DNSRecord {
found := make([]DNSRecord, 0)
matchesNeeded := len(options)
for _, record := range zone.Zone.Aaaa {
matchCounter := 0
if name, ok := options["name"]; ok && record.Name == name.(string) {
matchCounter++
}
if target, ok := options["target"]; ok && record.Target == target.(string) {
matchCounter++
}
if active, ok := options["active"]; ok && record.Active == active.(bool) {
matchCounter++
}
if ttl, ok := options["ttl"]; ok && record.TTL == ttl.(int) {
matchCounter++
}
if matchCounter >= matchesNeeded {
found = append(found, record)
}
}
return found
}
func (zone *Zone) findAfsdbRecord(options map[string]interface{}) []DNSRecord {
found := make([]DNSRecord, 0)
matchesNeeded := len(options)
for _, record := range zone.Zone.Afsdb {
matchCounter := 0
if name, ok := options["name"]; ok && record.Name == name.(string) {
matchCounter++
}
if target, ok := options["target"]; ok && record.Target == target.(string) {
matchCounter++
}
if active, ok := options["active"]; ok && record.Active == active.(bool) {
matchCounter++
}
if ttl, ok := options["ttl"]; ok && record.TTL == ttl.(int) {
matchCounter++
}
if subtype, ok := options["subtype"]; ok && record.Subtype == subtype.(int) {
matchCounter++
}
if matchCounter >= matchesNeeded {
found = append(found, record)
}
}
return found
}
func (zone *Zone) findCnameRecord(options map[string]interface{}) []DNSRecord {
found := make([]DNSRecord, 0)
matchesNeeded := len(options)
for _, record := range zone.Zone.Cname {
matchCounter := 0
if name, ok := options["name"]; ok && record.Name == name.(string) {
matchCounter++
}
if target, ok := options["target"]; ok && record.Target == target.(string) {
matchCounter++
}
if active, ok := options["active"]; ok && record.Active == active.(bool) {
matchCounter++
}
if ttl, ok := options["ttl"]; ok && record.TTL == ttl.(int) {
matchCounter++
}
if matchCounter >= matchesNeeded {
found = append(found, record)
}
}
return found
}
func (zone *Zone) findDnskeyRecord(options map[string]interface{}) []DNSRecord {
found := make([]DNSRecord, 0)
matchesNeeded := len(options)
for _, record := range zone.Zone.Dnskey {
matchCounter := 0
if name, ok := options["name"]; ok && record.Name == name.(string) {
matchCounter++
}
if active, ok := options["active"]; ok && record.Active == active.(bool) {
matchCounter++
}
if ttl, ok := options["ttl"]; ok && record.TTL == ttl.(int) {
matchCounter++
}
if flags, ok := options["flags"]; ok && record.Flags == flags.(int) {
matchCounter++
}
if protocol, ok := options["protocol"]; ok && record.Protocol == protocol.(int) {
matchCounter++
}
if algorithm, ok := options["algorithm"]; ok && record.Algorithm == algorithm.(int) {
matchCounter++
}
if key, ok := options["key"]; ok && record.Key == key.(string) {
matchCounter++
}
if matchCounter >= matchesNeeded {
found = append(found, record)
}
}
return found
}
func (zone *Zone) findDsRecord(options map[string]interface{}) []DNSRecord {
found := make([]DNSRecord, 0)
matchesNeeded := len(options)
for _, record := range zone.Zone.Ds {
matchCounter := 0
if name, ok := options["name"]; ok && record.Name == name.(string) {
matchCounter++
}
if active, ok := options["active"]; ok && record.Active == active.(bool) {
matchCounter++
}
if ttl, ok := options["ttl"]; ok && record.TTL == ttl.(int) {
matchCounter++
}
if keytag, ok := options["keytag"]; ok && record.Keytag == keytag.(int) {
matchCounter++
}
if algorithm, ok := options["algorithm"]; ok && record.Algorithm == algorithm.(int) {
matchCounter++
}
if digesttype, ok := options["digesttype"]; ok && record.DigestType == digesttype.(int) {
matchCounter++
}
if digest, ok := options["digest"]; ok && record.Digest == digest.(string) {
matchCounter++
}
if matchCounter >= matchesNeeded {
found = append(found, record)
}
}
return found
}
func (zone *Zone) findHinfoRecord(options map[string]interface{}) []DNSRecord {
found := make([]DNSRecord, 0)
matchesNeeded := len(options)
for _, record := range zone.Zone.Hinfo {
matchCounter := 0
if name, ok := options["name"]; ok && record.Name == name.(string) {
matchCounter++
}
if active, ok := options["active"]; ok && record.Active == active.(bool) {
matchCounter++
}
if ttl, ok := options["ttl"]; ok && record.TTL == ttl.(int) {
matchCounter++
}
if hardware, ok := options["hardware"]; ok && record.Hardware == hardware.(string) {
matchCounter++
}
if software, ok := options["software"]; ok && record.Software == software.(string) {
matchCounter++
}
if matchCounter >= matchesNeeded {
found = append(found, record)
}
}
return found
}
func (zone *Zone) findLocRecord(options map[string]interface{}) []DNSRecord {
found := make([]DNSRecord, 0)
matchesNeeded := len(options)
for _, record := range zone.Zone.Loc {
matchCounter := 0
if name, ok := options["name"]; ok && record.Name == name.(string) {
matchCounter++
}
if active, ok := options["active"]; ok && record.Active == active.(bool) {
matchCounter++
}
if ttl, ok := options["ttl"]; ok && record.TTL == ttl.(int) {
matchCounter++
}
if target, ok := options["target"]; ok && record.Target == target.(string) {
matchCounter++
}
if matchCounter >= matchesNeeded {
found = append(found, record)
}
}
return found
}
func (zone *Zone) findMxRecord(options map[string]interface{}) []DNSRecord {
found := make([]DNSRecord, 0)
matchesNeeded := len(options)
for _, record := range zone.Zone.Mx {
matchCounter := 0
if name, ok := options["name"]; ok && record.Name == name.(string) {
matchCounter++
}
if active, ok := options["active"]; ok && record.Active == active.(bool) {
matchCounter++
}
if ttl, ok := options["ttl"]; ok && record.TTL == ttl.(int) {
matchCounter++
}
if target, ok := options["target"]; ok && record.Target == target.(string) {
matchCounter++
}
if priority, ok := options["priority"]; ok && record.Priority == priority.(int) {
matchCounter++
}
if matchCounter >= matchesNeeded {
found = append(found, record)
}
}
return found
}
func (zone *Zone) findNaptrRecord(options map[string]interface{}) []DNSRecord {
found := make([]DNSRecord, 0)
matchesNeeded := len(options)
for _, record := range zone.Zone.Naptr {
matchCounter := 0
if name, ok := options["name"]; ok && record.Name == name.(string) {
matchCounter++
}
if active, ok := options["active"]; ok && record.Active == active.(bool) {
matchCounter++
}
if ttl, ok := options["ttl"]; ok && record.TTL == ttl.(int) {
matchCounter++
}
if order, ok := options["order"]; ok && record.Order == order.(uint16) {
matchCounter++
}
if preference, ok := options["preference"]; ok && record.Preference == preference.(uint16) {
matchCounter++
}
if flags, ok := options["flags"]; ok && record.Flags == flags.(string) {
matchCounter++
}
if service, ok := options["service"]; ok && record.Service == service.(string) {
matchCounter++
}
if regexp, ok := options["regexp"]; ok && record.Regexp == regexp.(string) {
matchCounter++
}
if replacement, ok := options["replacement"]; ok && record.Replacement == replacement.(string) {
matchCounter++
}
if matchCounter >= matchesNeeded {
found = append(found, record)
}
}
return found
}
func (zone *Zone) findNsRecord(options map[string]interface{}) []DNSRecord {
found := make([]DNSRecord, 0)
matchesNeeded := len(options)
for _, record := range zone.Zone.Ns {
matchCounter := 0
if name, ok := options["name"]; ok && record.Name == name.(string) {
matchCounter++
}
if active, ok := options["active"]; ok && record.Active == active.(bool) {
matchCounter++
}
if ttl, ok := options["ttl"]; ok && record.TTL == ttl.(int) {
matchCounter++
}
if target, ok := options["target"]; ok && record.Target == target.(string) {
matchCounter++
}
if matchCounter >= matchesNeeded {
found = append(found, record)
}
}
return found
}
func (zone *Zone) findNsec3Record(options map[string]interface{}) []DNSRecord {
found := make([]DNSRecord, 0)
matchesNeeded := len(options)
for _, record := range zone.Zone.Nsec3 {
matchCounter := 0
if name, ok := options["name"]; ok && record.Name == name.(string) {
matchCounter++
}
if active, ok := options["active"]; ok && record.Active == active.(bool) {
matchCounter++
}
if ttl, ok := options["ttl"]; ok && record.TTL == ttl.(int) {
matchCounter++
}
if algorithm, ok := options["algorithm"]; ok && record.Algorithm == algorithm.(int) {
matchCounter++
}
if flags, ok := options["flags"]; ok && record.Flags == flags.(int) {
matchCounter++
}
if iterations, ok := options["iterations"]; ok && record.Iterations == iterations.(int) {
matchCounter++
}
if salt, ok := options["salt"]; ok && record.Salt == salt.(string) {
matchCounter++
}
if nextHashedOwnerName, ok := options["nextHashedOwnerName"]; ok && record.NextHashedOwnerName == nextHashedOwnerName.(string) {
matchCounter++
}
if typeBitmaps, ok := options["typeBitmaps"]; ok && record.TypeBitmaps == typeBitmaps.(string) {
matchCounter++
}
if matchCounter >= matchesNeeded {
found = append(found, record)
}
}
return found
}
func (zone *Zone) findNsec3paramRecord(options map[string]interface{}) []DNSRecord {
found := make([]DNSRecord, 0)
matchesNeeded := len(options)
for _, record := range zone.Zone.Nsec3param {
matchCounter := 0
if name, ok := options["name"]; ok && record.Name == name.(string) {
matchCounter++
}
if active, ok := options["active"]; ok && record.Active == active.(bool) {
matchCounter++
}
if ttl, ok := options["ttl"]; ok && record.TTL == ttl.(int) {
matchCounter++
}
if algorithm, ok := options["algorithm"]; ok && record.Algorithm == algorithm.(int) {
matchCounter++
}
if flags, ok := options["flags"]; ok && record.Flags == flags.(int) {
matchCounter++
}
if iterations, ok := options["iterations"]; ok && record.Iterations == iterations.(int) {
matchCounter++
}
if salt, ok := options["salt"]; ok && record.Salt == salt.(string) {
matchCounter++
}
if matchCounter >= matchesNeeded {
found = append(found, record)
}
}
return found
}
func (zone *Zone) findPtrRecord(options map[string]interface{}) []DNSRecord {
found := make([]DNSRecord, 0)
matchesNeeded := len(options)
for _, record := range zone.Zone.Ptr {
matchCounter := 0
if name, ok := options["name"]; ok && record.Name == name.(string) {
matchCounter++
}
if active, ok := options["active"]; ok && record.Active == active.(bool) {
matchCounter++
}
if ttl, ok := options["ttl"]; ok && record.TTL == ttl.(int) {
matchCounter++
}
if target, ok := options["target"]; ok && record.Target == target.(string) {
matchCounter++
}
if matchCounter >= matchesNeeded {
found = append(found, record)
}
}
return found
}
func (zone *Zone) findRpRecord(options map[string]interface{}) []DNSRecord {
found := make([]DNSRecord, 0)
matchesNeeded := len(options)
for _, record := range zone.Zone.Rp {
matchCounter := 0
if name, ok := options["name"]; ok && record.Name == name.(string) {
matchCounter++
}
if active, ok := options["active"]; ok && record.Active == active.(bool) {
matchCounter++
}
if ttl, ok := options["ttl"]; ok && record.TTL == ttl.(int) {
matchCounter++
}
if mailbox, ok := options["mailbox"]; ok && record.Mailbox == mailbox.(string) {
matchCounter++
}
if txt, ok := options["txt"]; ok && record.Txt == txt.(string) {
matchCounter++
}
if matchCounter >= matchesNeeded {
found = append(found, record)
}
}
return found
}
func (zone *Zone) findRrsigRecord(options map[string]interface{}) []DNSRecord {
found := make([]DNSRecord, 0)
matchesNeeded := len(options)
for _, record := range zone.Zone.Rrsig {
matchCounter := 0
if name, ok := options["name"]; ok && record.Name == name.(string) {
matchCounter++
}
if active, ok := options["active"]; ok && record.Active == active.(bool) {
matchCounter++
}
if ttl, ok := options["ttl"]; ok && record.TTL == ttl.(int) {
matchCounter++
}
if typeCovered, ok := options["typeCovered"]; ok && record.TypeCovered == typeCovered.(string) {
matchCounter++
}
if algorithm, ok := options["algorithm"]; ok && record.Algorithm == algorithm.(int) {
matchCounter++
}
if originalTTL, ok := options["originalTTL"]; ok && record.OriginalTTL == originalTTL.(int) {
matchCounter++
}
if expiration, ok := options["expiration"]; ok && record.Expiration == expiration.(string) {
matchCounter++
}
if inception, ok := options["inception"]; ok && record.Inception == inception.(string) {
matchCounter++
}
if keytag, ok := options["keytag"]; ok && record.Keytag == keytag.(int) {
matchCounter++
}
if signer, ok := options["signer"]; ok && record.Signer == signer.(string) {
matchCounter++
}
if signature, ok := options["signature"]; ok && record.Signature == signature.(string) {
matchCounter++
}
if labels, ok := options["labels"]; ok && record.Labels == labels.(int) {
matchCounter++
}
if matchCounter >= matchesNeeded {
found = append(found, record)
}
}
return found
}
func (zone *Zone) findSpfRecord(options map[string]interface{}) []DNSRecord {
found := make([]DNSRecord, 0)
matchesNeeded := len(options)
for _, record := range zone.Zone.Spf {
matchCounter := 0
if name, ok := options["name"]; ok && record.Name == name.(string) {
matchCounter++
}
if active, ok := options["active"]; ok && record.Active == active.(bool) {
matchCounter++
}
if ttl, ok := options["ttl"]; ok && record.TTL == ttl.(int) {
matchCounter++
}
if target, ok := options["target"]; ok && record.Target == target.(string) {
matchCounter++
}
if matchCounter >= matchesNeeded {
found = append(found, record)
}
}
return found
}
func (zone *Zone) findSrvRecord(options map[string]interface{}) []DNSRecord {
found := make([]DNSRecord, 0)
matchesNeeded := len(options)
for _, record := range zone.Zone.Srv {
matchCounter := 0
if name, ok := options["name"]; ok && record.Name == name.(string) {
matchCounter++
}
if active, ok := options["active"]; ok && record.Active == active.(bool) {
matchCounter++
}
if ttl, ok := options["ttl"]; ok && record.TTL == ttl.(int) {
matchCounter++
}
if target, ok := options["target"]; ok && record.Target == target.(string) {
matchCounter++
}
if priority, ok := options["priority"]; ok && record.Priority == priority.(int) {
matchCounter++
}
if weight, ok := options["weight"]; ok && record.Weight == weight.(uint16) {
matchCounter++
}
if port, ok := options["port"]; ok && record.Port == port.(uint16) {
matchCounter++
}
if matchCounter >= matchesNeeded {
found = append(found, record)
}
}
return found
}
func (zone *Zone) findSshfpRecord(options map[string]interface{}) []DNSRecord {
found := make([]DNSRecord, 0)
matchesNeeded := len(options)
for _, record := range zone.Zone.Sshfp {
matchCounter := 0
if name, ok := options["name"]; ok && record.Name == name.(string) {
matchCounter++
}
if active, ok := options["active"]; ok && record.Active == active.(bool) {
matchCounter++
}
if ttl, ok := options["ttl"]; ok && record.TTL == ttl.(int) {
matchCounter++
}
if algorithm, ok := options["algorithm"]; ok && record.Algorithm == algorithm.(int) {
matchCounter++
}
if fingerprintType, ok := options["fingerprintType"]; ok && record.FingerprintType == fingerprintType.(int) {
matchCounter++
}
if fingerprint, ok := options["fingerprint"]; ok && record.Fingerprint == fingerprint.(string) {
matchCounter++
}
if matchCounter >= matchesNeeded {
found = append(found, record)
}
}
return found
}
func (zone *Zone) findTxtRecord(options map[string]interface{}) []DNSRecord {
found := make([]DNSRecord, 0)
matchesNeeded := len(options)
for _, record := range zone.Zone.Txt {
matchCounter := 0
if name, ok := options["name"]; ok && record.Name == name.(string) {
matchCounter++
}
if active, ok := options["active"]; ok && record.Active == active.(bool) {
matchCounter++
}
if ttl, ok := options["ttl"]; ok && record.TTL == ttl.(int) {
matchCounter++
}
if target, ok := options["target"]; ok && record.Target == target.(string) {
matchCounter++
}
if matchCounter >= matchesNeeded {
found = append(found, record)
}
}
return found
}