mirror of
https://github.com/coredns/coredns.git
synced 2025-11-12 23:12:17 -05:00
@@ -32,7 +32,6 @@ func fileParse(c *Controller) (file.Zones, error) {
|
|||||||
|
|
||||||
origin := c.ServerBlockHosts[c.ServerBlockHostIndex]
|
origin := c.ServerBlockHosts[c.ServerBlockHostIndex]
|
||||||
if c.NextArg() {
|
if c.NextArg() {
|
||||||
c.Next()
|
|
||||||
origin = c.Val()
|
origin = c.Val()
|
||||||
}
|
}
|
||||||
// normalize this origin
|
// normalize this origin
|
||||||
@@ -42,12 +41,31 @@ func fileParse(c *Controller) (file.Zones, error) {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return file.Zones{}, err
|
return file.Zones{}, err
|
||||||
}
|
}
|
||||||
|
|
||||||
zone, err := file.Parse(reader, origin, fileName)
|
zone, err := file.Parse(reader, origin, fileName)
|
||||||
if err == nil {
|
if err == nil {
|
||||||
z[origin] = zone
|
z[origin] = zone
|
||||||
}
|
}
|
||||||
names = append(names, origin)
|
names = append(names, origin)
|
||||||
|
if c.NextBlock() {
|
||||||
|
what := c.Val()
|
||||||
|
if !c.NextArg() {
|
||||||
|
return file.Zones{}, c.ArgErr()
|
||||||
|
}
|
||||||
|
value := c.Val()
|
||||||
|
var err error
|
||||||
|
switch what {
|
||||||
|
case "transfer":
|
||||||
|
if value == "out" {
|
||||||
|
z[origin].Transfer.Out = true
|
||||||
|
}
|
||||||
|
if value == "in" {
|
||||||
|
z[origin].Transfer.In = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if err != nil {
|
||||||
|
return file.Zones{}, err
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return file.Zones{Z: z, Names: names}, nil
|
return file.Zones{Z: z, Names: names}, nil
|
||||||
|
|||||||
@@ -1,10 +1,5 @@
|
|||||||
package file
|
package file
|
||||||
|
|
||||||
// TODO(miek): the zone's implementation is basically non-existent
|
|
||||||
// we return a list and when searching for an answer we iterate
|
|
||||||
// over the list. This must be moved to a tree-like structure and
|
|
||||||
// have some fluff for DNSSEC (and be memory efficient).
|
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"io"
|
"io"
|
||||||
"log"
|
"log"
|
||||||
@@ -19,7 +14,6 @@ type (
|
|||||||
File struct {
|
File struct {
|
||||||
Next middleware.Handler
|
Next middleware.Handler
|
||||||
Zones Zones
|
Zones Zones
|
||||||
// Maybe a list of all zones as well, as a []string?
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Zones struct {
|
Zones struct {
|
||||||
@@ -40,6 +34,11 @@ func (f File) ServeDNS(ctx context.Context, w dns.ResponseWriter, r *dns.Msg) (i
|
|||||||
return f.Next.ServeDNS(ctx, w, r)
|
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())
|
rrs, extra, result := z.Lookup(qname, state.QType(), state.Do())
|
||||||
|
|
||||||
m := new(dns.Msg)
|
m := new(dns.Msg)
|
||||||
|
|||||||
@@ -15,26 +15,15 @@ file dbfile [zones...]
|
|||||||
* `zones` zones it should be authoritative for. If empty the zones from the configuration block
|
* `zones` zones it should be authoritative for. If empty the zones from the configuration block
|
||||||
are used.
|
are used.
|
||||||
|
|
||||||
If you want to `round robin` A and AAAA responses look at the `loadbalance` middleware.
|
If you want to round robin A and AAAA responses look at the `loadbalance` middleware.
|
||||||
|
|
||||||
~~~
|
~~~
|
||||||
file {
|
file dbfile [zones... ] {
|
||||||
db <dsds>
|
transfer in|out
|
||||||
masters [...masters...]
|
|
||||||
}
|
}
|
||||||
~~~
|
~~~
|
||||||
|
|
||||||
|
* `transfer` enable zone transfers, for now only `transfer out` does something. It enables outgoing
|
||||||
|
zone transfers when defined.
|
||||||
|
|
||||||
|
|
||||||
* `path` /skydns
|
|
||||||
* `endpoint` endpoints...
|
|
||||||
* `stubzones`
|
|
||||||
|
|
||||||
## Examples
|
## Examples
|
||||||
|
|
||||||
dnssec {
|
|
||||||
file blaat, transparant allow already signed responses
|
|
||||||
ksk bliep.dsdsk
|
|
||||||
}
|
|
||||||
|
|||||||
8
middleware/file/notify.go
Normal file
8
middleware/file/notify.go
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
package file
|
||||||
|
|
||||||
|
// Notify sends notifies to the configured remotes. It will try up to three times
|
||||||
|
// before giving up on a specific remote.
|
||||||
|
func Notify(remotes []string) error {
|
||||||
|
return nil
|
||||||
|
|
||||||
|
}
|
||||||
21
middleware/file/tree/all.go
Normal file
21
middleware/file/tree/all.go
Normal file
@@ -0,0 +1,21 @@
|
|||||||
|
package tree
|
||||||
|
|
||||||
|
// All traverses tree and returns all elements
|
||||||
|
func (t *Tree) All() []*Elem {
|
||||||
|
if t.Root == nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
found := t.Root.all(nil)
|
||||||
|
return found
|
||||||
|
}
|
||||||
|
|
||||||
|
func (n *Node) all(found []*Elem) []*Elem {
|
||||||
|
if n.Left != nil {
|
||||||
|
found = n.Left.all(found)
|
||||||
|
}
|
||||||
|
found = append(found, n.Elem)
|
||||||
|
if n.Right != nil {
|
||||||
|
found = n.Right.all(found)
|
||||||
|
}
|
||||||
|
return found
|
||||||
|
}
|
||||||
@@ -528,6 +528,8 @@ func (n *Node) floor(rr dns.RR) *Node {
|
|||||||
return n
|
return n
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TODO(successor, predecessor)
|
||||||
|
|
||||||
// Ceil returns the smallest value equal to or greater than the query q according to q.Compare().
|
// Ceil returns the smallest value equal to or greater than the query q according to q.Compare().
|
||||||
func (t *Tree) Ceil(rr dns.RR) *Elem {
|
func (t *Tree) Ceil(rr dns.RR) *Elem {
|
||||||
if t.Root == nil {
|
if t.Root == nil {
|
||||||
|
|||||||
61
middleware/file/xfr.go
Normal file
61
middleware/file/xfr.go
Normal file
@@ -0,0 +1,61 @@
|
|||||||
|
package file
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
|
||||||
|
"github.com/miekg/coredns/middleware"
|
||||||
|
|
||||||
|
"github.com/miekg/dns"
|
||||||
|
"golang.org/x/net/context"
|
||||||
|
)
|
||||||
|
|
||||||
|
type (
|
||||||
|
Xfr struct {
|
||||||
|
*Zone
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
// Serve an AXFR (or maybe later an IXFR) as well.
|
||||||
|
func (x Xfr) ServeDNS(ctx context.Context, w dns.ResponseWriter, r *dns.Msg) (int, error) {
|
||||||
|
state := middleware.State{W: w, Req: r}
|
||||||
|
if !x.TransferAllowed(state) {
|
||||||
|
return dns.RcodeServerFailure, nil
|
||||||
|
}
|
||||||
|
if state.QType() != dns.TypeAXFR {
|
||||||
|
return 0, fmt.Errorf("file: xfr called with non xfr type: %d", state.QType())
|
||||||
|
}
|
||||||
|
if state.Proto() == "udp" {
|
||||||
|
return 0, fmt.Errorf("file: xfr called with udp")
|
||||||
|
}
|
||||||
|
|
||||||
|
records := x.All()
|
||||||
|
if len(records) == 0 {
|
||||||
|
return dns.RcodeServerFailure, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
ch := make(chan *dns.Envelope)
|
||||||
|
defer close(ch)
|
||||||
|
tr := new(dns.Transfer)
|
||||||
|
go tr.Out(w, r, ch)
|
||||||
|
|
||||||
|
j, l := 0, 0
|
||||||
|
records = append(records, records[0])
|
||||||
|
for i, r := range records {
|
||||||
|
l += dns.Len(r)
|
||||||
|
if l > transferLength {
|
||||||
|
ch <- &dns.Envelope{RR: records[j:i]}
|
||||||
|
l = 0
|
||||||
|
j = i
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if j < len(records) {
|
||||||
|
ch <- &dns.Envelope{RR: records[j:]}
|
||||||
|
}
|
||||||
|
|
||||||
|
w.Hijack()
|
||||||
|
// w.Close() // Client closes connection
|
||||||
|
return dns.RcodeSuccess, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
//const transferLength = 10e3 // Start a new envelop after message reaches this size.
|
||||||
|
const transferLength = 100 // Start a new envelop after message reaches this size.
|
||||||
34
middleware/file/xfr_test.go
Normal file
34
middleware/file/xfr_test.go
Normal file
@@ -0,0 +1,34 @@
|
|||||||
|
package file
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"strings"
|
||||||
|
)
|
||||||
|
|
||||||
|
func ExampleZone_All() {
|
||||||
|
zone, err := Parse(strings.NewReader(dbMiekNL), testzone, "stdin")
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
records := zone.All()
|
||||||
|
for _, r := range records {
|
||||||
|
fmt.Printf("%+v\n", r)
|
||||||
|
}
|
||||||
|
// Output
|
||||||
|
// xfr_test.go:15: miek.nl. 1800 IN SOA linode.atoom.net. miek.miek.nl. 1282630057 14400 3600 604800 14400
|
||||||
|
// xfr_test.go:15: www.miek.nl. 1800 IN CNAME a.miek.nl.
|
||||||
|
// xfr_test.go:15: miek.nl. 1800 IN NS linode.atoom.net.
|
||||||
|
// xfr_test.go:15: miek.nl. 1800 IN NS ns-ext.nlnetlabs.nl.
|
||||||
|
// xfr_test.go:15: miek.nl. 1800 IN NS omval.tednet.nl.
|
||||||
|
// xfr_test.go:15: miek.nl. 1800 IN NS ext.ns.whyscream.net.
|
||||||
|
// xfr_test.go:15: miek.nl. 1800 IN MX 1 aspmx.l.google.com.
|
||||||
|
// xfr_test.go:15: miek.nl. 1800 IN MX 5 alt1.aspmx.l.google.com.
|
||||||
|
// xfr_test.go:15: miek.nl. 1800 IN MX 5 alt2.aspmx.l.google.com.
|
||||||
|
// xfr_test.go:15: miek.nl. 1800 IN MX 10 aspmx2.googlemail.com.
|
||||||
|
// xfr_test.go:15: miek.nl. 1800 IN MX 10 aspmx3.googlemail.com.
|
||||||
|
// xfr_test.go:15: miek.nl. 1800 IN A 139.162.196.78
|
||||||
|
// xfr_test.go:15: miek.nl. 1800 IN AAAA 2a01:7e00::f03c:91ff:fef1:6735
|
||||||
|
// xfr_test.go:15: archive.miek.nl. 1800 IN CNAME a.miek.nl.
|
||||||
|
// xfr_test.go:15: a.miek.nl. 1800 IN A 139.162.196.78
|
||||||
|
// xfr_test.go:15: a.miek.nl. 1800 IN AAAA 2a01:7e00::f03c:91ff:fef1:6735
|
||||||
|
}
|
||||||
@@ -1,20 +1,29 @@
|
|||||||
package file
|
package file
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"github.com/miekg/coredns/middleware"
|
||||||
"github.com/miekg/coredns/middleware/file/tree"
|
"github.com/miekg/coredns/middleware/file/tree"
|
||||||
|
|
||||||
"github.com/miekg/dns"
|
"github.com/miekg/dns"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
type Transfer struct {
|
||||||
|
Out bool
|
||||||
|
In bool
|
||||||
|
// more later
|
||||||
|
}
|
||||||
|
|
||||||
type Zone struct {
|
type Zone struct {
|
||||||
SOA *dns.SOA
|
SOA *dns.SOA
|
||||||
SIG []*dns.RRSIG
|
SIG []dns.RR
|
||||||
name string
|
name string
|
||||||
*tree.Tree
|
*tree.Tree
|
||||||
|
Masters []string
|
||||||
|
Transfer *Transfer
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewZone(name string) *Zone {
|
func NewZone(name string) *Zone {
|
||||||
return &Zone{name: dns.Fqdn(name), Tree: &tree.Tree{}}
|
return &Zone{name: dns.Fqdn(name), Tree: &tree.Tree{}, Transfer: &Transfer{}}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (z *Zone) Insert(r dns.RR) {
|
func (z *Zone) Insert(r dns.RR) {
|
||||||
@@ -24,3 +33,28 @@ func (z *Zone) Insert(r dns.RR) {
|
|||||||
func (z *Zone) Delete(r dns.RR) {
|
func (z *Zone) Delete(r dns.RR) {
|
||||||
z.Tree.Delete(r)
|
z.Tree.Delete(r)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// It the transfer request allowed.
|
||||||
|
func (z *Zone) TransferAllowed(state middleware.State) bool {
|
||||||
|
if z.Transfer == nil {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
return z.Transfer.Out
|
||||||
|
}
|
||||||
|
|
||||||
|
// 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 {
|
||||||
|
records := []dns.RR{}
|
||||||
|
allNodes := z.Tree.All()
|
||||||
|
for _, a := range allNodes {
|
||||||
|
records = append(records, a.All()...)
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(z.SIG) > 0 {
|
||||||
|
records = append(z.SIG, records...)
|
||||||
|
}
|
||||||
|
return append([]dns.RR{z.SOA}, records...)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Apex function?
|
||||||
|
|||||||
@@ -37,7 +37,9 @@ func NewResponseRecorder(w dns.ResponseWriter) *ResponseRecorder {
|
|||||||
// underlying ResponseWriter's WriteMsg method.
|
// underlying ResponseWriter's WriteMsg method.
|
||||||
func (r *ResponseRecorder) WriteMsg(res *dns.Msg) error {
|
func (r *ResponseRecorder) WriteMsg(res *dns.Msg) error {
|
||||||
r.rcode = res.Rcode
|
r.rcode = res.Rcode
|
||||||
r.size = res.Len()
|
// We may get called multiple times (axfr for instance).
|
||||||
|
// Save the last message, but add the sizes.
|
||||||
|
r.size += res.Len()
|
||||||
r.msg = res
|
r.msg = res
|
||||||
return r.ResponseWriter.WriteMsg(res)
|
return r.ResponseWriter.WriteMsg(res)
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user