mirror of
https://github.com/StackExchange/dnscontrol.git
synced 2025-01-17 21:07:49 +08:00
b0f2945510
This should enable the diff2 code to be inserted with good "git blame" results for new code. I'm adding this early to catch any problems early.
212 lines
5.3 KiB
Go
212 lines
5.3 KiB
Go
package hostingde
|
|
|
|
import (
|
|
"encoding/json"
|
|
"fmt"
|
|
"sort"
|
|
"strings"
|
|
|
|
"github.com/StackExchange/dnscontrol/v3/models"
|
|
"github.com/StackExchange/dnscontrol/v3/pkg/diff"
|
|
"github.com/StackExchange/dnscontrol/v3/pkg/diff2"
|
|
"github.com/StackExchange/dnscontrol/v3/providers"
|
|
)
|
|
|
|
var defaultNameservers = []string{"ns1.hosting.de.", "ns2.hosting.de.", "ns3.hosting.de."}
|
|
|
|
var features = providers.DocumentationNotes{
|
|
providers.CanAutoDNSSEC: providers.Unimplemented("Supported but not implemented yet."),
|
|
providers.CanGetZones: providers.Can(),
|
|
providers.CanUseAlias: providers.Can(),
|
|
providers.CanUseCAA: providers.Can(),
|
|
providers.CanUseDS: providers.Can(),
|
|
providers.CanUseNAPTR: providers.Cannot(),
|
|
providers.CanUsePTR: providers.Can(),
|
|
providers.CanUseSRV: providers.Can(),
|
|
providers.CanUseSSHFP: providers.Can(),
|
|
providers.CanUseTLSA: providers.Can(),
|
|
providers.DocCreateDomains: providers.Can(),
|
|
providers.DocDualHost: providers.Can(),
|
|
providers.DocOfficiallySupported: providers.Cannot(),
|
|
}
|
|
|
|
func init() {
|
|
providers.RegisterRegistrarType("HOSTINGDE", newHostingdeReg)
|
|
fns := providers.DspFuncs{
|
|
Initializer: newHostingdeDsp,
|
|
RecordAuditor: AuditRecords,
|
|
}
|
|
providers.RegisterDomainServiceProviderType("HOSTINGDE", fns, features)
|
|
}
|
|
|
|
type providerMeta struct {
|
|
DefaultNS []string `json:"default_ns"`
|
|
}
|
|
|
|
func newHostingde(m map[string]string, providermeta json.RawMessage) (*hostingdeProvider, error) {
|
|
authToken, ownerAccountID, baseURL := m["authToken"], m["ownerAccountId"], m["baseURL"]
|
|
|
|
if authToken == "" {
|
|
return nil, fmt.Errorf("hosting.de: authtoken must be provided")
|
|
}
|
|
|
|
if baseURL == "" {
|
|
baseURL = "https://secure.hosting.de"
|
|
}
|
|
baseURL = strings.TrimSuffix(baseURL, "/")
|
|
|
|
hp := &hostingdeProvider{
|
|
authToken: authToken,
|
|
ownerAccountID: ownerAccountID,
|
|
baseURL: baseURL,
|
|
nameservers: defaultNameservers,
|
|
}
|
|
|
|
if len(providermeta) > 0 {
|
|
var pm providerMeta
|
|
if err := json.Unmarshal(providermeta, &pm); err != nil {
|
|
return nil, fmt.Errorf("hosting.de: could not parse providermeta: %w", err)
|
|
}
|
|
|
|
if len(pm.DefaultNS) > 0 {
|
|
hp.nameservers = pm.DefaultNS
|
|
}
|
|
}
|
|
|
|
return hp, nil
|
|
}
|
|
|
|
func newHostingdeDsp(m map[string]string, providermeta json.RawMessage) (providers.DNSServiceProvider, error) {
|
|
return newHostingde(m, providermeta)
|
|
}
|
|
|
|
func newHostingdeReg(m map[string]string) (providers.Registrar, error) {
|
|
return newHostingde(m, json.RawMessage{})
|
|
}
|
|
|
|
func (hp *hostingdeProvider) GetNameservers(domain string) ([]*models.Nameserver, error) {
|
|
return models.ToNameserversStripTD(hp.nameservers)
|
|
}
|
|
|
|
func (hp *hostingdeProvider) GetZoneRecords(domain string) (models.Records, error) {
|
|
src, err := hp.getRecords(domain)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
records := []*models.RecordConfig{}
|
|
for _, r := range src {
|
|
if r.Type == "SOA" {
|
|
continue
|
|
}
|
|
records = append(records, r.nativeToRecord(domain))
|
|
}
|
|
|
|
return records, nil
|
|
}
|
|
|
|
func (hp *hostingdeProvider) GetDomainCorrections(dc *models.DomainConfig) ([]*models.Correction, error) {
|
|
err := dc.Punycode()
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
// TTL must be between (inclusive) 1m and 1y (in fact, a little bit more)
|
|
for _, r := range dc.Records {
|
|
if r.TTL < 60 {
|
|
r.TTL = 60
|
|
}
|
|
if r.TTL > 31556926 {
|
|
r.TTL = 31556926
|
|
}
|
|
}
|
|
|
|
records, err := hp.GetZoneRecords(dc.Name)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
var corrections []*models.Correction
|
|
if !diff2.EnableDiff2 || true { // Remove "|| true" when diff2 version arrives
|
|
|
|
differ := diff.New(dc)
|
|
_, create, del, mod, err := differ.IncrementalDiff(records)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
// NOPURGE
|
|
if dc.KeepUnknown {
|
|
del = []diff.Correlation{}
|
|
}
|
|
|
|
msg := []string{}
|
|
for _, c := range append(del, append(create, mod...)...) {
|
|
msg = append(msg, c.String())
|
|
}
|
|
|
|
if len(create) == 0 && len(del) == 0 && len(mod) == 0 {
|
|
return nil, nil
|
|
}
|
|
|
|
corrections := []*models.Correction{
|
|
{
|
|
Msg: fmt.Sprintf("\n%s", strings.Join(msg, "\n")),
|
|
F: func() error {
|
|
return hp.updateRecords(dc.Name, create, del, mod)
|
|
},
|
|
},
|
|
}
|
|
|
|
return corrections, nil
|
|
}
|
|
|
|
// Insert Future diff2 version here.
|
|
|
|
return corrections, nil
|
|
}
|
|
|
|
func (hp *hostingdeProvider) GetRegistrarCorrections(dc *models.DomainConfig) ([]*models.Correction, error) {
|
|
err := dc.Punycode()
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
found, err := hp.getNameservers(dc.Name)
|
|
if err != nil {
|
|
return nil, fmt.Errorf("error getting nameservers: %w", err)
|
|
}
|
|
sort.Strings(found)
|
|
foundNameservers := strings.Join(found, ",")
|
|
|
|
expected := []string{}
|
|
for _, ns := range dc.Nameservers {
|
|
expected = append(expected, ns.Name)
|
|
}
|
|
sort.Strings(expected)
|
|
expectedNameservers := strings.Join(expected, ",")
|
|
|
|
// We don't care about glued records because we disallowed them
|
|
if foundNameservers != expectedNameservers {
|
|
return []*models.Correction{
|
|
{
|
|
Msg: fmt.Sprintf("Update nameservers %s -> %s", foundNameservers, expectedNameservers),
|
|
F: hp.updateNameservers(expected, dc.Name),
|
|
},
|
|
}, nil
|
|
}
|
|
|
|
return nil, nil
|
|
|
|
// TODO: Handle AutoDNSSEC
|
|
}
|
|
|
|
func (hp *hostingdeProvider) EnsureDomainExists(domain string) error {
|
|
_, err := hp.getZoneConfig(domain)
|
|
if err == errZoneNotFound {
|
|
if err := hp.createZone(domain); err != nil {
|
|
return err
|
|
}
|
|
}
|
|
return nil
|
|
}
|