-
Notifications
You must be signed in to change notification settings - Fork 4
/
Copy pathgoresolver.go
111 lines (95 loc) · 3.48 KB
/
goresolver.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
package goresolver
import (
"errors"
"time"
"github.com/miekg/dns"
)
const (
DefaultTimeout = 5 * time.Second
)
// Resolver contains the client configuration for github.com/miekg/dns,
// the instantiated client and the func that performs the actual queries.
// queryFn can be used for mocking the actual DNS lookups in the test suite.
type Resolver struct {
queryFn func(string, uint16) (*dns.Msg, error)
dnsClient *dns.Client
dnsClientConfig *dns.ClientConfig
}
// Errors returned by the verification/validation methods at all levels.
var (
ErrResourceNotSigned = errors.New("resource is not signed with RRSIG")
ErrNoResult = errors.New("requested RR not found")
ErrNsNotAvailable = errors.New("no name server to answer the question")
ErrDnskeyNotAvailable = errors.New("DNSKEY RR does not exist")
ErrDsNotAvailable = errors.New("DS RR does not exist")
ErrInvalidRRsig = errors.New("invalid RRSIG")
ErrForgedRRsig = errors.New("forged RRSIG header")
ErrRrsigValidationError = errors.New("RR doesn't validate against RRSIG")
ErrRrsigValidityPeriod = errors.New("invalid RRSIG validity period")
ErrUnknownDsDigestType = errors.New("unknown DS digest type")
ErrDsInvalid = errors.New("DS RR does not match DNSKEY")
ErrInvalidQuery = errors.New("invalid query input")
)
var resolver *Resolver
// NewDNSMessage creates and initializes a dns.Msg object, with EDNS enabled
// and the DO (DNSSEC OK) flag set. It returns a pointer to the created
// object.
func NewDNSMessage() *dns.Msg {
dnsMessage := &dns.Msg{
MsgHdr: dns.MsgHdr{
RecursionDesired: true,
},
}
dnsMessage.SetEdns0(4096, true)
return dnsMessage
}
// localQuery takes a query name (qname) and query type (qtype) and
// performs a DNS lookup by calling dnsClient.Exchange.
// It returns the answer in a *dns.Msg (or nil in case of an error, in which
// case err will be set accordingly.)
func localQuery(qname string, qtype uint16) (*dns.Msg, error) {
dnsMessage := NewDNSMessage()
dnsMessage.SetQuestion(qname, qtype)
if resolver.dnsClientConfig == nil {
return nil, errors.New("dns client not initialized")
}
for _, server := range resolver.dnsClientConfig.Servers {
r, _, err := resolver.dnsClient.Exchange(dnsMessage, server+":"+resolver.dnsClientConfig.Port)
if err != nil {
return nil, err
}
if r == nil || r.Rcode == dns.RcodeNameError || r.Rcode == dns.RcodeSuccess {
return r, err
}
}
return nil, ErrNsNotAvailable
}
// queryDelegation takes a domain name and fetches the DS and DNSKEY records
// in that zone. Returns a SignedZone or nil in case of error.
func queryDelegation(domainName string) (signedZone *SignedZone, err error) {
signedZone = NewSignedZone(domainName)
signedZone.dnskey, err = resolver.queryRRset(domainName, dns.TypeDNSKEY)
if err != nil {
return nil, err
}
signedZone.pubKeyLookup = make(map[uint16]*dns.DNSKEY)
for _, rr := range signedZone.dnskey.rrSet {
signedZone.addPubKey(rr.(*dns.DNSKEY))
}
signedZone.ds, _ = resolver.queryRRset(domainName, dns.TypeDS)
return signedZone, nil
}
// NewResolver initializes the package Resolver instance using the default
// dnsClientConfig.
func NewResolver(resolvConf string) (res *Resolver, err error) {
resolver = &Resolver{}
resolver.dnsClient = &dns.Client{
ReadTimeout: DefaultTimeout,
}
resolver.dnsClientConfig, err = dns.ClientConfigFromFile(resolvConf)
if err != nil {
return nil, err
}
resolver.queryFn = localQuery
return resolver, nil
}