mirror of
https://github.com/StackExchange/dnscontrol.git
synced 2024-09-20 06:46:19 +08:00
NEW PROVIDER: Mythic Beasts DNS (#2528)
Co-authored-by: Tom Limoncelli <tlimoncelli@stackoverflow.com>
This commit is contained in:
parent
c69bd43678
commit
541679386b
|
@ -33,7 +33,7 @@ changelog:
|
|||
regexp: "(?i)^.*(major|new provider|feature)[(\\w)]*:+.*$"
|
||||
order: 1
|
||||
- title: 'Provider-specific changes:'
|
||||
regexp: "(?i)((akamaiedge|autodns|axfrd|azure|bind|cloudflare|cloudflareapi_old|cloudns|cscglobal|desec|digitalocean|dnsimple|dnsmadeeasy|doh|domainnameshop|easyname|exoscale|gandi|gcloud|gcore|hedns|hetzner|hexonet|hostingde|inwx|linode|loopia|luadns|msdns|namecheap|namedotcom|netcup|netlify|ns1|opensrs|oracle|ovh|packetframe|porkbun|powerdns|route53|rwth|softlayer|transip|vultr).*:)+.*"
|
||||
regexp: "(?i)((akamaiedge|autodns|axfrd|azure|bind|cloudflare|cloudflareapi_old|cloudns|cscglobal|desec|digitalocean|dnsimple|dnsmadeeasy|doh|domainnameshop|easyname|exoscale|gandi|gcloud|gcore|hedns|hetzner|hexonet|hostingde|inwx|linode|loopia|luadns|msdns|mythicbeasts|namecheap|namedotcom|netcup|netlify|ns1|opensrs|oracle|ovh|packetframe|porkbun|powerdns|route53|rwth|softlayer|transip|vultr).*:)+.*"
|
||||
order: 2
|
||||
- title: 'Deprecation warnings:'
|
||||
regexp: "(?i)^.*Deprecate[(\\w)]*:+.*$"
|
||||
|
|
1
OWNERS
1
OWNERS
|
@ -27,6 +27,7 @@ providers/linode @koesie10
|
|||
providers/loopia @systemcrash
|
||||
providers/luadns @riku22
|
||||
providers/msdns @tlimoncelli
|
||||
providers/mythicbeasts @tomfitzhenry
|
||||
providers/namecheap @willpower232
|
||||
# providers/namedotcom NEEDS VOLUNTEER
|
||||
providers/netcup @kordianbruck
|
||||
|
|
|
@ -42,6 +42,7 @@ Currently supported DNS providers:
|
|||
- Loopia
|
||||
- LuaDNS
|
||||
- Microsoft Windows Server DNS Server
|
||||
- Mythic Beasts
|
||||
- Namecheap
|
||||
- Name.com
|
||||
- Netcup
|
||||
|
|
|
@ -124,6 +124,7 @@
|
|||
* [Loopia](providers/loopia.md)
|
||||
* [LuaDNS](providers/luadns.md)
|
||||
* [Microsoft DNS Server on Microsoft Windows Server](providers/msdns.md)
|
||||
* [Mythic Beasts](providers/mythicbeasts.md)
|
||||
* [Namecheap](providers/namecheap.md)
|
||||
* [Name.com](providers/namedotcom.md)
|
||||
* [Netcup](providers/netcup.md)
|
||||
|
|
|
@ -43,6 +43,7 @@ If a feature is definitively not supported for whatever reason, we would also li
|
|||
| [`LOOPIA`](providers/loopia.md) | ❌ | ✅ | ✅ | ❌ | ✅ | ❌ | ✅ | ✅ | ❌ | ❌ | ✅ | ✅ | ✅ | ❌ | ✅ | ❌ | ✅ | ✅ |
|
||||
| [`LUADNS`](providers/luadns.md) | ❌ | ✅ | ❌ | ✅ | ✅ | ❔ | ❌ | ❔ | ✅ | ❔ | ✅ | ✅ | ✅ | ❔ | ✅ | ✅ | ✅ | ✅ |
|
||||
| [`MSDNS`](providers/msdns.md) | ✅ | ✅ | ❌ | ❌ | ❌ | ❔ | ❌ | ✅ | ✅ | ❔ | ✅ | ❔ | ❔ | ❔ | ❌ | ❌ | ✅ | ✅ |
|
||||
| [`MYTHICBEASTS`](providers/mythicbeasts.md) | ❌ | ✅ | ❌ | ❌ | ✅ | ❔ | ❌ | ❔ | ✅ | ❔ | ✅ | ❔ | ✅ | ❔ | ✅ | ❌ | ✅ | ✅ |
|
||||
| [`NAMECHEAP`](providers/namecheap.md) | ❌ | ✅ | ✅ | ✅ | ✅ | ❔ | ❌ | ❔ | ❌ | ❔ | ❌ | ❔ | ❌ | ❔ | ❌ | ❌ | ❌ | ✅ |
|
||||
| [`NAMEDOTCOM`](providers/namedotcom.md) | ❌ | ✅ | ✅ | ✅ | ❔ | ❔ | ❌ | ❔ | ❌ | ❔ | ✅ | ❔ | ❔ | ❔ | ✅ | ❌ | ✅ | ✅ |
|
||||
| [`NETCUP`](providers/netcup.md) | ❌ | ✅ | ❌ | ❔ | ✅ | ❔ | ❌ | ❔ | ❌ | ❔ | ✅ | ❔ | ❔ | ❔ | ❌ | ❌ | ✅ | ❌ |
|
||||
|
|
39
documentation/providers/mythicbeasts.md
Normal file
39
documentation/providers/mythicbeasts.md
Normal file
|
@ -0,0 +1,39 @@
|
|||
This is the provider for [Mythic Beasts](https://www.mythic-beasts.com/) using its [Primary DNS API v2](https://www.mythic-beasts.com/support/api/dnsv2).
|
||||
|
||||
## Configuration
|
||||
|
||||
To use this provider, add an entry to `creds.json` with `TYPE` set to `MYTHICBEASTS` along with a Mythic Beasts API key ID and secret.
|
||||
|
||||
Example:
|
||||
|
||||
{% code title="creds.json" %}
|
||||
```json
|
||||
{
|
||||
"mythicbeasts": {
|
||||
"TYPE": "MYTHICBEASTS",
|
||||
"keyID": "xxxxxxx",
|
||||
"secret": "xxxxxx"
|
||||
}
|
||||
}
|
||||
```
|
||||
{% endcode %}
|
||||
|
||||
## Usage
|
||||
|
||||
For each domain:
|
||||
|
||||
* Domains must be added in the [web UI](https://www.mythic-beasts.com/customer/domains), and have DNS enabled.
|
||||
* In Mythic Beasts' DNS management web UI, new domains will have set a default DNS template of "Mythic Beasts nameservers only". You must set this to "None".
|
||||
|
||||
An example configuration:
|
||||
|
||||
{% code title="dnsconfig.js" %}
|
||||
```javascript
|
||||
var REG_NONE = NewRegistrar("none");
|
||||
var DSP_MYTHIC = NewDnsProvider("mythicbeasts");
|
||||
|
||||
D("example.com", REG_NONE, DnsProvider(DSP_MYTHIC),
|
||||
A("test", "1.2.3.4")
|
||||
);
|
||||
```
|
||||
{% endcode %}
|
|
@ -179,6 +179,12 @@
|
|||
"domain": "$MSDNS_DOMAIN",
|
||||
"pssession": "$MSDNS_PSSESSION"
|
||||
},
|
||||
"MYTHICBEASTS": {
|
||||
"TYPE": "MYTHICBEASTS",
|
||||
"keyID": "$MYTHICBEASTS_KEYID",
|
||||
"secret": "$MYTHICBEASTS_SECRET",
|
||||
"domain": "$MYTHICBEASTS_DOMAIN"
|
||||
},
|
||||
"NAMECHEAP": {
|
||||
"BaseURL": "$NAMECHEAP_BASEURL",
|
||||
"TYPE": "NAMECHEAP",
|
||||
|
|
|
@ -32,6 +32,7 @@ import (
|
|||
_ "github.com/StackExchange/dnscontrol/v4/providers/loopia"
|
||||
_ "github.com/StackExchange/dnscontrol/v4/providers/luadns"
|
||||
_ "github.com/StackExchange/dnscontrol/v4/providers/msdns"
|
||||
_ "github.com/StackExchange/dnscontrol/v4/providers/mythicbeasts"
|
||||
_ "github.com/StackExchange/dnscontrol/v4/providers/namecheap"
|
||||
_ "github.com/StackExchange/dnscontrol/v4/providers/namedotcom"
|
||||
_ "github.com/StackExchange/dnscontrol/v4/providers/netcup"
|
||||
|
|
15
providers/mythicbeasts/auditrecords.go
Normal file
15
providers/mythicbeasts/auditrecords.go
Normal file
|
@ -0,0 +1,15 @@
|
|||
package mythicbeasts
|
||||
|
||||
import (
|
||||
"github.com/StackExchange/dnscontrol/v4/models"
|
||||
"github.com/StackExchange/dnscontrol/v4/pkg/rejectif"
|
||||
)
|
||||
|
||||
// AuditRecords returns a list of errors corresponding to the records
|
||||
// that aren't supported by this provider. If all records are
|
||||
// supported, an empty list is returned.
|
||||
func AuditRecords(records []*models.RecordConfig) []error {
|
||||
a := rejectif.Auditor{}
|
||||
a.Add("TXT", rejectif.TxtHasDoubleQuotes)
|
||||
return nil
|
||||
}
|
147
providers/mythicbeasts/mythicbeastsProvider.go
Normal file
147
providers/mythicbeasts/mythicbeastsProvider.go
Normal file
|
@ -0,0 +1,147 @@
|
|||
// Package mythicbeasts provides a provider for managing zones in Mythic Beasts.
|
||||
//
|
||||
// This package uses the Primary DNS API v2, as described in https://www.mythic-beasts.com/support/api/dnsv2
|
||||
package mythicbeasts
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
"net/http"
|
||||
"strings"
|
||||
|
||||
"github.com/StackExchange/dnscontrol/v4/models"
|
||||
"github.com/StackExchange/dnscontrol/v4/pkg/diff2"
|
||||
"github.com/StackExchange/dnscontrol/v4/providers"
|
||||
"github.com/miekg/dns"
|
||||
)
|
||||
|
||||
// mythicBeastsDefaultNS lists the default nameservers, per https://www.mythic-beasts.com/support/domains/nameservers.
|
||||
var mythicBeastsDefaultNS = []string{
|
||||
"ns1.mythic-beasts.com",
|
||||
"ns2.mythic-beasts.com",
|
||||
}
|
||||
|
||||
// mythicBeastsProvider is the handle for this provider.
|
||||
type mythicBeastsProvider struct {
|
||||
secret string
|
||||
keyID string
|
||||
client *http.Client
|
||||
}
|
||||
|
||||
var features = providers.DocumentationNotes{
|
||||
providers.CanGetZones: providers.Can(),
|
||||
providers.CanUseAlias: providers.Cannot(),
|
||||
providers.CanUseCAA: providers.Can(),
|
||||
providers.CanUseLOC: providers.Cannot(),
|
||||
providers.CanUsePTR: providers.Can(),
|
||||
providers.CanUseSRV: providers.Can(),
|
||||
providers.CanUseTLSA: providers.Can(),
|
||||
providers.DocCreateDomains: providers.Cannot("Requires domain registered through Web UI"),
|
||||
providers.DocDualHost: providers.Can(),
|
||||
providers.DocOfficiallySupported: providers.Cannot(),
|
||||
}
|
||||
|
||||
func init() {
|
||||
fns := providers.DspFuncs{
|
||||
Initializer: newDsp,
|
||||
RecordAuditor: AuditRecords,
|
||||
}
|
||||
providers.RegisterDomainServiceProviderType("MYTHICBEASTS", fns, features)
|
||||
}
|
||||
|
||||
func newDsp(conf map[string]string, metadata json.RawMessage) (providers.DNSServiceProvider, error) {
|
||||
if conf["keyID"] == "" {
|
||||
return nil, fmt.Errorf("missing Mythic Beasts auth keyID")
|
||||
}
|
||||
if conf["secret"] == "" {
|
||||
return nil, fmt.Errorf("missing Mythic Beasts auth secret")
|
||||
}
|
||||
return &mythicBeastsProvider{
|
||||
keyID: conf["keyID"],
|
||||
secret: conf["secret"],
|
||||
client: &http.Client{},
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (n *mythicBeastsProvider) httpRequest(method, url string, body io.Reader) (*http.Response, error) {
|
||||
req, err := http.NewRequest(method, "https://api.mythic-beasts.com/dns/v2"+url, body)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
// https://www.mythic-beasts.com/support/api/auth
|
||||
req.SetBasicAuth(n.keyID, n.secret)
|
||||
req.Header.Add("Content-Type", "text/dns")
|
||||
req.Header.Add("Accept", "text/dns")
|
||||
return n.client.Do(req)
|
||||
}
|
||||
|
||||
// GetZoneRecords gets the records of a zone and returns them in RecordConfig format.
|
||||
func (n *mythicBeastsProvider) GetZoneRecords(domain string, meta map[string]string) (models.Records, error) {
|
||||
resp, err := n.httpRequest("GET", "/zones/"+domain+"/records", nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if got, want := resp.StatusCode, 200; got != want {
|
||||
body, _ := ioutil.ReadAll(resp.Body)
|
||||
return nil, fmt.Errorf("got HTTP %v, want %v: %v", got, want, string(body))
|
||||
}
|
||||
return zoneFileToRecords(resp.Body, domain)
|
||||
}
|
||||
|
||||
func zoneFileToRecords(r io.Reader, origin string) (models.Records, error) {
|
||||
zp := dns.NewZoneParser(r, origin, origin)
|
||||
var records []*models.RecordConfig
|
||||
for rr, ok := zp.Next(); ok; rr, ok = zp.Next() {
|
||||
rec, err := models.RRtoRC(rr, origin)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
records = append(records, &rec)
|
||||
}
|
||||
|
||||
if err := zp.Err(); err != nil {
|
||||
return nil, fmt.Errorf("parsing zone for %v: %w", origin, err)
|
||||
}
|
||||
return records, nil
|
||||
}
|
||||
|
||||
// GetZoneRecordsCorrections returns a list of corrections that will turn existing records into dc.Records.
|
||||
func (n *mythicBeastsProvider) GetZoneRecordsCorrections(dc *models.DomainConfig, actual models.Records) ([]*models.Correction, error) {
|
||||
msgs, changes, err := diff2.ByZone(actual, dc, nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
var corrections []*models.Correction
|
||||
if changes {
|
||||
corrections = append(corrections,
|
||||
&models.Correction{
|
||||
Msg: strings.Join(msgs, "\n"),
|
||||
F: func() error {
|
||||
var b strings.Builder
|
||||
for _, rr := range dc.Records {
|
||||
fmt.Fprintf(&b, "%v\n", rr.ToRR().String())
|
||||
}
|
||||
|
||||
resp, err := n.httpRequest("PUT", "/zones/"+dc.Name+"/records", strings.NewReader(b.String()))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if got, want := resp.StatusCode, 200; got != want {
|
||||
body, _ := ioutil.ReadAll(resp.Body)
|
||||
return fmt.Errorf("got HTTP %v, want %v: %v", got, want, string(body))
|
||||
}
|
||||
return nil
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
return corrections, nil
|
||||
}
|
||||
|
||||
// GetNameservers returns the nameservers for a domain.
|
||||
func (n *mythicBeastsProvider) GetNameservers(domainName string) ([]*models.Nameserver, error) {
|
||||
return models.ToNameservers(mythicBeastsDefaultNS)
|
||||
}
|
Loading…
Reference in a new issue