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

Merged
merged 72 commits into from
Dec 18, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
72 commits
Select commit Hold shift + click to select a range
5bb6d81
refactor: return raw dns response from auxiliary functions
developStorm Oct 9, 2024
5070760
feat: basic, same-level DNSSEC validation
developStorm Oct 10, 2024
2e432e7
fix: newLayer should not be updated if extractAuthority fails
developStorm Oct 23, 2024
b1f0b6b
refactor: extend trace, fix depth for couple places
developStorm Oct 23, 2024
f45eab2
refactor: more comprehensive validation of DNSKEY/RRSIG
developStorm Oct 30, 2024
f276da1
patch: disregard RRSIG in authorities
developStorm Oct 31, 2024
bf9c009
fix: remove depth parameter in lookup function
developStorm Oct 31, 2024
38b23f6
feat: implement DS verification
developStorm Nov 1, 2024
a922e1c
feat: cache DS in referrals
developStorm Nov 1, 2024
2b69182
feat: validate dnssec for referrals
developStorm Nov 1, 2024
ca5a2b5
build(ci): bump to go1.21
developStorm Nov 1, 2024
4d62421
fix: answer section is always validated
developStorm Nov 1, 2024
856f34f
fix: resolve linter issues
developStorm Nov 12, 2024
97d20e5
Merge branch 'main' into feat/basic-dnssec-validation
developStorm Nov 12, 2024
b73a77e
fix: resolve linter issues
developStorm Nov 13, 2024
148eb28
refactor: store current retry in resolver struct
developStorm Nov 13, 2024
7926796
patch: don't modify original res
developStorm Nov 16, 2024
a11ef2f
docs: rrset validation failure
developStorm Nov 16, 2024
2af2290
build(deps): bump root anchors
developStorm Nov 16, 2024
67f28a4
fix: add validity period check for RRSIG
developStorm Nov 16, 2024
cb6dde4
feat: add dnssec result types
developStorm Nov 17, 2024
3561c36
docs: clarify comments for retries and retriesRemaining in Resolver
developStorm Nov 17, 2024
12d8bda
feat: dnssec result field
developStorm Nov 17, 2024
1c8d186
refactor: simplify param list with validator struct
developStorm Nov 17, 2024
cf2a665
refactor: extended DNSSEC result handling
developStorm Nov 17, 2024
d508b85
feat: add JSON tags to DNSSEC types for improved serialization
developStorm Nov 17, 2024
ea51f64
refactor: DNSSEC functions now does not stop resolution
developStorm Nov 18, 2024
21ab2f7
fix: regression in authority caching
developStorm Nov 18, 2024
3126130
feat: add DNSSEC validation as CLI option
developStorm Nov 18, 2024
c0fb013
feat: implement circular query detection
developStorm Nov 18, 2024
8c258a4
chore: suppress some lint warnings
developStorm Nov 18, 2024
f2a9dad
fix: handle DNSSEC insecure and bogus statuses
developStorm Nov 18, 2024
2b074a2
test: add DNSSEC integration tests
developStorm Nov 18, 2024
6b8174b
fix: RRset should be identified by all of name, class and type
developStorm Nov 18, 2024
b213bd8
fix: dedup ds/dnskey
developStorm Nov 18, 2024
a69785b
docs: function comments for dnssec
developStorm Nov 18, 2024
211b9f1
fix: shortcut Insecure if entire answer is unsigned
developStorm Nov 18, 2024
d46c8ce
feat: add dnssec output fields
developStorm Nov 18, 2024
2baa4a4
Revert "test: add DNSSEC integration tests"
developStorm Nov 18, 2024
6721055
test: add DNSSEC integration tests
developStorm Nov 18, 2024
0e0b72c
fix: rrsig error handling and DS validation on DNSKEY response
developStorm Nov 19, 2024
3d7db6f
fix: KSK is a lie :(
developStorm Nov 19, 2024
769ec0b
chore: error logging
developStorm Nov 19, 2024
6deec0b
docs: comments
developStorm Nov 19, 2024
f696461
fix: skip validation for some sections if answer is authoritative
developStorm Nov 19, 2024
a9074ce
feat: lazy query A/AAAA of NSes when iterating on authorities
developStorm Nov 19, 2024
a7962e5
fix: should restore the previous dnssec setting
developStorm Nov 20, 2024
310056a
docs: add RFC references
developStorm Nov 20, 2024
521263c
Merge branch 'main' into feat/basic-dnssec-validation
zakird Nov 24, 2024
4e56d4c
docs: add one rfc reference
developStorm Nov 25, 2024
947fd5b
Merge branch 'main' into feat/basic-dnssec-validation
developStorm Nov 25, 2024
c5a7996
refactor: additionals -> additional
developStorm Dec 9, 2024
666544e
refactor: passing on validation result from front of the chain
developStorm Dec 9, 2024
a8fb551
Merge branch 'main' into feat/basic-dnssec-validation
developStorm Dec 9, 2024
52af38a
refactor: miscellaneous bits
developStorm Dec 10, 2024
5a7ce49
fix: NSEC3 type definition
developStorm Dec 14, 2024
ea40f42
feat: NSEC3 validation for DS records
developStorm Dec 14, 2024
4b7f63b
style: fix linter issues
developStorm Dec 14, 2024
2a6b6b1
test: add integration test for dnssec with cnames
developStorm Dec 14, 2024
84a7719
fix: bogus case classification
developStorm Dec 14, 2024
67f9eeb
patch: comment
developStorm Dec 14, 2024
b960441
feat: support NSEC for DS check
developStorm Dec 14, 2024
c77f9d0
fix: always cache under lower-cased authname
developStorm Dec 14, 2024
026347f
fix: DS records should always be cached as secure
developStorm Dec 14, 2024
5d2b3f7
fix: support DS/NSEC in authority section
developStorm Dec 15, 2024
9f7d891
chore: logging for a specific nsec3 case
developStorm Dec 15, 2024
602ff82
revert change to go 1.21.1
phillip-stephens Dec 18, 2024
08ae4c5
downgrade required go version to 1.20
phillip-stephens Dec 18, 2024
c0a07ad
Merge branch 'main' into feat/basic-dnssec-validation
phillip-stephens Dec 18, 2024
488aa8a
fix lint error
phillip-stephens Dec 18, 2024
78751aa
toolchain directive not available in go 1.20
phillip-stephens Dec 18, 2024
2991a13
upgrade -> go 1.21
phillip-stephens Dec 18, 2024
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
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
2 changes: 1 addition & 1 deletion .github/workflows/large_scan_integration_test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,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 Down
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -3,3 +3,4 @@
*.iml
*.code-workspace
/zdns
*.log
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -311,7 +311,7 @@ result verbosity levels: `short`, `normal` (default), `long`, and `trace`:

Users can also include specific additional fields using the `--include-fields`
flag and specifying a list of fields, e.g., `--include-fields=flags,resolver`.
Additional fields are: class, protocol, ttl, resolver, flags.
Additional fields are: class, protocol, ttl, resolver, flags, dnssec.

Name Server Mode
----------------
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

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.10.0
github.com/zmap/go-dns-root-anchors v0.0.0-20241218192521-63aee68224b6
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-20241218192521-63aee68224b6 h1:vJV1O3ZIH9ywqPKaiYCHkyZOZmSZvdRHjlqmBk3JIIs=
github.com/zmap/go-dns-root-anchors v0.0.0-20241218192521-63aee68224b6/go.mod h1:cmGnqnZjrvWCBaJclyvXNP6yHEDjwoSV06GmM1zmdXU=
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
3 changes: 2 additions & 1 deletion src/cli/cli.go
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,7 @@ type QueryOptions struct {
ClassString string `long:"class" default:"INET" description:"DNS class to query. Options: INET, CSNET, CHAOS, HESIOD, NONE, ANY."`
ClientSubnetString string `long:"client-subnet" description:"Client subnet in CIDR format for EDNS0."`
Dnssec bool `long:"dnssec" description:"Requests DNSSEC records by setting the DNSSEC OK (DO) bit"`
ValidateDNSSEC bool `long:"validate-dnssec" description:"Validate DNSSEC records, only applicable with --iterative"`
developStorm marked this conversation as resolved.
Show resolved Hide resolved
UseNSID bool `long:"nsid" description:"Request NSID."`
}

Expand All @@ -93,7 +94,7 @@ type InputOutputOptions struct {
BlacklistFilePath string `long:"blacklist-file" description:"blacklist file for servers to exclude from lookups"`
DNSConfigFilePath string `long:"conf-file" default:"/etc/resolv.conf" description:"config file for DNS servers"`
MultipleModuleConfigFilePath string `short:"c" long:"multi-config-file" description:"config file path for multiple module"`
IncludeInOutput string `long:"include-fields" description:"Comma separated list of fields to additionally output beyond result verbosity. Options: class, protocol, ttl, resolver, flags"`
IncludeInOutput string `long:"include-fields" description:"Comma separated list of fields to additionally output beyond result verbosity. Options: class, protocol, ttl, resolver, flags, dnssec"`
InputFilePath string `short:"f" long:"input-file" default:"-" description:"names to read, defaults to stdin"`
LogFilePath string `long:"log-file" default:"-" description:"where should JSON logs be saved, defaults to stderr"`
MetadataFilePath string `long:"metadata-file" description:"where should JSON metadata be saved, defaults to no metadata output. Use '-' for stderr."`
Expand Down
12 changes: 11 additions & 1 deletion src/cli/worker_manager.go
Original file line number Diff line number Diff line change
Expand Up @@ -214,7 +214,17 @@ func populateResolverConfig(gc *CLIConf) *zdns.ResolverConfig {
config.MaxDepth = gc.MaxDepth
config.CheckingDisabledBit = gc.CheckingDisabled
config.ShouldRecycleSockets = !gc.DisableRecycleSockets
config.DNSSecEnabled = gc.Dnssec

config.ShouldValidateDNSSEC = gc.ValidateDNSSEC
if config.ShouldValidateDNSSEC {
config.DNSSecEnabled = true
if !gc.IterativeResolution {
log.Fatal("DNSSEC validation is only supported with iterative resolution")
}
} else {
config.DNSSecEnabled = gc.Dnssec
}

config.DNSConfigFilePath = gc.DNSConfigFilePath

config.LogLevel = log.Level(gc.Verbosity)
Expand Down
106 changes: 106 additions & 0 deletions src/zdns/answers.go
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,21 @@ type DNSKEYAnswer struct {
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 @@ type DSAnswer struct {
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 @@ -143,16 +174,50 @@ type NSECAnswer struct {
TypeBitMap string `json:"type_bit_map" groups:"short,normal,long,trace"`
}

func (r *NSECAnswer) ToVanillaType() *dns.NSEC {
return &dns.NSEC{
Hdr: dns.RR_Header{
Name: dns.CanonicalName(r.Name),
Rrtype: r.RrType,
Class: dns.StringToClass[r.Class],
Ttl: r.TTL,
},
NextDomain: r.NextDomain,
TypeBitMap: makeBitArray(r.TypeBitMap),
}
}

type NSEC3Answer struct {
Answer
HashAlgorithm uint8 `json:"hash_algorithm" groups:"short,normal,long,trace"`
Flags uint8 `json:"flags" groups:"short,normal,long,trace"`
Iterations uint16 `json:"iterations" groups:"short,normal,long,trace"`
SaltLength uint8 `json:"salt_length" groups:"short,normal,long,trace"`
Salt string `json:"salt" groups:"short,normal,long,trace"`
HashLength uint8 `json:"hash_length" groups:"short,normal,long,trace"`
NextDomain string `json:"next_domain" groups:"short,normal,long,trace"`
TypeBitMap string `json:"type_bit_map" groups:"short,normal,long,trace"`
}

func (r *NSEC3Answer) ToVanillaType() *dns.NSEC3 {
return &dns.NSEC3{
Hdr: dns.RR_Header{
Name: dns.CanonicalName(r.Name),
Rrtype: r.RrType,
Class: dns.StringToClass[r.Class],
Ttl: r.TTL,
},
Hash: r.HashAlgorithm,
Flags: r.Flags,
Iterations: r.Iterations,
SaltLength: uint8(len(r.Salt)),
Salt: r.Salt,
HashLength: r.HashLength,
NextDomain: r.NextDomain,
TypeBitMap: makeBitArray(r.TypeBitMap),
}
}

type NSEC3ParamAnswer struct {
Answer
HashAlgorithm uint8 `json:"hash_algorithm" groups:"short,normal,long,trace"`
Expand Down Expand Up @@ -186,6 +251,36 @@ type RRSIGAnswer struct {
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("failed to parse expiration time: " + r.Expiration)
}

inception, err := dns.StringToTime(r.Inception)
if err != nil {
panic("failed to parse inception time: " + r.Inception)
}

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 Expand Up @@ -324,6 +419,15 @@ func makeBitString(bm []uint16) string {
return retv
}

func makeBitArray(s string) []uint16 {
fields := strings.Fields(s)
retv := make([]uint16, 0, len(fields))
for _, t := range fields {
retv = append(retv, dns.StringToType[t])
}
return retv
}

func makeBaseAnswer(hdr *dns.RR_Header, answer string) Answer {
return Answer{
TTL: hdr.Ttl,
Expand Down Expand Up @@ -661,7 +765,9 @@ func ParseAnswer(ans dns.RR) interface{} {
HashAlgorithm: cAns.Hash,
Flags: cAns.Flags,
Iterations: cAns.Iterations,
SaltLength: cAns.SaltLength,
Salt: cAns.Salt,
HashLength: cAns.HashLength,
NextDomain: cAns.NextDomain,
TypeBitMap: makeBitString(cAns.TypeBitMap),
}
Expand Down
Loading
Loading