github.com/StackExchange/DNSControl@v0.2.8/providers/hexonet/nameservers.go (about)

     1  package hexonet
     2  
     3  import (
     4  	"fmt"
     5  	"regexp"
     6  	"sort"
     7  	"strings"
     8  
     9  	"github.com/StackExchange/dnscontrol/models"
    10  )
    11  
    12  var defaultNameservers = []*models.Nameserver{
    13  	{Name: "ns1.ispapi.net"},
    14  	{Name: "ns2.ispapi.net"},
    15  	{Name: "ns3.ispapi.net"},
    16  }
    17  
    18  var nsRegex = regexp.MustCompile(`ns([1-3]{1})[0-9]+\.ispapi\.net`)
    19  
    20  // GetNameservers gets the nameservers set on a domain.
    21  func (n *HXClient) GetNameservers(domain string) ([]*models.Nameserver, error) {
    22  	// This is an interesting edge case. hexonet expects you to SET the nameservers to ns[1-3].ispapi.net,
    23  	// but it will internally set it to (ns1xyz|ns2uvw|ns3asd).ispapi.net, where xyz/uvw/asd is a uniqueish number.
    24  	// In order to avoid endless loops, we will use the unique nameservers if present, or else the generic ones if not.
    25  	nss, err := n.getNameserversRaw(domain)
    26  	if err != nil {
    27  		return nil, err
    28  	}
    29  	toUse := []string{
    30  		defaultNameservers[0].Name,
    31  		defaultNameservers[1].Name,
    32  		defaultNameservers[2].Name,
    33  	}
    34  	for _, ns := range nss {
    35  		if matches := nsRegex.FindStringSubmatch(ns); len(matches) == 2 && len(matches[1]) == 1 {
    36  			idx := matches[1][0] - '1' // regex ensures proper range
    37  			toUse[idx] = matches[0]
    38  		}
    39  	}
    40  	return models.StringsToNameservers(toUse), nil
    41  }
    42  
    43  func (n *HXClient) getNameserversRaw(domain string) ([]string, error) {
    44  	r := n.client.Request(map[string]string{
    45  		"COMMAND": "StatusDomain",
    46  		"DOMAIN":  domain,
    47  	})
    48  	code := r.Code()
    49  	if code != 200 {
    50  		return nil, n.GetHXApiError("Could not get status for domain", domain, r)
    51  	}
    52  	ns := r.GetColumn("NAMESERVER")
    53  	sort.Strings(ns)
    54  	return ns, nil
    55  }
    56  
    57  // GetRegistrarCorrections gathers corrections that would being n to match dc.
    58  func (n *HXClient) GetRegistrarCorrections(dc *models.DomainConfig) ([]*models.Correction, error) {
    59  	nss, err := n.getNameserversRaw(dc.Name)
    60  	if err != nil {
    61  		return nil, err
    62  	}
    63  	foundNameservers := strings.Join(nss, ",")
    64  
    65  	expected := []string{}
    66  	for _, ns := range dc.Nameservers {
    67  		name := strings.TrimRight(ns.Name, ".")
    68  		expected = append(expected, name)
    69  	}
    70  	sort.Strings(expected)
    71  	expectedNameservers := strings.Join(expected, ",")
    72  
    73  	if foundNameservers != expectedNameservers {
    74  		return []*models.Correction{
    75  			{
    76  				Msg: fmt.Sprintf("Update nameservers %s -> %s", foundNameservers, expectedNameservers),
    77  				F:   n.updateNameservers(expected, dc.Name),
    78  			},
    79  		}, nil
    80  	}
    81  	return nil, nil
    82  }
    83  
    84  func (n *HXClient) updateNameservers(ns []string, domain string) func() error {
    85  	return func() error {
    86  		cmd := map[string]string{
    87  			"COMMAND": "ModifyDomain",
    88  			"DOMAIN":  domain,
    89  		}
    90  		for idx, ns := range ns {
    91  			cmd[fmt.Sprintf("NAMESERVER%d", idx)] = ns
    92  		}
    93  		response := n.client.Request(cmd)
    94  		code := response.Code()
    95  		if code != 200 {
    96  			return fmt.Errorf(fmt.Sprintf("%d %s", code, response.Description()))
    97  		}
    98  		return nil
    99  	}
   100  }