Add middleware/dnssec (#133)

This adds an online dnssec middleware. The middleware will sign
responses on the fly. Negative responses are signed with NSEC black
lies.
This commit is contained in:
Miek Gieben
2016-04-26 17:57:11 +01:00
parent 8e6c690484
commit 1aa1a92198
39 changed files with 1206 additions and 144 deletions

View File

@@ -27,8 +27,7 @@ func cacheParse(c *Controller) (int, []string, error) {
for c.Next() {
if c.Val() == "cache" {
// cache [ttl] [zones..]
origins := []string{c.ServerBlockHosts[c.ServerBlockHostIndex]}
origins := c.ServerBlockHosts
args := c.RemainingArgs()
if len(args) > 0 {
origins = args
@@ -39,7 +38,7 @@ func cacheParse(c *Controller) (int, []string, error) {
origins = origins[1:]
if len(origins) == 0 {
// There was *only* the ttl, revert back to server block
origins = []string{c.ServerBlockHosts[c.ServerBlockHostIndex]}
origins = c.ServerBlockHosts
}
}
}

View File

@@ -10,7 +10,7 @@ func TestChaos(t *testing.T) {
tests := []struct {
input string
shouldErr bool
expectedVersion string // expected veresion.
expectedVersion string // expected version.
expectedAuthor string // expected author (string, although we get a map).
expectedErrContent string // substring from the expected error. Empty for positive cases.
}{

79
core/setup/dnssec.go Normal file
View File

@@ -0,0 +1,79 @@
package setup
import (
"path"
"github.com/miekg/coredns/middleware"
"github.com/miekg/coredns/middleware/dnssec"
)
// Dnssec sets up the dnssec middleware.
func Dnssec(c *Controller) (middleware.Middleware, error) {
zones, keys, err := dnssecParse(c)
if err != nil {
return nil, err
}
return func(next middleware.Handler) middleware.Handler {
return dnssec.NewDnssec(zones, keys, next)
}, nil
}
func dnssecParse(c *Controller) ([]string, []*dnssec.DNSKEY, error) {
zones := []string{}
keys := []*dnssec.DNSKEY{}
for c.Next() {
if c.Val() == "dnssec" {
// dnssec [zones...]
zones = c.ServerBlockHosts
args := c.RemainingArgs()
if len(args) > 0 {
zones = args
}
for c.NextBlock() {
k, e := keyParse(c)
if e != nil {
// TODO(miek): Log and drop or something? stop startup?
continue
}
keys = append(keys, k...)
}
}
}
for i, _ := range zones {
zones[i] = middleware.Host(zones[i]).Normalize()
}
return zones, keys, nil
}
func keyParse(c *Controller) ([]*dnssec.DNSKEY, error) {
keys := []*dnssec.DNSKEY{}
what := c.Val()
if !c.NextArg() {
return nil, c.ArgErr()
}
value := c.Val()
switch what {
case "key":
if value == "file" {
ks := c.RemainingArgs()
for _, k := range ks {
// Kmiek.nl.+013+26205.key, handle .private or without extension: Kmiek.nl.+013+26205
ext := path.Ext(k) // TODO(miek): test things like .key
base := k
if len(ext) > 0 {
base = k[:len(k)-len(ext)]
}
k, err := dnssec.ParseKeyFile(base+".key", base+".private")
if err != nil {
return nil, err
}
keys = append(keys, k)
}
}
}
return keys, nil
}

54
core/setup/dnssec_test.go Normal file
View File

@@ -0,0 +1,54 @@
package setup
import (
"strings"
"testing"
)
func TestDnssec(t *testing.T) {
tests := []struct {
input string
shouldErr bool
expectedZones []string
expectedKeys []string
expectedErrContent string
}{
{
`dnssec`, false, nil, nil, "",
},
{
`dnssec miek.nl`, false, []string{"miek.nl."}, nil, "",
},
}
for i, test := range tests {
c := NewTestController(test.input)
zones, keys, err := dnssecParse(c)
if test.shouldErr && err == nil {
t.Errorf("Test %d: Expected error but found %s for input %s", i, err, test.input)
}
if err != nil {
if !test.shouldErr {
t.Errorf("Test %d: Expected no error but found one for input %s. Error was: %v", i, test.input, err)
}
if !strings.Contains(err.Error(), test.expectedErrContent) {
t.Errorf("Test %d: Expected error to contain: %v, found error: %v, input: %s", i, test.expectedErrContent, err, test.input)
}
}
if !test.shouldErr {
for i, z := range test.expectedZones {
if zones[i] != z {
t.Errorf("Dnssec not correctly set for input %s. Expected: %s, actual: %s", test.input, z, zones[i])
}
}
for i, k := range test.expectedKeys {
if k != keys[i].K.Header().Name {
t.Errorf("Dnssec not correctly set for input %s. Expected: '%s', actual: '%s'", test.input, k, keys[i].K.Header().Name)
}
}
}
}
}

View File

@@ -10,8 +10,8 @@ import (
"github.com/miekg/coredns/middleware"
"github.com/miekg/coredns/middleware/etcd"
"github.com/miekg/coredns/middleware/etcd/singleflight"
"github.com/miekg/coredns/middleware/proxy"
"github.com/miekg/coredns/middleware/singleflight"
etcdc "github.com/coreos/etcd/client"
"golang.org/x/net/context"

View File

@@ -46,7 +46,7 @@ func fileParse(c *Controller) (file.Zones, error) {
}
fileName := c.Val()
origins := []string{c.ServerBlockHosts[c.ServerBlockHostIndex]}
origins := c.ServerBlockHosts
args := c.RemainingArgs()
if len(args) > 0 {
origins = args
@@ -54,7 +54,7 @@ func fileParse(c *Controller) (file.Zones, error) {
reader, err := os.Open(fileName)
if err != nil {
return file.Zones{}, err
continue
}
for i, _ := range origins {
@@ -68,7 +68,7 @@ func fileParse(c *Controller) (file.Zones, error) {
noReload := false
for c.NextBlock() {
t, _, e := parseTransfer(c)
t, _, e := transferParse(c)
if e != nil {
return file.Zones{}, e
}
@@ -89,8 +89,8 @@ func fileParse(c *Controller) (file.Zones, error) {
return file.Zones{Z: z, Names: names}, nil
}
// transfer to [address...]
func parseTransfer(c *Controller) (tos, froms []string, err error) {
// transferParse parses transfer statements: 'transfer to [address...]'.
func transferParse(c *Controller) (tos, froms []string, err error) {
what := c.Val()
if !c.NextArg() {
return nil, nil, c.ArgErr()

View File

@@ -7,10 +7,7 @@ import (
"github.com/miekg/coredns/middleware/metrics"
)
const (
path = "/metrics"
addr = "localhost:9135" // 9153 is occupied by bind_exporter
)
const addr = "localhost:9135" // 9153 is occupied by bind_exporter
var once sync.Once

View File

@@ -40,7 +40,7 @@ func secondaryParse(c *Controller) (file.Zones, error) {
for c.Next() {
if c.Val() == "secondary" {
// secondary [origin]
origins := []string{c.ServerBlockHosts[c.ServerBlockHostIndex]}
origins := c.ServerBlockHosts
args := c.RemainingArgs()
if len(args) > 0 {
origins = args
@@ -52,7 +52,7 @@ func secondaryParse(c *Controller) (file.Zones, error) {
}
for c.NextBlock() {
t, f, e := parseTransfer(c)
t, f, e := transferParse(c)
if e != nil {
return file.Zones{}, e
}