mirror of
https://github.com/StackExchange/dnscontrol.git
synced 2025-12-09 13:46:07 +08:00
INWX: Fix INWX provider after their unexpected data-type breaking-change (#3855)
Fixes #3854 Unfortunately I couldn't run the integrationTests properly as INWX doesn't seem to have properly updated their sandbox environment (it still presents `int` instead of `string` like production). Hence, the tests do fail. I don't want to run this against my own production account, to be frank. See: ```shell $ curl -X POST https://api.ote.domrobot.com/xmlrpc/ -H "Content-Type: application/xml" -d '<?xml version="1.0" encoding="UTF-8"?> <methodCall> <methodName>nameserver.info</methodName> <params> <param> <value> <struct> <member> <name>user</name> <value> <string>[USER]</string> </value> </member> <member> <name>lang</name> <value> <string>en</string> </value> </member> <member> <name>pass</name> <value> <string>[PASS]</string> </value> </member> <member> <name>domain</name> <value> <string>[DOMAIN]</string> </value> </member> </struct> </value> </param> </params> </methodCall>' | xmllint --format - | grep -iE "id|roId" -C3 % Total % Received % Xferd Average Speed Time Time Time Current Dload Upload Total Spent Left Speed 100 3968 0 2971 100 997 13375 4488 --:--:-- --:--:-- --:--:-- 17954 <value> <struct> <member> <name>roId</name> <value> <int>9677</int> </value> -- <value> <struct> <member> <name>id</name> <value> <int>118057</int> </value> -- <value> <struct> <member> <name>id</name> <value> <int>118060</int> </value> -- <value> <struct> <member> <name>id</name> <value> <int>79610</int> </value> -- <value> <struct> <member> <name>id</name> <value> <int>77243</int> </value> -- </value> </member> <member> <name>svTRID</name> <value> <string>20251127--ote</string> </value> ``` Hence, only done manualy tests via `dnscontrol push --domains <example.com>`: (tested create, delete and modify) ```text CONCURRENTLY checking for 0 zone(s) SERIALLY checking for 1 zone(s) Serially checking for zone: "example.tld" CONCURRENTLY gathering records of 0 zone(s) SERIALLY gathering records of 1 zone(s) Serially Gathering: "example.tld" ******************** Domain: example.tld 3 corrections (PK-INWX) #1: - DELETE _test1.example.tld TXT "123" ttl=43200 SUCCESS! #2: ± MODIFY _test2.example.tld TXT ("1234" ttl=43200) -> ("12345" ttl=43200) SUCCESS! #3: + CREATE _test4.example.tld TXT "123" ttl=43200 SUCCESS! Done. 3 corrections. ```
This commit is contained in:
parent
f306472d5a
commit
9aad2926fb
6 changed files with 28 additions and 34 deletions
2
go.mod
2
go.mod
|
|
@ -38,7 +38,7 @@ require (
|
||||||
github.com/miekg/dns v1.1.68
|
github.com/miekg/dns v1.1.68
|
||||||
github.com/mittwald/go-powerdns v0.6.7
|
github.com/mittwald/go-powerdns v0.6.7
|
||||||
github.com/namedotcom/go v0.0.0-20180403034216-08470befbe04
|
github.com/namedotcom/go v0.0.0-20180403034216-08470befbe04
|
||||||
github.com/nrdcg/goinwx v0.11.0
|
github.com/nrdcg/goinwx v0.12.0
|
||||||
github.com/ovh/go-ovh v1.9.0
|
github.com/ovh/go-ovh v1.9.0
|
||||||
github.com/philhug/opensrs-go v0.0.0-20171126225031-9dfa7433020d
|
github.com/philhug/opensrs-go v0.0.0-20171126225031-9dfa7433020d
|
||||||
github.com/pkg/errors v0.9.1
|
github.com/pkg/errors v0.9.1
|
||||||
|
|
|
||||||
4
go.sum
4
go.sum
|
|
@ -307,8 +307,8 @@ github.com/nicholas-fedor/shoutrrr v0.12.0 h1:8mwJdfU+uBEybSymwQJMGl/grG7lvVUKbV
|
||||||
github.com/nicholas-fedor/shoutrrr v0.12.0/go.mod h1:WYiRalR4C43Qmd2zhPWGIFIxu633NB1hDM6Ap/DQcsA=
|
github.com/nicholas-fedor/shoutrrr v0.12.0/go.mod h1:WYiRalR4C43Qmd2zhPWGIFIxu633NB1hDM6Ap/DQcsA=
|
||||||
github.com/nozzle/throttler v0.0.0-20180817012639-2ea982251481 h1:Up6+btDp321ZG5/zdSLo48H9Iaq0UQGthrhWC6pCxzE=
|
github.com/nozzle/throttler v0.0.0-20180817012639-2ea982251481 h1:Up6+btDp321ZG5/zdSLo48H9Iaq0UQGthrhWC6pCxzE=
|
||||||
github.com/nozzle/throttler v0.0.0-20180817012639-2ea982251481/go.mod h1:yKZQO8QE2bHlgozqWDiRVqTFlLQSj30K/6SAK8EeYFw=
|
github.com/nozzle/throttler v0.0.0-20180817012639-2ea982251481/go.mod h1:yKZQO8QE2bHlgozqWDiRVqTFlLQSj30K/6SAK8EeYFw=
|
||||||
github.com/nrdcg/goinwx v0.11.0 h1:GER0SE3POub7rxARt3Y3jRy1OON1hwF1LRxHz5xsFBw=
|
github.com/nrdcg/goinwx v0.12.0 h1:ujdUqDBnaRSFwzVnImvPHYw3w3m9XgmGImNUw1GyMb4=
|
||||||
github.com/nrdcg/goinwx v0.11.0/go.mod h1:0BXSC0FxVtU4aTjX0Zw3x0DK32tjugLzeNIAGtwXvPQ=
|
github.com/nrdcg/goinwx v0.12.0/go.mod h1:IrVKd3ZDbFiMjdPgML4CSxZAY9wOoqLvH44zv3NodJ0=
|
||||||
github.com/onsi/ginkgo/v2 v2.27.2 h1:LzwLj0b89qtIy6SSASkzlNvX6WktqurSHwkk2ipF/Ns=
|
github.com/onsi/ginkgo/v2 v2.27.2 h1:LzwLj0b89qtIy6SSASkzlNvX6WktqurSHwkk2ipF/Ns=
|
||||||
github.com/onsi/ginkgo/v2 v2.27.2/go.mod h1:ArE1D/XhNXBXCBkKOLkbsb2c81dQHCRcF5zwn/ykDRo=
|
github.com/onsi/ginkgo/v2 v2.27.2/go.mod h1:ArE1D/XhNXBXCBkKOLkbsb2c81dQHCRcF5zwn/ykDRo=
|
||||||
github.com/onsi/gomega v1.38.2 h1:eZCjf2xjZAqe+LeWvKb5weQ+NcPwX84kqJ0cZNxok2A=
|
github.com/onsi/gomega v1.38.2 h1:eZCjf2xjZAqe+LeWvKb5weQ+NcPwX84kqJ0cZNxok2A=
|
||||||
|
|
|
||||||
|
|
@ -19,7 +19,7 @@ func CorrectZoneRecords(driver models.DNSProvider, dc *models.DomainConfig) ([]*
|
||||||
models.CanonicalizeTargets(existingRecords, dc.Name)
|
models.CanonicalizeTargets(existingRecords, dc.Name)
|
||||||
models.CanonicalizeTargets(dc.Records, dc.Name)
|
models.CanonicalizeTargets(dc.Records, dc.Name)
|
||||||
|
|
||||||
// Copy dc so that any corrections code that wants to
|
// Copy dc so that any correction code that wants to
|
||||||
// modify the records may. For example, if the provider only
|
// modify the records may. For example, if the provider only
|
||||||
// supports certain TTL values, it will adjust the ones in
|
// supports certain TTL values, it will adjust the ones in
|
||||||
// dc.Records.
|
// dc.Records.
|
||||||
|
|
|
||||||
|
|
@ -10,12 +10,8 @@ import (
|
||||||
// supported, an empty list is returned.
|
// supported, an empty list is returned.
|
||||||
func AuditRecords(records []*models.RecordConfig) []error {
|
func AuditRecords(records []*models.RecordConfig) []error {
|
||||||
a := rejectif.Auditor{}
|
a := rejectif.Auditor{}
|
||||||
|
a.Add("TXT", rejectif.TxtHasBackticks) // Last verified 2021-03-01
|
||||||
a.Add("TXT", rejectif.TxtHasBackticks) // Last verified 2021-03-01
|
|
||||||
|
|
||||||
a.Add("TXT", rejectif.TxtHasTrailingSpace) // Last verified 2021-03-01
|
a.Add("TXT", rejectif.TxtHasTrailingSpace) // Last verified 2021-03-01
|
||||||
|
a.Add("TXT", rejectif.TxtIsEmpty) // Last verified 2021-03-01
|
||||||
a.Add("TXT", rejectif.TxtIsEmpty) // Last verified 2021-03-01
|
|
||||||
|
|
||||||
return a.Audit(records)
|
return a.Audit(records)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -10,25 +10,22 @@ const (
|
||||||
// testing shows 'AUTO' is what to expect if the domain has automatic
|
// testing shows 'AUTO' is what to expect if the domain has automatic
|
||||||
// DNSSEC enabled.
|
// DNSSEC enabled.
|
||||||
|
|
||||||
// AutoDNSSEC is the status for DNSSEC enabled with automatic management
|
// AutoDNSSECStatus is the status for DNSSEC enabled with automatic management
|
||||||
AutoDNSSECStatus = "AUTO"
|
AutoDNSSECStatus = "AUTO"
|
||||||
// ManualDNSSEC is the status for DNSSEC enabled with manual management
|
// ManualDNSSECStatus is the status for DNSSEC enabled with manual management
|
||||||
ManualDNSSECStatus = "MANUAL"
|
ManualDNSSECStatus = "MANUAL"
|
||||||
)
|
)
|
||||||
|
|
||||||
// DNSSecStatus returns domain dnssec status
|
// DNSSecStatus returns domain dnssec status
|
||||||
func (api *inwxAPI) DNSSecStatus(domain string) (string, error) {
|
func (api *inwxAPI) DNSSecStatus(domain string) (string, error) {
|
||||||
|
|
||||||
resp, err := api.client.Dnssec.Info([]string{domain})
|
resp, err := api.client.Dnssec.Info([]string{domain})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "", err
|
return "", err
|
||||||
}
|
}
|
||||||
|
|
||||||
// domain has no DNSSEC configuration
|
// domain has no DNSSEC configuration
|
||||||
if len(resp.Data) == 0 {
|
if len(resp.Data) == 0 {
|
||||||
return "", nil
|
return "", nil
|
||||||
}
|
}
|
||||||
|
|
||||||
return resp.Data[0].DNSSecStatus, nil
|
return resp.Data[0].DNSSecStatus, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -40,16 +37,12 @@ func (api *inwxAPI) enableAutoDNSSEC(domain string) error {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
err = api.client.Dnssec.Enable(domain)
|
err = api.client.Dnssec.Enable(domain)
|
||||||
|
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
// disableAutoDNSSEC disables automatic management of DNSSEC
|
// disableAutoDNSSEC disables automatic management of DNSSEC
|
||||||
func (api *inwxAPI) disableAutoDNSSEC(domain string) error {
|
func (api *inwxAPI) disableAutoDNSSEC(domain string) error {
|
||||||
|
|
||||||
err := api.client.Dnssec.Disable(domain)
|
err := api.client.Dnssec.Disable(domain)
|
||||||
|
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -22,6 +22,9 @@ import (
|
||||||
/*
|
/*
|
||||||
INWX Registrar and DNS provider
|
INWX Registrar and DNS provider
|
||||||
|
|
||||||
|
Based on this great INWX API implementation:
|
||||||
|
https://github.com/nrdcg/goinwx
|
||||||
|
|
||||||
Info required in `creds.json`:
|
Info required in `creds.json`:
|
||||||
- username
|
- username
|
||||||
- password
|
- password
|
||||||
|
|
@ -34,7 +37,6 @@ Either of the following settings is required when two factor authentication is e
|
||||||
|
|
||||||
Additional settings available in `creds.json`:
|
Additional settings available in `creds.json`:
|
||||||
- sandbox (set to 1 to use the sandbox API from INWX)
|
- sandbox (set to 1 to use the sandbox API from INWX)
|
||||||
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
// InwxProductionDefaultNs contains the default INWX nameservers.
|
// InwxProductionDefaultNs contains the default INWX nameservers.
|
||||||
|
|
@ -182,10 +184,10 @@ func makeNameserverRecordRequest(domain string, rec *models.RecordConfig) *goinw
|
||||||
|
|
||||||
switch rType := rec.Type; rType {
|
switch rType := rec.Type; rType {
|
||||||
/*
|
/*
|
||||||
INWX is a little bit special for CNAME,NS,MX and SRV records:
|
INWX is a little bit special for CNAME, NS, MX and SRV records:
|
||||||
The API will not accept any target with a final dot but will
|
The API will not accept any target with a final dot but will
|
||||||
instead always add this final dot internally.
|
instead always add this final dot internally.
|
||||||
Records with empty targets (i.e. records with target ".")
|
Records with empty targets (i.e., records with target ".")
|
||||||
are allowed.
|
are allowed.
|
||||||
*/
|
*/
|
||||||
case "CNAME", "NS", "ALIAS":
|
case "CNAME", "NS", "ALIAS":
|
||||||
|
|
@ -219,14 +221,14 @@ func (api *inwxAPI) createRecord(domain string, rec *models.RecordConfig) error
|
||||||
}
|
}
|
||||||
|
|
||||||
// updateRecord is used by GetDomainCorrections to update an existing record.
|
// updateRecord is used by GetDomainCorrections to update an existing record.
|
||||||
func (api *inwxAPI) updateRecord(RecordID int, rec *models.RecordConfig) error {
|
func (api *inwxAPI) updateRecord(RecordID string, rec *models.RecordConfig) error {
|
||||||
req := makeNameserverRecordRequest("", rec)
|
req := makeNameserverRecordRequest("", rec)
|
||||||
err := api.client.Nameservers.UpdateRecord(RecordID, req)
|
err := api.client.Nameservers.UpdateRecord(RecordID, req)
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
// deleteRecord is used by GetDomainCorrections to delete a record.
|
// deleteRecord is used by GetDomainCorrections to delete a record.
|
||||||
func (api *inwxAPI) deleteRecord(RecordID int) error {
|
func (api *inwxAPI) deleteRecord(RecordID string) error {
|
||||||
return api.client.Nameservers.DeleteRecord(RecordID)
|
return api.client.Nameservers.DeleteRecord(RecordID)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -244,7 +246,8 @@ func (api *inwxAPI) AutoDnssecToggle(dc *models.DomainConfig, corrections []*mod
|
||||||
}
|
}
|
||||||
|
|
||||||
if dnssecStatus == ManualDNSSECStatus && dc.AutoDNSSEC != "" {
|
if dnssecStatus == ManualDNSSECStatus && dc.AutoDNSSEC != "" {
|
||||||
return corrections, fmt.Errorf("INWX: Domain %s has manual DNSSEC enabled. Disable it before using AUTODNSSEC_ON/AUTODNSSEC_OFF", dc.Name)
|
return corrections, fmt.Errorf("INWX: Domain %s has manual DNSSEC enabled. Disable it before using "+
|
||||||
|
"AUTODNSSEC_ON/AUTODNSSEC_OFF", dc.Name)
|
||||||
}
|
}
|
||||||
|
|
||||||
if dnssecStatus != AutoDNSSECStatus && dc.AutoDNSSEC == "on" {
|
if dnssecStatus != AutoDNSSECStatus && dc.AutoDNSSEC == "on" {
|
||||||
|
|
@ -289,23 +292,25 @@ func (api *inwxAPI) GetZoneRecordsCorrections(dc *models.DomainConfig, foundReco
|
||||||
return nil, 0, err
|
return nil, 0, err
|
||||||
}
|
}
|
||||||
for _, change := range changes {
|
for _, change := range changes {
|
||||||
changeMsgs := change.MsgsJoined
|
changeMessage := change.MsgsJoined
|
||||||
switch change.Type {
|
switch change.Type {
|
||||||
case diff2.REPORT:
|
case diff2.REPORT:
|
||||||
corrections = append(corrections, &models.Correction{Msg: changeMsgs})
|
corrections = append(corrections, &models.Correction{Msg: changeMessage})
|
||||||
case diff2.CHANGE:
|
case diff2.CHANGE:
|
||||||
oldRec := change.Old[0]
|
oldRec := change.Old[0]
|
||||||
newRec := change.New[0]
|
newRec := change.New[0]
|
||||||
if isNullMX(newRec) || isNullMX(oldRec) {
|
if isNullMX(newRec) || isNullMX(oldRec) {
|
||||||
// changing to or from a Null MX has to be delete then create
|
// changing to or from a Null MX has to be deleted then create
|
||||||
deletes = append(deletes, &models.Correction{
|
deletes = append(deletes, &models.Correction{
|
||||||
Msg: color.RedString("- DELETE %s %s %s ttl=%d", oldRec.GetLabelFQDN(), oldRec.Type, oldRec.ToComparableNoTTL(), oldRec.TTL),
|
Msg: color.RedString("- DELETE %s %s %s ttl=%d", oldRec.GetLabelFQDN(), oldRec.Type,
|
||||||
|
oldRec.ToComparableNoTTL(), oldRec.TTL),
|
||||||
F: func() error {
|
F: func() error {
|
||||||
return api.deleteRecord(oldRec.Original.(goinwx.NameserverRecord).ID)
|
return api.deleteRecord(oldRec.Original.(goinwx.NameserverRecord).ID)
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
deferred = append(deferred, &models.Correction{
|
deferred = append(deferred, &models.Correction{
|
||||||
Msg: color.GreenString("+ CREATE %s %s %s ttl=%d", newRec.GetLabelFQDN(), newRec.Type, newRec.ToComparableNoTTL(), newRec.TTL),
|
Msg: color.GreenString("+ CREATE %s %s %s ttl=%d", newRec.GetLabelFQDN(), newRec.Type,
|
||||||
|
newRec.ToComparableNoTTL(), newRec.TTL),
|
||||||
F: func() error {
|
F: func() error {
|
||||||
return api.createRecord(dc.Name, newRec)
|
return api.createRecord(dc.Name, newRec)
|
||||||
},
|
},
|
||||||
|
|
@ -313,7 +318,7 @@ func (api *inwxAPI) GetZoneRecordsCorrections(dc *models.DomainConfig, foundReco
|
||||||
} else {
|
} else {
|
||||||
recID := oldRec.Original.(goinwx.NameserverRecord).ID
|
recID := oldRec.Original.(goinwx.NameserverRecord).ID
|
||||||
corrections = append(corrections, &models.Correction{
|
corrections = append(corrections, &models.Correction{
|
||||||
Msg: changeMsgs,
|
Msg: changeMessage,
|
||||||
F: func() error {
|
F: func() error {
|
||||||
return api.updateRecord(recID, newRec)
|
return api.updateRecord(recID, newRec)
|
||||||
},
|
},
|
||||||
|
|
@ -322,7 +327,7 @@ func (api *inwxAPI) GetZoneRecordsCorrections(dc *models.DomainConfig, foundReco
|
||||||
}
|
}
|
||||||
case diff2.CREATE:
|
case diff2.CREATE:
|
||||||
creates = append(creates, &models.Correction{
|
creates = append(creates, &models.Correction{
|
||||||
Msg: changeMsgs,
|
Msg: changeMessage,
|
||||||
F: func() error {
|
F: func() error {
|
||||||
return api.createRecord(dc.Name, change.New[0])
|
return api.createRecord(dc.Name, change.New[0])
|
||||||
},
|
},
|
||||||
|
|
@ -330,7 +335,7 @@ func (api *inwxAPI) GetZoneRecordsCorrections(dc *models.DomainConfig, foundReco
|
||||||
case diff2.DELETE:
|
case diff2.DELETE:
|
||||||
recID := change.Old[0].Original.(goinwx.NameserverRecord).ID
|
recID := change.Old[0].Original.(goinwx.NameserverRecord).ID
|
||||||
deletes = append(deletes, &models.Correction{
|
deletes = append(deletes, &models.Correction{
|
||||||
Msg: changeMsgs,
|
Msg: changeMessage,
|
||||||
F: func() error { return api.deleteRecord(recID) },
|
F: func() error { return api.deleteRecord(recID) },
|
||||||
})
|
})
|
||||||
default:
|
default:
|
||||||
|
|
@ -343,7 +348,7 @@ func (api *inwxAPI) GetZoneRecordsCorrections(dc *models.DomainConfig, foundReco
|
||||||
return corrections, actualChangeCount, nil
|
return corrections, actualChangeCount, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// getDefaultNameservers returns string map with default nameservers based on e.g. sandbox mode.
|
// getDefaultNameservers returns a string map with default nameservers based on e.g. sandbox mode.
|
||||||
func (api *inwxAPI) getDefaultNameservers() []string {
|
func (api *inwxAPI) getDefaultNameservers() []string {
|
||||||
if api.sandbox {
|
if api.sandbox {
|
||||||
return InwxSandboxDefaultNs
|
return InwxSandboxDefaultNs
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue