mirror of
https://github.com/StackExchange/dnscontrol.git
synced 2025-01-10 17:38:13 +08:00
NEW PROVIDER: ClouDNS (#578)
* ClouDNS: first version of provider * ClouDNS: documentation * ClouDNS: code cleanup * ClouDNS: GetNameservers now uses ClouDNS API to fetch NS servers list * ClouDNS: CAA support * ClouDNS: TLSA support * ClouDNS: tests credentials now use variables instead of hardcoded values * ClouDNS: SSHFP support * ClouDNS: export only necessary methods
This commit is contained in:
parent
16d0043cce
commit
253cd07154
8 changed files with 557 additions and 0 deletions
1
OWNERS
1
OWNERS
|
@ -2,6 +2,7 @@
|
|||
providers/azuredns @vatsalyagoel
|
||||
providers/bind @tlimoncelli
|
||||
# providers/cloudflare
|
||||
providers/cloudns @pragmaton
|
||||
providers/digitalocean @Deraen
|
||||
providers/dnsimple @aeden
|
||||
providers/gandi @TomOnTime
|
||||
|
|
|
@ -17,6 +17,7 @@ Currently supported DNS providers:
|
|||
- Azure DNS
|
||||
- BIND
|
||||
- Cloudflare
|
||||
- ClouDNS
|
||||
- DigitalOcean
|
||||
- DNSimple
|
||||
- Exoscale
|
||||
|
|
58
docs/_providers/cloudns.md
Normal file
58
docs/_providers/cloudns.md
Normal file
|
@ -0,0 +1,58 @@
|
|||
---
|
||||
name: ClouDNS
|
||||
title: ClouDNS Provider
|
||||
layout: default
|
||||
jsId: CLOUDNS
|
||||
---
|
||||
# ClouDNS Provider
|
||||
|
||||
## Configuration
|
||||
In your credentials file, you must provide your [Api user ID and password](https://asia.cloudns.net/wiki/article/42/).
|
||||
|
||||
Current version of provider doesn't support `sub-auth-id` or `sub-auth-user`.
|
||||
|
||||
{% highlight json %}
|
||||
{
|
||||
"cloudns": {
|
||||
"auth-id": "12345",
|
||||
"auth-password": "your-password"
|
||||
}
|
||||
}
|
||||
{% endhighlight %}
|
||||
|
||||
## Metadata
|
||||
This provider does not recognize any special metadata fields unique to ClouDNS.
|
||||
|
||||
## Usage
|
||||
Example Javascript:
|
||||
|
||||
{% highlight js %}
|
||||
var REG_NONE = NewRegistrar('none', 'NONE')
|
||||
var CLOUDNS = NewDnsProvider("cloudns", "CLOUDNS");
|
||||
|
||||
D("example.tld", REG_NONE, DnsProvider(CLOUDNS),
|
||||
A("test","1.2.3.4")
|
||||
);
|
||||
{%endhighlight%}
|
||||
|
||||
## Activation
|
||||
[Create Auth ID](https://asia.cloudns.net/api-settings/). Only paid account can use API
|
||||
|
||||
## Caveats
|
||||
ClouDNS does not allow all TTLs, but only a specific subset of TTLs. The following [TTLs are supported](https://asia.cloudns.net/wiki/article/188/):
|
||||
- 60 (1 minute)
|
||||
- 300 (5 minutes)
|
||||
- 900 (15 minutes)
|
||||
- 1800 (30 minutes)
|
||||
- 3600 (1 hour)
|
||||
- 21600 (6 hours)
|
||||
- 43200 (12 hours)
|
||||
- 86400 (1 day)
|
||||
- 172800 (2 days)
|
||||
- 259200 (3 days)
|
||||
- 604800 (1 week)
|
||||
- 1209600 (2 weeks)
|
||||
- 2419200 (4 weeks)
|
||||
|
||||
The provider will automatically round up your TTL to one of these values. For example, 350 seconds would become 900
|
||||
seconds, but 300 seconds would stay 300 seconds.
|
|
@ -61,6 +61,7 @@ provided to help community members support their code independently.
|
|||
|
||||
Maintainers of contributed providers:
|
||||
|
||||
* ClouDNS @pragmaton
|
||||
* digital ocean @Deraen
|
||||
* dnsimple @aeden
|
||||
* gandi @TomOnTime
|
||||
|
|
|
@ -15,6 +15,13 @@
|
|||
"BIND": {
|
||||
"domain": "example.com"
|
||||
},
|
||||
"CLOUDNS": {
|
||||
"auth-id": "$CLOUDNS_AUTH_ID",
|
||||
"auth-password": "$CLOUDNS_AUTH_PASSWORD",
|
||||
"domain": "$CLOUDNS_DOMAIN",
|
||||
"knownFailures": "53"
|
||||
},
|
||||
|
||||
"CLOUDFLAREAPI_OLD": {
|
||||
"apikey": "$CF_KEY",
|
||||
"apiuser": "$CF_USER",
|
||||
|
|
|
@ -7,6 +7,7 @@ import (
|
|||
_ "github.com/StackExchange/dnscontrol/providers/azuredns"
|
||||
_ "github.com/StackExchange/dnscontrol/providers/bind"
|
||||
_ "github.com/StackExchange/dnscontrol/providers/cloudflare"
|
||||
_ "github.com/StackExchange/dnscontrol/providers/cloudns"
|
||||
_ "github.com/StackExchange/dnscontrol/providers/digitalocean"
|
||||
_ "github.com/StackExchange/dnscontrol/providers/dnsimple"
|
||||
_ "github.com/StackExchange/dnscontrol/providers/exoscale"
|
||||
|
|
235
providers/cloudns/api.go
Normal file
235
providers/cloudns/api.go
Normal file
|
@ -0,0 +1,235 @@
|
|||
package cloudns
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"github.com/pkg/errors"
|
||||
"io/ioutil"
|
||||
"net/http"
|
||||
"strconv"
|
||||
)
|
||||
|
||||
// Api layer for CloDNS
|
||||
type api struct {
|
||||
domainIndex map[string]string
|
||||
nameserversNames []string
|
||||
creds struct {
|
||||
id string
|
||||
password string
|
||||
}
|
||||
}
|
||||
|
||||
type requestParams map[string]string
|
||||
|
||||
type errorResponse struct {
|
||||
Status string `json:"status"`
|
||||
Description string `json:"statusDescription"`
|
||||
}
|
||||
|
||||
type nameserverRecord struct {
|
||||
Type string `json:"type"`
|
||||
Name string `json:"name"`
|
||||
}
|
||||
|
||||
type nameserverResponse []nameserverRecord
|
||||
|
||||
type zoneRecord struct {
|
||||
Name string `json:"name"`
|
||||
Type string `json:"type"`
|
||||
Status string `json:"status"`
|
||||
Zone string `json:"zone"`
|
||||
}
|
||||
|
||||
type zoneResponse []zoneRecord
|
||||
|
||||
type domainRecord struct {
|
||||
ID string `json:"id"`
|
||||
Type string `json:"type"`
|
||||
Host string `json:"host"`
|
||||
Target string `json:"record"`
|
||||
Priority string `json:"priority"`
|
||||
Weight string `json:"weight"`
|
||||
Port string `json:"port"`
|
||||
Service string `json:"service"`
|
||||
Protocol string `json:"protocol"`
|
||||
TTL string `json:"ttl"`
|
||||
Status int8 `json:"status"`
|
||||
CaaFlag string `json:"caa_flag,omitempty"`
|
||||
CaaTag string `json:"caa_type,omitempty"`
|
||||
CaaValue string `json:"caa_value,omitempty"`
|
||||
TlsaUsage string `json:"tlsa_usage,omitempty"`
|
||||
TlsaSelector string `json:"tlsa_selector,omitempty"`
|
||||
TlsaMatchingType string `json:"tlsa_matching_type,omitempty"`
|
||||
SshfpAlgorithm string `json:"algorithm,omitempty"`
|
||||
SshfpFingerprint string `json:"fp_type,omitempty"`
|
||||
}
|
||||
|
||||
type recordResponse map[string]domainRecord
|
||||
|
||||
var allowedTTLValues = []uint32{
|
||||
60, // 1 minute
|
||||
300, // 5 minutes
|
||||
900, // 15 minutes
|
||||
1800, // 30 minutes
|
||||
3600, // 1 hour
|
||||
21600, // 6 hours
|
||||
43200, // 12 hours
|
||||
86400, // 1 day
|
||||
172800, // 2 days
|
||||
259200, // 3 days
|
||||
604800, // 1 week
|
||||
1209600, // 2 weeks
|
||||
2419200, // 4 weeks
|
||||
}
|
||||
|
||||
func (c *api) fetchAvailableNameservers() error {
|
||||
c.nameserversNames = nil
|
||||
|
||||
var bodyString, err = c.get("/dns/available-name-servers.json", requestParams{})
|
||||
if err != nil {
|
||||
return errors.Errorf("Error fetching available nameservers list from ClouDNS: %s", err)
|
||||
}
|
||||
|
||||
var nr nameserverResponse
|
||||
json.Unmarshal(bodyString, &nr)
|
||||
|
||||
for _, nameserver := range nr {
|
||||
if nameserver.Type == "premium" {
|
||||
c.nameserversNames = append(c.nameserversNames, nameserver.Name)
|
||||
}
|
||||
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (c *api) fetchDomainList() error {
|
||||
c.domainIndex = map[string]string{}
|
||||
rowsPerPage := 100
|
||||
page := 1
|
||||
for {
|
||||
var dr zoneResponse
|
||||
params := requestParams{
|
||||
"page": strconv.Itoa(page),
|
||||
"rows-per-page": strconv.Itoa(rowsPerPage),
|
||||
}
|
||||
endpoint := "/dns/list-zones.json"
|
||||
var bodyString, err = c.get(endpoint, params)
|
||||
if err != nil {
|
||||
return errors.Errorf("Error fetching domain list from ClouDNS: %s", err)
|
||||
}
|
||||
json.Unmarshal(bodyString, &dr)
|
||||
|
||||
for _, domain := range dr {
|
||||
c.domainIndex[domain.Name] = domain.Name
|
||||
}
|
||||
if len(dr) < rowsPerPage {
|
||||
break
|
||||
}
|
||||
page++
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (c *api) createDomain(domain string) error {
|
||||
params := requestParams{
|
||||
"domain-name": domain,
|
||||
"zone-type": "master",
|
||||
}
|
||||
if _, err := c.get("/dns/register.json", params); err != nil {
|
||||
return errors.Errorf("Error create domain ClouDNS: %s", err)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (c *api) createRecord(domainID string, rec requestParams) error {
|
||||
rec["domain-name"] = domainID
|
||||
if _, err := c.get("/dns/add-record.json", rec); err != nil {
|
||||
return errors.Errorf("Error create record ClouDNS: %s", err)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (c *api) deleteRecord(domainID string, recordID string) error {
|
||||
params := requestParams{
|
||||
"domain-name": domainID,
|
||||
"record-id": recordID,
|
||||
}
|
||||
if _, err := c.get("/dns/delete-record.json", params); err != nil {
|
||||
return errors.Errorf("Error delete record ClouDNS: %s", err)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (c *api) modifyRecord(domainID string, recordID string, rec requestParams) error {
|
||||
rec["domain-name"] = domainID
|
||||
rec["record-id"] = recordID
|
||||
if _, err := c.get("/dns/mod-record.json", rec); err != nil {
|
||||
return errors.Errorf("Error create update ClouDNS: %s", err)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (c *api) getRecords(id string) ([]domainRecord, error) {
|
||||
params := requestParams{"domain-name": id}
|
||||
|
||||
var bodyString, err = c.get("/dns/records.json", params)
|
||||
if err != nil {
|
||||
return nil, errors.Errorf("Error fetching record list from ClouDNS: %s", err)
|
||||
}
|
||||
|
||||
var dr recordResponse
|
||||
json.Unmarshal(bodyString, &dr)
|
||||
|
||||
var records []domainRecord
|
||||
for _, rec := range dr {
|
||||
records = append(records, rec)
|
||||
}
|
||||
return records, nil
|
||||
}
|
||||
|
||||
func (c *api) get(endpoint string, params requestParams) ([]byte, error) {
|
||||
client := &http.Client{}
|
||||
req, _ := http.NewRequest("GET", "https://api.cloudns.net"+endpoint, nil)
|
||||
q := req.URL.Query()
|
||||
|
||||
//TODO: Suport sub-auth-id / sub-auth-user https://asia.cloudns.net/wiki/article/42/
|
||||
// Add auth params
|
||||
q.Add("auth-id", c.creds.id)
|
||||
q.Add("auth-password", c.creds.password)
|
||||
|
||||
for pName, pValue := range params {
|
||||
q.Add(pName, pValue)
|
||||
}
|
||||
|
||||
req.URL.RawQuery = q.Encode()
|
||||
|
||||
resp, err := client.Do(req)
|
||||
if err != nil {
|
||||
return []byte{}, err
|
||||
}
|
||||
|
||||
bodyString, _ := ioutil.ReadAll(resp.Body)
|
||||
|
||||
// Got error from API ?
|
||||
var errResp errorResponse
|
||||
err = json.Unmarshal(bodyString, &errResp)
|
||||
if errResp.Status == "Failed" {
|
||||
return bodyString, errors.Errorf("ClouDNS API error: %s URL:%s%s ", errResp.Description, req.Host, req.URL.RequestURI())
|
||||
}
|
||||
|
||||
return bodyString, nil
|
||||
}
|
||||
|
||||
func fixTTL(ttl uint32) uint32 {
|
||||
// if the TTL is larger than the largest allowed value, return the largest allowed value
|
||||
if ttl > allowedTTLValues[len(allowedTTLValues)-1] {
|
||||
return allowedTTLValues[len(allowedTTLValues)-1]
|
||||
}
|
||||
|
||||
for _, v := range allowedTTLValues {
|
||||
if v >= ttl {
|
||||
return v
|
||||
}
|
||||
}
|
||||
|
||||
return allowedTTLValues[0]
|
||||
}
|
253
providers/cloudns/cloudnsProvider.go
Normal file
253
providers/cloudns/cloudnsProvider.go
Normal file
|
@ -0,0 +1,253 @@
|
|||
package cloudns
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"github.com/StackExchange/dnscontrol/models"
|
||||
"github.com/StackExchange/dnscontrol/providers"
|
||||
"github.com/StackExchange/dnscontrol/providers/diff"
|
||||
"github.com/miekg/dns/dnsutil"
|
||||
"github.com/pkg/errors"
|
||||
"strconv"
|
||||
)
|
||||
|
||||
/*
|
||||
|
||||
CloDNS API DNS provider:
|
||||
|
||||
Info required in `creds.json`:
|
||||
- auth-id
|
||||
- auth-password
|
||||
|
||||
*/
|
||||
|
||||
// NewCloudns creates the provider.
|
||||
func NewCloudns(m map[string]string, metadata json.RawMessage) (providers.DNSServiceProvider, error) {
|
||||
c := &api{}
|
||||
|
||||
c.creds.id, c.creds.password = m["auth-id"], m["auth-password"]
|
||||
if c.creds.id == "" || c.creds.password == "" {
|
||||
return nil, errors.Errorf("missing ClouDNS auth-id and auth-password")
|
||||
}
|
||||
|
||||
// Get a domain to validate authentication
|
||||
if err := c.fetchDomainList(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return c, nil
|
||||
}
|
||||
|
||||
var features = providers.DocumentationNotes{
|
||||
providers.DocDualHost: providers.Unimplemented(),
|
||||
providers.DocOfficiallySupported: providers.Cannot(),
|
||||
providers.DocCreateDomains: providers.Can(),
|
||||
providers.CanUseAlias: providers.Can(),
|
||||
providers.CanUseSRV: providers.Can(),
|
||||
providers.CanUseSSHFP: providers.Can(),
|
||||
providers.CanUseCAA: providers.Can(),
|
||||
providers.CanUseTLSA: providers.Can(),
|
||||
providers.CanUsePTR: providers.Unimplemented(),
|
||||
}
|
||||
|
||||
func init() {
|
||||
providers.RegisterDomainServiceProviderType("CLOUDNS", NewCloudns, features)
|
||||
}
|
||||
|
||||
// GetNameservers returns the nameservers for a domain.
|
||||
func (c *api) GetNameservers(domain string) ([]*models.Nameserver, error) {
|
||||
if len(c.nameserversNames) == 0 {
|
||||
c.fetchAvailableNameservers()
|
||||
}
|
||||
return models.StringsToNameservers(c.nameserversNames), nil
|
||||
}
|
||||
|
||||
// GetDomainCorrections returns the corrections for a domain.
|
||||
func (c *api) GetDomainCorrections(dc *models.DomainConfig) ([]*models.Correction, error) {
|
||||
dc, err := dc.Copy()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
dc.Punycode()
|
||||
|
||||
if c.domainIndex == nil {
|
||||
if err := c.fetchDomainList(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
domainID, ok := c.domainIndex[dc.Name]
|
||||
if !ok {
|
||||
return nil, errors.Errorf("%s not listed in domains for ClouDNS account", dc.Name)
|
||||
}
|
||||
|
||||
records, err := c.getRecords(domainID)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
existingRecords := make([]*models.RecordConfig, len(records), len(records)+len(c.nameserversNames))
|
||||
for i := range records {
|
||||
existingRecords[i] = toRc(dc, &records[i])
|
||||
}
|
||||
// Normalize
|
||||
models.PostProcessRecords(existingRecords)
|
||||
|
||||
// ClouDNS doesn't allow selecting an arbitrary TTL, only a set of predefined values https://asia.cloudns.net/wiki/article/188/
|
||||
// We need to make sure we don't change it every time if it is as close as it's going to get
|
||||
for _, record := range dc.Records {
|
||||
record.TTL = fixTTL(record.TTL)
|
||||
}
|
||||
|
||||
differ := diff.New(dc)
|
||||
_, create, del, modify := differ.IncrementalDiff(existingRecords)
|
||||
|
||||
var corrections []*models.Correction
|
||||
|
||||
// Deletes first so changing type works etc.
|
||||
for _, m := range del {
|
||||
id := m.Existing.Original.(*domainRecord).ID
|
||||
corr := &models.Correction{
|
||||
Msg: fmt.Sprintf("%s, ClouDNS ID: %s", m.String(), id),
|
||||
F: func() error {
|
||||
return c.deleteRecord(domainID, id)
|
||||
},
|
||||
}
|
||||
corrections = append(corrections, corr)
|
||||
}
|
||||
|
||||
for _, m := range create {
|
||||
req, err := toReq(m.Desired)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
corr := &models.Correction{
|
||||
Msg: m.String(),
|
||||
F: func() error {
|
||||
return c.createRecord(domainID, req)
|
||||
},
|
||||
}
|
||||
corrections = append(corrections, corr)
|
||||
}
|
||||
for _, m := range modify {
|
||||
id := m.Existing.Original.(*domainRecord).ID
|
||||
req, err := toReq(m.Desired)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
corr := &models.Correction{
|
||||
Msg: fmt.Sprintf("%s, ClouDNS ID: %s: ", m.String(), id),
|
||||
F: func() error {
|
||||
return c.modifyRecord(domainID, id, req)
|
||||
},
|
||||
}
|
||||
corrections = append(corrections, corr)
|
||||
}
|
||||
|
||||
return corrections, nil
|
||||
}
|
||||
|
||||
// EnsureDomainExists returns an error if domain doesn't exist.
|
||||
func (c *api) EnsureDomainExists(domain string) error {
|
||||
if err := c.fetchDomainList(); err != nil {
|
||||
return err
|
||||
}
|
||||
// domain already exists
|
||||
if _, ok := c.domainIndex[domain]; ok {
|
||||
return nil
|
||||
}
|
||||
return c.createDomain(domain)
|
||||
}
|
||||
|
||||
func toRc(dc *models.DomainConfig, r *domainRecord) *models.RecordConfig {
|
||||
|
||||
ttl, _ := strconv.ParseUint(r.TTL, 10, 32)
|
||||
priority, _ := strconv.ParseUint(r.Priority, 10, 32)
|
||||
weight, _ := strconv.ParseUint(r.Weight, 10, 32)
|
||||
port, _ := strconv.ParseUint(r.Port, 10, 32)
|
||||
|
||||
rc := &models.RecordConfig{
|
||||
Type: r.Type,
|
||||
TTL: uint32(ttl),
|
||||
MxPreference: uint16(priority),
|
||||
SrvPriority: uint16(priority),
|
||||
SrvWeight: uint16(weight),
|
||||
SrvPort: uint16(port),
|
||||
Original: r,
|
||||
}
|
||||
rc.SetLabel(r.Host, dc.Name)
|
||||
|
||||
switch rtype := r.Type; rtype { // #rtype_variations
|
||||
case "TXT":
|
||||
rc.SetTargetTXT(r.Target)
|
||||
case "CNAME", "MX", "NS", "SRV", "ALIAS":
|
||||
rc.SetTarget(dnsutil.AddOrigin(r.Target+".", dc.Name))
|
||||
case "CAA":
|
||||
caaFlag, _ := strconv.ParseUint(r.CaaFlag, 10, 32)
|
||||
rc.CaaFlag = uint8(caaFlag)
|
||||
rc.CaaTag = r.CaaTag
|
||||
rc.SetTarget(r.CaaValue)
|
||||
case "TLSA":
|
||||
tlsaUsage, _ := strconv.ParseUint(r.TlsaUsage, 10, 32)
|
||||
rc.TlsaUsage = uint8(tlsaUsage)
|
||||
tlsaSelector, _ := strconv.ParseUint(r.TlsaSelector, 10, 32)
|
||||
rc.TlsaSelector = uint8(tlsaSelector)
|
||||
tlsaMatchingType, _ := strconv.ParseUint(r.TlsaMatchingType, 10, 32)
|
||||
rc.TlsaMatchingType = uint8(tlsaMatchingType)
|
||||
rc.SetTarget(r.Target)
|
||||
case "SSHFP":
|
||||
sshfpAlgorithm, _ := strconv.ParseUint(r.SshfpAlgorithm, 10, 32)
|
||||
rc.SshfpAlgorithm = uint8(sshfpAlgorithm)
|
||||
sshfpFingerprint, _ := strconv.ParseUint(r.SshfpFingerprint, 10, 32)
|
||||
rc.SshfpFingerprint = uint8(sshfpFingerprint)
|
||||
rc.SetTarget(r.Target)
|
||||
default:
|
||||
rc.SetTarget(r.Target)
|
||||
}
|
||||
|
||||
return rc
|
||||
}
|
||||
|
||||
func toReq(rc *models.RecordConfig) (requestParams, error) {
|
||||
req := requestParams{
|
||||
"record-type": rc.Type,
|
||||
"host": rc.GetLabel(),
|
||||
"record": rc.GetTargetField(),
|
||||
"ttl": strconv.Itoa(int(rc.TTL)),
|
||||
}
|
||||
|
||||
// ClouDNS doesn't use "@", it uses an empty name
|
||||
if req["host"] == "@" {
|
||||
req["host"] = ""
|
||||
}
|
||||
|
||||
switch rc.Type { // #rtype_variations
|
||||
case "A", "AAAA", "NS", "PTR", "TXT", "SOA", "ALIAS", "CNAME":
|
||||
// Nothing special.
|
||||
case "MX":
|
||||
req["priority"] = strconv.Itoa(int(rc.MxPreference))
|
||||
case "SRV":
|
||||
req["priority"] = strconv.Itoa(int(rc.SrvPriority))
|
||||
req["weight"] = strconv.Itoa(int(rc.SrvWeight))
|
||||
req["port"] = strconv.Itoa(int(rc.SrvPort))
|
||||
case "CAA":
|
||||
req["caa_flag"] = strconv.Itoa(int(rc.CaaFlag))
|
||||
req["caa_type"] = rc.CaaTag
|
||||
req["caa_value"] = rc.Target
|
||||
case "TLSA":
|
||||
req["tlsa_usage"] = strconv.Itoa(int(rc.TlsaUsage))
|
||||
req["tlsa_selector"] = strconv.Itoa(int(rc.TlsaSelector))
|
||||
req["tlsa_matching_type"] = strconv.Itoa(int(rc.TlsaMatchingType))
|
||||
case "SSHFP":
|
||||
req["algorithm"] = strconv.Itoa(int(rc.SshfpAlgorithm))
|
||||
req["fptype"] = strconv.Itoa(int(rc.SshfpFingerprint))
|
||||
default:
|
||||
msg := fmt.Sprintf("ClouDNS.toReq rtype %v unimplemented", rc.Type)
|
||||
panic(msg)
|
||||
// We panic so that we quickly find any switch statements
|
||||
}
|
||||
|
||||
return req, nil
|
||||
}
|
Loading…
Reference in a new issue