INWX: Add AutoDNSSEC support (#3534)

Co-authored-by: Tom Limoncelli <tlimoncelli@stackoverflow.com>
This commit is contained in:
Eli Heady 2025-05-03 08:23:38 -04:00 committed by GitHub
parent d0fffaf8c2
commit 1c04affe7c
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
3 changed files with 98 additions and 5 deletions

View file

@ -43,7 +43,7 @@ If a feature is definitively not supported for whatever reason, we would also li
| [`HOSTINGDE`](hostingde.md) | ❌ | ✅ | ✅ | ❔ | ✅ | ✅ | ✅ | ❔ | ❌ | ❌ | ✅ | ✅ | ✅ | ✅ | ❔ | ✅ | ✅ | ❔ | ❔ | ❔ | ✅ | ✅ | ✅ |
| [`HUAWEICLOUD`](huaweicloud.md) | ❌ | ✅ | ❌ | ❔ | ❌ | ✅ | ❔ | ❌ | ❌ | ❌ | ❌ | ❌ | ✅ | ❌ | ❌ | ❌ | ❌ | ❔ | ❔ | ❔ | ✅ | ✅ | ✅ |
| [`INTERNETBS`](internetbs.md) | ❌ | ❌ | ✅ | ❔ | ❔ | ❔ | ❔ | ❔ | ❔ | ❔ | ❔ | ❔ | ❔ | ❔ | ❔ | ❔ | ❔ | ❔ | ❔ | ❔ | ❔ | ❌ | ❔ |
| [`INWX`](inwx.md) | ❌ | ✅ | ✅ | ❔ | ❌ | ✅ | | ✅ | ❔ | ✅ | ✅ | ❔ | ✅ | ✅ | ✅ | ✅ | ❔ | ❔ | ❔ | ❔ | ✅ | ✅ | ✅ |
| [`INWX`](inwx.md) | ❌ | ✅ | ✅ | ❔ | ❌ | ✅ | | ✅ | ❔ | ✅ | ✅ | ❔ | ✅ | ✅ | ✅ | ✅ | ❔ | ❔ | ❔ | ❔ | ✅ | ✅ | ✅ |
| [`LINODE`](linode.md) | ❌ | ✅ | ❌ | ❔ | ❔ | ✅ | ❔ | ❔ | ❌ | ❔ | ❔ | ❔ | ❔ | ❔ | ❔ | ❔ | ❔ | ❔ | ❔ | ❔ | ❌ | ❌ | ✅ |
| [`LOOPIA`](loopia.md) | ❌ | ✅ | ✅ | ❔ | ❌ | ✅ | ❌ | ❔ | ✅ | ✅ | ❌ | ❌ | ✅ | ✅ | ❔ | ✅ | ❌ | ❔ | ❔ | ❔ | ✅ | ❌ | ✅ |
| [`LUADNS`](luadns.md) | ❌ | ✅ | ❌ | ❔ | ✅ | ✅ | ❔ | ❔ | ❌ | ❔ | ✅ | ❔ | ✅ | ✅ | ❔ | ✅ | ❔ | ❔ | ❔ | ❔ | ✅ | ✅ | ✅ |

55
providers/inwx/dnssec.go Normal file
View file

@ -0,0 +1,55 @@
package inwx
import (
"golang.org/x/net/idna"
)
const (
// https://www.inwx.com/en/help/apidoc/f/ch03.html#type.dnssecdomainstatus
// claims status values can be 'DELETE_ALL', 'MANUAL', 'UPDATE', but
// testing shows 'AUTO' is what to expect if the domain has automatic
// DNSSEC enabled.
// AutoDNSSEC is the status for DNSSEC enabled with automatic management
AutoDNSSECStatus = "AUTO"
// ManualDNSSEC is the status for DNSSEC enabled with manual management
ManualDNSSECStatus = "MANUAL"
)
// DNSSecStatus returns domain dnssec status
func (api *inwxAPI) DNSSecStatus(domain string) (string, error) {
resp, err := api.client.Dnssec.Info([]string{domain})
if err != nil {
return "", err
}
// domain has no DNSSEC configuration
if len(resp.Data) == 0 {
return "", nil
}
return resp.Data[0].DNSSecStatus, nil
}
// enableAutoDNSSEC enables automatic management of DNSSEC
func (api *inwxAPI) enableAutoDNSSEC(domain string) error {
// if the domain is IDN, it must be in Unicode - ACE encoding is not supported
// in the INWX dnssec.enablednssec endpoint
domain, err := idna.ToUnicode(domain)
if err != nil {
return err
}
err = api.client.Dnssec.Enable(domain)
return err
}
// disableAutoDNSSEC disables automatic management of DNSSEC
func (api *inwxAPI) disableAutoDNSSEC(domain string) error {
err := api.client.Dnssec.Disable(domain)
return err
}

View file

@ -47,7 +47,7 @@ var InwxSandboxDefaultNs = []string{"ns.ote.inwx.de", "ns2.ote.inwx.de"}
var features = providers.DocumentationNotes{
// The default for unlisted capabilities is 'Cannot'.
// See providers/capabilities.go for the entire list of capabilities.
providers.CanAutoDNSSEC: providers.Unimplemented("Supported by INWX but not implemented yet."),
providers.CanAutoDNSSEC: providers.Can(),
providers.CanGetZones: providers.Can(),
providers.CanConcur: providers.Unimplemented(),
providers.CanUseAlias: providers.Cannot("INWX does not support the ALIAS or ANAME record type."),
@ -252,7 +252,7 @@ func isNullMX(rec *models.RecordConfig) bool {
}
// MXCorrections generates required delete corrections when a MX change can not be applied in an updateRecord call.
func (api *inwxAPI) MXCorrections(dc *models.DomainConfig, foundRecords models.Records) ([]*models.Correction, models.Records, error) {
func (api *inwxAPI) MXCorrections(dc *models.DomainConfig, foundRecords models.Records, corrections []*models.Correction) ([]*models.Correction, models.Records, error) {
// If a null MX is present in the zone, we have to take special care of any
// planned MX changes: No non-null MX records can be added until the null
@ -261,7 +261,6 @@ func (api *inwxAPI) MXCorrections(dc *models.DomainConfig, foundRecords models.R
// MX record because an update would be rejected with "2308 Data management policy violation"
removals := make(map[string]struct{})
corrections := []*models.Correction{}
tempRecords := []*models.RecordConfig{}
// Detect Null MX in foundRecords
@ -334,10 +333,49 @@ func (api *inwxAPI) MXCorrections(dc *models.DomainConfig, foundRecords models.R
return corrections, cleanedRecords, nil
}
// AutoDnssecToggle enables and disables AutoDNSSEC for INWX domains.
func (api *inwxAPI) AutoDnssecToggle(dc *models.DomainConfig, corrections []*models.Correction) ([]*models.Correction, error) {
dnssecStatus, err := api.DNSSecStatus(dc.Name)
if err != nil {
return corrections, err
}
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)
}
if dnssecStatus != AutoDNSSECStatus && dc.AutoDNSSEC == "on" {
corrections = append(corrections, &models.Correction{
Msg: color.YellowString("Enable AutoDNSSEC"),
F: func() error {
return api.enableAutoDNSSEC(dc.Name)
},
})
}
if dnssecStatus == AutoDNSSECStatus && dc.AutoDNSSEC == "off" {
corrections = append(corrections, &models.Correction{
Msg: color.RedString("Disable AutoDNSSEC"),
F: func() error {
return api.disableAutoDNSSEC(dc.Name)
},
})
}
return corrections, nil
}
// GetZoneRecordsCorrections returns a list of corrections that will turn existing records into dc.Records.
func (api *inwxAPI) GetZoneRecordsCorrections(dc *models.DomainConfig, foundRecords models.Records) ([]*models.Correction, int, error) {
corrections, records, err := api.MXCorrections(dc, foundRecords)
corrections := []*models.Correction{}
corrections, records, err := api.MXCorrections(dc, foundRecords, corrections)
if err != nil {
return nil, 0, err
}
corrections, err = api.AutoDnssecToggle(dc, corrections)
if err != nil {
return nil, 0, err
}