github.com/teknogeek/dnscontrol/v2@v2.10.1-0.20200227202244-ae299b55ba42/providers/cloudns/api.go (about)

     1  package cloudns
     2  
     3  import (
     4  	"encoding/json"
     5  	"fmt"
     6  	"io/ioutil"
     7  	"net/http"
     8  	"strconv"
     9  )
    10  
    11  // Api layer for CloDNS
    12  type api struct {
    13  	domainIndex      map[string]string
    14  	nameserversNames []string
    15  	creds            struct {
    16  		id       string
    17  		password string
    18  	}
    19  }
    20  
    21  type requestParams map[string]string
    22  
    23  type errorResponse struct {
    24  	Status      string `json:"status"`
    25  	Description string `json:"statusDescription"`
    26  }
    27  
    28  type nameserverRecord struct {
    29  	Type string `json:"type"`
    30  	Name string `json:"name"`
    31  }
    32  
    33  type nameserverResponse []nameserverRecord
    34  
    35  type zoneRecord struct {
    36  	Name   string `json:"name"`
    37  	Type   string `json:"type"`
    38  	Status string `json:"status"`
    39  	Zone   string `json:"zone"`
    40  }
    41  
    42  type zoneResponse []zoneRecord
    43  
    44  type domainRecord struct {
    45  	ID               string `json:"id"`
    46  	Type             string `json:"type"`
    47  	Host             string `json:"host"`
    48  	Target           string `json:"record"`
    49  	Priority         string `json:"priority"`
    50  	Weight           string `json:"weight"`
    51  	Port             string `json:"port"`
    52  	Service          string `json:"service"`
    53  	Protocol         string `json:"protocol"`
    54  	TTL              string `json:"ttl"`
    55  	Status           int8   `json:"status"`
    56  	CaaFlag          string `json:"caa_flag,omitempty"`
    57  	CaaTag           string `json:"caa_type,omitempty"`
    58  	CaaValue         string `json:"caa_value,omitempty"`
    59  	TlsaUsage        string `json:"tlsa_usage,omitempty"`
    60  	TlsaSelector     string `json:"tlsa_selector,omitempty"`
    61  	TlsaMatchingType string `json:"tlsa_matching_type,omitempty"`
    62  	SshfpAlgorithm   string `json:"algorithm,omitempty"`
    63  	SshfpFingerprint string `json:"fp_type,omitempty"`
    64  }
    65  
    66  type recordResponse map[string]domainRecord
    67  
    68  var allowedTTLValues = []uint32{
    69  	60,      // 1 minute
    70  	300,     // 5 minutes
    71  	900,     // 15 minutes
    72  	1800,    // 30 minutes
    73  	3600,    // 1 hour
    74  	21600,   // 6 hours
    75  	43200,   // 12 hours
    76  	86400,   // 1 day
    77  	172800,  // 2 days
    78  	259200,  // 3 days
    79  	604800,  // 1 week
    80  	1209600, // 2 weeks
    81  	2419200, // 4 weeks
    82  }
    83  
    84  func (c *api) fetchAvailableNameservers() error {
    85  	c.nameserversNames = nil
    86  
    87  	var bodyString, err = c.get("/dns/available-name-servers.json", requestParams{})
    88  	if err != nil {
    89  		return fmt.Errorf("Error fetching available nameservers list from ClouDNS: %s", err)
    90  	}
    91  
    92  	var nr nameserverResponse
    93  	json.Unmarshal(bodyString, &nr)
    94  
    95  	for _, nameserver := range nr {
    96  		if nameserver.Type == "premium" {
    97  			c.nameserversNames = append(c.nameserversNames, nameserver.Name)
    98  		}
    99  
   100  	}
   101  	return nil
   102  }
   103  
   104  func (c *api) fetchDomainList() error {
   105  	c.domainIndex = map[string]string{}
   106  	rowsPerPage := 100
   107  	page := 1
   108  	for {
   109  		var dr zoneResponse
   110  		params := requestParams{
   111  			"page":          strconv.Itoa(page),
   112  			"rows-per-page": strconv.Itoa(rowsPerPage),
   113  		}
   114  		endpoint := "/dns/list-zones.json"
   115  		var bodyString, err = c.get(endpoint, params)
   116  		if err != nil {
   117  			return fmt.Errorf("Error fetching domain list from ClouDNS: %s", err)
   118  		}
   119  		json.Unmarshal(bodyString, &dr)
   120  
   121  		for _, domain := range dr {
   122  			c.domainIndex[domain.Name] = domain.Name
   123  		}
   124  		if len(dr) < rowsPerPage {
   125  			break
   126  		}
   127  		page++
   128  	}
   129  	return nil
   130  }
   131  
   132  func (c *api) createDomain(domain string) error {
   133  	params := requestParams{
   134  		"domain-name": domain,
   135  		"zone-type":   "master",
   136  	}
   137  	if _, err := c.get("/dns/register.json", params); err != nil {
   138  		return fmt.Errorf("Error create domain  ClouDNS: %s", err)
   139  	}
   140  	return nil
   141  }
   142  
   143  func (c *api) createRecord(domainID string, rec requestParams) error {
   144  	rec["domain-name"] = domainID
   145  	if _, err := c.get("/dns/add-record.json", rec); err != nil {
   146  		return fmt.Errorf("Error create record  ClouDNS: %s", err)
   147  	}
   148  	return nil
   149  }
   150  
   151  func (c *api) deleteRecord(domainID string, recordID string) error {
   152  	params := requestParams{
   153  		"domain-name": domainID,
   154  		"record-id":   recordID,
   155  	}
   156  	if _, err := c.get("/dns/delete-record.json", params); err != nil {
   157  		return fmt.Errorf("Error delete record  ClouDNS: %s", err)
   158  	}
   159  	return nil
   160  }
   161  
   162  func (c *api) modifyRecord(domainID string, recordID string, rec requestParams) error {
   163  	rec["domain-name"] = domainID
   164  	rec["record-id"] = recordID
   165  	if _, err := c.get("/dns/mod-record.json", rec); err != nil {
   166  		return fmt.Errorf("Error create update ClouDNS: %s", err)
   167  	}
   168  	return nil
   169  }
   170  
   171  func (c *api) getRecords(id string) ([]domainRecord, error) {
   172  	params := requestParams{"domain-name": id}
   173  
   174  	var bodyString, err = c.get("/dns/records.json", params)
   175  	if err != nil {
   176  		return nil, fmt.Errorf("Error fetching record list from ClouDNS: %s", err)
   177  	}
   178  
   179  	var dr recordResponse
   180  	json.Unmarshal(bodyString, &dr)
   181  
   182  	var records []domainRecord
   183  	for _, rec := range dr {
   184  		records = append(records, rec)
   185  	}
   186  	return records, nil
   187  }
   188  
   189  func (c *api) get(endpoint string, params requestParams) ([]byte, error) {
   190  	client := &http.Client{}
   191  	req, _ := http.NewRequest("GET", "https://api.cloudns.net"+endpoint, nil)
   192  	q := req.URL.Query()
   193  
   194  	//TODO: Suport  sub-auth-id / sub-auth-user https://asia.cloudns.net/wiki/article/42/
   195  	// Add auth params
   196  	q.Add("auth-id", c.creds.id)
   197  	q.Add("auth-password", c.creds.password)
   198  
   199  	for pName, pValue := range params {
   200  		q.Add(pName, pValue)
   201  	}
   202  
   203  	req.URL.RawQuery = q.Encode()
   204  
   205  	resp, err := client.Do(req)
   206  	if err != nil {
   207  		return []byte{}, err
   208  	}
   209  
   210  	bodyString, _ := ioutil.ReadAll(resp.Body)
   211  
   212  	// Got error from API ?
   213  	var errResp errorResponse
   214  	err = json.Unmarshal(bodyString, &errResp)
   215  	if errResp.Status == "Failed" {
   216  		return bodyString, fmt.Errorf("ClouDNS API error: %s URL:%s%s ", errResp.Description, req.Host, req.URL.RequestURI())
   217  	}
   218  
   219  	return bodyString, nil
   220  }
   221  
   222  func fixTTL(ttl uint32) uint32 {
   223  	// if the TTL is larger than the largest allowed value, return the largest allowed value
   224  	if ttl > allowedTTLValues[len(allowedTTLValues)-1] {
   225  		return allowedTTLValues[len(allowedTTLValues)-1]
   226  	}
   227  
   228  	for _, v := range allowedTTLValues {
   229  		if v >= ttl {
   230  			return v
   231  		}
   232  	}
   233  
   234  	return allowedTTLValues[0]
   235  }