* plugin/dnssec: implement shotgun from CloudFlare Put a whole bunch of types in the NSEC bitmap and remove the one that's being asked for. Add more records for queries to the apex, SOA, DNSKEY, MX.
253 lines
6.3 KiB
Go
253 lines
6.3 KiB
Go
package dnssec
|
|
|
|
import (
|
|
"testing"
|
|
"time"
|
|
|
|
"github.com/coredns/coredns/plugin/pkg/cache"
|
|
"github.com/coredns/coredns/plugin/test"
|
|
"github.com/coredns/coredns/request"
|
|
|
|
"github.com/miekg/dns"
|
|
)
|
|
|
|
func TestZoneSigning(t *testing.T) {
|
|
d, rm1, rm2 := newDnssec(t, []string{"miek.nl."})
|
|
defer rm1()
|
|
defer rm2()
|
|
|
|
m := testMsg()
|
|
state := request.Request{Req: m, Zone: "miek.nl."}
|
|
|
|
m = d.Sign(state, time.Now().UTC())
|
|
if !section(m.Answer, 1) {
|
|
t.Errorf("Answer section should have 1 RRSIG")
|
|
}
|
|
if !section(m.Ns, 1) {
|
|
t.Errorf("Authority section should have 1 RRSIG")
|
|
}
|
|
}
|
|
|
|
func TestZoneSigningDouble(t *testing.T) {
|
|
d, rm1, rm2 := newDnssec(t, []string{"miek.nl."})
|
|
defer rm1()
|
|
defer rm2()
|
|
|
|
fPriv1, rmPriv1, _ := test.TempFile(".", privKey1)
|
|
fPub1, rmPub1, _ := test.TempFile(".", pubKey1)
|
|
defer rmPriv1()
|
|
defer rmPub1()
|
|
|
|
key1, err := ParseKeyFile(fPub1, fPriv1)
|
|
if err != nil {
|
|
t.Fatalf("Failed to parse key: %v\n", err)
|
|
}
|
|
d.keys = append(d.keys, key1)
|
|
|
|
m := testMsg()
|
|
state := request.Request{Req: m, Zone: "miek.nl."}
|
|
m = d.Sign(state, time.Now().UTC())
|
|
if !section(m.Answer, 2) {
|
|
t.Errorf("Answer section should have 1 RRSIG")
|
|
}
|
|
if !section(m.Ns, 2) {
|
|
t.Errorf("Authority section should have 1 RRSIG")
|
|
}
|
|
}
|
|
|
|
// TestSigningDifferentZone tests if a key for miek.nl and be used for example.org.
|
|
func TestSigningDifferentZone(t *testing.T) {
|
|
fPriv, rmPriv, _ := test.TempFile(".", privKey)
|
|
fPub, rmPub, _ := test.TempFile(".", pubKey)
|
|
defer rmPriv()
|
|
defer rmPub()
|
|
|
|
key, err := ParseKeyFile(fPub, fPriv)
|
|
if err != nil {
|
|
t.Fatalf("Failed to parse key: %v\n", err)
|
|
}
|
|
|
|
m := testMsgEx()
|
|
state := request.Request{Req: m, Zone: "example.org."}
|
|
c := cache.New(defaultCap)
|
|
d := New([]string{"example.org."}, []*DNSKEY{key}, nil, c)
|
|
m = d.Sign(state, time.Now().UTC())
|
|
if !section(m.Answer, 1) {
|
|
t.Errorf("Answer section should have 1 RRSIG")
|
|
t.Logf("%+v\n", m)
|
|
}
|
|
if !section(m.Ns, 1) {
|
|
t.Errorf("Authority section should have 1 RRSIG")
|
|
t.Logf("%+v\n", m)
|
|
}
|
|
}
|
|
|
|
func TestSigningCname(t *testing.T) {
|
|
d, rm1, rm2 := newDnssec(t, []string{"miek.nl."})
|
|
defer rm1()
|
|
defer rm2()
|
|
|
|
m := testMsgCname()
|
|
state := request.Request{Req: m, Zone: "miek.nl."}
|
|
m = d.Sign(state, time.Now().UTC())
|
|
if !section(m.Answer, 1) {
|
|
t.Errorf("Answer section should have 1 RRSIG")
|
|
}
|
|
}
|
|
|
|
// Disabled for now, see #1211.
|
|
func testZoneSigningDelegation(t *testing.T) {
|
|
d, rm1, rm2 := newDnssec(t, []string{"miek.nl."})
|
|
defer rm1()
|
|
defer rm2()
|
|
|
|
m := testDelegationMsg()
|
|
state := request.Request{Req: m, Zone: "miek.nl."}
|
|
m = d.Sign(state, time.Now().UTC())
|
|
if !section(m.Ns, 1) {
|
|
t.Errorf("Authority section should have 1 RRSIG")
|
|
t.Logf("%v\n", m)
|
|
}
|
|
|
|
ds := 0
|
|
for i := range m.Ns {
|
|
if _, ok := m.Ns[i].(*dns.DS); ok {
|
|
ds++
|
|
}
|
|
}
|
|
if ds != 1 {
|
|
t.Errorf("Authority section should have 1 DS")
|
|
t.Logf("%v\n", m)
|
|
|
|
}
|
|
if !section(m.Extra, 0) {
|
|
t.Errorf("Answer section should have 0 RRSIGs")
|
|
t.Logf("%v\n", m)
|
|
}
|
|
}
|
|
|
|
func TestSigningDname(t *testing.T) {
|
|
d, rm1, rm2 := newDnssec(t, []string{"miek.nl."})
|
|
defer rm1()
|
|
defer rm2()
|
|
|
|
m := testMsgDname()
|
|
state := request.Request{Req: m, Zone: "miek.nl."}
|
|
// We sign *everything* we see, also the synthesized CNAME.
|
|
m = d.Sign(state, time.Now().UTC())
|
|
if !section(m.Answer, 3) {
|
|
t.Errorf("Answer section should have 3 RRSIGs")
|
|
}
|
|
}
|
|
|
|
func TestSigningEmpty(t *testing.T) {
|
|
d, rm1, rm2 := newDnssec(t, []string{"miek.nl."})
|
|
defer rm1()
|
|
defer rm2()
|
|
|
|
m := testEmptyMsg()
|
|
m.SetQuestion("a.miek.nl.", dns.TypeA)
|
|
state := request.Request{Req: m, Zone: "miek.nl."}
|
|
m = d.Sign(state, time.Now().UTC())
|
|
if !section(m.Ns, 2) {
|
|
t.Errorf("Authority section should have 2 RRSIGs")
|
|
}
|
|
}
|
|
|
|
func section(rss []dns.RR, nrSigs int) bool {
|
|
i := 0
|
|
for _, r := range rss {
|
|
if r.Header().Rrtype == dns.TypeRRSIG {
|
|
i++
|
|
}
|
|
}
|
|
return nrSigs == i
|
|
}
|
|
|
|
func testMsg() *dns.Msg {
|
|
// don't care about the message header
|
|
return &dns.Msg{
|
|
Answer: []dns.RR{test.MX("miek.nl. 1703 IN MX 1 aspmx.l.google.com.")},
|
|
Ns: []dns.RR{test.NS("miek.nl. 1703 IN NS omval.tednet.nl.")},
|
|
}
|
|
}
|
|
func testMsgEx() *dns.Msg {
|
|
return &dns.Msg{
|
|
Answer: []dns.RR{test.MX("example.org. 1703 IN MX 1 aspmx.l.google.com.")},
|
|
Ns: []dns.RR{test.NS("example.org. 1703 IN NS omval.tednet.nl.")},
|
|
}
|
|
}
|
|
|
|
func testMsgCname() *dns.Msg {
|
|
return &dns.Msg{
|
|
Answer: []dns.RR{test.CNAME("www.miek.nl. 1800 IN CNAME a.miek.nl.")},
|
|
}
|
|
}
|
|
|
|
func testDelegationMsg() *dns.Msg {
|
|
return &dns.Msg{
|
|
Ns: []dns.RR{
|
|
test.NS("miek.nl. 3600 IN NS linode.atoom.net."),
|
|
test.NS("miek.nl. 3600 IN NS ns-ext.nlnetlabs.nl."),
|
|
test.NS("miek.nl. 3600 IN NS omval.tednet.nl."),
|
|
},
|
|
Extra: []dns.RR{
|
|
test.A("omval.tednet.nl. 3600 IN A 185.49.141.42"),
|
|
test.AAAA("omval.tednet.nl. 3600 IN AAAA 2a04:b900:0:100::42"),
|
|
},
|
|
}
|
|
}
|
|
|
|
func testMsgDname() *dns.Msg {
|
|
return &dns.Msg{
|
|
Answer: []dns.RR{
|
|
test.CNAME("a.dname.miek.nl. 1800 IN CNAME a.test.miek.nl."),
|
|
test.A("a.test.miek.nl. 1800 IN A 139.162.196.78"),
|
|
test.DNAME("dname.miek.nl. 1800 IN DNAME test.miek.nl."),
|
|
},
|
|
}
|
|
}
|
|
|
|
func testEmptyMsg() *dns.Msg {
|
|
// don't care about the message header
|
|
return &dns.Msg{
|
|
Ns: []dns.RR{test.SOA("miek.nl. 1800 IN SOA ns.miek.nl. dnsmaster.miek.nl. 2017100301 200 100 604800 3600")},
|
|
}
|
|
}
|
|
|
|
func newDnssec(t *testing.T, zones []string) (Dnssec, func(), func()) {
|
|
k, rm1, rm2 := newKey(t)
|
|
c := cache.New(defaultCap)
|
|
d := New(zones, []*DNSKEY{k}, nil, c)
|
|
return d, rm1, rm2
|
|
}
|
|
|
|
func newKey(t *testing.T) (*DNSKEY, func(), func()) {
|
|
fPriv, rmPriv, _ := test.TempFile(".", privKey)
|
|
fPub, rmPub, _ := test.TempFile(".", pubKey)
|
|
|
|
key, err := ParseKeyFile(fPub, fPriv)
|
|
if err != nil {
|
|
t.Fatalf("failed to parse key: %v\n", err)
|
|
}
|
|
return key, rmPriv, rmPub
|
|
}
|
|
|
|
const (
|
|
pubKey = `miek.nl. IN DNSKEY 257 3 13 0J8u0XJ9GNGFEBXuAmLu04taHG4BXPP3gwhetiOUMnGA+x09nqzgF5IY OyjWB7N3rXqQbnOSILhH1hnuyh7mmA==`
|
|
privKey = `Private-key-format: v1.3
|
|
Algorithm: 13 (ECDSAP256SHA256)
|
|
PrivateKey: /4BZk8AFvyW5hL3cOLSVxIp1RTqHSAEloWUxj86p3gs=
|
|
Created: 20160423195532
|
|
Publish: 20160423195532
|
|
Activate: 20160423195532
|
|
`
|
|
pubKey1 = `example.org. IN DNSKEY 257 3 13 tVRWNSGpHZbCi7Pr7OmbADVUO3MxJ0Lb8Lk3o/HBHqCxf5K/J50lFqRa 98lkdAIiFOVRy8LyMvjwmxZKwB5MNw==`
|
|
privKey1 = `Private-key-format: v1.3
|
|
Algorithm: 13 (ECDSAP256SHA256)
|
|
PrivateKey: i8j4OfDGT8CQt24SDwLz2hg9yx4qKOEOh1LvbAuSp1c=
|
|
Created: 20160423211746
|
|
Publish: 20160423211746
|
|
Activate: 20160423211746
|
|
`
|
|
)
|