| 
									
										
										
										
											2016-03-27 07:37:23 +01:00
										 |  |  | package file
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | import (
 | 
					
						
							| 
									
										
										
										
											2016-04-15 14:26:27 +01:00
										 |  |  | 	"fmt"
 | 
					
						
							| 
									
										
										
										
											2017-06-21 23:46:20 -07:00
										 |  |  | 	"net"
 | 
					
						
							| 
									
										
										
										
											2016-04-15 20:00:17 +01:00
										 |  |  | 	"path"
 | 
					
						
							| 
									
										
										
										
											2016-04-16 16:16:52 +01:00
										 |  |  | 	"strings"
 | 
					
						
							| 
									
										
										
										
											2016-04-13 20:14:03 +01:00
										 |  |  | 	"sync"
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-09-14 09:36:06 +01:00
										 |  |  | 	"github.com/coredns/coredns/plugin/file/tree"
 | 
					
						
							| 
									
										
										
										
											2018-02-16 03:44:50 -05:00
										 |  |  | 	"github.com/coredns/coredns/plugin/pkg/upstream"
 | 
					
						
							| 
									
										
										
										
											2017-02-21 22:51:47 -08:00
										 |  |  | 	"github.com/coredns/coredns/request"
 | 
					
						
							| 
									
										
										
										
											2016-03-27 07:37:23 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	"github.com/miekg/dns"
 | 
					
						
							|  |  |  | )
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-09-23 09:14:12 +01:00
										 |  |  | // Zone defines a structure that contains all data related to a DNS zone.
 | 
					
						
							| 
									
										
										
										
											2016-03-27 07:37:23 +01:00
										 |  |  | type Zone struct {
 | 
					
						
							| 
									
										
										
										
											2016-11-05 14:39:49 +00:00
										 |  |  | 	origin  string
 | 
					
						
							|  |  |  | 	origLen int
 | 
					
						
							|  |  |  | 	file    string
 | 
					
						
							| 
									
										
										
										
											2016-03-27 07:37:23 +01:00
										 |  |  | 	*tree.Tree
 | 
					
						
							| 
									
										
										
										
											2016-04-16 16:16:52 +01:00
										 |  |  | 	Apex Apex
 | 
					
						
							| 
									
										
										
										
											2016-04-03 09:02:34 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	TransferTo   []string
 | 
					
						
							| 
									
										
										
										
											2016-04-13 20:14:03 +01:00
										 |  |  | 	StartupOnce  sync.Once
 | 
					
						
							| 
									
										
										
										
											2016-04-03 09:02:34 +01:00
										 |  |  | 	TransferFrom []string
 | 
					
						
							|  |  |  | 	Expired      *bool
 | 
					
						
							| 
									
										
										
										
											2016-04-15 14:26:27 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-10-17 18:37:56 +01:00
										 |  |  | 	NoReload       bool
 | 
					
						
							|  |  |  | 	reloadMu       sync.RWMutex
 | 
					
						
							| 
									
										
										
										
											2018-02-28 18:19:37 -08:00
										 |  |  | 	reloadShutdown chan bool
 | 
					
						
							| 
									
										
										
										
											2018-02-16 03:44:50 -05:00
										 |  |  | 	Upstream       upstream.Upstream // Upstream for looking up names during the resolution process
 | 
					
						
							| 
									
										
										
										
											2016-03-27 07:37:23 +01:00
										 |  |  | }
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-09-23 09:14:12 +01:00
										 |  |  | // Apex contains the apex records of a zone: SOA, NS and their potential signatures.
 | 
					
						
							| 
									
										
										
										
											2016-04-16 16:16:52 +01:00
										 |  |  | type Apex struct {
 | 
					
						
							|  |  |  | 	SOA    *dns.SOA
 | 
					
						
							|  |  |  | 	NS     []dns.RR
 | 
					
						
							|  |  |  | 	SIGSOA []dns.RR
 | 
					
						
							|  |  |  | 	SIGNS  []dns.RR
 | 
					
						
							|  |  |  | }
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-04-02 16:56:16 +01:00
										 |  |  | // NewZone returns a new zone.
 | 
					
						
							| 
									
										
										
										
											2016-04-15 14:26:27 +01:00
										 |  |  | func NewZone(name, file string) *Zone {
 | 
					
						
							| 
									
										
										
										
											2016-10-17 18:37:56 +01:00
										 |  |  | 	z := &Zone{
 | 
					
						
							|  |  |  | 		origin:         dns.Fqdn(name),
 | 
					
						
							| 
									
										
										
										
											2016-11-05 14:39:49 +00:00
										 |  |  | 		origLen:        dns.CountLabel(dns.Fqdn(name)),
 | 
					
						
							| 
									
										
										
										
											2016-10-17 18:37:56 +01:00
										 |  |  | 		file:           path.Clean(file),
 | 
					
						
							|  |  |  | 		Tree:           &tree.Tree{},
 | 
					
						
							|  |  |  | 		Expired:        new(bool),
 | 
					
						
							| 
									
										
										
										
											2018-02-28 18:19:37 -08:00
										 |  |  | 		reloadShutdown: make(chan bool),
 | 
					
						
							| 
									
										
										
										
											2016-10-17 18:37:56 +01:00
										 |  |  | 	}
 | 
					
						
							| 
									
										
										
										
											2016-04-03 09:02:34 +01:00
										 |  |  | 	*z.Expired = false
 | 
					
						
							| 
									
										
										
										
											2016-11-05 14:39:49 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-04-03 09:02:34 +01:00
										 |  |  | 	return z
 | 
					
						
							| 
									
										
										
										
											2016-03-27 07:37:23 +01:00
										 |  |  | }
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-08-04 09:46:40 -07:00
										 |  |  | // Copy copies a zone.
 | 
					
						
							| 
									
										
										
										
											2016-04-05 10:53:23 +01:00
										 |  |  | func (z *Zone) Copy() *Zone {
 | 
					
						
							| 
									
										
										
										
											2016-04-15 14:26:27 +01:00
										 |  |  | 	z1 := NewZone(z.origin, z.file)
 | 
					
						
							| 
									
										
										
										
											2016-04-05 10:53:23 +01:00
										 |  |  | 	z1.TransferTo = z.TransferTo
 | 
					
						
							|  |  |  | 	z1.TransferFrom = z.TransferFrom
 | 
					
						
							|  |  |  | 	z1.Expired = z.Expired
 | 
					
						
							| 
									
										
										
										
											2017-06-21 23:46:20 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-04-16 16:16:52 +01:00
										 |  |  | 	z1.Apex = z.Apex
 | 
					
						
							| 
									
										
										
										
											2016-04-05 10:53:23 +01:00
										 |  |  | 	return z1
 | 
					
						
							|  |  |  | }
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-01-23 10:35:31 +00:00
										 |  |  | // CopyWithoutApex copies zone z without the Apex records.
 | 
					
						
							|  |  |  | func (z *Zone) CopyWithoutApex() *Zone {
 | 
					
						
							|  |  |  | 	z1 := NewZone(z.origin, z.file)
 | 
					
						
							|  |  |  | 	z1.TransferTo = z.TransferTo
 | 
					
						
							|  |  |  | 	z1.TransferFrom = z.TransferFrom
 | 
					
						
							|  |  |  | 	z1.Expired = z.Expired
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	return z1
 | 
					
						
							|  |  |  | }
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-04-02 16:56:16 +01:00
										 |  |  | // Insert inserts r into z.
 | 
					
						
							| 
									
										
										
										
											2016-04-15 14:26:27 +01:00
										 |  |  | func (z *Zone) Insert(r dns.RR) error {
 | 
					
						
							| 
									
										
										
										
											2016-04-16 16:16:52 +01:00
										 |  |  | 	r.Header().Name = strings.ToLower(r.Header().Name)
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-04-15 14:26:27 +01:00
										 |  |  | 	switch h := r.Header().Rrtype; h {
 | 
					
						
							| 
									
										
										
										
											2016-04-16 16:16:52 +01:00
										 |  |  | 	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
 | 
					
						
							|  |  |  | 		}
 | 
					
						
							| 
									
										
										
										
											2016-04-15 14:26:27 +01:00
										 |  |  | 	case dns.TypeSOA:
 | 
					
						
							| 
									
										
										
										
											2016-04-16 16:16:52 +01:00
										 |  |  | 		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)
 | 
					
						
							| 
									
										
										
										
											2016-04-15 14:26:27 +01:00
										 |  |  | 		return nil
 | 
					
						
							|  |  |  | 	case dns.TypeNSEC3, dns.TypeNSEC3PARAM:
 | 
					
						
							| 
									
										
										
										
											2016-09-03 09:37:36 +01:00
										 |  |  | 		return fmt.Errorf("NSEC3 zone is not supported, dropping RR: %s for zone: %s", r.Header().Name, z.origin)
 | 
					
						
							| 
									
										
										
										
											2016-04-15 14:26:27 +01:00
										 |  |  | 	case dns.TypeRRSIG:
 | 
					
						
							| 
									
										
										
										
											2016-04-16 16:16:52 +01:00
										 |  |  | 		x := r.(*dns.RRSIG)
 | 
					
						
							|  |  |  | 		switch x.TypeCovered {
 | 
					
						
							|  |  |  | 		case dns.TypeSOA:
 | 
					
						
							|  |  |  | 			z.Apex.SIGSOA = append(z.Apex.SIGSOA, x)
 | 
					
						
							| 
									
										
										
										
											2016-04-15 14:26:27 +01:00
										 |  |  | 			return nil
 | 
					
						
							| 
									
										
										
										
											2016-04-16 16:16:52 +01:00
										 |  |  | 		case dns.TypeNS:
 | 
					
						
							|  |  |  | 			if r.Header().Name == z.origin {
 | 
					
						
							|  |  |  | 				z.Apex.SIGNS = append(z.Apex.SIGNS, x)
 | 
					
						
							|  |  |  | 				return nil
 | 
					
						
							|  |  |  | 			}
 | 
					
						
							| 
									
										
										
										
											2016-04-15 14:26:27 +01:00
										 |  |  | 		}
 | 
					
						
							| 
									
										
										
										
											2016-04-16 16:16:52 +01:00
										 |  |  | 	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)
 | 
					
						
							| 
									
										
										
										
											2016-04-15 14:26:27 +01:00
										 |  |  | 	}
 | 
					
						
							| 
									
										
										
										
											2016-11-05 14:39:49 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-04-16 16:16:52 +01:00
										 |  |  | 	z.Tree.Insert(r)
 | 
					
						
							| 
									
										
										
										
											2016-04-15 14:26:27 +01:00
										 |  |  | 	return nil
 | 
					
						
							|  |  |  | }
 | 
					
						
							| 
									
										
										
										
											2016-03-27 07:37:23 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-04-02 16:56:16 +01:00
										 |  |  | // Delete deletes r from z.
 | 
					
						
							|  |  |  | func (z *Zone) Delete(r dns.RR) { z.Tree.Delete(r) }
 | 
					
						
							| 
									
										
										
										
											2016-03-28 12:08:05 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-04-03 09:02:34 +01:00
										 |  |  | // TransferAllowed checks if incoming request for transferring the zone is allowed according to the ACLs.
 | 
					
						
							| 
									
										
										
										
											2017-06-21 23:46:20 -07:00
										 |  |  | func (z *Zone) TransferAllowed(state request.Request) bool {
 | 
					
						
							| 
									
										
										
										
											2016-04-03 09:02:34 +01:00
										 |  |  | 	for _, t := range z.TransferTo {
 | 
					
						
							|  |  |  | 		if t == "*" {
 | 
					
						
							|  |  |  | 			return true
 | 
					
						
							|  |  |  | 		}
 | 
					
						
							| 
									
										
										
										
											2017-06-21 23:46:20 -07:00
										 |  |  | 		// If remote IP matches we accept.
 | 
					
						
							|  |  |  | 		remote := state.IP()
 | 
					
						
							|  |  |  | 		to, _, err := net.SplitHostPort(t)
 | 
					
						
							|  |  |  | 		if err != nil {
 | 
					
						
							|  |  |  | 			continue
 | 
					
						
							|  |  |  | 		}
 | 
					
						
							|  |  |  | 		if to == remote {
 | 
					
						
							|  |  |  | 			return true
 | 
					
						
							|  |  |  | 		}
 | 
					
						
							| 
									
										
										
										
											2016-03-28 12:08:05 +01:00
										 |  |  | 	}
 | 
					
						
							| 
									
										
										
										
											2016-04-05 07:37:05 +01:00
										 |  |  | 	// TODO(miek): future matching against IP/CIDR notations
 | 
					
						
							| 
									
										
										
										
											2016-04-03 09:02:34 +01:00
										 |  |  | 	return false
 | 
					
						
							| 
									
										
										
										
											2016-03-28 12:08:05 +01:00
										 |  |  | }
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // All returns all records from the zone, the first record will be the SOA record,
 | 
					
						
							|  |  |  | // otionally followed by all RRSIG(SOA)s.
 | 
					
						
							|  |  |  | func (z *Zone) All() []dns.RR {
 | 
					
						
							| 
									
										
										
										
											2016-10-28 12:57:02 +01:00
										 |  |  | 	if !z.NoReload {
 | 
					
						
							|  |  |  | 		z.reloadMu.RLock()
 | 
					
						
							|  |  |  | 		defer z.reloadMu.RUnlock()
 | 
					
						
							|  |  |  | 	}
 | 
					
						
							| 
									
										
										
										
											2016-04-16 16:16:52 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-03-28 12:08:05 +01:00
										 |  |  | 	records := []dns.RR{}
 | 
					
						
							|  |  |  | 	allNodes := z.Tree.All()
 | 
					
						
							|  |  |  | 	for _, a := range allNodes {
 | 
					
						
							|  |  |  | 		records = append(records, a.All()...)
 | 
					
						
							|  |  |  | 	}
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-04-16 16:16:52 +01:00
										 |  |  | 	if len(z.Apex.SIGNS) > 0 {
 | 
					
						
							|  |  |  | 		records = append(z.Apex.SIGNS, records...)
 | 
					
						
							|  |  |  | 	}
 | 
					
						
							|  |  |  | 	records = append(z.Apex.NS, records...)
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if len(z.Apex.SIGSOA) > 0 {
 | 
					
						
							|  |  |  | 		records = append(z.Apex.SIGSOA, records...)
 | 
					
						
							| 
									
										
										
										
											2016-03-28 12:08:05 +01:00
										 |  |  | 	}
 | 
					
						
							| 
									
										
										
										
											2016-04-16 16:16:52 +01:00
										 |  |  | 	return append([]dns.RR{z.Apex.SOA}, records...)
 | 
					
						
							| 
									
										
										
										
											2016-03-28 12:08:05 +01:00
										 |  |  | }
 | 
					
						
							| 
									
										
										
										
											2016-04-15 14:26:27 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-11-05 14:39:49 +00:00
										 |  |  | // Print prints the zone's tree to stdout.
 | 
					
						
							|  |  |  | func (z *Zone) Print() {
 | 
					
						
							|  |  |  | 	z.Tree.Print()
 | 
					
						
							|  |  |  | }
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // 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
 | 
					
						
							|  |  |  | 	shot := false
 | 
					
						
							|  |  |  | 	for j := 1; j <= i; j++ {
 | 
					
						
							|  |  |  | 		k, shot = dns.PrevLabel(qname, j+z.origLen)
 | 
					
						
							|  |  |  | 		if shot {
 | 
					
						
							|  |  |  | 			return qname, shot
 | 
					
						
							|  |  |  | 		}
 | 
					
						
							|  |  |  | 	}
 | 
					
						
							|  |  |  | 	return qname[k:], false
 | 
					
						
							|  |  |  | }
 |