From 0049230a935b8e45ffcb290723a3a17df4b59f77 Mon Sep 17 00:00:00 2001 From: jremond Date: Tue, 11 Jul 2017 00:49:24 -0400 Subject: [PATCH] add wildcard parameter to allow resolving multiple name to the same IP (#755) * add wildcard parameter to allow resolving multiple name to the same IP * first test for the reverse wildcard middleware * update wildcard keyword test to pass code coverage --- middleware/reverse/README.md | 7 +++ middleware/reverse/reverse_test.go | 71 ++++++++++++++++++++++++++++++ middleware/reverse/setup.go | 10 ++++- middleware/reverse/setup_test.go | 17 +++++++ 4 files changed, 104 insertions(+), 1 deletion(-) create mode 100644 middleware/reverse/reverse_test.go diff --git a/middleware/reverse/README.md b/middleware/reverse/README.md index 117daeba3..a26942178 100644 --- a/middleware/reverse/README.md +++ b/middleware/reverse/README.md @@ -9,6 +9,7 @@ reverse NETWORK... { hostname TEMPLATE [ttl TTL] [fallthrough] + [wildcard] ~~~ * **NETWORK** one or more CIDR formatted networks to respond on. @@ -34,6 +35,12 @@ The `{zone[i]}` symbol is **optional** and can be replaced by a fixed (zone) str The zone will be matched by the zones listed in *this* configuration stanza. `i` needs to be replaced with the index of the configured listener zones, starting with 1. +### `wildcard` + +If `wildcard` is true : +any.thing.ip-1.2.3.4.example.org resolves to 1.2.3.4 (ip-{ip}.{zone} is the hostname/template) + + ## Examples ~~~ txt diff --git a/middleware/reverse/reverse_test.go b/middleware/reverse/reverse_test.go new file mode 100644 index 000000000..4b17f0971 --- /dev/null +++ b/middleware/reverse/reverse_test.go @@ -0,0 +1,71 @@ +package reverse + +import ( + "net" + "regexp" + "testing" + + "github.com/coredns/coredns/middleware" + "github.com/coredns/coredns/middleware/pkg/dnsrecorder" + "github.com/coredns/coredns/middleware/test" + + "github.com/miekg/dns" + "golang.org/x/net/context" +) + +func TestReverse(t *testing.T) { + _, net4, _ := net.ParseCIDR("10.1.1.0/24") + regexIP4, _ := regexp.Compile("^.*ip-" + regexMatchV4 + "\\.example\\.org\\.$") + + em := Reverse{ + Networks: networks{network{ + IPnet: net4, + Zone: "example.org", + Template: "ip-{ip}.example.org.", + RegexMatchIP: regexIP4, + }}, + Fallthrough: false, + } + + tests := []struct { + next middleware.Handler + qname string + qtype uint16 + expectedCode int + expectedReply string + expectedErr error + }{ + { + next: test.NextHandler(dns.RcodeSuccess, nil), + qname: "test.ip-10.1.1.2.example.org", + expectedCode: dns.RcodeSuccess, + expectedReply: "10.1.1.2", + expectedErr: nil, + }, + } + + ctx := context.TODO() + + for i, tr := range tests { + req := new(dns.Msg) + + tr.qtype = dns.TypeA + req.SetQuestion(dns.Fqdn(tr.qname), tr.qtype) + + rec := dnsrecorder.New(&test.ResponseWriter{}) + code, err := em.ServeDNS(ctx, rec, req) + + if err != tr.expectedErr { + t.Errorf("Test %d: Expected error %v, but got %v", i, tr.expectedErr, err) + } + if code != int(tr.expectedCode) { + t.Errorf("Test %d: Expected status code %d, but got %d", i, tr.expectedCode, code) + } + if tr.expectedReply != "" { + answer := rec.Msg.Answer[0].(*dns.A).A.String() + if answer != tr.expectedReply { + t.Errorf("Test %d: Expected answer %s, but got %s", i, tr.expectedReply, answer) + } + } + } +} diff --git a/middleware/reverse/setup.go b/middleware/reverse/setup.go index 56ab620fa..ee426f852 100644 --- a/middleware/reverse/setup.go +++ b/middleware/reverse/setup.go @@ -38,6 +38,7 @@ func reverseParse(c *caddy.Controller) (nets networks, fall bool, err error) { // normalize zones, validation is almost done by dnsserver // TODO(miek): need sane helpers for these. zones := make([]string, len(c.ServerBlockKeys)) + wildcard := false for i, str := range c.ServerBlockKeys { zones[i] = middleware.Host(str).Normalize() @@ -85,6 +86,9 @@ func reverseParse(c *caddy.Controller) (nets networks, fall bool, err error) { return nil, false, err } + case "wildcard": + wildcard = true + case "fallthrough": fall = true @@ -117,8 +121,12 @@ func reverseParse(c *caddy.Controller) (nets networks, fall bool, err error) { if ipnet.IP.To4() == nil { regexIP = regexMatchV6 } + prefix := "^" + if wildcard { + prefix += ".*" + } regex, err := regexp.Compile( - "^" + strings.Replace( // inject ip regex into template + prefix + strings.Replace( // inject ip regex into template regexp.QuoteMeta(template), // escape dots regexp.QuoteMeta(templateNameIP), regexIP, diff --git a/middleware/reverse/setup_test.go b/middleware/reverse/setup_test.go index 88dbccf1c..5b4c04e82 100644 --- a/middleware/reverse/setup_test.go +++ b/middleware/reverse/setup_test.go @@ -14,6 +14,7 @@ func TestSetupParse(t *testing.T) { _, net4, _ := net.ParseCIDR("10.1.1.0/24") _, net6, _ := net.ParseCIDR("fd01::/64") + regexIP4wildcard, _ := regexp.Compile("^.*ip-" + regexMatchV4 + "\\.domain\\.com\\.$") regexIP6, _ := regexp.Compile("^ip-" + regexMatchV6 + "\\.domain\\.com\\.$") regexIpv4dynamic, _ := regexp.Compile("^dynamic-" + regexMatchV4 + "-intern\\.dynamic\\.domain\\.com\\.$") regexIpv6dynamic, _ := regexp.Compile("^dynamic-" + regexMatchV6 + "-intern\\.dynamic\\.domain\\.com\\.$") @@ -157,6 +158,22 @@ func TestSetupParse(t *testing.T) { RegexMatchIP: regexIpv6dynamic, }}, }, + { + `reverse 10.1.1.0/24 { + hostname ip-{ip}.{zone[1]} + ttl 50 + wildcard + fallthrough + }`, + false, + networks{network{ + IPnet: net4, + Template: "ip-{ip}.domain.com.", + Zone: "domain.com.", + TTL: 50, + RegexMatchIP: regexIP4wildcard, + }}, + }, } for i, test := range tests { c := caddy.NewTestController("dns", test.inputFileRules)