diff options
Diffstat (limited to 'plugin/tsig/setup.go')
-rw-r--r-- | plugin/tsig/setup.go | 168 |
1 files changed, 168 insertions, 0 deletions
diff --git a/plugin/tsig/setup.go b/plugin/tsig/setup.go new file mode 100644 index 000000000..a187a4b4a --- /dev/null +++ b/plugin/tsig/setup.go @@ -0,0 +1,168 @@ +package tsig + +import ( + "bufio" + "fmt" + "io" + "os" + "strings" + + "github.com/coredns/caddy" + "github.com/coredns/coredns/core/dnsserver" + "github.com/coredns/coredns/plugin" + + "github.com/miekg/dns" +) + +func init() { + caddy.RegisterPlugin(pluginName, caddy.Plugin{ + ServerType: "dns", + Action: setup, + }) +} + +func setup(c *caddy.Controller) error { + t, err := parse(c) + if err != nil { + return plugin.Error(pluginName, c.ArgErr()) + } + + config := dnsserver.GetConfig(c) + + config.TsigSecret = t.secrets + + config.AddPlugin(func(next plugin.Handler) plugin.Handler { + t.Next = next + return t + }) + + return nil +} + +func parse(c *caddy.Controller) (*TSIGServer, error) { + t := &TSIGServer{ + secrets: make(map[string]string), + types: defaultQTypes, + } + + for i := 0; c.Next(); i++ { + if i > 0 { + return nil, plugin.ErrOnce + } + + t.Zones = plugin.OriginsFromArgsOrServerBlock(c.RemainingArgs(), c.ServerBlockKeys) + for c.NextBlock() { + switch c.Val() { + case "secret": + args := c.RemainingArgs() + if len(args) != 2 { + return nil, c.ArgErr() + } + k := plugin.Name(args[0]).Normalize() + if _, exists := t.secrets[k]; exists { + return nil, fmt.Errorf("key %q redefined", k) + } + t.secrets[k] = args[1] + case "secrets": + args := c.RemainingArgs() + if len(args) != 1 { + return nil, c.ArgErr() + } + f, err := os.Open(args[0]) + if err != nil { + return nil, err + } + secrets, err := parseKeyFile(f) + if err != nil { + return nil, err + } + for k, s := range secrets { + if _, exists := t.secrets[k]; exists { + return nil, fmt.Errorf("key %q redefined", k) + } + t.secrets[k] = s + } + case "require": + t.types = qTypes{} + args := c.RemainingArgs() + if len(args) == 0 { + return nil, c.ArgErr() + } + if args[0] == "all" { + t.all = true + continue + } + if args[0] == "none" { + continue + } + for _, str := range args { + qt, ok := dns.StringToType[str] + if !ok { + return nil, c.Errf("unknown query type '%s'", str) + } + t.types[qt] = struct{}{} + } + default: + return nil, c.Errf("unknown property '%s'", c.Val()) + } + } + } + return t, nil +} + +func parseKeyFile(f io.Reader) (map[string]string, error) { + secrets := make(map[string]string) + s := bufio.NewScanner(f) + for s.Scan() { + fields := strings.Fields(s.Text()) + if len(fields) == 0 { + continue + } + if fields[0] != "key" { + return nil, fmt.Errorf("unexpected token %q", fields[0]) + } + if len(fields) < 2 { + return nil, fmt.Errorf("expected key name %q", s.Text()) + } + key := strings.Trim(fields[1], "\"{") + if len(key) == 0 { + return nil, fmt.Errorf("expected key name %q", s.Text()) + } + key = plugin.Name(key).Normalize() + if _, ok := secrets[key]; ok { + return nil, fmt.Errorf("key %q redefined", key) + } + key: + for s.Scan() { + fields := strings.Fields(s.Text()) + if len(fields) == 0 { + continue + } + switch fields[0] { + case "algorithm": + continue + case "secret": + if len(fields) < 2 { + return nil, fmt.Errorf("expected secret key %q", s.Text()) + } + secret := strings.Trim(fields[1], "\";") + if len(secret) == 0 { + return nil, fmt.Errorf("expected secret key %q", s.Text()) + } + secrets[key] = secret + case "}": + fallthrough + case "};": + break key + default: + return nil, fmt.Errorf("unexpected token %q", fields[0]) + } + } + if _, ok := secrets[key]; !ok { + return nil, fmt.Errorf("expected secret for key %q", key) + } + } + return secrets, nil +} + +var defaultQTypes = qTypes{} |