mirror of
https://github.com/StackExchange/dnscontrol.git
synced 2024-05-11 05:55:12 +00:00
Add SPF support for RecordConfig (#1020)
This type is identical to TXT but used for other purposes, it is officially supported by OctoDNS. Co-authored-by: Tom Limoncelli <tlimoncelli@stackoverflow.com>
This commit is contained in:
@ -295,6 +295,8 @@ func (rc *RecordConfig) ToRR() dns.RR {
|
|||||||
rr.(*dns.TLSA).MatchingType = rc.TlsaMatchingType
|
rr.(*dns.TLSA).MatchingType = rc.TlsaMatchingType
|
||||||
rr.(*dns.TLSA).Selector = rc.TlsaSelector
|
rr.(*dns.TLSA).Selector = rc.TlsaSelector
|
||||||
rr.(*dns.TLSA).Certificate = rc.GetTargetField()
|
rr.(*dns.TLSA).Certificate = rc.GetTargetField()
|
||||||
|
case dns.TypeSPF:
|
||||||
|
rr.(*dns.SPF).Txt = rc.TxtStrings
|
||||||
case dns.TypeTXT:
|
case dns.TypeTXT:
|
||||||
rr.(*dns.TXT).Txt = rc.TxtStrings
|
rr.(*dns.TXT).Txt = rc.TxtStrings
|
||||||
default:
|
default:
|
||||||
|
@ -47,7 +47,7 @@ func (r *RecordConfig) PopulateFromString(rtype, contents, origin string) error
|
|||||||
return r.SetTargetSSHFPString(contents)
|
return r.SetTargetSSHFPString(contents)
|
||||||
case "TLSA":
|
case "TLSA":
|
||||||
return r.SetTargetTLSAString(contents)
|
return r.SetTargetTLSAString(contents)
|
||||||
case "TXT":
|
case "SPF", "TXT":
|
||||||
return r.SetTargetTXTString(contents)
|
return r.SetTargetTXTString(contents)
|
||||||
default:
|
default:
|
||||||
return fmt.Errorf("unknown rtype (%s) when parsing (%s) domain=(%s)",
|
return fmt.Errorf("unknown rtype (%s) when parsing (%s) domain=(%s)",
|
||||||
|
@ -5,6 +5,18 @@ import (
|
|||||||
"strings"
|
"strings"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// HasFormatIdenticalToTXT returns if a RecordConfig has a format which is
|
||||||
|
// identical to TXT, such as SPF. For more details, read
|
||||||
|
// https://tools.ietf.org/html/rfc4408#section-3.1.1
|
||||||
|
func (rc *RecordConfig) HasFormatIdenticalToTXT() bool {
|
||||||
|
switch rc.Type {
|
||||||
|
case "SPF", "TXT":
|
||||||
|
return true
|
||||||
|
default:
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// 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.SetTarget(s)
|
rc.SetTarget(s)
|
||||||
@ -12,8 +24,8 @@ func (rc *RecordConfig) SetTargetTXT(s string) error {
|
|||||||
if rc.Type == "" {
|
if rc.Type == "" {
|
||||||
rc.Type = "TXT"
|
rc.Type = "TXT"
|
||||||
}
|
}
|
||||||
if rc.Type != "TXT" {
|
if !rc.HasFormatIdenticalToTXT() {
|
||||||
panic("assertion failed: SetTargetTXT called when .Type is not TXT")
|
panic("assertion failed: SetTargetTXT called when .Type is not identical to TXT")
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
@ -25,8 +37,8 @@ func (rc *RecordConfig) SetTargetTXTs(s []string) error {
|
|||||||
if rc.Type == "" {
|
if rc.Type == "" {
|
||||||
rc.Type = "TXT"
|
rc.Type = "TXT"
|
||||||
}
|
}
|
||||||
if rc.Type != "TXT" {
|
if !rc.HasFormatIdenticalToTXT() {
|
||||||
panic("assertion failed: SetTargetTXT called when .Type is not TXT")
|
panic("assertion failed: SetTargetTXT called when .Type is not identical to TXT")
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
@ -68,8 +80,8 @@ func splitChunks(buf string, lim int) []string {
|
|||||||
// ValidateTXT returns an error if the txt record is invalid.
|
// ValidateTXT returns an error if the txt record is invalid.
|
||||||
// Verifies the Target and TxtStrings are less than 255 bytes each.
|
// Verifies the Target and TxtStrings are less than 255 bytes each.
|
||||||
func ValidateTXT(rc *RecordConfig) error {
|
func ValidateTXT(rc *RecordConfig) error {
|
||||||
if rc.Type != "TXT" {
|
if !rc.HasFormatIdenticalToTXT() {
|
||||||
return fmt.Errorf("rc.Type=%q, expecting TXT", rc.Type)
|
return fmt.Errorf("rc.Type=%q, expecting something identical to TXT", rc.Type)
|
||||||
}
|
}
|
||||||
for i := range rc.TxtStrings {
|
for i := range rc.TxtStrings {
|
||||||
l := len(rc.TxtStrings[i])
|
l := len(rc.TxtStrings[i])
|
||||||
|
@ -23,7 +23,7 @@ so that it is easy to do things the right way in preparation.
|
|||||||
// GetTargetField returns the target. There may be other fields (for example
|
// GetTargetField returns the target. There may be other fields (for example
|
||||||
// an MX record also has a .MxPreference field.
|
// an MX record also has a .MxPreference field.
|
||||||
func (rc *RecordConfig) GetTargetField() string {
|
func (rc *RecordConfig) GetTargetField() string {
|
||||||
if rc.Type == "TXT" {
|
if rc.HasFormatIdenticalToTXT() {
|
||||||
return strings.Join(rc.TxtStrings, "")
|
return strings.Join(rc.TxtStrings, "")
|
||||||
}
|
}
|
||||||
return rc.Target
|
return rc.Target
|
||||||
|
@ -351,7 +351,7 @@ func ValidateAndNormalizeConfig(config *models.DNSConfig) (errs []error) {
|
|||||||
// Split TXT targets that are >255 bytes (if permitted)
|
// Split TXT targets that are >255 bytes (if permitted)
|
||||||
for _, domain := range config.Domains {
|
for _, domain := range config.Domains {
|
||||||
for _, rec := range domain.Records {
|
for _, rec := range domain.Records {
|
||||||
if rec.Type == "TXT" {
|
if rec.HasFormatIdenticalToTXT() {
|
||||||
if txtAlgo, ok := rec.Metadata["txtSplitAlgorithm"]; ok {
|
if txtAlgo, ok := rec.Metadata["txtSplitAlgorithm"]; ok {
|
||||||
rec.TxtNormalize(txtAlgo)
|
rec.TxtNormalize(txtAlgo)
|
||||||
}
|
}
|
||||||
@ -371,12 +371,12 @@ func ValidateAndNormalizeConfig(config *models.DNSConfig) (errs []error) {
|
|||||||
}
|
}
|
||||||
// Validate TXT records.
|
// Validate TXT records.
|
||||||
for _, rec := range domain.Records {
|
for _, rec := range domain.Records {
|
||||||
if rec.Type == "TXT" {
|
if rec.HasFormatIdenticalToTXT() {
|
||||||
// If TXTMulti is required, all providers must support that feature.
|
// If TXTMulti is required, all providers must support that feature.
|
||||||
if len(rec.TxtStrings) > 1 && len(txtMultiDissenters) > 0 {
|
if len(rec.TxtStrings) > 1 && len(txtMultiDissenters) > 0 {
|
||||||
errs = append(errs,
|
errs = append(errs,
|
||||||
fmt.Errorf("TXT records with multiple strings not supported by %s (label=%q domain=%v)",
|
fmt.Errorf("%s records with multiple strings not supported by %s (label=%q domain=%v)",
|
||||||
strings.Join(txtMultiDissenters, ","), rec.GetLabel(), domain.Name))
|
rec.Type, strings.Join(txtMultiDissenters, ","), rec.GetLabel(), domain.Name))
|
||||||
}
|
}
|
||||||
// Validate the record:
|
// Validate the record:
|
||||||
if err := models.ValidateTXT(rec); err != nil {
|
if err := models.ValidateTXT(rec); err != nil {
|
||||||
|
@ -236,7 +236,7 @@ func newRecordConfig(rname, rtype, target string, ttl uint32, origin string) *mo
|
|||||||
}
|
}
|
||||||
rc.SetLabel(rname, origin)
|
rc.SetLabel(rname, origin)
|
||||||
switch rtype {
|
switch rtype {
|
||||||
case "TXT":
|
case "SPF", "TXT":
|
||||||
rc.SetTargetTXT(target)
|
rc.SetTargetTXT(target)
|
||||||
default:
|
default:
|
||||||
rc.SetTarget(target)
|
rc.SetTarget(target)
|
||||||
|
Reference in New Issue
Block a user