mirror of
				https://github.com/coredns/coredns.git
				synced 2025-10-31 02:03:20 -04:00 
			
		
		
		
	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:
		
							
								
								
									
										193
									
								
								middleware/dnssec/dnssec_test.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										193
									
								
								middleware/dnssec/dnssec_test.go
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,193 @@ | ||||
| package dnssec | ||||
|  | ||||
| import ( | ||||
| 	"testing" | ||||
| 	"time" | ||||
|  | ||||
| 	"github.com/miekg/coredns/middleware" | ||||
| 	"github.com/miekg/coredns/middleware/test" | ||||
|  | ||||
| 	"github.com/miekg/dns" | ||||
| ) | ||||
|  | ||||
| func TestZoneSigning(t *testing.T) { | ||||
| 	d, rm1, rm2 := newDnssec(t, []string{"miek.nl."}) | ||||
| 	defer rm1() | ||||
| 	defer rm2() | ||||
|  | ||||
| 	m := testMsg() | ||||
| 	state := middleware.State{Req: m} | ||||
|  | ||||
| 	m = d.Sign(state, "miek.nl.", time.Now().UTC()) | ||||
| 	if !section(m.Answer, 1) { | ||||
| 		t.Errorf("answer section should have 1 sig") | ||||
| 	} | ||||
| 	if !section(m.Ns, 1) { | ||||
| 		t.Errorf("authority section should have 1 sig") | ||||
| 	} | ||||
| } | ||||
|  | ||||
| func TestZoneSigningDouble(t *testing.T) { | ||||
| 	d, rm1, rm2 := newDnssec(t, []string{"miek.nl."}) | ||||
| 	defer rm1() | ||||
| 	defer rm2() | ||||
|  | ||||
| 	fPriv1, rmPriv1, _ := test.TempFile(t, ".", privKey1) | ||||
| 	fPub1, rmPub1, _ := test.TempFile(t, ".", 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 := middleware.State{Req: m} | ||||
| 	m = d.Sign(state, "miek.nl.", time.Now().UTC()) | ||||
| 	if !section(m.Answer, 2) { | ||||
| 		t.Errorf("answer section should have 1 sig") | ||||
| 	} | ||||
| 	if !section(m.Ns, 2) { | ||||
| 		t.Errorf("authority section should have 1 sig") | ||||
| 	} | ||||
| 	t.Logf("%+v\n", m) | ||||
| } | ||||
|  | ||||
| // TestSigningDifferentZone tests if a key for miek.nl and be used for example.org. | ||||
| func TestSigningDifferentZone(t *testing.T) { | ||||
| 	fPriv, rmPriv, _ := test.TempFile(t, ".", privKey) | ||||
| 	fPub, rmPub, _ := test.TempFile(t, ".", 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 := middleware.State{Req: m} | ||||
| 	d := NewDnssec([]string{"example.org."}, []*DNSKEY{key}, nil) | ||||
| 	m = d.Sign(state, "example.org.", time.Now().UTC()) | ||||
| 	if !section(m.Answer, 1) { | ||||
| 		t.Errorf("answer section should have 1 sig") | ||||
| 	} | ||||
| 	if !section(m.Ns, 1) { | ||||
| 		t.Errorf("authority section should have 1 sig") | ||||
| 	} | ||||
| 	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 := middleware.State{Req: m} | ||||
| 	m = d.Sign(state, "miek.nl.", time.Now().UTC()) | ||||
| 	if !section(m.Answer, 1) { | ||||
| 		t.Errorf("answer section should have 1 sig") | ||||
| 	} | ||||
| 	t.Logf("%+v\n", m) | ||||
| } | ||||
|  | ||||
| func TestZoneSigningDelegation(t *testing.T) { | ||||
| 	d, rm1, rm2 := newDnssec(t, []string{"miek.nl."}) | ||||
| 	defer rm1() | ||||
| 	defer rm2() | ||||
|  | ||||
| 	m := testDelegationMsg() | ||||
| 	state := middleware.State{Req: m} | ||||
| 	m = d.Sign(state, "miek.nl.", time.Now().UTC()) | ||||
| 	if !section(m.Ns, 0) { | ||||
| 		t.Errorf("authority section should have 0 sig") | ||||
| 		t.Logf("%v\n", m) | ||||
| 	} | ||||
| 	if !section(m.Extra, 0) { | ||||
| 		t.Errorf("answer section should have 0 sig") | ||||
| 		t.Logf("%v\n", m) | ||||
| 	} | ||||
| } | ||||
|  | ||||
| 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 newDnssec(t *testing.T, zones []string) (Dnssec, func(), func()) { | ||||
| 	k, rm1, rm2 := newKey(t) | ||||
| 	d := NewDnssec(zones, []*DNSKEY{k}, nil) | ||||
| 	return d, rm1, rm2 | ||||
| } | ||||
|  | ||||
| func newKey(t *testing.T) (*DNSKEY, func(), func()) { | ||||
| 	fPriv, rmPriv, _ := test.TempFile(t, ".", privKey) | ||||
| 	fPub, rmPub, _ := test.TempFile(t, ".", 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 | ||||
| ` | ||||
| ) | ||||
		Reference in New Issue
	
	Block a user