Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: DNSSEC Validation #470

Draft
wants to merge 12 commits into
base: main
Choose a base branch
from
Draft
4 changes: 2 additions & 2 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ jobs:
- name: Setup Go
uses: actions/setup-go@v5
with:
go-version: '1.20'
go-version: "1.21"
- name: Build
run: |
go version
Expand All @@ -46,7 +46,7 @@ jobs:
- name: Setup Go
uses: actions/setup-go@v5
with:
go-version: '1.23'
go-version: "1.23"
- name: Other lint
run: |
go install golang.org/x/tools/cmd/goimports@latest
Expand Down
3 changes: 2 additions & 1 deletion go.mod
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
module github.com/zmap/zdns

go 1.20
go 1.21.1

require (
github.com/hashicorp/go-version v1.7.0
Expand All @@ -10,6 +10,7 @@ require (
github.com/schollz/progressbar/v3 v3.15.0
github.com/sirupsen/logrus v1.9.3
github.com/stretchr/testify v1.9.0
github.com/zmap/go-dns-root-anchors v0.0.0-20241013070941-7d9393cc3f64
github.com/zmap/go-iptree v0.0.0-20210731043055-d4e632617837
github.com/zmap/zcrypto v0.0.0-20240803002437-3a861682ac77
github.com/zmap/zflags v1.4.0-beta.1.0.20200204220219-9d95409821b6
Expand Down
2 changes: 2 additions & 0 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -269,6 +269,8 @@ github.com/yuin/goldmark v1.1.32/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9de
github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY=
github.com/zmap/dns v1.1.63-zdns1 h1:vaZIXXLZqjmZTGcpu9qPDcunqWfxeRMh0OwLiCxcjsI=
github.com/zmap/dns v1.1.63-zdns1/go.mod h1:L50pXblXGxDFLaon9W4vGSfC1rGIcBL29sS7sNvNKuI=
github.com/zmap/go-dns-root-anchors v0.0.0-20241013070941-7d9393cc3f64 h1:nimnL754tetLIX/BtOp7lXk5H2/Jqo472MYBNhWTgAo=
github.com/zmap/go-dns-root-anchors v0.0.0-20241013070941-7d9393cc3f64/go.mod h1:AkYq/HWOOEFPx6YgVn2oYjaZjLw2R/HV5WUWfJrFQ6s=
github.com/zmap/go-iptree v0.0.0-20210731043055-d4e632617837 h1:DjHnADS2r2zynZ3WkCFAQ+PNYngMSNceRROi0pO6c3M=
github.com/zmap/go-iptree v0.0.0-20210731043055-d4e632617837/go.mod h1:9vp0bxqozzQwcjBwenEXfKVq8+mYbwHkQ1NF9Ap0DMw=
github.com/zmap/rc2 v0.0.0-20131011165748-24b9757f5521/go.mod h1:3YZ9o3WnatTIZhuOtot4IcUfzoKVjUHqu6WALIyI0nE=
Expand Down
61 changes: 61 additions & 0 deletions src/zdns/answers.go
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,21 @@
PublicKey string `json:"public_key" groups:"short,normal,long,trace"`
}

func (r *DNSKEYAnswer) ToVanillaType() *dns.DNSKEY {
return &dns.DNSKEY{
Hdr: dns.RR_Header{
Name: dns.CanonicalName(r.Name),
Rrtype: r.RrType,
Class: dns.StringToClass[r.Class],
Ttl: r.TTL,
},
Flags: r.Flags,
Protocol: r.Protocol,
Algorithm: r.Algorithm,
PublicKey: r.PublicKey,
}
}

type DSAnswer struct {
Answer
KeyTag uint16 `json:"key_tag" groups:"short,normal,long,trace"`
Expand All @@ -86,6 +101,22 @@
Digest string `json:"digest" groups:"short,normal,long,trace"`
}

func (r *DSAnswer) ToVanillaType() *dns.DS {
return &dns.DS{
Hdr: dns.RR_Header{

Name: dns.CanonicalName(r.Name),
Rrtype: r.RrType,
Class: dns.StringToClass[r.Class],
Ttl: r.TTL,
},
KeyTag: r.KeyTag,
Algorithm: r.Algorithm,
DigestType: r.DigestType,
Digest: r.Digest,
}
}

type GPOSAnswer struct {
Answer
Longitude string `json:"preference" groups:"short,normal,long,trace"`
Expand Down Expand Up @@ -186,6 +217,36 @@
Signature string `json:"signature" groups:"short,normal,long,trace"`
}

func (r *RRSIGAnswer) ToVanillaType() *dns.RRSIG {
expiration, err := dns.StringToTime(r.Expiration)
if err != nil {
panic(fmt.Sprintf("failed to parse expiration time: %s", r.Expiration))

Check failure on line 223 in src/zdns/answers.go

View workflow job for this annotation

GitHub Actions / lint

fmt.Sprintf can be replaced with string concatenation (perfsprint)
}

inception, err := dns.StringToTime(r.Inception)
if err != nil {
panic(fmt.Sprintf("failed to parse inception time: %s", r.Inception))

Check failure on line 228 in src/zdns/answers.go

View workflow job for this annotation

GitHub Actions / lint

fmt.Sprintf can be replaced with string concatenation (perfsprint)
}

return &dns.RRSIG{
Hdr: dns.RR_Header{
Name: dns.CanonicalName(r.Name),
Rrtype: r.RrType,
Class: dns.StringToClass[r.Class],
Ttl: r.TTL,
},
TypeCovered: r.TypeCovered,
Algorithm: r.Algorithm,
Labels: r.Labels,
OrigTtl: r.OriginalTTL,
Expiration: expiration,
Inception: inception,
KeyTag: r.KeyTag,
SignerName: r.SignerName,
Signature: r.Signature,
}
}

type RPAnswer struct {
Answer
Mbox string `json:"mbox" groups:"short,normal,long,trace"`
Expand Down
26 changes: 26 additions & 0 deletions src/zdns/cache.go
Original file line number Diff line number Diff line change
Expand Up @@ -309,6 +309,32 @@ func (s *Cache) SafeAddCachedAuthority(res *SingleQueryResult, ns *NameServer, d
nsString = ns.String()
}

// Referrals may contain DS records in the authority section. These need to be cached under the child name.
var dsRRs []interface{}
var otherRRs []interface{}
for _, rr := range res.Authorities {
if dsRR, ok := rr.(DSAnswer); ok {
dsRRs = append(dsRRs, dsRR)
} else {
otherRRs = append(otherRRs, rr)
}
}

if len(dsRRs) > 0 {
dsRes := &SingleQueryResult{
Answers: dsRRs,
Protocol: res.Protocol,
Resolver: res.Resolver,
Flags: res.Flags,
TLSServerHandshake: res.TLSServerHandshake,
}
dsRes.Flags.Authoritative = true
delegateName := removeTrailingDotIfNotRoot(dsRRs[0].(DSAnswer).BaseAns().Name)
dsCachedRes := s.buildCachedResult(dsRes, depth, layer)
s.addCachedAnswer(Question{Name: delegateName, Type: dns.TypeDS, Class: dns.ClassINET}, nsString, false, dsCachedRes, depth)
}

res.Authorities = otherRRs
cachedRes := s.buildCachedResult(res, depth, layer)
if len(cachedRes.Answers) == 0 && len(cachedRes.Authorities) == 0 && len(cachedRes.Additionals) == 0 {
s.VerboseLog(depth+1, "SafeAddCachedAnswer: no cacheable records found, aborting")
Expand Down
Loading