Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
82 changes: 82 additions & 0 deletions providers/ns1/dnssec.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
package ns1

import (
"errors"
"net/http"

"github.com/StackExchange/dnscontrol/v4/models"
"gopkg.in/ns1/ns1-go.v2/rest"
)

// GetZoneDNSSEC gets DNSSEC status for zone. Returns true for enabled, false for disabled
// a domain in NS1 can be in 3 states:
// 1. DNSSEC is enabled (returns true)
// 2. DNSSEC is disabled (returns false)
// 3. some error state (return false plus the error)
func (n *nsone) GetZoneDNSSEC(domain string) (bool, error) {
for rtr := 0; ; rtr++ {
_, httpResp, err := n.DNSSEC.Get(domain)
// rest.ErrDNSECNotEnabled is our "disabled" state
if err != nil && errors.Is(err, rest.ErrDNSECNotEnabled) {
return false, nil
}
if httpResp.StatusCode == http.StatusTooManyRequests && rtr < clientRetries {
continue
}
// any other errors not expected, let's surface them
if err != nil {
return false, err
}

// no errors returned, we assume DNSSEC is enabled
return true, nil
}
}

// getDomainCorrectionsDNSSEC creates DNSSEC zone corrections based on current state and preference
func (n *nsone) getDomainCorrectionsDNSSEC(domain, toggleDNSSEC string) *models.Correction {
// get dnssec status from NS1 for domain
// if errors are returned, we bail out without any DNSSEC corrections
status, err := n.GetZoneDNSSEC(domain)
if err != nil {
return nil
}

if toggleDNSSEC == "on" && !status {
// disabled, but prefer it on, let's enable DNSSEC
return &models.Correction{
Msg: "ENABLE DNSSEC",
F: func() error { return n.configureDNSSEC(domain, true) },
}
} else if toggleDNSSEC == "off" && status {
// enabled, but prefer it off, let's disable DNSSEC
return &models.Correction{
Msg: "DISABLE DNSSEC",
F: func() error { return n.configureDNSSEC(domain, false) },
}
}
return nil
}

// configureDNSSEC configures DNSSEC for a zone. Set 'enabled' to true to enable, false to disable.
// There's a cornercase, in which DNSSEC is globally disabled for the account.
// In that situation, enabling DNSSEC will always fail with:
//
// #1: ENABLE DNSSEC
// FAILURE! POST https://api.nsone.net/v1/zones/example.com: 400 DNSSEC support is not enabled for this account. Please contact [email protected] to enable it
//
// Unfortunately this is not detectable otherwise, so given that we have a nice error message, we just let this through.
func (n *nsone) configureDNSSEC(domain string, enabled bool) error {
z, _, err := n.Zones.Get(domain, true)
if err != nil {
return err
}
z.DNSSEC = &enabled
for rtr := 0; ; rtr++ {
httpResp, err := n.Zones.Update(z)
if httpResp.StatusCode == http.StatusTooManyRequests && rtr < clientRetries {
continue
}
return err
}
}
41 changes: 41 additions & 0 deletions providers/ns1/nameservers.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
package ns1

import (
"errors"
"strings"

"github.com/StackExchange/dnscontrol/v4/models"
"github.com/StackExchange/dnscontrol/v4/pkg/printer"
"gopkg.in/ns1/ns1-go.v2/rest"
)

func (n *nsone) GetNameservers(domain string) ([]*models.Nameserver, error) {
var nservers []string

z, err := n.GetZone(domain)
if err != nil && errors.Is(err, rest.ErrZoneMissing) {
// if we get here, zone wasn't created, but we ended up continuing regardless.
// This should be revisited, but for now let's get out early with a relevant message
// one case: preview --no-populate
printer.Warnf("GetNameservers: Zone %s not created in NS1. Either create manually or ensure dnscontrol can create it.\n", domain)
return models.ToNameservers(nservers)
}

if err != nil {
return nil, err
}

// on newly-created domains NS1 may assign nameservers with or without a
// trailing dot. This is not reflected in the actual DNS records, that
// always have the trailing dots.
//
// Handle both scenarios by stripping dots where existing, before continuing.
for _, ns := range z.DNSServers {
if strings.HasSuffix(ns, ".") {
nservers = append(nservers, ns[0:len(ns)-1])
} else {
nservers = append(nservers, ns)
}
}
return models.ToNameservers(nservers)
}
Loading
Loading