2016-10-17 18:37:56 +01:00
|
|
|
// Package auto implements an on-the-fly loading file backend.
|
|
|
|
|
package auto
|
|
|
|
|
|
|
|
|
|
import (
|
2018-04-22 08:34:35 +01:00
|
|
|
"context"
|
2016-10-17 18:37:56 +01:00
|
|
|
"regexp"
|
|
|
|
|
"time"
|
|
|
|
|
|
2017-09-14 09:36:06 +01:00
|
|
|
"github.com/coredns/coredns/plugin"
|
|
|
|
|
"github.com/coredns/coredns/plugin/file"
|
|
|
|
|
"github.com/coredns/coredns/plugin/metrics"
|
2018-02-16 03:44:50 -05:00
|
|
|
"github.com/coredns/coredns/plugin/pkg/upstream"
|
2020-09-24 11:30:39 -07:00
|
|
|
"github.com/coredns/coredns/plugin/transfer"
|
2017-02-21 22:51:47 -08:00
|
|
|
"github.com/coredns/coredns/request"
|
2016-10-17 18:37:56 +01:00
|
|
|
|
|
|
|
|
"github.com/miekg/dns"
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
type (
|
|
|
|
|
// Auto holds the zones and the loader configuration for automatically loading zones.
|
|
|
|
|
Auto struct {
|
2017-09-14 09:36:06 +01:00
|
|
|
Next plugin.Handler
|
2016-10-17 18:37:56 +01:00
|
|
|
*Zones
|
|
|
|
|
|
2020-09-24 11:30:39 -07:00
|
|
|
metrics *metrics.Metrics
|
|
|
|
|
transfer *transfer.Transfer
|
2016-10-17 18:37:56 +01:00
|
|
|
loader
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
loader struct {
|
|
|
|
|
directory string
|
|
|
|
|
template string
|
|
|
|
|
re *regexp.Regexp
|
|
|
|
|
|
2018-09-29 17:50:49 +02:00
|
|
|
ReloadInterval time.Duration
|
2019-01-13 16:54:49 +00:00
|
|
|
upstream *upstream.Upstream // Upstream for looking up names during the resolution process.
|
2016-10-17 18:37:56 +01:00
|
|
|
}
|
|
|
|
|
)
|
|
|
|
|
|
2018-03-01 17:14:53 -08:00
|
|
|
// ServeDNS implements the plugin.Handler interface.
|
2016-10-17 18:37:56 +01:00
|
|
|
func (a Auto) ServeDNS(ctx context.Context, w dns.ResponseWriter, r *dns.Msg) (int, error) {
|
2019-03-26 14:37:30 +00:00
|
|
|
state := request.Request{W: w, Req: r}
|
2016-10-17 18:37:56 +01:00
|
|
|
qname := state.Name()
|
|
|
|
|
|
2018-03-01 17:14:53 -08:00
|
|
|
// Precheck with the origins, i.e. are we allowed to look here?
|
2017-09-14 09:36:06 +01:00
|
|
|
zone := plugin.Zones(a.Zones.Origins()).Matches(qname)
|
2016-10-17 18:37:56 +01:00
|
|
|
if zone == "" {
|
2017-09-14 09:36:06 +01:00
|
|
|
return plugin.NextOrFailure(a.Name(), a.Next, ctx, w, r)
|
2016-10-17 18:37:56 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Now the real zone.
|
2017-09-14 09:36:06 +01:00
|
|
|
zone = plugin.Zones(a.Zones.Names()).Matches(qname)
|
2020-10-01 21:25:19 +08:00
|
|
|
if zone == "" {
|
|
|
|
|
return plugin.NextOrFailure(a.Name(), a.Next, ctx, w, r)
|
|
|
|
|
}
|
2016-10-17 18:37:56 +01:00
|
|
|
|
2025-04-04 20:27:39 +02:00
|
|
|
a.RLock()
|
|
|
|
|
z, ok := a.Z[zone]
|
|
|
|
|
a.RUnlock()
|
2016-10-17 18:37:56 +01:00
|
|
|
|
2016-11-07 11:12:20 +00:00
|
|
|
if !ok || z == nil {
|
2016-10-17 18:37:56 +01:00
|
|
|
return dns.RcodeServerFailure, nil
|
|
|
|
|
}
|
|
|
|
|
|
2021-03-09 21:17:34 +01:00
|
|
|
// If transfer is not loaded, we'll see these, answer with refused (no transfer allowed).
|
|
|
|
|
if state.QType() == dns.TypeAXFR || state.QType() == dns.TypeIXFR {
|
|
|
|
|
return dns.RcodeRefused, nil
|
|
|
|
|
}
|
|
|
|
|
|
2019-03-26 14:37:30 +00:00
|
|
|
answer, ns, extra, result := z.Lookup(ctx, state, qname)
|
2016-10-17 18:37:56 +01:00
|
|
|
|
|
|
|
|
m := new(dns.Msg)
|
|
|
|
|
m.SetReply(r)
|
2018-12-30 17:05:08 +01:00
|
|
|
m.Authoritative = true
|
2016-10-17 18:37:56 +01:00
|
|
|
m.Answer, m.Ns, m.Extra = answer, ns, extra
|
|
|
|
|
|
|
|
|
|
switch result {
|
|
|
|
|
case file.Success:
|
|
|
|
|
case file.NoData:
|
|
|
|
|
case file.NameError:
|
|
|
|
|
m.Rcode = dns.RcodeNameError
|
|
|
|
|
case file.Delegation:
|
|
|
|
|
m.Authoritative = false
|
|
|
|
|
case file.ServerFailure:
|
2021-09-14 04:08:22 -04:00
|
|
|
// If the result is SERVFAIL and the answer is non-empty, then the SERVFAIL came from an
|
|
|
|
|
// external CNAME lookup and the answer contains the CNAME with no target record. We should
|
|
|
|
|
// write the CNAME record to the client instead of sending an empty SERVFAIL response.
|
|
|
|
|
if len(m.Answer) == 0 {
|
|
|
|
|
return dns.RcodeServerFailure, nil
|
|
|
|
|
}
|
|
|
|
|
// The rcode in the response should be the rcode received from the target lookup. RFC 6604 section 3
|
|
|
|
|
m.Rcode = dns.RcodeServerFailure
|
2016-10-17 18:37:56 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
w.WriteMsg(m)
|
|
|
|
|
return dns.RcodeSuccess, nil
|
|
|
|
|
}
|
2016-10-26 10:01:52 +01:00
|
|
|
|
2016-10-27 11:48:37 +00:00
|
|
|
// Name implements the Handler interface.
|
2016-10-26 10:01:52 +01:00
|
|
|
func (a Auto) Name() string { return "auto" }
|