1
0
mirror of https://github.com/StackExchange/dnscontrol.git synced 2024-05-11 05:55:12 +00:00
Files
stackexchange-dnscontrol/models/target.go
Tom Limoncelli de4455942b Refactor RecordConfig: Add getters/setters (#314)
* Replace RecordConfig.Name and .NameFQDN with getters and setters.
* Replace RecordConfig.Target with getters and setters.
* Eliminate the CombinedTarget concept.
* Add RecordConfig.PopulateFromString to reduce code in all providers.
* encode and decode name.com txt records (#315)
* Replace fmt.Errorf with errors.Errorf
2018-02-15 12:02:50 -05:00

116 lines
4.2 KiB
Go

package models
import (
"net"
"strings"
"github.com/miekg/dns"
"github.com/pkg/errors"
)
/* .Target is kind of a mess.
For simple rtypes it is the record's value. (i.e. for an A record
it is the IP address).
For complex rtypes (like an MX record has a preference and a value)
it might be a space-delimited string with all the parameters, or it
might just be the hostname.
This was a bad design decision that I regret. Eventually we will eliminate this
field and replace it with setters/getters. The setters/getters are below
so that it is easy to do things the right way in preparation.
*/
// GetTargetField returns the target. There may be other fields (for example
// an MX record also has a .MxPreference field.
func (rc *RecordConfig) GetTargetField() string {
return rc.Target
}
// // GetTargetSingle returns the target for types that have a single value target
// // and panics for all others.
// func (rc *RecordConfig) GetTargetSingle() string {
// if rc.Type == "MX" || rc.Type == "SRV" || rc.Type == "CAA" || rc.Type == "TLSA" || rc.Type == "TXT" {
// panic("TargetSingle called on a type with a multi-parameter rtype.")
// }
// return rc.Target
// }
// GetTargetIP returns the net.IP stored in Target.
func (rc *RecordConfig) GetTargetIP() net.IP {
if rc.Type != "A" && rc.Type != "AAAA" {
panic(errors.Errorf("GetTargetIP called on an inappropriate rtype (%s)", rc.Type))
}
return net.ParseIP(rc.Target)
}
// GetTargetCombined returns a string with the various fields combined.
// For example, an MX record might output `10 mx10.example.tld`.
func (rc *RecordConfig) GetTargetCombined() string {
// If this is a pseudo record, just return the target.
if _, ok := dns.StringToType[rc.Type]; !ok {
return rc.Target
}
// We cheat by converting to a dns.RR and use the String() function.
// This combines all the data for us, and even does proper quoting.
// Sadly String() always includes a header, which we must strip out.
// TODO(tlim): Request the dns project add a function that returns
// the string without the header.
rr := rc.ToRR()
header := rr.Header().String()
full := rr.String()
if !strings.HasPrefix(full, header) {
panic("assertion failed. dns.Hdr.String() behavior has changed in an incompatible way")
}
return full[len(header):]
}
// // GetTargetDebug returns a string with the various fields spelled out.
// func (rc *RecordConfig) GetTargetDebug() string {
// content := fmt.Sprintf("%s %s %s %d", rc.Type, rc.NameFQDN, rc.Target, rc.TTL)
// switch rc.Type { // #rtype_variations
// case "A", "AAAA", "CNAME", "NS", "PTR", "TXT":
// // Nothing special.
// case "MX":
// content += fmt.Sprintf(" pref=%d", rc.MxPreference)
// case "SOA":
// content = fmt.Sprintf("%s %s %s %d", rc.Type, rc.Name, rc.Target, rc.TTL)
// case "SRV":
// content += fmt.Sprintf(" srvpriority=%d srvweight=%d srvport=%d", rc.SrvPriority, rc.SrvWeight, rc.SrvPort)
// case "TLSA":
// content += fmt.Sprintf(" tlsausage=%d tlsaselector=%d tlsamatchingtype=%d", rc.TlsaUsage, rc.TlsaSelector, rc.TlsaMatchingType)
// case "CAA":
// content += fmt.Sprintf(" caatag=%s caaflag=%d", rc.CaaTag, rc.CaaFlag)
// case "R53_ALIAS":
// content += fmt.Sprintf(" type=%s zone_id=%s", rc.R53Alias["type"], rc.R53Alias["zone_id"])
// default:
// panic(errors.Errorf("rc.String rtype %v unimplemented", rc.Type))
// // We panic so that we quickly find any switch statements
// // that have not been updated for a new RR type.
// }
// for k, v := range rc.Metadata {
// content += fmt.Sprintf(" %s=%s", k, v)
// }
// return content
// }
// SetTarget sets the target (assumes that the rtype is appropriate).
func (rc *RecordConfig) SetTarget(fqdn string) error {
rc.Target = fqdn
return nil
}
// SetTargetIP sets the target to an IP, verifying this is an appropriate rtype.
func (rc *RecordConfig) SetTargetIP(ip net.IP) error {
// TODO(tlim): Verify the rtype is appropriate for an IP.
rc.Target = ip.String()
return nil
}
// // SetTargetFQDN sets the target to an IP, verifying this is an appropriate rtype.
// func (rc *RecordConfig) SetTargetFQDN(target string) error {
// // TODO(tlim): Verify the rtype is appropriate for an hostname.
// rc.Target = target
// return nil
// }