aboutsummaryrefslogtreecommitdiff
path: root/plugin/reverse/setup.go
diff options
context:
space:
mode:
Diffstat (limited to 'plugin/reverse/setup.go')
-rw-r--r--plugin/reverse/setup.go147
1 files changed, 147 insertions, 0 deletions
diff --git a/plugin/reverse/setup.go b/plugin/reverse/setup.go
new file mode 100644
index 000000000..26e21eea9
--- /dev/null
+++ b/plugin/reverse/setup.go
@@ -0,0 +1,147 @@
+package reverse
+
+import (
+ "net"
+ "regexp"
+ "sort"
+ "strconv"
+ "strings"
+
+ "github.com/coredns/coredns/core/dnsserver"
+ "github.com/coredns/coredns/plugin"
+
+ "github.com/mholt/caddy"
+)
+
+func init() {
+ caddy.RegisterPlugin("reverse", caddy.Plugin{
+ ServerType: "dns",
+ Action: setupReverse,
+ })
+}
+
+func setupReverse(c *caddy.Controller) error {
+ networks, fallThrough, 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 nil
+}
+
+func reverseParse(c *caddy.Controller) (nets networks, fall bool, err error) {
+ zones := make([]string, len(c.ServerBlockKeys))
+ wildcard := false
+
+ // We copy from the serverblock, these contains Hosts.
+ for i, str := range c.ServerBlockKeys {
+ zones[i] = plugin.Host(str).Normalize()
+ }
+
+ for c.Next() {
+ var cidrs []*net.IPNet
+
+ // parse all networks
+ for _, cidr := range c.RemainingArgs() {
+ if cidr == "{" {
+ break
+ }
+ _, ipnet, err := net.ParseCIDR(cidr)
+ if err != nil {
+ return nil, false, c.Errf("network needs to be CIDR formatted: %q\n", cidr)
+ }
+ cidrs = append(cidrs, ipnet)
+ }
+ if len(cidrs) == 0 {
+ return nil, false, c.ArgErr()
+ }
+
+ // set defaults
+ var (
+ template = "ip-" + templateNameIP + ".{zone[1]}"
+ ttl = 60
+ )
+ for c.NextBlock() {
+ switch c.Val() {
+ case "hostname":
+ if !c.NextArg() {
+ return nil, false, c.ArgErr()
+ }
+ template = c.Val()
+
+ case "ttl":
+ if !c.NextArg() {
+ return nil, false, c.ArgErr()
+ }
+ ttl, err = strconv.Atoi(c.Val())
+ if err != nil {
+ return nil, false, err
+ }
+
+ case "wildcard":
+ wildcard = true
+
+ case "fallthrough":
+ fall = true
+
+ default:
+ return nil, false, c.ArgErr()
+ }
+ }
+
+ // prepare template
+ // replace {zone[index]} by the listen zone/domain of this config block
+ for i, zone := range zones {
+ // TODO: we should be smarter about actually replacing this. This works, but silently allows "zone[-1]"
+ // for instance.
+ template = strings.Replace(template, "{zone["+strconv.Itoa(i+1)+"]}", zone, 1)
+ }
+ if !strings.HasSuffix(template, ".") {
+ template += "."
+ }
+
+ // 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)
+ }
+
+ // Create for each configured network in this stanza
+ for _, ipnet := range cidrs {
+ // precompile regex for hostname to ip matching
+ regexIP := regexMatchV4
+ if ipnet.IP.To4() == nil {
+ regexIP = regexMatchV6
+ }
+ prefix := "^"
+ if wildcard {
+ prefix += ".*"
+ }
+ regex, err := regexp.Compile(
+ prefix + strings.Replace( // inject ip regex into template
+ regexp.QuoteMeta(template), // escape dots
+ regexp.QuoteMeta(templateNameIP),
+ regexIP,
+ 1) + "$")
+ if err != nil {
+ return nil, false, err
+ }
+
+ nets = append(nets, network{
+ IPnet: ipnet,
+ Zone: templateZone[1],
+ Template: template,
+ RegexMatchIP: regex,
+ TTL: uint32(ttl),
+ })
+ }
+ }
+
+ // sort by cidr
+ sort.Sort(nets)
+ return nets, fall, nil
+}