mirror of
https://github.com/StackExchange/dnscontrol.git
synced 2025-01-11 18:08:57 +08:00
201 lines
4.2 KiB
Go
201 lines
4.2 KiB
Go
package packetframe
|
|
|
|
import (
|
|
"bytes"
|
|
"encoding/json"
|
|
"fmt"
|
|
"io/ioutil"
|
|
"net/http"
|
|
"net/url"
|
|
)
|
|
|
|
const (
|
|
mediaType = "application/json"
|
|
defaultBaseURL = "https://packetframe.com/api/"
|
|
)
|
|
|
|
var defaultNameServerNames = []string{
|
|
"ns1.packetframe.com",
|
|
"ns2.packetframe.com",
|
|
}
|
|
|
|
type zone struct {
|
|
ID string `json:"id"`
|
|
Zone string `json:"zone"`
|
|
Users []string `json:"users"`
|
|
UserEmails []string `json:"user_emails"`
|
|
}
|
|
|
|
type domainResponse struct {
|
|
Data struct {
|
|
Zones []zone `json:"zones"`
|
|
} `json:"data"`
|
|
Message string `json:"message"`
|
|
Success bool `json:"success"`
|
|
}
|
|
|
|
type deleteRequest struct {
|
|
Record string `json:"record"`
|
|
Zone string `json:"zone"`
|
|
}
|
|
|
|
type recordResponse struct {
|
|
Data struct {
|
|
Records []domainRecord `json:"records"`
|
|
} `json:"data"`
|
|
Message string `json:"message"`
|
|
Success bool `json:"success"`
|
|
}
|
|
|
|
type domainRecord struct {
|
|
ID string `json:"id"`
|
|
Type string `json:"type"`
|
|
Label string `json:"label"`
|
|
Value string `json:"value"`
|
|
TTL int `json:"ttl"`
|
|
Proxy bool `json:"proxy"`
|
|
Zone string `json:"zone"`
|
|
}
|
|
|
|
func (c *packetframeProvider) fetchDomainList() error {
|
|
c.domainIndex = map[string]zone{}
|
|
dr := &domainResponse{}
|
|
endpoint := "dns/zones"
|
|
if err := c.get(endpoint, dr); err != nil {
|
|
return fmt.Errorf("failed fetching domain list (Packetframe): %w", err)
|
|
}
|
|
for _, zone := range dr.Data.Zones {
|
|
c.domainIndex[zone.Zone] = zone
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
func (c *packetframeProvider) getRecords(zoneID string) ([]domainRecord, error) {
|
|
var records []domainRecord
|
|
dr := &recordResponse{}
|
|
endpoint := "dns/records/" + zoneID
|
|
if err := c.get(endpoint, dr); err != nil {
|
|
return records, fmt.Errorf("failed fetching domain list (Packetframe): %w", err)
|
|
}
|
|
records = append(records, dr.Data.Records...)
|
|
|
|
for i := range defaultNameServerNames {
|
|
records = append(records, domainRecord{
|
|
Type: "NS",
|
|
TTL: 86400,
|
|
Value: defaultNameServerNames[i] + ".",
|
|
Zone: zoneID,
|
|
ID: "0",
|
|
})
|
|
}
|
|
|
|
return records, nil
|
|
}
|
|
|
|
func (c *packetframeProvider) createRecord(rec *domainRecord) (*domainRecord, error) {
|
|
endpoint := "dns/records"
|
|
|
|
req, err := c.newRequest(http.MethodPost, endpoint, rec)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
_, err = c.client.Do(req)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
return rec, nil
|
|
}
|
|
|
|
func (c *packetframeProvider) modifyRecord(rec *domainRecord) error {
|
|
endpoint := "dns/records"
|
|
|
|
req, err := c.newRequest(http.MethodPut, endpoint, rec)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
_, err = c.client.Do(req)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
func (c *packetframeProvider) deleteRecord(zoneID string, recordID string) error {
|
|
endpoint := "dns/records"
|
|
req, err := c.newRequest(http.MethodDelete, endpoint, deleteRequest{Zone: zoneID, Record: recordID})
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
resp, err := c.client.Do(req)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
if resp.StatusCode != http.StatusOK {
|
|
return c.handleErrors(resp)
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
func (c *packetframeProvider) newRequest(method, endpoint string, body interface{}) (*http.Request, error) {
|
|
rel, err := url.Parse(endpoint)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
u := c.baseURL.ResolveReference(rel)
|
|
|
|
buf := new(bytes.Buffer)
|
|
if body != nil {
|
|
err = json.NewEncoder(buf).Encode(body)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
}
|
|
|
|
req, err := http.NewRequest(method, u.String(), buf)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
req.Header.Add("Content-Type", mediaType)
|
|
req.Header.Add("Accept", mediaType)
|
|
req.Header.Add("Authorization", "Token "+c.token)
|
|
return req, nil
|
|
}
|
|
|
|
func (c *packetframeProvider) get(endpoint string, target interface{}) error {
|
|
req, err := c.newRequest(http.MethodGet, endpoint, nil)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
resp, err := c.client.Do(req)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
if resp.StatusCode != http.StatusOK {
|
|
return c.handleErrors(resp)
|
|
}
|
|
defer resp.Body.Close()
|
|
|
|
decoder := json.NewDecoder(resp.Body)
|
|
return decoder.Decode(target)
|
|
}
|
|
|
|
func (c *packetframeProvider) handleErrors(resp *http.Response) error {
|
|
body, err := ioutil.ReadAll(resp.Body)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
dr := &domainResponse{}
|
|
json.Unmarshal(body, &dr)
|
|
|
|
return fmt.Errorf("packetframe API error: %s", dr.Message)
|
|
}
|