1 package bdns
2
3 import (
4 "context"
5 "fmt"
6 "net"
7
8 "github.com/miekg/dns"
9 )
10
11
12 type Error struct {
13 recordType uint16
14 hostname string
15
16 underlying error
17 rCode int
18
19
20
21 extended *dns.EDNS0_EDE
22 }
23
24
25
26 func extendedDNSError(msg *dns.Msg) *dns.EDNS0_EDE {
27 opt := msg.IsEdns0()
28 if opt != nil {
29 for _, opt := range opt.Option {
30 ede, ok := opt.(*dns.EDNS0_EDE)
31 if !ok {
32 continue
33 }
34 return ede
35 }
36 }
37 return nil
38 }
39
40
41
42 func wrapErr(queryType uint16, hostname string, resp *dns.Msg, err error) error {
43 if err != nil {
44 return Error{
45 recordType: queryType,
46 hostname: hostname,
47 underlying: err,
48 extended: nil,
49 }
50 }
51 if resp.Rcode != dns.RcodeSuccess {
52 return Error{
53 recordType: queryType,
54 hostname: hostname,
55 rCode: resp.Rcode,
56 underlying: nil,
57 extended: extendedDNSError(resp),
58 }
59 }
60 return nil
61 }
62
63
64
65
66
67
68 var extendedErrorCodeToString = map[uint16]string{
69 dns.ExtendedErrorCodeOther: "Other",
70 dns.ExtendedErrorCodeUnsupportedDNSKEYAlgorithm: "DNSSEC: Unsupported DNSKEY Algorithm",
71 dns.ExtendedErrorCodeUnsupportedDSDigestType: "DNSSEC: Unsupported DS Digest Type",
72 dns.ExtendedErrorCodeStaleAnswer: "Stale Answer",
73 dns.ExtendedErrorCodeForgedAnswer: "Forged Answer",
74 dns.ExtendedErrorCodeDNSSECIndeterminate: "DNSSEC: Indeterminate",
75 dns.ExtendedErrorCodeDNSBogus: "DNSSEC: Bogus",
76 dns.ExtendedErrorCodeSignatureExpired: "DNSSEC: Signature Expired",
77 dns.ExtendedErrorCodeSignatureNotYetValid: "DNSSEC: Signature Not Yet Valid",
78 dns.ExtendedErrorCodeDNSKEYMissing: "DNSSEC: DNSKEY Missing",
79 dns.ExtendedErrorCodeRRSIGsMissing: "DNSSEC: RRSIGs Missing",
80 dns.ExtendedErrorCodeNoZoneKeyBitSet: "DNSSEC: No Zone Key Bit Set",
81 dns.ExtendedErrorCodeNSECMissing: "DNSSEC: NSEC Missing",
82 dns.ExtendedErrorCodeCachedError: "Cached Error",
83 dns.ExtendedErrorCodeNotReady: "Not Ready",
84 dns.ExtendedErrorCodeBlocked: "Blocked",
85 dns.ExtendedErrorCodeCensored: "Censored",
86 dns.ExtendedErrorCodeFiltered: "Filtered",
87 dns.ExtendedErrorCodeProhibited: "Prohibited",
88 dns.ExtendedErrorCodeStaleNXDOMAINAnswer: "Stale NXDOMAIN Answer",
89 dns.ExtendedErrorCodeNotAuthoritative: "Not Authoritative",
90 dns.ExtendedErrorCodeNotSupported: "Not Supported",
91 dns.ExtendedErrorCodeNoReachableAuthority: "No Reachable Authority",
92 dns.ExtendedErrorCodeNetworkError: "Network Error between Resolver and Authority",
93 dns.ExtendedErrorCodeInvalidData: "Invalid Data",
94 }
95
96 func (d Error) Error() string {
97 var detail, additional string
98 if d.underlying != nil {
99 if netErr, ok := d.underlying.(*net.OpError); ok {
100 if netErr.Timeout() {
101 detail = detailDNSTimeout
102 } else {
103 detail = detailDNSNetFailure
104 }
105
106
107 } else if d.underlying == context.DeadlineExceeded {
108 detail = detailDNSTimeout
109 } else if d.underlying == context.Canceled {
110 detail = detailCanceled
111 } else {
112 detail = detailServerFailure
113 }
114 } else if d.rCode != dns.RcodeSuccess {
115 detail = dns.RcodeToString[d.rCode]
116 if explanation, ok := rcodeExplanations[d.rCode]; ok {
117 additional = " - " + explanation
118 }
119 } else {
120 detail = detailServerFailure
121 }
122
123 if d.extended == nil {
124 return fmt.Sprintf("DNS problem: %s looking up %s for %s%s", detail,
125 dns.TypeToString[d.recordType], d.hostname, additional)
126 }
127
128 summary := extendedErrorCodeToString[d.extended.InfoCode]
129 if summary == "" {
130 summary = fmt.Sprintf("Unknown Extended DNS Error code %d", d.extended.InfoCode)
131 }
132 result := fmt.Sprintf("DNS problem: looking up %s for %s: %s",
133 dns.TypeToString[d.recordType], d.hostname, summary)
134 if d.extended.ExtraText != "" {
135 result = result + ": " + d.extended.ExtraText
136 }
137 return result
138 }
139
140 const detailDNSTimeout = "query timed out"
141 const detailCanceled = "query timed out (and was canceled)"
142 const detailDNSNetFailure = "networking error"
143 const detailServerFailure = "server failure at resolver"
144
145
146
147 var rcodeExplanations = map[int]string{
148 dns.RcodeNameError: "check that a DNS record exists for this domain",
149 dns.RcodeServerFailure: "the domain's nameservers may be malfunctioning",
150 }
151
View as plain text