mirror of
https://github.com/StackExchange/dnscontrol.git
synced 2025-09-11 15:44:55 +08:00
DNSIMPLE: Add compatibility with TXT changes (#2745)
Co-authored-by: Tom Limoncelli <tlimoncelli@stackoverflow.com>
This commit is contained in:
parent
9221a0638c
commit
4cd3c78059
5 changed files with 60 additions and 12 deletions
|
@ -24,9 +24,11 @@ Examples:
|
|||
{% endcode %}
|
||||
|
||||
## Metadata
|
||||
|
||||
This provider does not recognize any special metadata fields unique to DNSimple.
|
||||
|
||||
## Usage
|
||||
|
||||
An example configuration:
|
||||
|
||||
{% code title="dnsconfig.js" %}
|
||||
|
@ -41,8 +43,20 @@ D("example.com", REG_DNSIMPLE, DnsProvider(DSP_DNSIMPLE),
|
|||
{% endcode %}
|
||||
|
||||
## Activation
|
||||
|
||||
DNSControl depends on a DNSimple account access token.
|
||||
|
||||
## Caveats
|
||||
|
||||
None at this time
|
||||
### TXT record length
|
||||
|
||||
The DNSimple API supports TXT records of up to 1000 "characters" (assumed to
|
||||
be octets, per DNS norms, not Unicode characters in an encoding).
|
||||
|
||||
See https://support.dnsimple.com/articles/txt-record/
|
||||
|
||||
## Development
|
||||
|
||||
### Debugging
|
||||
|
||||
Set `DNSIMPLE_DEBUG_HTTP` environment variable to `1` to dump all API calls made by this provider.
|
||||
|
|
3
go.mod
3
go.mod
|
@ -26,7 +26,7 @@ require (
|
|||
github.com/cloudflare/cloudflare-go v0.84.0
|
||||
github.com/digitalocean/godo v1.107.0
|
||||
github.com/ditashi/jsbeautifier-go v0.0.0-20141206144643-2520a8026a9c
|
||||
github.com/dnsimple/dnsimple-go v1.2.0
|
||||
github.com/dnsimple/dnsimple-go v1.5.1
|
||||
github.com/exoscale/egoscale v0.90.2
|
||||
github.com/go-acme/lego v2.7.2+incompatible
|
||||
github.com/go-gandi/go-gandi v0.7.0
|
||||
|
@ -135,6 +135,7 @@ require (
|
|||
github.com/russross/blackfriday/v2 v2.1.0 // indirect
|
||||
github.com/ryanuber/go-glob v1.0.0 // indirect
|
||||
github.com/sergi/go-diff v1.2.0 // indirect
|
||||
github.com/shopspring/decimal v1.3.1 // indirect
|
||||
github.com/sirupsen/logrus v1.9.0 // indirect
|
||||
github.com/softlayer/xmlrpc v0.0.0-20200409220501-5f089df7cb7e // indirect
|
||||
github.com/stretchr/objx v0.5.0 // indirect
|
||||
|
|
6
go.sum
6
go.sum
|
@ -109,8 +109,8 @@ github.com/ditashi/jsbeautifier-go v0.0.0-20141206144643-2520a8026a9c h1:+Zo5Ca9
|
|||
github.com/ditashi/jsbeautifier-go v0.0.0-20141206144643-2520a8026a9c/go.mod h1:HJGU9ULdREjOcVGZVPB5s6zYmHi1RxzT71l2wQyLmnE=
|
||||
github.com/dnaeon/go-vcr v1.2.0 h1:zHCHvJYTMh1N7xnV7zf1m1GPBF9Ad0Jk/whtQ1663qI=
|
||||
github.com/dnaeon/go-vcr v1.2.0/go.mod h1:R4UdLID7HZT3taECzJs4YgbbH6PIGXB6W/sc5OLb6RQ=
|
||||
github.com/dnsimple/dnsimple-go v1.2.0 h1:ddTGyLVKly5HKb5L65AkLqFqwZlWo3WnR0BlFZlIddM=
|
||||
github.com/dnsimple/dnsimple-go v1.2.0/go.mod h1:z/cs26v/eiRvUyXsHQBLd8lWF8+cD6GbmkPH84plM4U=
|
||||
github.com/dnsimple/dnsimple-go v1.5.1 h1:zr7OJgQBfS8kJJGMRpcXC6DEeKErR71aNogCMnWGawU=
|
||||
github.com/dnsimple/dnsimple-go v1.5.1/go.mod h1:QWFwNXg2hV2PrGQE9b69Ig6UwHyIOxQRrECmVvaugss=
|
||||
github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=
|
||||
github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=
|
||||
github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98=
|
||||
|
@ -389,6 +389,8 @@ github.com/ryanuber/go-glob v1.0.0 h1:iQh3xXAumdQ+4Ufa5b25cRpC5TYKlno6hsv6Cb3pkB
|
|||
github.com/ryanuber/go-glob v1.0.0/go.mod h1:807d1WSdnB0XRJzKNil9Om6lcp/3a0v4qIHxIXzX/Yc=
|
||||
github.com/sergi/go-diff v1.2.0 h1:XU+rvMAioB0UC3q1MFrIQy4Vo5/4VsRDQQXHsEya6xQ=
|
||||
github.com/sergi/go-diff v1.2.0/go.mod h1:STckp+ISIX8hZLjrqAeVduY0gWCT9IjLuqbuNXdaHfM=
|
||||
github.com/shopspring/decimal v1.3.1 h1:2Usl1nmF/WZucqkFZhnfFYxxxu8LG21F6nPQBE5gKV8=
|
||||
github.com/shopspring/decimal v1.3.1/go.mod h1:DKyhrW/HYNuLGql+MJL6WCR6knT2jwCFRcu2hWCYk4o=
|
||||
github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE=
|
||||
github.com/sirupsen/logrus v1.9.0 h1:trlNQbNUG3OdDrDil03MCb1H2o9nJ1x4/5LYw7byDE0=
|
||||
github.com/sirupsen/logrus v1.9.0/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ=
|
||||
|
|
|
@ -13,7 +13,7 @@ func AuditRecords(records []*models.RecordConfig) []error {
|
|||
|
||||
a.Add("MX", rejectif.MxNull) // Last verified 2023-03
|
||||
|
||||
a.Add("TXT", rejectif.TxtLongerThan(255)) // Last verified 2023-03
|
||||
a.Add("TXT", rejectif.TxtLongerThan(1000)) // Last verified 2023-12
|
||||
|
||||
a.Add("TXT", rejectif.TxtHasTrailingSpace) // Last verified 2023-03
|
||||
|
||||
|
|
|
@ -5,6 +5,7 @@ import (
|
|||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
"os"
|
||||
"sort"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
@ -12,6 +13,7 @@ import (
|
|||
"github.com/StackExchange/dnscontrol/v4/models"
|
||||
"github.com/StackExchange/dnscontrol/v4/pkg/diff"
|
||||
"github.com/StackExchange/dnscontrol/v4/pkg/printer"
|
||||
"github.com/StackExchange/dnscontrol/v4/pkg/txtutil"
|
||||
"github.com/StackExchange/dnscontrol/v4/providers"
|
||||
dnsimpleapi "github.com/dnsimple/dnsimple-go/dnsimple"
|
||||
"golang.org/x/oauth2"
|
||||
|
@ -96,7 +98,14 @@ func (c *dnsimpleProvider) GetZoneRecords(domain string, meta map[string]string)
|
|||
|
||||
// DNSimple adds TXT records that mirror the alias records.
|
||||
// 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
|
||||
}
|
||||
// This second check is the same of before, but it exists for compatibility purpose.
|
||||
// Until Nov 2023 DNSimple did not normalize TXT records, and they used to store TXT records without quotes.
|
||||
//
|
||||
// This is a backward-compatible function to facilitate the TXT transition.
|
||||
if r.Type == "TXT" && strings.HasPrefix(r.Content, `ALIAS for `) {
|
||||
continue
|
||||
}
|
||||
|
||||
|
@ -120,7 +129,12 @@ func (c *dnsimpleProvider) GetZoneRecords(domain string, meta map[string]string)
|
|||
case "SRV":
|
||||
err = rec.SetTargetSRVPriorityString(uint16(r.Priority), r.Content)
|
||||
case "TXT":
|
||||
err = rec.SetTargetTXT(r.Content)
|
||||
// This is a backward-compatible function to facilitate the TXT transition.
|
||||
if isQuotedTXT(r.Content) {
|
||||
err = rec.PopulateFromStringFunc(r.Type, r.Content, domain, txtutil.ParseQuoted)
|
||||
} else {
|
||||
err = rec.SetTargetTXT(fmt.Sprintf("legacy: %s", r.Content))
|
||||
}
|
||||
default:
|
||||
err = rec.PopulateFromString(r.Type, r.Content, domain)
|
||||
}
|
||||
|
@ -255,6 +269,10 @@ func (c *dnsimpleProvider) getDNSSECCorrections(dc *models.DomainConfig) ([]*mod
|
|||
|
||||
// DNSimple calls
|
||||
|
||||
// Initializes a new DNSimple API client.
|
||||
//
|
||||
// - if BaseURL is present, the provided BaseURL is used. Useful to switch to DNSimple sandbox site. It defaults to production otherwise.
|
||||
// - if "DNSIMPLE_DEBUG_HTTP" is set to "1", it enables the API client logging.
|
||||
func (c *dnsimpleProvider) getClient() *dnsimpleapi.Client {
|
||||
ts := oauth2.StaticTokenSource(&oauth2.Token{AccessToken: c.AccountToken})
|
||||
tc := oauth2.NewClient(context.Background(), ts)
|
||||
|
@ -266,6 +284,9 @@ func (c *dnsimpleProvider) getClient() *dnsimpleapi.Client {
|
|||
if c.BaseURL != "" {
|
||||
client.BaseURL = c.BaseURL
|
||||
}
|
||||
if os.Getenv("DNSIMPLE_DEBUG_HTTP") == "1" {
|
||||
client.Debug = true
|
||||
}
|
||||
return client
|
||||
}
|
||||
|
||||
|
@ -632,8 +653,10 @@ func newProvider(m map[string]string, _ json.RawMessage) (*dnsimpleProvider, err
|
|||
return api, nil
|
||||
}
|
||||
|
||||
// remove all non-dnsimple NS records from our desired state.
|
||||
// if any are found, print a warning
|
||||
// utilities
|
||||
|
||||
// Removes all non-dnsimple NS records from our desired state.
|
||||
// If any are found, print a warning.
|
||||
func removeOtherApexNS(dc *models.DomainConfig) {
|
||||
newList := make([]*models.RecordConfig, 0, len(dc.Records))
|
||||
for _, rec := range dc.Records {
|
||||
|
@ -653,7 +676,7 @@ func removeOtherApexNS(dc *models.DomainConfig) {
|
|||
dc.Records = newList
|
||||
}
|
||||
|
||||
// Return the correct combined content for all special record types, Target for everything else
|
||||
// Returns the correct combined content for all special record types, Target for everything else
|
||||
// Using RecordConfig.GetTargetCombined returns priority in the string, which we do not allow
|
||||
func getTargetRecordContent(rc *models.RecordConfig) string {
|
||||
switch rtype := rc.Type; rtype {
|
||||
|
@ -670,13 +693,13 @@ func getTargetRecordContent(rc *models.RecordConfig) string {
|
|||
case "SRV":
|
||||
return fmt.Sprintf("%d %d %s", rc.SrvWeight, rc.SrvPort, rc.GetTargetField())
|
||||
case "TXT":
|
||||
return rc.GetTargetTXTJoined()
|
||||
return rc.GetTargetCombinedFunc(txtutil.EncodeQuoted)
|
||||
default:
|
||||
return rc.GetTargetField()
|
||||
}
|
||||
}
|
||||
|
||||
// Return the correct priority for the record type, 0 for records without priority
|
||||
// Returns the correct priority for the record type, 0 for records without priority
|
||||
func getTargetRecordPriority(rc *models.RecordConfig) int {
|
||||
switch rtype := rc.Type; rtype {
|
||||
case "MX":
|
||||
|
@ -711,3 +734,11 @@ func isDnsimpleNameServerDomain(name string) bool {
|
|||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// Tests if the content is encoded, performing a naive check on the presence of quotes
|
||||
// at the beginning and end of the string.
|
||||
//
|
||||
// This is a backward-compatible function to facilitate the TXT transition.
|
||||
func isQuotedTXT(content string) bool {
|
||||
return content[0:1] == `"` && content[len(content)-1:] == `"`
|
||||
}
|
||||
|
|
Loading…
Add table
Reference in a new issue