mirror of
https://github.com/StackExchange/dnscontrol.git
synced 2024-05-11 05:55:12 +00:00
Add support for TXT records with multiple strings (BIND, ROUTE53) (#293)
* BIND: Support TXT records with multiple strings (#289) * ROUTE53: Add support for TXT records with multiple strings (#292)
This commit is contained in:
@@ -101,6 +101,7 @@ type RecordConfig struct {
|
||||
TlsaUsage uint8 `json:"tlsausage,omitempty"`
|
||||
TlsaSelector uint8 `json:"tlsaselector,omitempty"`
|
||||
TlsaMatchingType uint8 `json:"tlsamatchingtype,omitempty"`
|
||||
TxtStrings []string `json:"txtstrings,omitempty"` // TxtStrings stores all strings (including the first). Target stores only the first one.
|
||||
|
||||
CombinedTarget bool `json:"-"`
|
||||
|
||||
@@ -247,7 +248,7 @@ func (rc *RecordConfig) ToRR() dns.RR {
|
||||
rr.(*dns.TLSA).Selector = rc.TlsaSelector
|
||||
rr.(*dns.TLSA).Certificate = rc.Target
|
||||
case dns.TypeTXT:
|
||||
rr.(*dns.TXT).Txt = []string{rc.Target}
|
||||
rr.(*dns.TXT).Txt = rc.TxtStrings
|
||||
default:
|
||||
panic(fmt.Sprintf("ToRR: Unimplemented rtype %v", rc.Type))
|
||||
// We panic so that we quickly find any switch statements
|
||||
@@ -275,6 +276,12 @@ func (r Records) Grouped() map[RecordKey]Records {
|
||||
return groups
|
||||
}
|
||||
|
||||
// PostProcessRecords does any post-processing of the downloaded DNS records.
|
||||
func PostProcessRecords(recs []*RecordConfig) {
|
||||
Downcase(recs)
|
||||
fixTxt(recs)
|
||||
}
|
||||
|
||||
// Downcase converts all labels and targets to lowercase in a list of RecordConfig.
|
||||
func Downcase(recs []*RecordConfig) {
|
||||
for _, r := range recs {
|
||||
@@ -292,6 +299,17 @@ func Downcase(recs []*RecordConfig) {
|
||||
return
|
||||
}
|
||||
|
||||
// fixTxt fixes TXT records generated by providers that do not understand CanUseTXTMulti.
|
||||
func fixTxt(recs []*RecordConfig) {
|
||||
for _, r := range recs {
|
||||
if r.Type == "TXT" {
|
||||
if len(r.TxtStrings) == 0 {
|
||||
r.TxtStrings = []string{r.Target}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
type RecordKey struct {
|
||||
Name string
|
||||
Type string
|
||||
@@ -453,7 +471,6 @@ func (dc *DomainConfig) CombineCAAs() {
|
||||
panic(pm)
|
||||
}
|
||||
rec.Target = rec.Content()
|
||||
fmt.Printf("DEBUG: NEW TARGET: %v\n", rec.Target)
|
||||
rec.CombinedTarget = true
|
||||
}
|
||||
}
|
||||
|
57
models/txt.go
Normal file
57
models/txt.go
Normal file
@@ -0,0 +1,57 @@
|
||||
package models
|
||||
|
||||
import "strings"
|
||||
|
||||
// SetTxt sets the value of a TXT record to s.
|
||||
func (rc *RecordConfig) SetTxt(s string) {
|
||||
rc.Target = s
|
||||
rc.TxtStrings = []string{s}
|
||||
}
|
||||
|
||||
// SetTxts sets the value of a TXT record to the list of strings s.
|
||||
func (rc *RecordConfig) SetTxts(s []string) {
|
||||
rc.Target = s[0]
|
||||
rc.TxtStrings = s
|
||||
}
|
||||
|
||||
// SetTxtParse sets the value of TXT record if the list of strings is combined into one string.
|
||||
// `foo` -> []string{"foo"}
|
||||
// `"foo"` -> []string{"foo"}
|
||||
// `"foo" "bar"` -> []string{"foo" "bar"}
|
||||
func (rc *RecordConfig) SetTxtParse(s string) {
|
||||
rc.SetTxts(ParseQuotedTxt(s))
|
||||
}
|
||||
|
||||
// IsQuoted returns true if the string starts and ends with a double quote.
|
||||
func IsQuoted(s string) bool {
|
||||
if s == "" {
|
||||
return false
|
||||
}
|
||||
if len(s) < 2 {
|
||||
return false
|
||||
}
|
||||
if s[0] == '"' && s[len(s)-1] == s[0] {
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// StripQuotes returns the string with the starting and ending quotes removed.
|
||||
func StripQuotes(s string) string {
|
||||
if IsQuoted(s) {
|
||||
return s[1 : len(s)-1]
|
||||
}
|
||||
return s
|
||||
}
|
||||
|
||||
// ParseQuotedTxt returns the individual strings of a combined quoted string.
|
||||
// `foo` -> []string{"foo"}
|
||||
// `"foo"` -> []string{"foo"}
|
||||
// `"foo" "bar"` -> []string{"foo" "bar"}
|
||||
// NOTE: it is assumed there is exactly one space between the quotes.
|
||||
func ParseQuotedTxt(s string) []string {
|
||||
if !IsQuoted(s) {
|
||||
return []string{s}
|
||||
}
|
||||
return strings.Split(StripQuotes(s), `" "`)
|
||||
}
|
71
models/txt_test.go
Normal file
71
models/txt_test.go
Normal file
@@ -0,0 +1,71 @@
|
||||
package models
|
||||
|
||||
import (
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestIsQuoted(t *testing.T) {
|
||||
tests := []struct {
|
||||
d1 string
|
||||
e1 bool
|
||||
}{
|
||||
{``, false},
|
||||
{`foo`, false},
|
||||
{`""`, true},
|
||||
{`"a"`, true},
|
||||
{`"bb"`, true},
|
||||
{`"ccc"`, true},
|
||||
{`"aaa" "bbb"`, true},
|
||||
}
|
||||
for i, test := range tests {
|
||||
r := IsQuoted(test.d1)
|
||||
if r != test.e1 {
|
||||
t.Errorf("%v: expected (%v) got (%v)", i, test.e1, r)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestStripQuotes(t *testing.T) {
|
||||
tests := []struct {
|
||||
d1 string
|
||||
e1 string
|
||||
}{
|
||||
{``, ``},
|
||||
{`a`, `a`},
|
||||
{`bb`, `bb`},
|
||||
{`ccc`, `ccc`},
|
||||
{`dddd`, `dddd`},
|
||||
{`"A"`, `A`},
|
||||
{`"BB"`, `BB`},
|
||||
{`"CCC"`, `CCC`},
|
||||
{`"DDDD"`, `DDDD`},
|
||||
{`"EEEEE"`, `EEEEE`},
|
||||
{`"aaa" "bbb"`, `aaa" "bbb`},
|
||||
}
|
||||
for i, test := range tests {
|
||||
r := StripQuotes(test.d1)
|
||||
if r != test.e1 {
|
||||
t.Errorf("%v: expected (%v) got (%v)", i, test.e1, r)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestSetTxtParse(t *testing.T) {
|
||||
tests := []struct {
|
||||
d1 string
|
||||
e1 string
|
||||
e2 []string
|
||||
}{
|
||||
{``, ``, []string{``}},
|
||||
{`foo`, `foo`, []string{`foo`}},
|
||||
{`"foo"`, `foo`, []string{`foo`}},
|
||||
{`"aaa" "bbb"`, `aaa`, []string{`aaa`, `bbb`}},
|
||||
}
|
||||
for i, test := range tests {
|
||||
x := &RecordConfig{Type: "TXT"}
|
||||
x.SetTxtParse(test.d1)
|
||||
if x.Target != test.e1 {
|
||||
t.Errorf("%v: expected Target=(%v) got (%v)", i, test.e1, x.Target)
|
||||
}
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user