* Implement notifies for transfer plugin (#3972) * Fix notifies in transfer plugin Signed-off-by: Miek Gieben <miek@miek.nl> * Make it compile Signed-off-by: Miek Gieben <miek@miek.nl> * Port more plugins Signed-off-by: Miek Gieben <miek@miek.nl> * golint Signed-off-by: Miek Gieben <miek@miek.nl> * Fix tests Signed-off-by: Miek Gieben <miek@miek.nl> * Fix notifies in transfer plugin Signed-off-by: Miek Gieben <miek@miek.nl> * Make it compile Signed-off-by: Miek Gieben <miek@miek.nl> * Port more plugins Signed-off-by: Miek Gieben <miek@miek.nl> * golint Signed-off-by: Miek Gieben <miek@miek.nl> * Fix tests Signed-off-by: Miek Gieben <miek@miek.nl> * Fix tests Signed-off-by: Miek Gieben <miek@miek.nl> * really fix test Signed-off-by: Miek Gieben <miek@miek.nl> * Implement ixfr fallback and unify file and auto for transfering Signed-off-by: Miek Gieben <miek@miek.nl> * Add transfer tests copied and modified from #3452 Signed-off-by: Miek Gieben <miek@miek.nl> * Test correct selection of plugin Signed-off-by: Miek Gieben <miek@miek.nl> * add upstream back in Signed-off-by: Miek Gieben <miek@miek.nl> * Implement ixfr fallback and unify file and auto for transfering Signed-off-by: Miek Gieben <miek@miek.nl> * fix test Signed-off-by: Miek Gieben <miek@miek.nl> * properly merge Signed-off-by: Miek Gieben <miek@miek.nl> * Remove plugin/kubernetes/setup_transfer_test.go Signed-off-by: Yong Tang <yong.tang.github@outlook.com> Co-authored-by: Miek Gieben <miek@miek.nl>
178 lines
3.9 KiB
Go
178 lines
3.9 KiB
Go
package file
|
|
|
|
import (
|
|
"fmt"
|
|
"path/filepath"
|
|
"strings"
|
|
"sync"
|
|
"time"
|
|
|
|
"github.com/coredns/coredns/plugin/file/tree"
|
|
"github.com/coredns/coredns/plugin/pkg/upstream"
|
|
|
|
"github.com/miekg/dns"
|
|
)
|
|
|
|
// Zone is a structure that contains all data related to a DNS zone.
|
|
type Zone struct {
|
|
origin string
|
|
origLen int
|
|
file string
|
|
*tree.Tree
|
|
Apex
|
|
Expired bool
|
|
|
|
sync.RWMutex
|
|
|
|
StartupOnce sync.Once
|
|
TransferFrom []string
|
|
|
|
ReloadInterval time.Duration
|
|
reloadShutdown chan bool
|
|
|
|
Upstream *upstream.Upstream // Upstream for looking up external names during the resolution process.
|
|
}
|
|
|
|
// Apex contains the apex records of a zone: SOA, NS and their potential signatures.
|
|
type Apex struct {
|
|
SOA *dns.SOA
|
|
NS []dns.RR
|
|
SIGSOA []dns.RR
|
|
SIGNS []dns.RR
|
|
}
|
|
|
|
// NewZone returns a new zone.
|
|
func NewZone(name, file string) *Zone {
|
|
return &Zone{
|
|
origin: dns.Fqdn(name),
|
|
origLen: dns.CountLabel(dns.Fqdn(name)),
|
|
file: filepath.Clean(file),
|
|
Tree: &tree.Tree{},
|
|
reloadShutdown: make(chan bool),
|
|
}
|
|
}
|
|
|
|
// Copy copies a zone.
|
|
func (z *Zone) Copy() *Zone {
|
|
z1 := NewZone(z.origin, z.file)
|
|
z1.TransferFrom = z.TransferFrom
|
|
z1.Expired = z.Expired
|
|
|
|
z1.Apex = z.Apex
|
|
return z1
|
|
}
|
|
|
|
// CopyWithoutApex copies zone z without the Apex records.
|
|
func (z *Zone) CopyWithoutApex() *Zone {
|
|
z1 := NewZone(z.origin, z.file)
|
|
z1.TransferFrom = z.TransferFrom
|
|
z1.Expired = z.Expired
|
|
|
|
return z1
|
|
}
|
|
|
|
// Insert inserts r into z.
|
|
func (z *Zone) Insert(r dns.RR) error {
|
|
r.Header().Name = strings.ToLower(r.Header().Name)
|
|
|
|
switch h := r.Header().Rrtype; h {
|
|
case dns.TypeNS:
|
|
r.(*dns.NS).Ns = strings.ToLower(r.(*dns.NS).Ns)
|
|
|
|
if r.Header().Name == z.origin {
|
|
z.Apex.NS = append(z.Apex.NS, r)
|
|
return nil
|
|
}
|
|
case dns.TypeSOA:
|
|
r.(*dns.SOA).Ns = strings.ToLower(r.(*dns.SOA).Ns)
|
|
r.(*dns.SOA).Mbox = strings.ToLower(r.(*dns.SOA).Mbox)
|
|
|
|
z.Apex.SOA = r.(*dns.SOA)
|
|
return nil
|
|
case dns.TypeNSEC3, dns.TypeNSEC3PARAM:
|
|
return fmt.Errorf("NSEC3 zone is not supported, dropping RR: %s for zone: %s", r.Header().Name, z.origin)
|
|
case dns.TypeRRSIG:
|
|
x := r.(*dns.RRSIG)
|
|
switch x.TypeCovered {
|
|
case dns.TypeSOA:
|
|
z.Apex.SIGSOA = append(z.Apex.SIGSOA, x)
|
|
return nil
|
|
case dns.TypeNS:
|
|
if r.Header().Name == z.origin {
|
|
z.Apex.SIGNS = append(z.Apex.SIGNS, x)
|
|
return nil
|
|
}
|
|
}
|
|
case dns.TypeCNAME:
|
|
r.(*dns.CNAME).Target = strings.ToLower(r.(*dns.CNAME).Target)
|
|
case dns.TypeMX:
|
|
r.(*dns.MX).Mx = strings.ToLower(r.(*dns.MX).Mx)
|
|
case dns.TypeSRV:
|
|
r.(*dns.SRV).Target = strings.ToLower(r.(*dns.SRV).Target)
|
|
}
|
|
|
|
z.Tree.Insert(r)
|
|
return nil
|
|
}
|
|
|
|
// File retrieves the file path in a safe way.
|
|
func (z *Zone) File() string {
|
|
z.RLock()
|
|
defer z.RUnlock()
|
|
return z.file
|
|
}
|
|
|
|
// SetFile updates the file path in a safe way.
|
|
func (z *Zone) SetFile(path string) {
|
|
z.Lock()
|
|
z.file = path
|
|
z.Unlock()
|
|
}
|
|
|
|
// ApexIfDefined returns the apex nodes from z. The SOA record is the first record, if it does not exist, an error is returned.
|
|
func (z *Zone) ApexIfDefined() ([]dns.RR, error) {
|
|
z.RLock()
|
|
defer z.RUnlock()
|
|
if z.Apex.SOA == nil {
|
|
return nil, fmt.Errorf("no SOA")
|
|
}
|
|
|
|
rrs := []dns.RR{z.Apex.SOA}
|
|
|
|
if len(z.Apex.SIGSOA) > 0 {
|
|
rrs = append(rrs, z.Apex.SIGSOA...)
|
|
}
|
|
if len(z.Apex.NS) > 0 {
|
|
rrs = append(rrs, z.Apex.NS...)
|
|
}
|
|
if len(z.Apex.SIGNS) > 0 {
|
|
rrs = append(rrs, z.Apex.SIGNS...)
|
|
}
|
|
|
|
return rrs, nil
|
|
}
|
|
|
|
// NameFromRight returns the labels from the right, staring with the
|
|
// origin and then i labels extra. When we are overshooting the name
|
|
// the returned boolean is set to true.
|
|
func (z *Zone) nameFromRight(qname string, i int) (string, bool) {
|
|
if i <= 0 {
|
|
return z.origin, false
|
|
}
|
|
|
|
for j := 1; j <= z.origLen; j++ {
|
|
if _, shot := dns.PrevLabel(qname, j); shot {
|
|
return qname, shot
|
|
}
|
|
}
|
|
|
|
k := 0
|
|
var shot bool
|
|
for j := 1; j <= i; j++ {
|
|
k, shot = dns.PrevLabel(qname, j+z.origLen)
|
|
if shot {
|
|
return qname, shot
|
|
}
|
|
}
|
|
return qname[k:], false
|
|
}
|