aboutsummaryrefslogtreecommitdiff
path: root/middleware/file/file.go
blob: 237515a57cd97938a5c186c06b472ef79b8a0256 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
package file

import (
	"io"
	"log"

	"github.com/miekg/coredns/middleware"

	"github.com/miekg/dns"
	"golang.org/x/net/context"
)

type (
	File struct {
		Next  middleware.Handler
		Zones Zones
	}

	Zones struct {
		Z     map[string]*Zone
		Names []string
	}
)

func (f File) ServeDNS(ctx context.Context, w dns.ResponseWriter, r *dns.Msg) (int, error) {
	state := middleware.State{W: w, Req: r}
	qname := state.Name()
	zone := middleware.Zones(f.Zones.Names).Matches(qname)
	if zone == "" {
		return f.Next.ServeDNS(ctx, w, r)
	}
	z, ok := f.Zones.Z[zone]
	if !ok {
		return f.Next.ServeDNS(ctx, w, r)
	}

	if state.Proto() != "udp" && state.QType() == dns.TypeAXFR {
		xfr := Xfr{z}
		return xfr.ServeDNS(ctx, w, r)
	}

	rrs, extra, result := z.Lookup(qname, state.QType(), state.Do())

	m := new(dns.Msg)
	m.SetReply(r)
	m.Authoritative, m.RecursionAvailable, m.Compress = true, true, true

	switch result {
	case Success:
		// case?
		m.Answer = rrs
		m.Extra = extra
		// Ns section
	case NameError:
		m.Rcode = dns.RcodeNameError
		fallthrough
	case NoData:
		// case?
		m.Ns = rrs
	default:
		// TODO
	}
	m, _ = state.Scrub(m)
	w.WriteMsg(m)
	return dns.RcodeSuccess, nil
}

// Parse parses the zone in filename and returns a new Zone or an error.
func Parse(f io.Reader, origin, fileName string) (*Zone, error) {
	tokens := dns.ParseZone(f, dns.Fqdn(origin), fileName)
	z := NewZone(origin)
	for x := range tokens {
		if x.Error != nil {
			log.Printf("[ERROR] failed to parse %s: %v", origin, x.Error)
			return nil, x.Error
		}
		if x.RR.Header().Rrtype == dns.TypeSOA {
			z.SOA = x.RR.(*dns.SOA)
			continue
		}
		z.Insert(x.RR)
	}
	return z, nil
}