1
0
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:
Armand Grillet
2021-01-24 21:36:48 +01:00
committed by GitHub
parent 945ffb7e80
commit 0d9cc35deb
6 changed files with 27 additions and 13 deletions

View File

@ -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:

View File

@ -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)",

View File

@ -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])

View File

@ -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

View File

@ -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 {

View File

@ -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)