aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGravatar Miek Gieben <miek@miek.nl> 2018-01-07 16:32:59 +0000
committerGravatar GitHub <noreply@github.com> 2018-01-07 16:32:59 +0000
commitc6febe6250361eee580dbb8a601a444f23ed7ac2 (patch)
treeee81ab66cfa382d66bc085d31804efb8c1059af2
parent84ebbbc7225a8d7eb5e00c0c525f7e12932a9fe4 (diff)
downloadcoredns-c6febe6250361eee580dbb8a601a444f23ed7ac2.tar.gz
coredns-c6febe6250361eee580dbb8a601a444f23ed7ac2.tar.zst
coredns-c6febe6250361eee580dbb8a601a444f23ed7ac2.zip
Add pkg/fall for Fallthrough (#1355)
* Add pkg/fall for Fallthrough Move this into it's own package to facilitate tests. Important bug was fixed: make the names fully qualified. Add fall package to hosts, reverse, etcd, and fix kubernetes and any tests. The k8s tests are still as-is, might need a future cleanup.
-rw-r--r--plugin.md8
-rw-r--r--plugin/etcd/README.md5
-rw-r--r--plugin/etcd/etcd.go17
-rw-r--r--plugin/etcd/handler.go2
-rw-r--r--plugin/etcd/multi_test.go3
-rw-r--r--plugin/etcd/setup.go4
-rw-r--r--plugin/hosts/README.md7
-rw-r--r--plugin/hosts/hosts.go5
-rw-r--r--plugin/hosts/setup.go11
-rw-r--r--plugin/hosts/setup_test.go46
-rw-r--r--plugin/kubernetes/handler.go2
-rw-r--r--plugin/kubernetes/kubernetes.go3
-rw-r--r--plugin/kubernetes/setup.go5
-rw-r--r--plugin/kubernetes/setup_test.go4
-rw-r--r--plugin/pkg/fall/fall.go77
-rw-r--r--plugin/pkg/fall/fall_test.go48
-rw-r--r--plugin/plugin.go15
-rw-r--r--plugin/plugin_test.go21
-rw-r--r--plugin/reverse/README.md5
-rw-r--r--plugin/reverse/reverse.go10
-rw-r--r--plugin/reverse/reverse_test.go1
-rw-r--r--plugin/reverse/setup.go28
22 files changed, 217 insertions, 110 deletions
diff --git a/plugin.md b/plugin.md
index 40701cf34..28168f241 100644
--- a/plugin.md
+++ b/plugin.md
@@ -41,15 +41,15 @@ We use the Unix manual page style:
### Example Domain Names
-Please be sure to use `example.org` or `example.net` in any examples you provide. These are the
-standard domain names created for this purpose.
+Please be sure to use `example.org` or `example.net` in any examples and tests you provide. These
+are the standard domain names created for this purpose.
## Fallthrough
In a perfect world the following would be true for plugin: "Either you are responsible for a zone or
not". If the answer is "not", the plugin should call the next plugin in the chain. If "yes" it
should handle *all* names that fall in this zone and the names below - i.e. it should handle the
-entire domain.
+entire domain and all sub domains.
~~~ txt
. {
@@ -61,7 +61,7 @@ In this example the *file* plugin is handling all names below (and including) `e
a query comes in that is not a subdomain (or equal to) `example.org` the next plugin is called.
Now, the world isn't perfect, and there are good reasons to "fallthrough" to the next middlware,
-meaning a plugin is only responsible for a subset of names within the zone. The first of these
+meaning a plugin is only responsible for a *subset* of names within the zone. The first of these
to appear was the *reverse* plugin that synthesis PTR and A/AAAA responses (useful with IPv6).
The nature of the *reverse* plugin is such that it only deals with A,AAAA and PTR and then only
diff --git a/plugin/etcd/README.md b/plugin/etcd/README.md
index 6073a008a..e5e30a63c 100644
--- a/plugin/etcd/README.md
+++ b/plugin/etcd/README.md
@@ -29,7 +29,7 @@ If you want to `round robin` A and AAAA responses look at the `loadbalance` plug
~~~
etcd [ZONES...] {
stubzones
- fallthrough
+ fallthrough [ZONES...]
path PATH
endpoint ENDPOINT...
upstream ADDRESS...
@@ -40,6 +40,9 @@ etcd [ZONES...] {
* `stubzones` enables the stub zones feature. The stubzone is *only* done in the etcd tree located
under the *first* zone specified.
* `fallthrough` If zone matches but no record can be generated, pass request to the next plugin.
+ If **[ZONES...]** is omitted, then fallthrough happens for all zones for which the plugin
+ is authoritative. If specific zones are listed (for example `in-addr.arpa` and `ip6.arpa`), then only
+ queries for those zones will be subject to fallthrough.
* **PATH** the path inside etcd. Defaults to "/skydns".
* **ENDPOINT** the etcd endpoints. Defaults to "http://localhost:2397".
* `upstream` upstream resolvers to be used resolve external names found in etcd (think CNAMEs)
diff --git a/plugin/etcd/etcd.go b/plugin/etcd/etcd.go
index adc8331f2..14c24d06e 100644
--- a/plugin/etcd/etcd.go
+++ b/plugin/etcd/etcd.go
@@ -9,6 +9,7 @@ import (
"github.com/coredns/coredns/plugin"
"github.com/coredns/coredns/plugin/etcd/msg"
+ "github.com/coredns/coredns/plugin/pkg/fall"
"github.com/coredns/coredns/plugin/proxy"
"github.com/coredns/coredns/request"
@@ -19,14 +20,14 @@ import (
// Etcd is a plugin talks to an etcd cluster.
type Etcd struct {
- Next plugin.Handler
- Fallthrough bool
- Zones []string
- PathPrefix string
- Proxy proxy.Proxy // Proxy for looking up names during the resolution process
- Client etcdc.KeysAPI
- Ctx context.Context
- Stubmap *map[string]proxy.Proxy // list of proxies for stub resolving.
+ Next plugin.Handler
+ Fall *fall.F
+ Zones []string
+ PathPrefix string
+ Proxy proxy.Proxy // Proxy for looking up names during the resolution process
+ Client etcdc.KeysAPI
+ Ctx context.Context
+ Stubmap *map[string]proxy.Proxy // list of proxies for stub resolving.
endpoints []string // Stored here as well, to aid in testing.
}
diff --git a/plugin/etcd/handler.go b/plugin/etcd/handler.go
index 06dae1e9b..6d2a7a2bf 100644
--- a/plugin/etcd/handler.go
+++ b/plugin/etcd/handler.go
@@ -67,7 +67,7 @@ func (e *Etcd) ServeDNS(ctx context.Context, w dns.ResponseWriter, r *dns.Msg) (
}
if e.IsNameError(err) {
- if e.Fallthrough {
+ if e.Fall.Through(state.Name()) {
return plugin.NextOrFailure(e.Name(), e.Next, ctx, w, r)
}
// Make err nil when returning here, so we don't log spam for NXDOMAIN.
diff --git a/plugin/etcd/multi_test.go b/plugin/etcd/multi_test.go
index 3ff423d7e..d58d22de0 100644
--- a/plugin/etcd/multi_test.go
+++ b/plugin/etcd/multi_test.go
@@ -7,6 +7,7 @@ import (
"github.com/coredns/coredns/plugin/etcd/msg"
"github.com/coredns/coredns/plugin/pkg/dnstest"
+ "github.com/coredns/coredns/plugin/pkg/fall"
"github.com/coredns/coredns/plugin/test"
"github.com/miekg/dns"
@@ -15,7 +16,7 @@ import (
func TestMultiLookup(t *testing.T) {
etc := newEtcdPlugin()
etc.Zones = []string{"skydns.test.", "miek.nl."}
- etc.Fallthrough = true
+ etc.Fall = fall.New()
etc.Next = test.ErrorHandler()
for _, serv := range servicesMulti {
diff --git a/plugin/etcd/setup.go b/plugin/etcd/setup.go
index e78ce6de7..5fbfe4d18 100644
--- a/plugin/etcd/setup.go
+++ b/plugin/etcd/setup.go
@@ -6,6 +6,7 @@ import (
"github.com/coredns/coredns/core/dnsserver"
"github.com/coredns/coredns/plugin"
"github.com/coredns/coredns/plugin/pkg/dnsutil"
+ "github.com/coredns/coredns/plugin/pkg/fall"
mwtls "github.com/coredns/coredns/plugin/pkg/tls"
"github.com/coredns/coredns/plugin/proxy"
@@ -73,7 +74,8 @@ func etcdParse(c *caddy.Controller) (*Etcd, bool, error) {
case "stubzones":
stubzones = true
case "fallthrough":
- etc.Fallthrough = true
+ etc.Fall = fall.New()
+ etc.Fall.SetZones(c.RemainingArgs())
case "debug":
/* it is a noop now */
case "path":
diff --git a/plugin/hosts/README.md b/plugin/hosts/README.md
index 0b7bef38b..b435e0a88 100644
--- a/plugin/hosts/README.md
+++ b/plugin/hosts/README.md
@@ -16,12 +16,12 @@ available hosts files that block access to advertising servers.
~~~
hosts [FILE [ZONES...]] {
[INLINE]
- fallthrough
+ fallthrough [ZONES...]
}
~~~
* **FILE** the hosts file to read and parse. If the path is relative the path from the *root*
- directive will be prepended to it. Defaults to /etc/hosts if omitted. We scan the file for changes
+ directive will be prepended to it. Defaults to /etc/hosts if omitted. We scan the file for changes
every 5 seconds.
* **ZONES** zones it should be authoritative for. If empty, the zones from the configuration block
are used.
@@ -29,6 +29,9 @@ hosts [FILE [ZONES...]] {
then all of them will be treated as the additional content for hosts file. The specified hosts
file path will still be read but entries will be overrided.
* `fallthrough` If zone matches and no record can be generated, pass request to the next plugin.
+ If **[ZONES...]** is omitted, then fallthrough happens for all zones for which the plugin
+ is authoritative. If specific zones are listed (for example `in-addr.arpa` and `ip6.arpa`), then only
+ queries for those zones will be subject to fallthrough.
## Examples
diff --git a/plugin/hosts/hosts.go b/plugin/hosts/hosts.go
index 09dedbb64..5f9766d47 100644
--- a/plugin/hosts/hosts.go
+++ b/plugin/hosts/hosts.go
@@ -7,6 +7,7 @@ import (
"github.com/coredns/coredns/plugin"
"github.com/coredns/coredns/plugin/pkg/dnsutil"
+ "github.com/coredns/coredns/plugin/pkg/fall"
"github.com/coredns/coredns/request"
"github.com/miekg/dns"
)
@@ -16,7 +17,7 @@ type Hosts struct {
Next plugin.Handler
*Hostsfile
- Fallthrough bool
+ Fall *fall.F
}
// ServeDNS implements the plugin.Handle interface.
@@ -52,7 +53,7 @@ func (h Hosts) ServeDNS(ctx context.Context, w dns.ResponseWriter, r *dns.Msg) (
}
if len(answers) == 0 {
- if h.Fallthrough {
+ if h.Fall.Through(qname) {
return plugin.NextOrFailure(h.Name(), h.Next, ctx, w, r)
}
if !h.otherRecordsExist(state.QType(), qname) {
diff --git a/plugin/hosts/setup.go b/plugin/hosts/setup.go
index 1b281b9a3..35b0c5483 100644
--- a/plugin/hosts/setup.go
+++ b/plugin/hosts/setup.go
@@ -9,6 +9,7 @@ import (
"github.com/coredns/coredns/core/dnsserver"
"github.com/coredns/coredns/plugin"
+ "github.com/coredns/coredns/plugin/pkg/fall"
"github.com/mholt/caddy"
)
@@ -105,14 +106,10 @@ func hostsParse(c *caddy.Controller) (Hosts, error) {
for c.NextBlock() {
switch c.Val() {
case "fallthrough":
- args := c.RemainingArgs()
- if len(args) == 0 {
- h.Fallthrough = true
- continue
- }
- return h, c.ArgErr()
+ h.Fall = fall.New()
+ h.Fall.SetZones(c.RemainingArgs())
default:
- if !h.Fallthrough {
+ if h.Fall.IsNil() {
line := strings.Join(append([]string{c.Val()}, c.RemainingArgs()...), " ")
inline = append(inline, line)
continue
diff --git a/plugin/hosts/setup_test.go b/plugin/hosts/setup_test.go
index b401d58dc..58351cc52 100644
--- a/plugin/hosts/setup_test.go
+++ b/plugin/hosts/setup_test.go
@@ -3,6 +3,8 @@ package hosts
import (
"testing"
+ "github.com/coredns/coredns/plugin/pkg/fall"
+
"github.com/mholt/caddy"
)
@@ -12,48 +14,48 @@ func TestHostsParse(t *testing.T) {
shouldErr bool
expectedPath string
expectedOrigins []string
- expectedFallthrough bool
+ expectedFallthrough *fall.F
}{
{
`hosts
`,
- false, "/etc/hosts", nil, false,
+ false, "/etc/hosts", nil, nil,
},
{
`hosts /tmp`,
- false, "/tmp", nil, false,
+ false, "/tmp", nil, nil,
},
{
`hosts /etc/hosts miek.nl.`,
- false, "/etc/hosts", []string{"miek.nl."}, false,
+ false, "/etc/hosts", []string{"miek.nl."}, nil,
},
{
`hosts /etc/hosts miek.nl. pun.gent.`,
- false, "/etc/hosts", []string{"miek.nl.", "pun.gent."}, false,
+ false, "/etc/hosts", []string{"miek.nl.", "pun.gent."}, nil,
},
{
`hosts {
fallthrough
}`,
- false, "/etc/hosts", nil, true,
+ false, "/etc/hosts", nil, fall.Zero(),
},
{
`hosts /tmp {
fallthrough
}`,
- false, "/tmp", nil, true,
+ false, "/tmp", nil, fall.Zero(),
},
{
`hosts /etc/hosts miek.nl. {
fallthrough
}`,
- false, "/etc/hosts", []string{"miek.nl."}, true,
+ false, "/etc/hosts", []string{"miek.nl."}, fall.Zero(),
},
{
`hosts /etc/hosts miek.nl 10.0.0.9/8 {
fallthrough
}`,
- false, "/etc/hosts", []string{"miek.nl.", "10.in-addr.arpa."}, true,
+ false, "/etc/hosts", []string{"miek.nl.", "10.in-addr.arpa."}, fall.Zero(),
},
}
@@ -70,8 +72,8 @@ func TestHostsParse(t *testing.T) {
t.Fatalf("Test %d expected %v, got %v", i, test.expectedPath, h.path)
}
} else {
- if h.Fallthrough != test.expectedFallthrough {
- t.Fatalf("Test %d expected fallthrough of %v, got %v", i, test.expectedFallthrough, h.Fallthrough)
+ if !h.Fall.Equal(test.expectedFallthrough) {
+ t.Fatalf("Test %d expected fallthrough of %v, got %v", i, test.expectedFallthrough, h.Fall)
}
if len(h.Origins) != len(test.expectedOrigins) {
t.Fatalf("Test %d expected %v, got %v", i, test.expectedOrigins, h.Origins)
@@ -90,7 +92,7 @@ func TestHostsInlineParse(t *testing.T) {
inputFileRules string
shouldErr bool
expectedbyAddr map[string][]string
- expectedFallthrough bool
+ expectedFallthrough *fall.F
}{
{
`hosts highly_unlikely_to_exist_hosts_file example.org {
@@ -103,28 +105,28 @@ func TestHostsInlineParse(t *testing.T) {
`example.org.`,
},
},
- true,
+ fall.Zero(),
},
{
`hosts highly_unlikely_to_exist_hosts_file example.org {
- 10.0.0.1 example.org
- }`,
+ 10.0.0.1 example.org
+ }`,
false,
map[string][]string{
`10.0.0.1`: {
`example.org.`,
},
},
- false,
+ nil,
},
{
`hosts highly_unlikely_to_exist_hosts_file example.org {
- fallthrough
- 10.0.0.1 example.org
- }`,
+ fallthrough
+ 10.0.0.1 example.org
+ }`,
true,
map[string][]string{},
- true,
+ fall.Zero(),
},
}
@@ -137,8 +139,8 @@ func TestHostsInlineParse(t *testing.T) {
} else if err != nil && !test.shouldErr {
t.Fatalf("Test %d expected no errors, but got '%v'", i, err)
} else if !test.shouldErr {
- if h.Fallthrough != test.expectedFallthrough {
- t.Fatalf("Test %d expected fallthrough of %v, got %v", i, test.expectedFallthrough, h.Fallthrough)
+ if !h.Fall.Equal(test.expectedFallthrough) {
+ t.Fatalf("Test %d expected fallthrough of %v, got %v", i, test.expectedFallthrough, h.Fall)
}
for k, expectedVal := range test.expectedbyAddr {
if val, ok := h.hmap.byAddr[k]; !ok {
diff --git a/plugin/kubernetes/handler.go b/plugin/kubernetes/handler.go
index 4606e3747..e02608a6b 100644
--- a/plugin/kubernetes/handler.go
+++ b/plugin/kubernetes/handler.go
@@ -59,7 +59,7 @@ func (k Kubernetes) ServeDNS(ctx context.Context, w dns.ResponseWriter, r *dns.M
}
if k.IsNameError(err) {
- if plugin.Fallthrough(k.Fallthrough, state.Name()) {
+ if k.Fall.Through(state.Name()) {
return plugin.NextOrFailure(k.Name(), k.Next, ctx, w, r)
}
return plugin.BackendError(&k, zone, dns.RcodeNameError, state, nil /* err */, plugin.Options{})
diff --git a/plugin/kubernetes/kubernetes.go b/plugin/kubernetes/kubernetes.go
index 66821380e..a41397848 100644
--- a/plugin/kubernetes/kubernetes.go
+++ b/plugin/kubernetes/kubernetes.go
@@ -12,6 +12,7 @@ import (
"github.com/coredns/coredns/plugin"
"github.com/coredns/coredns/plugin/etcd/msg"
"github.com/coredns/coredns/plugin/pkg/dnsutil"
+ "github.com/coredns/coredns/plugin/pkg/fall"
"github.com/coredns/coredns/plugin/pkg/healthcheck"
"github.com/coredns/coredns/plugin/proxy"
"github.com/coredns/coredns/request"
@@ -40,7 +41,7 @@ type Kubernetes struct {
Namespaces map[string]bool
podMode string
endpointNameMode bool
- Fallthrough *[]string // nil = disabled, empty = all zones, o/w zones
+ Fall *fall.F
ttl uint32
primaryZoneIndex int
diff --git a/plugin/kubernetes/setup.go b/plugin/kubernetes/setup.go
index 41727cb7e..f4de8d72a 100644
--- a/plugin/kubernetes/setup.go
+++ b/plugin/kubernetes/setup.go
@@ -10,6 +10,7 @@ import (
"github.com/coredns/coredns/core/dnsserver"
"github.com/coredns/coredns/plugin"
"github.com/coredns/coredns/plugin/pkg/dnsutil"
+ "github.com/coredns/coredns/plugin/pkg/fall"
"github.com/coredns/coredns/plugin/proxy"
"github.com/mholt/caddy"
@@ -172,8 +173,8 @@ func kubernetesParse(c *caddy.Controller) (*Kubernetes, dnsControlOpts, error) {
}
return nil, opts, c.ArgErr()
case "fallthrough":
- zones := c.RemainingArgs()
- k8s.Fallthrough = &zones
+ k8s.Fall = fall.New()
+ k8s.Fall.SetZones(c.RemainingArgs())
case "upstream":
args := c.RemainingArgs()
if len(args) == 0 {
diff --git a/plugin/kubernetes/setup_test.go b/plugin/kubernetes/setup_test.go
index 6f726c7c4..c7c6c15ce 100644
--- a/plugin/kubernetes/setup_test.go
+++ b/plugin/kubernetes/setup_test.go
@@ -347,7 +347,7 @@ func TestKubernetesParse(t *testing.T) {
defaultResyncPeriod,
"",
podModeDisabled,
- &[]string{"ip6.arpa", "inaddr.arpa", "foo.com"},
+ &[]string{"ip6.arpa.", "inaddr.arpa.", "foo.com."},
nil,
},
// Valid upstream
@@ -443,7 +443,7 @@ func TestKubernetesParse(t *testing.T) {
}
// fallthrough
- foundFallthrough := k8sController.Fallthrough
+ foundFallthrough := k8sController.Fall
if foundFallthrough != nil {
failed := false
if test.expectedFallthrough == nil {
diff --git a/plugin/pkg/fall/fall.go b/plugin/pkg/fall/fall.go
new file mode 100644
index 000000000..99ad34618
--- /dev/null
+++ b/plugin/pkg/fall/fall.go
@@ -0,0 +1,77 @@
+// Package fall handles the fallthrough logic used in plugins that support it.
+package fall
+
+import (
+ "github.com/coredns/coredns/plugin"
+)
+
+// F can be nil to allow for no fallthrough, empty allow all zones to fallthrough or
+// contain a zone list that is checked.
+type F []string
+
+// New returns a new F.
+func New() *F { return new(F) }
+
+// Through will check if we should fallthrough for qname. Note that we've named the
+// variable in each plugin "Fall", so this then reads Fall.Through().
+func (f *F) Through(qname string) bool {
+ if f == nil {
+ return false
+ }
+ if len(*f) == 0 {
+ return true
+ }
+ zone := plugin.Zones(*f).Matches(qname)
+ return zone != ""
+}
+
+// SetZones will set zones in f.
+func (f *F) SetZones(zones []string) {
+ for i := range zones {
+ zones[i] = plugin.Host(zones[i]).Normalize()
+ }
+ *f = zones
+}
+
+// Example returns an F with example.org. as the zone name.
+var Example = func() *F {
+ f := F([]string{"example.org."})
+ return &f
+}()
+
+// Zero returns a zero valued F.
+var Zero = func() *F {
+ f := F([]string{})
+ return &f
+}
+
+// IsNil returns true is f is nil.
+func (f *F) IsNil() bool { return f == nil }
+
+// IsZero returns true is f is zero (and not nil).
+func (f *F) IsZero() bool {
+ if f == nil {
+ return false
+ }
+ return len(*f) == 0
+}
+
+// Equal returns true if f and g are equal. Only useful in tests, The (possible) zones
+// are *not* checked.
+func (f *F) Equal(g *F) bool {
+ if f.IsNil() {
+ if g.IsNil() {
+ return true
+ }
+ return false
+ }
+ if f.IsZero() {
+ if g.IsZero() {
+ return true
+ }
+ }
+ if len(*f) != len(*g) {
+ return false
+ }
+ return true
+}
diff --git a/plugin/pkg/fall/fall_test.go b/plugin/pkg/fall/fall_test.go
new file mode 100644
index 000000000..4cc043a38
--- /dev/null
+++ b/plugin/pkg/fall/fall_test.go
@@ -0,0 +1,48 @@
+package fall
+
+import "testing"
+
+func TestIsNil(t *testing.T) {
+ var f *F
+ if !f.IsNil() {
+ t.Errorf("F should be nil")
+ }
+}
+
+func TestIsZero(t *testing.T) {
+ f := New()
+ if !f.IsZero() {
+ t.Errorf("F should be zero")
+ }
+}
+
+func TestFallThroughExample(t *testing.T) {
+ if !Example.Through("example.org.") {
+ t.Errorf("example.org. should fall through")
+ }
+ if Example.Through("example.net.") {
+ t.Errorf("example.net. should not fall through")
+ }
+}
+
+func TestFallthrough(t *testing.T) {
+ var fall *F
+ if fall.Through("foo.com.") {
+ t.Errorf("Expected false, got true for nil fallthrough")
+ }
+
+ fall = New()
+ if !fall.Through("foo.net.") {
+ t.Errorf("Expected true, got false for all zone fallthrough")
+ }
+
+ fall.SetZones([]string{"foo.com", "bar.com"})
+
+ if fall.Through("foo.net.") {
+ t.Errorf("Expected false, got true for non-matching fallthrough zone")
+ }
+
+ if !fall.Through("bar.com.") {
+ t.Errorf("Expected true, got false for matching fallthrough zone")
+ }
+}
diff --git a/plugin/plugin.go b/plugin/plugin.go
index 137bb48af..a50f10830 100644
--- a/plugin/plugin.go
+++ b/plugin/plugin.go
@@ -83,21 +83,6 @@ func NextOrFailure(name string, next Handler, ctx context.Context, w dns.Respons
return dns.RcodeServerFailure, Error(name, errors.New("no next plugin found"))
}
-// Fallthrough handles the fallthrough logic used in plugins that support it
-func Fallthrough(ftzones *[]string, qname string) bool {
- if ftzones == nil {
- return false
- }
- if len(*ftzones) == 0 {
- return true
- }
- zone := Zones(*ftzones).Matches(qname)
- if zone != "" {
- return true
- }
- return false
-}
-
// ClientWrite returns true if the response has been written to the client.
// Each plugin to adhire to this protocol.
func ClientWrite(rcode int) bool {
diff --git a/plugin/plugin_test.go b/plugin/plugin_test.go
deleted file mode 100644
index 80c253843..000000000
--- a/plugin/plugin_test.go
+++ /dev/null
@@ -1,21 +0,0 @@
-package plugin
-
-import "testing"
-
-func TestFallthrough(t *testing.T) {
- if Fallthrough(nil, "foo.com.") {
- t.Errorf("Expected false, got true for nil fallthrough")
- }
-
- if !Fallthrough(&[]string{}, "foo.net.") {
- t.Errorf("Expected true, got false for all zone fallthrough")
- }
-
- if Fallthrough(&[]string{"foo.com", "bar.com"}, "foo.net") {
- t.Errorf("Expected false, got true for non-matching fallthrough zone")
- }
-
- if !Fallthrough(&[]string{"foo.com.", "bar.com."}, "bar.com.") {
- t.Errorf("Expected true, got false for matching fallthrough zone")
- }
-}
diff --git a/plugin/reverse/README.md b/plugin/reverse/README.md
index c0da8676a..7b4c0670f 100644
--- a/plugin/reverse/README.md
+++ b/plugin/reverse/README.md
@@ -15,7 +15,7 @@ response. This is only done for "address" records (PTR, A and AAAA).
reverse NETWORK... {
hostname TEMPLATE
[ttl TTL]
- [fallthrough]
+ [fallthrough [ZONES...]]
[wildcard]
~~~
@@ -23,6 +23,9 @@ reverse NETWORK... {
* `hostname` injects the IP and zone to a template for the hostname. Defaults to "ip-{IP}.{zone[1]}". See below for template.
* `ttl` defaults to 60
* `fallthrough` if zone matches and no record can be generated, pass request to the next plugin.
+ If **[ZONES...]** is omitted, then fallthrough happens for all zones for which the plugin
+ is authoritative. If specific zones are listed (for example `in-addr.arpa` and `ip6.arpa`), then only
+ queries for those zones will be subject to fallthrough.
* `wildcard` allows matches to catch all subdomains as well.
### Template Syntax
diff --git a/plugin/reverse/reverse.go b/plugin/reverse/reverse.go
index 7d7681867..912d998b8 100644
--- a/plugin/reverse/reverse.go
+++ b/plugin/reverse/reverse.go
@@ -5,6 +5,7 @@ import (
"github.com/coredns/coredns/plugin"
"github.com/coredns/coredns/plugin/pkg/dnsutil"
+ "github.com/coredns/coredns/plugin/pkg/fall"
"github.com/coredns/coredns/request"
"github.com/miekg/dns"
@@ -13,9 +14,10 @@ import (
// Reverse provides dynamic reverse DNS and the related forward RR.
type Reverse struct {
- Next plugin.Handler
- Networks networks
- Fallthrough bool
+ Next plugin.Handler
+ Networks networks
+
+ Fall *fall.F
}
// ServeDNS implements the plugin.Handler interface.
@@ -97,7 +99,7 @@ func (re Reverse) ServeDNS(ctx context.Context, w dns.ResponseWriter, r *dns.Msg
return dns.RcodeSuccess, nil
}
- if re.Fallthrough {
+ if re.Fall.Through(state.Name()) {
return plugin.NextOrFailure(re.Name(), re.Next, ctx, w, r)
}
return dns.RcodeServerFailure, nil
diff --git a/plugin/reverse/reverse_test.go b/plugin/reverse/reverse_test.go
index dcd60d5dc..da0997c1c 100644
--- a/plugin/reverse/reverse_test.go
+++ b/plugin/reverse/reverse_test.go
@@ -24,7 +24,6 @@ func TestReverse(t *testing.T) {
Template: "ip-{ip}.example.org.",
RegexMatchIP: regexIP4,
}},
- Fallthrough: false,
}
tests := []struct {
diff --git a/plugin/reverse/setup.go b/plugin/reverse/setup.go
index 26e21eea9..b45d3cada 100644
--- a/plugin/reverse/setup.go
+++ b/plugin/reverse/setup.go
@@ -9,6 +9,7 @@ import (
"github.com/coredns/coredns/core/dnsserver"
"github.com/coredns/coredns/plugin"
+ "github.com/coredns/coredns/plugin/pkg/fall"
"github.com/mholt/caddy"
)
@@ -21,19 +22,19 @@ func init() {
}
func setupReverse(c *caddy.Controller) error {
- networks, fallThrough, err := reverseParse(c)
+ networks, fall, err := reverseParse(c)
if err != nil {
return plugin.Error("reverse", err)
}
dnsserver.GetConfig(c).AddPlugin(func(next plugin.Handler) plugin.Handler {
- return Reverse{Next: next, Networks: networks, Fallthrough: fallThrough}
+ return Reverse{Next: next, Networks: networks, Fall: fall}
})
return nil
}
-func reverseParse(c *caddy.Controller) (nets networks, fall bool, err error) {
+func reverseParse(c *caddy.Controller) (nets networks, f *fall.F, err error) {
zones := make([]string, len(c.ServerBlockKeys))
wildcard := false
@@ -52,12 +53,12 @@ func reverseParse(c *caddy.Controller) (nets networks, fall bool, err error) {
}
_, ipnet, err := net.ParseCIDR(cidr)
if err != nil {
- return nil, false, c.Errf("network needs to be CIDR formatted: %q\n", cidr)
+ return nil, f, c.Errf("network needs to be CIDR formatted: %q\n", cidr)
}
cidrs = append(cidrs, ipnet)
}
if len(cidrs) == 0 {
- return nil, false, c.ArgErr()
+ return nil, f, c.ArgErr()
}
// set defaults
@@ -69,27 +70,28 @@ func reverseParse(c *caddy.Controller) (nets networks, fall bool, err error) {
switch c.Val() {
case "hostname":
if !c.NextArg() {
- return nil, false, c.ArgErr()
+ return nil, f, c.ArgErr()
}
template = c.Val()
case "ttl":
if !c.NextArg() {
- return nil, false, c.ArgErr()
+ return nil, f, c.ArgErr()
}
ttl, err = strconv.Atoi(c.Val())
if err != nil {
- return nil, false, err
+ return nil, f, err
}
case "wildcard":
wildcard = true
case "fallthrough":
- fall = true
+ f = fall.New()
+ f.SetZones(c.RemainingArgs())
default:
- return nil, false, c.ArgErr()
+ return nil, f, c.ArgErr()
}
}
@@ -107,7 +109,7 @@ func reverseParse(c *caddy.Controller) (nets networks, fall bool, err error) {
// extract zone from template
templateZone := strings.SplitAfterN(template, ".", 2)
if len(templateZone) != 2 || templateZone[1] == "" {
- return nil, false, c.Errf("cannot find domain in template '%v'", template)
+ return nil, f, c.Errf("cannot find domain in template '%v'", template)
}
// Create for each configured network in this stanza
@@ -128,7 +130,7 @@ func reverseParse(c *caddy.Controller) (nets networks, fall bool, err error) {
regexIP,
1) + "$")
if err != nil {
- return nil, false, err
+ return nil, f, err
}
nets = append(nets, network{
@@ -143,5 +145,5 @@ func reverseParse(c *caddy.Controller) (nets networks, fall bool, err error) {
// sort by cidr
sort.Sort(nets)
- return nets, fall, nil
+ return nets, f, nil
}