Skip to content
This repository was archived by the owner on Nov 24, 2025. It is now read-only.
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
23 changes: 23 additions & 0 deletions test/router/dnssec/Readme.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
DNSSEC Tests
============

Running the test

`ginkgo -- -ns=router-01.thecdn.example.com:53 -ds=ds-01.thecdn.example.com.`

Sample Output
```
Running Suite: Dnssec Suite
===========================
Random Seed: 1476984556
Will run 4 of 4 specs

2016/10/20 11:29:17 Nameserver router-01.thecdn.example.com:53
2016/10/20 11:29:17 DeliveryService ds-01.thecdn.example.com.
••••
Ran 4 of 4 Specs in 0.110 seconds
SUCCESS! -- 4 Passed | 0 Failed | 0 Pending | 0 Skipped PASS

Ginkgo ran 1 suite in 825.345359ms
Test Suite Passed
```
139 changes: 139 additions & 0 deletions test/router/dnssec/dnssec.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,139 @@
package dnssec

import (
. "github.com/miekg/dns"
. "github.com/onsi/gomega"
"log"
)

type DnssecClient struct {
*Client
}

type SignedRRSet struct {
RRSIG RRSIG
RRSet []RR
}

type SignedKeys struct {
SignedZsks []SignedRRSet
SignedKsks []SignedRRSet
}

func MakeLabelHierarchy(label string) []string {
labels := []string{}
done := false
i := 0
for !done {
label = label[i:]
labels = append([]string{label}, labels...)
i, done = NextLabel(label,i)
}

return append([]string{"."}, labels...)
}

func (d *DnssecClient) GetRecords(nameserver string, name string, t uint16) (*Msg) {
m := new(Msg)
m.Id = Id()
m.RecursionDesired = true
m.SetEdns0(4096, true)
m.Question = []Question{{name, t, ClassINET}}
r, _, err := d.Exchange(m, nameserver)

Expect(err).Should(BeNil())
Expect(len(r.Answer)).ToNot(Equal(0), "Received no answers from %v for query of records type %d for zone %v", nameserver, t, name)
return r
}

func sigCovers(s RRSIG, rr RR) bool {
return s.TypeCovered == rr.Header().Rrtype &&
s.Hdr.Class == rr.Header().Class &&
s.Hdr.Ttl == rr.Header().Ttl
}

func (d *DnssecClient) GetSignedRRSets(nameserver string, name string, t uint16) ([]SignedRRSet) {
records := []RR{}
rrsigs := []RR{}

answers := d.GetRecords(nameserver, name, t).Answer
for _, ans := range answers {
if ans.Header().Rrtype == TypeRRSIG {
rrsigs = append(rrsigs, ans)
} else {
records = append(records, ans)
}
}

rrsets := []SignedRRSet{}
for _, sig := range rrsigs {
switch s := sig.(type) {
case *RRSIG:
rs := RRSIG{
Hdr: s.Hdr,
Signature: s.Signature,
Algorithm: s.Algorithm,
Expiration: s.Expiration,
Inception: s.Inception,
KeyTag: s.KeyTag,
Labels: s.Labels,
OrigTtl: s.OrigTtl,
SignerName: s.SignerName,
TypeCovered: s.TypeCovered,
}

signedSet := SignedRRSet{
RRSIG: rs,
}

for _, rr := range records {
if sigCovers(*s,rr) {
signedSet.RRSet = append(signedSet.RRSet, rr)
} else {
log.Println("rrsig does not cover record")
log.Println(s.Header(),s.TypeCovered)
log.Println(rr.Header(),rr.Header().Rrtype)
}
}

rrsets = append(rrsets, signedSet)
}

}

return rrsets
}

func (d *DnssecClient) DelegationSignerData(nameserver string, name string) ([]SignedRRSet) {
return d.GetSignedRRSets(nameserver, name, TypeDS)
}

func (d *DnssecClient) SigningData(nameserver string, name string) SignedKeys {
var signedKeys = SignedKeys{
SignedZsks: []SignedRRSet{},
SignedKsks: []SignedRRSet{},
}

signedRrsets := d.GetSignedRRSets(nameserver, name, TypeDNSKEY)

for _, signedRRset := range signedRrsets {
if len(signedRRset.RRSet) < 1 {
log.Println("****** no rrset")
continue;
}

for _, rr := range signedRRset.RRSet {
switch k := rr.(type) {
case *DNSKEY:
if k.Flags & 1 == 1 {
signedKeys.SignedKsks = append(signedKeys.SignedKsks, signedRRset)
} else {
signedKeys.SignedZsks = append(signedKeys.SignedZsks, signedRRset)
}
}
}
}

return signedKeys
}

36 changes: 36 additions & 0 deletions test/router/dnssec/dnssec_suite_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
package dnssec_test

import (
. "github.com/onsi/ginkgo"
. "github.com/onsi/gomega"

"testing"
"github.com/apache/incubator-trafficcontrol/test/router/dnssec"
"github.com/miekg/dns"
"flag"
"log"
)

var d *dnssec.DnssecClient
var nameserver string
var deliveryService string

func init() {
flag.StringVar(&nameserver,"ns","changeit","ns is used to direct dns queries to a traffic router")
flag.StringVar(&deliveryService,"ds","changeit","ds is used to target some dns DS and DNS queries made by traffic router")
}

var _ = BeforeSuite(func() {
d = &dnssec.DnssecClient{new(dns.Client)}
d.Net = "udp"

Expect(nameserver).ToNot(Equal("changeit"), "Pass in a ns flag with the hostname of the traffic router")
Expect(deliveryService).ToNot(Equal("changeit"), "Pass in a ds flag with the dns label for a DNS delivery service")
log.Println("Nameserver",nameserver)
log.Println("DeliveryService", deliveryService)
})

func TestDnssec(t *testing.T) {
RegisterFailHandler(Fail)
RunSpecs(t, "Dnssec Suite")
}
109 changes: 109 additions & 0 deletions test/router/dnssec/dnssec_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,109 @@
package dnssec_test

import (
"github.com/apache/incubator-trafficcontrol/test/router/dnssec"
"github.com/miekg/dns"
. "github.com/onsi/ginkgo"
. "github.com/onsi/gomega"
)

var _ = Describe("Dnssec", func() {
Context("The Interwebs", func() {
It("Makes Label Hierarchy", func() {
Expect(dnssec.MakeLabelHierarchy("example.com.")).To(Equal([]string{".", "com.", "example.com."}))
})

It("Uses Parent Zone Key to validate DS", func() {
signedDSSets := d.DelegationSignerData(nameserver, deliveryService)

Expect(len(signedDSSets)).ToNot(Equal(0))
Expect(len(signedDSSets[0].RRSet)).ToNot(Equal(0))

verifiedCount := 0
for _, signedDSSet := range signedDSSets {

signedKeys := d.SigningData(nameserver, signedDSSet.RRSIG.SignerName)

Expect(len(signedKeys.SignedKsks)).ToNot(Equal(0))
Expect(len(signedKeys.SignedZsks)).ToNot(Equal(0))

for _, sk := range signedKeys.SignedZsks {
for _, k := range sk.RRSet {
switch kk := k.(type) {
case *dns.DNSKEY:
if kk.KeyTag() == signedDSSet.RRSIG.KeyTag {
Expect(signedDSSet.RRSIG.Verify(kk, signedDSSet.RRSet)).To(BeNil())
verifiedCount++
}
}
}
}

for _, sk := range signedKeys.SignedKsks {
for _, k := range sk.RRSet {
switch kk := k.(type) {
case *dns.DNSKEY:
if kk.KeyTag() == signedDSSet.RRSIG.KeyTag {
Expect(signedDSSet.RRSIG.Verify(kk, signedDSSet.RRSet)).To(BeNil())
verifiedCount++
}
}
}
}
}

Expect(verifiedCount).ToNot(Equal(0))
})

It("Uses DS to validate Public Key", func() {
signedKeys := d.SigningData(nameserver, deliveryService)
signedDSSets := d.DelegationSignerData(nameserver, deliveryService)

Expect(len(signedDSSets)).ToNot(Equal(0))

count := 0
for _, signedZsk := range signedKeys.SignedZsks {
for _, zsk := range signedZsk.RRSet {
switch z := zsk.(type) {
case *dns.DNSKEY:
for _, signedDs := range signedDSSets {
for _, ds := range signedDs.RRSet {
switch d := ds.(type) {
case *dns.DS:
if d.KeyTag == z.KeyTag() {
computedDS := z.ToDS(d.DigestType)
Expect(d.Digest).To(Equal(computedDS.Digest))
count++
}
}
}
}
}
}
}

Expect(count).ToNot(Equal(0))
})

It("Uses KSK public key to verify ZSK RRSig", func() {
signedKeys := d.SigningData(nameserver, deliveryService)


count := 0
for _, signedZsk := range signedKeys.SignedZsks {
for _, signedKsk := range signedKeys.SignedKsks {
for _, ksk := range signedKsk.RRSet {
switch k := ksk.(type) {
case *dns.DNSKEY:
if k.KeyTag() == signedZsk.RRSIG.KeyTag {
Expect(signedZsk.RRSIG.Verify(k, signedZsk.RRSet)).To(BeNil())
count++
}
}
}
}
}
Expect(count).ToNot(Equal(0))
})
})
})