2020-04-18 01:58:44 +08:00
|
|
|
package netcup
|
|
|
|
|
|
|
|
import (
|
|
|
|
"encoding/json"
|
2025-01-10 23:43:16 +08:00
|
|
|
"errors"
|
2020-04-18 01:58:44 +08:00
|
|
|
"fmt"
|
2022-08-15 08:46:56 +08:00
|
|
|
|
2023-05-21 01:21:45 +08:00
|
|
|
"github.com/StackExchange/dnscontrol/v4/models"
|
|
|
|
"github.com/StackExchange/dnscontrol/v4/pkg/diff"
|
|
|
|
"github.com/StackExchange/dnscontrol/v4/providers"
|
2020-04-18 01:58:44 +08:00
|
|
|
)
|
|
|
|
|
|
|
|
var features = providers.DocumentationNotes{
|
2024-03-19 06:30:09 +08:00
|
|
|
// The default for unlisted capabilities is 'Cannot'.
|
|
|
|
// See providers/capabilities.go for the entire list of capabilities.
|
2022-03-03 00:19:15 +08:00
|
|
|
providers.CanGetZones: providers.Cannot(),
|
2024-03-21 00:36:54 +08:00
|
|
|
providers.CanConcur: providers.Cannot(),
|
2022-03-03 00:19:15 +08:00
|
|
|
providers.CanUseCAA: providers.Can(),
|
2023-03-17 02:04:20 +08:00
|
|
|
providers.CanUseLOC: providers.Cannot(),
|
2022-03-03 00:19:15 +08:00
|
|
|
providers.CanUsePTR: providers.Cannot(),
|
|
|
|
providers.CanUseSRV: providers.Can(),
|
2020-04-18 01:58:44 +08:00
|
|
|
providers.DocCreateDomains: providers.Cannot(),
|
|
|
|
providers.DocDualHost: providers.Cannot(),
|
|
|
|
providers.DocOfficiallySupported: providers.Cannot(),
|
|
|
|
}
|
|
|
|
|
|
|
|
func init() {
|
2024-07-11 03:53:50 +08:00
|
|
|
const providerName = "NETCUP"
|
|
|
|
const providerMaintainer = "@kordianbruck"
|
2021-03-08 02:19:22 +08:00
|
|
|
fns := providers.DspFuncs{
|
2021-05-05 02:15:31 +08:00
|
|
|
Initializer: New,
|
2021-03-09 09:14:30 +08:00
|
|
|
RecordAuditor: AuditRecords,
|
2021-03-08 02:19:22 +08:00
|
|
|
}
|
2024-07-11 03:53:50 +08:00
|
|
|
providers.RegisterDomainServiceProviderType(providerName, fns, features)
|
|
|
|
providers.RegisterMaintainer(providerName, providerMaintainer)
|
2020-04-18 01:58:44 +08:00
|
|
|
}
|
|
|
|
|
2020-06-18 21:37:57 +08:00
|
|
|
// New creates a new API handle.
|
2020-04-18 01:58:44 +08:00
|
|
|
func New(settings map[string]string, _ json.RawMessage) (providers.DNSServiceProvider, error) {
|
|
|
|
if settings["api-key"] == "" || settings["api-password"] == "" || settings["customer-number"] == "" {
|
2025-01-10 23:43:16 +08:00
|
|
|
return nil, errors.New("missing netcup login parameters")
|
2020-04-18 01:58:44 +08:00
|
|
|
}
|
|
|
|
|
2020-10-26 21:25:30 +08:00
|
|
|
api := &netcupProvider{}
|
2020-04-18 01:58:44 +08:00
|
|
|
err := api.login(settings["api-key"], settings["api-password"], settings["customer-number"])
|
|
|
|
if err != nil {
|
2025-01-10 23:43:16 +08:00
|
|
|
return nil, fmt.Errorf("login to netcup DNS failed, please check your credentials: %w", err)
|
2020-04-18 01:58:44 +08:00
|
|
|
}
|
|
|
|
return api, nil
|
|
|
|
}
|
|
|
|
|
|
|
|
// GetZoneRecords gets the records of a zone and returns them in RecordConfig format.
|
2023-05-03 01:04:59 +08:00
|
|
|
func (api *netcupProvider) GetZoneRecords(domain string, meta map[string]string) (models.Records, error) {
|
2020-04-18 01:58:44 +08:00
|
|
|
records, err := api.getRecords(domain)
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
existingRecords := make([]*models.RecordConfig, len(records))
|
|
|
|
for i := range records {
|
|
|
|
existingRecords[i] = toRecordConfig(domain, &records[i])
|
|
|
|
}
|
2023-04-15 03:22:23 +08:00
|
|
|
|
2020-04-18 01:58:44 +08:00
|
|
|
return existingRecords, nil
|
|
|
|
}
|
|
|
|
|
|
|
|
// GetNameservers returns the nameservers for a domain.
|
|
|
|
// As netcup doesn't support setting nameservers over this API, these are static.
|
|
|
|
// Domains not managed by netcup DNS will return an error
|
2020-10-26 21:25:30 +08:00
|
|
|
func (api *netcupProvider) GetNameservers(domain string) ([]*models.Nameserver, error) {
|
2020-04-18 01:58:44 +08:00
|
|
|
return models.ToNameservers([]string{
|
|
|
|
"root-dns.netcup.net",
|
|
|
|
"second-dns.netcup.net",
|
|
|
|
"third-dns.netcup.net",
|
|
|
|
})
|
|
|
|
}
|
|
|
|
|
2023-04-15 03:22:23 +08:00
|
|
|
// GetZoneRecordsCorrections returns a list of corrections that will turn existing records into dc.Records.
|
2024-09-17 00:20:30 +08:00
|
|
|
func (api *netcupProvider) GetZoneRecordsCorrections(dc *models.DomainConfig, existingRecords models.Records) ([]*models.Correction, int, error) {
|
2020-04-18 01:58:44 +08:00
|
|
|
domain := dc.Name
|
|
|
|
|
|
|
|
// Setting the TTL is not supported for netcup
|
|
|
|
for _, r := range dc.Records {
|
|
|
|
r.TTL = 0
|
|
|
|
}
|
|
|
|
|
|
|
|
// Filter out types we can't modify (like NS)
|
|
|
|
newRecords := models.Records{}
|
|
|
|
for _, r := range dc.Records {
|
|
|
|
if r.Type != "NS" {
|
|
|
|
newRecords = append(newRecords, r)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
dc.Records = newRecords
|
|
|
|
|
2024-09-17 00:20:30 +08:00
|
|
|
toReport, create, del, modify, actualChangeCount, err := diff.NewCompat(dc).IncrementalDiff(existingRecords)
|
2023-01-19 01:34:45 +08:00
|
|
|
if err != nil {
|
2024-09-17 00:20:30 +08:00
|
|
|
return nil, 0, err
|
2023-01-19 01:34:45 +08:00
|
|
|
}
|
2023-10-23 01:56:13 +08:00
|
|
|
// Start corrections with the reports
|
|
|
|
corrections := diff.GenerateMessageCorrections(toReport)
|
2020-04-18 01:58:44 +08:00
|
|
|
|
2023-01-19 01:34:45 +08:00
|
|
|
// Deletes first so changing type works etc.
|
|
|
|
for _, m := range del {
|
|
|
|
req := m.Existing.Original.(*record)
|
|
|
|
corr := &models.Correction{
|
|
|
|
Msg: fmt.Sprintf("%s, Netcup ID: %s", m.String(), req.ID),
|
|
|
|
F: func() error {
|
|
|
|
return api.deleteRecord(domain, req)
|
|
|
|
},
|
2020-04-18 01:58:44 +08:00
|
|
|
}
|
2023-01-19 01:34:45 +08:00
|
|
|
corrections = append(corrections, corr)
|
|
|
|
}
|
2022-12-12 04:02:58 +08:00
|
|
|
|
2023-01-19 01:34:45 +08:00
|
|
|
for _, m := range create {
|
|
|
|
req := fromRecordConfig(m.Desired)
|
|
|
|
corr := &models.Correction{
|
|
|
|
Msg: m.String(),
|
|
|
|
F: func() error {
|
|
|
|
return api.createRecord(domain, req)
|
|
|
|
},
|
2022-12-12 04:02:58 +08:00
|
|
|
}
|
2023-01-19 01:34:45 +08:00
|
|
|
corrections = append(corrections, corr)
|
|
|
|
}
|
|
|
|
for _, m := range modify {
|
|
|
|
id := m.Existing.Original.(*record).ID
|
|
|
|
req := fromRecordConfig(m.Desired)
|
|
|
|
req.ID = id
|
|
|
|
corr := &models.Correction{
|
|
|
|
Msg: fmt.Sprintf("%s, Netcup ID: %s: ", m.String(), id),
|
|
|
|
F: func() error {
|
|
|
|
return api.modifyRecord(domain, req)
|
|
|
|
},
|
2020-04-18 01:58:44 +08:00
|
|
|
}
|
2023-01-19 01:34:45 +08:00
|
|
|
corrections = append(corrections, corr)
|
2020-04-18 01:58:44 +08:00
|
|
|
}
|
|
|
|
|
2024-09-17 00:20:30 +08:00
|
|
|
return corrections, actualChangeCount, nil
|
2020-04-18 01:58:44 +08:00
|
|
|
}
|