coredns/plugin/tsig/setup.go
Chris O'Haver 68e141eff2
plugin/tsig: new plugin TSIG ()
* expose tsig secrets via dnsserver.Config
* add tsig plugin

Signed-off-by: Chris O'Haver <cohaver@infoblox.com>
2022-06-27 15:48:34 -04:00

168 lines
3.5 KiB
Go

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{}