Initial euclide.org release
This commit is contained in:
174
pdns_zones.go
Normal file
174
pdns_zones.go
Normal file
@@ -0,0 +1,174 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"fmt"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/pyke369/golang-support/rcache"
|
||||
)
|
||||
|
||||
type (
|
||||
// DNSZones is a list of DNSZone
|
||||
DNSZones []*DNSZone
|
||||
|
||||
// DNSZone is the json structure of a DNS zone in the PDNS API
|
||||
DNSZone struct {
|
||||
DNSQuery
|
||||
Name string `json:"name"`
|
||||
Kind string `json:"kind"`
|
||||
NameServers []string `json:"nameservers"`
|
||||
SOAEditAPI string `json:"soa_edit_api"`
|
||||
}
|
||||
)
|
||||
|
||||
type listCache struct {
|
||||
result []*DNSZone
|
||||
expire time.Time
|
||||
}
|
||||
|
||||
// List all zones in the DNSZones struct as string
|
||||
func (z DNSZones) List(sep string) string {
|
||||
ret := []string{}
|
||||
for _, l := range z {
|
||||
ret = append(ret, trimPoint(l.Name))
|
||||
}
|
||||
domainSort(ret)
|
||||
return strings.Join(ret, sep)
|
||||
}
|
||||
|
||||
// NewZone returns a new DNSZone struct, use for domain creation
|
||||
func (p *PowerDNS) NewZone(name, zoneType, soa, user, comment string, ttl int, nameServers []string, autoInc bool) (*DNSZone, error) {
|
||||
z := &DNSZone{
|
||||
Name: name,
|
||||
Kind: zoneType,
|
||||
NameServers: nameServers,
|
||||
}
|
||||
if autoInc {
|
||||
z.SOAEditAPI = "INCEPTION-INCREMENT"
|
||||
}
|
||||
// create SOA record
|
||||
soaRec, err := p.GetRecord(name, "SOA", true)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
soaRec.ChangeValue(name, soa, "SOA", false, false)
|
||||
soaRec.ChangeDomain(name)
|
||||
soaRec.AddCommentAndTTL(user, comment, ttl)
|
||||
|
||||
// merge it into z
|
||||
z.RRSets = soaRec.RRSets
|
||||
return z, nil
|
||||
}
|
||||
|
||||
func (z *DNSZone) String() string {
|
||||
return string(printJSON(z))
|
||||
}
|
||||
|
||||
// AddEntries put all RRSets in q into z
|
||||
func (z *DNSZone) AddEntries(q *DNSQuery) bool {
|
||||
if q.Domain != z.Name {
|
||||
return false
|
||||
}
|
||||
z.RRSets = append(z.RRSets, q.RRSets...)
|
||||
return true
|
||||
}
|
||||
|
||||
// TransformIntoDNSQuery converts a DNSZone into a DNSQuery
|
||||
func (z *DNSZone) TransformIntoDNSQuery() *DNSQuery {
|
||||
return &DNSQuery{
|
||||
Domain: z.Name,
|
||||
RRSets: z.RRSets,
|
||||
}
|
||||
}
|
||||
|
||||
// ListZones list every zone matchin the re regexp if not empty
|
||||
func (p *PowerDNS) ListZones(re string) (DNSZones, error) {
|
||||
now := time.Now()
|
||||
if cache, ok := p.listCache[re]; ok && len(cache.result) > 0 && now.Before(cache.expire) {
|
||||
p.lock()
|
||||
cache.expire = now.Add(3 * time.Minute)
|
||||
p.unlock()
|
||||
return cache.result, nil
|
||||
}
|
||||
list, err := p.listZones(re)
|
||||
if err == nil && len(list) > 0 {
|
||||
p.lock()
|
||||
p.listCache[re] = &listCache{
|
||||
result: list,
|
||||
expire: now.Add(3 * time.Minute),
|
||||
}
|
||||
p.unlock()
|
||||
}
|
||||
return list, err
|
||||
}
|
||||
|
||||
// ListZones list every zone matchin the re regexp if not empty
|
||||
func (p *PowerDNS) listZones(re string) (DNSZones, error) {
|
||||
domains := DNSZones{}
|
||||
ret := DNSZones{}
|
||||
if _, _, err := p.sendQuery(context.Background(), fmt.Sprintf("%s/%s", p.apiURL, "zones"), "GET", nil, &domains); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if re == "" || re == "." {
|
||||
re = ".*"
|
||||
}
|
||||
matcher := rcache.Get(fmt.Sprintf("^%s$", re))
|
||||
if matcher == nil {
|
||||
return nil, errors.New("invalid regexp")
|
||||
}
|
||||
for _, domain := range domains {
|
||||
if !matcher.MatchString(domain.Name) {
|
||||
continue
|
||||
}
|
||||
ret = append(ret, domain)
|
||||
}
|
||||
return ret, nil
|
||||
}
|
||||
|
||||
// GetDomain find the domain where the record r should be
|
||||
// ex : www.example.org should be in the domain example.org, or org, or doesn't
|
||||
// exist and we return an error
|
||||
func (p *PowerDNS) GetDomain(r string) (string, error) {
|
||||
domains, err := p.ListZones("")
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
// Remove the final point of the record if necessary
|
||||
r = trimPoint(r)
|
||||
best := ""
|
||||
|
||||
for _, domain := range domains {
|
||||
possible := trimPoint(domain.Name)
|
||||
if possible == r {
|
||||
return r, nil
|
||||
}
|
||||
if r == possible || strings.HasSuffix(r, "."+possible) && len(possible) > len(best) {
|
||||
best = possible
|
||||
}
|
||||
}
|
||||
if len(best) == 0 {
|
||||
return "", errors.New("Unknown domain")
|
||||
}
|
||||
// check there is no delegation down the road
|
||||
subs := strings.Split(strings.TrimSuffix(r, "."+best), ".")
|
||||
current := best
|
||||
rp := addPoint(r)
|
||||
for i := len(subs) - 1; i > 0; i-- {
|
||||
current = subs[i] + "." + current
|
||||
search, err := p.Search(fmt.Sprintf(current))
|
||||
if err != nil {
|
||||
return best, nil
|
||||
}
|
||||
for _, entry := range search {
|
||||
if entry.IsRecord() && // ignore non record
|
||||
entry.Type == "NS" && // need a NS
|
||||
strings.HasSuffix(rp, "."+entry.Name) {
|
||||
return best, fmt.Errorf("%s is delegated to another server", r)
|
||||
}
|
||||
}
|
||||
}
|
||||
return best, nil
|
||||
}
|
||||
Reference in New Issue
Block a user