1
0
mirror of https://github.com/StackExchange/dnscontrol.git synced 2024-05-11 05:55:12 +00:00

DNSIMPLE: Fix TXT Handling, Second Edition (#1624)

* Fix typo and add sandbox information

* Use SetTargetTXT in GetZoneRecords

This fixes the behavior documented in #1622

Also apply cleanup to GetZoneRecords

* Remove SetTargetTXT, does not work in all tests

* Set The most correct TXT handling

* Well, There's your problem

* Add an audit and test for unpaired quotes

* Add some commentary

Co-authored-by: Tom Limoncelli <tlimoncelli@stackoverflow.com>
This commit is contained in:
Amelia Aronsohn
2022-07-22 06:36:28 -07:00
committed by GitHub
parent 15e6c95042
commit befb52be86
5 changed files with 62 additions and 22 deletions

View File

@@ -7,16 +7,23 @@ jsId: DNSIMPLE
# DNSimple Provider # DNSimple Provider
## Configuration ## Configuration
To use this provider, add an entry to `creds.json` with `TYPE` set to `DIGITALOCEAN` To use this provider, add an entry to `creds.json` with `TYPE` set to `DNSIMPLE`
along with a DNSimple account access token. along with a DNSimple account access token.
Example: You can also set the `baseurl` to use [DNSimple's free sandbox](https://developer.dnsimple.com/sandbox/) for testing.
Examples:
```json ```json
{ {
"dnsimple": { "dnsimple": {
"TYPE": "DNSIMPLE", "TYPE": "DNSIMPLE",
"token": "your-dnsimple-account-access-token" "token": "your-dnsimple-account-access-token"
},
"dnsimple_sandbox": {
"TYPE": "DNSIMPLE",
"baseurl": "https://api.sandbox.dnsimple.com",
"token": "your-sandbox-account-access-token"
} }
} }
``` ```

View File

@@ -845,6 +845,8 @@ func makeTests(t *testing.T) []*TestGroup {
clear(), clear(),
tc("Create TXT with double-quote", txt("foodq", `quo"te`)), tc("Create TXT with double-quote", txt("foodq", `quo"te`)),
clear(), clear(),
tc("Create TXT with double-quotes", txt("foodqs", `q"uo"te`)),
clear(),
tc("Create TXT with ws at end", txt("foows1", "with space at end ")), tc("Create TXT with ws at end", txt("foows1", "with space at end ")),
//clear(), //clear(),
// TODO(tlim): Re-add this when we fix the RFC1035 escaped-quotes issue. // TODO(tlim): Re-add this when we fix the RFC1035 escaped-quotes issue.

View File

@@ -141,3 +141,19 @@ func TxtNotEmpty(records []*models.RecordConfig) error {
} }
return nil return nil
} }
// TxtNoUnpairedDoubleQuotes audits TXT records for strings that contain unpaired doublequotes.
func TxtNoUnpairedDoubleQuotes(records []*models.RecordConfig) error {
for _, rc := range records {
if rc.HasFormatIdenticalToTXT() {
for _, txt := range rc.TxtStrings {
if strings.Count(txt, `"`)%2 == 1 {
return fmt.Errorf("txtstring contains unpaired doublequotes")
}
}
}
}
return nil
}

View File

@@ -8,8 +8,22 @@ import (
// AuditRecords returns an error if any records are not // AuditRecords returns an error if any records are not
// supportable by this provider. // supportable by this provider.
func AuditRecords(records []*models.RecordConfig) error { func AuditRecords(records []*models.RecordConfig) error {
if err := recordaudit.TxtNoDoubleQuotes(records); err != nil { //TODO(onlyhavecans) I think we can support multiple strings.
if err := recordaudit.TxtNoMultipleStrings(records); err != nil {
return err return err
} }
if err := recordaudit.TxtNoTrailingSpace(records); err != nil {
return err
} // as of 2022-07
if err := recordaudit.TxtNotEmpty(records); err != nil {
return err
} // as of 2022-07
if err := recordaudit.TxtNoUnpairedDoubleQuotes(records); err != nil {
return err
} // as of 2022-07
return nil return nil
} }

View File

@@ -4,7 +4,6 @@ import (
"context" "context"
"encoding/json" "encoding/json"
"fmt" "fmt"
"github.com/StackExchange/dnscontrol/v3/pkg/printer"
"sort" "sort"
"strconv" "strconv"
"strings" "strings"
@@ -14,7 +13,7 @@ import (
"github.com/StackExchange/dnscontrol/v3/models" "github.com/StackExchange/dnscontrol/v3/models"
"github.com/StackExchange/dnscontrol/v3/pkg/diff" "github.com/StackExchange/dnscontrol/v3/pkg/diff"
"github.com/StackExchange/dnscontrol/v3/pkg/txtutil" "github.com/StackExchange/dnscontrol/v3/pkg/printer"
"github.com/StackExchange/dnscontrol/v3/providers" "github.com/StackExchange/dnscontrol/v3/providers"
) )
@@ -77,51 +76,54 @@ func (c *dnsimpleProvider) GetZoneRecords(domain string) (models.Records, error)
if r.Type == "SOA" { if r.Type == "SOA" {
continue continue
} }
if r.Name == "" { if r.Name == "" {
r.Name = "@" r.Name = "@"
} }
if r.Type == "CNAME" || r.Type == "MX" || r.Type == "ALIAS" || r.Type == "NS" { if r.Type == "CNAME" || r.Type == "MX" || r.Type == "ALIAS" || r.Type == "NS" {
r.Content += "." r.Content += "."
} }
// DNSimple adds TXT records that mirror the alias records. // DNSimple adds TXT records that mirror the alias records.
// They manage them on ALIAS updates, so pretend they don't exist // They manage them on ALIAS updates, so pretend they don't exist
if r.Type == "TXT" && strings.HasPrefix(r.Content, "ALIAS for ") { if r.Type == "TXT" && strings.HasPrefix(r.Content, "ALIAS for ") {
continue continue
} }
rec := &models.RecordConfig{ rec := &models.RecordConfig{
TTL: uint32(r.TTL), TTL: uint32(r.TTL),
Original: r, Original: r,
} }
rec.SetLabel(r.Name, domain) rec.SetLabel(r.Name, domain)
var err error
switch rtype := r.Type; rtype { switch rtype := r.Type; rtype {
case "DNSKEY", "CDNSKEY", "CDS": case "DNSKEY", "CDNSKEY", "CDS":
continue continue
case "ALIAS", "URL": case "ALIAS", "URL":
rec.Type = r.Type rec.Type = r.Type
if err := rec.SetTarget(r.Content); err != nil { err = rec.SetTarget(r.Content)
return nil, fmt.Errorf("unparsable record received from dnsimple: %w", err)
}
case "DS": case "DS":
if err := rec.SetTargetDSString(r.Content); err != nil { err = rec.SetTargetDSString(r.Content)
return nil, fmt.Errorf("unparsable record received from dnsimple: %w", err)
}
case "MX": case "MX":
if err := rec.SetTargetMX(uint16(r.Priority), r.Content); err != nil { err = rec.SetTargetMX(uint16(r.Priority), r.Content)
return nil, fmt.Errorf("unparsable record received from dnsimple: %w", err)
}
case "SRV": case "SRV":
parts := strings.Fields(r.Content) parts := strings.Fields(r.Content)
if len(parts) == 3 { if len(parts) == 3 {
r.Content += "." r.Content += "."
} }
if err := rec.SetTargetSRVPriorityString(uint16(r.Priority), r.Content); err != nil { err = rec.SetTargetSRVPriorityString(uint16(r.Priority), r.Content)
return nil, fmt.Errorf("unparsable record received from dnsimple: %w", err) case "TXT":
} err = rec.SetTargetTXT(r.Content)
default: default:
if err := rec.PopulateFromString(r.Type, r.Content, domain); err != nil { err = rec.PopulateFromString(r.Type, r.Content, domain)
}
if err != nil {
return nil, fmt.Errorf("unparsable record received from dnsimple: %w", err) return nil, fmt.Errorf("unparsable record received from dnsimple: %w", err)
} }
}
cleanedRecords = append(cleanedRecords, rec) cleanedRecords = append(cleanedRecords, rec)
} }
@@ -152,7 +154,6 @@ func (c *dnsimpleProvider) GetDomainCorrections(dc *models.DomainConfig) ([]*mod
// Normalize // Normalize
models.PostProcessRecords(actual) models.PostProcessRecords(actual)
txtutil.SplitSingleLongTxt(dc.Records) // Autosplit long TXT records
differ := diff.New(dc) differ := diff.New(dc)
_, create, del, modify, err := differ.IncrementalDiff(actual) _, create, del, modify, err := differ.IncrementalDiff(actual)
@@ -592,7 +593,7 @@ func getTargetRecordContent(rc *models.RecordConfig) string {
case "SRV": case "SRV":
return fmt.Sprintf("%d %d %s", rc.SrvWeight, rc.SrvPort, rc.GetTargetField()) return fmt.Sprintf("%d %d %s", rc.SrvWeight, rc.SrvPort, rc.GetTargetField())
case "TXT": case "TXT":
return rc.GetTargetRFC1035Quoted() return rc.GetTargetTXTJoined()
default: default:
return rc.GetTargetField() return rc.GetTargetField()
} }