1 // Copyright 2009 The Go Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style
3 // license that can be found in the LICENSE file.
12 // DNSError represents a DNS lookup error.
13 type DNSError
struct {
14 Err
string // description of the error
15 Name
string // name looked for
16 Server
string // server used
20 func (e
*DNSError
) Error() string {
24 s
:= "lookup " + e
.Name
26 s
+= " on " + e
.Server
32 func (e
*DNSError
) Timeout() bool { return e
.IsTimeout
}
33 func (e
*DNSError
) Temporary() bool { return e
.IsTimeout
}
35 const noSuchHost
= "no such host"
37 // reverseaddr returns the in-addr.arpa. or ip6.arpa. hostname of the IP
38 // address addr suitable for rDNS (PTR) record lookup or an error if it fails
39 // to parse the IP address.
40 func reverseaddr(addr
string) (arpa
string, err error
) {
43 return "", &DNSError
{Err
: "unrecognized address", Name
: addr
}
46 return itoa(int(ip
[15])) + "." + itoa(int(ip
[14])) + "." + itoa(int(ip
[13])) + "." +
47 itoa(int(ip
[12])) + ".in-addr.arpa.", nil
50 buf
:= make([]byte, 0, len(ip
)*4+len("ip6.arpa."))
51 // Add it, in reverse, to the buffer
52 for i
:= len(ip
) - 1; i
>= 0; i
-- {
54 buf
= append(buf
, hexDigit
[v
&0xF])
55 buf
= append(buf
, '.')
56 buf
= append(buf
, hexDigit
[v
>>4])
57 buf
= append(buf
, '.')
59 // Append "ip6.arpa." and return (buf already has the final .)
60 buf
= append(buf
, "ip6.arpa."...)
61 return string(buf
), nil
64 // Find answer for name in dns message.
65 // On return, if err == nil, addrs != nil.
66 func answer(name
, server
string, dns
*dnsMsg
, qtype
uint16) (cname
string, addrs
[]dnsRR
, err error
) {
67 addrs
= make([]dnsRR
, 0, len(dns
.answer
))
69 if dns
.rcode
== dnsRcodeNameError
&& dns
.recursion_available
{
70 return "", nil, &DNSError
{Err
: noSuchHost
, Name
: name
}
72 if dns
.rcode
!= dnsRcodeSuccess
{
73 // None of the error codes make sense
74 // for the query we sent. If we didn't get
75 // a name error and we didn't get success,
76 // the server is behaving incorrectly.
77 return "", nil, &DNSError
{Err
: "server misbehaving", Name
: name
, Server
: server
}
81 // Presotto says it's okay to assume that servers listed in
82 // /etc/resolv.conf are recursive resolvers.
83 // We asked for recursion, so it should have included
84 // all the answers we need in this one packet.
86 for cnameloop
:= 0; cnameloop
< 10; cnameloop
++ {
88 for _
, rr
:= range dns
.answer
{
89 if _
, justHeader
:= rr
.(*dnsRR_Header
); justHeader
{
90 // Corrupt record: we only have a
91 // header. That header might say it's
92 // of type qtype, but we don't
93 // actually have it. Skip.
97 if h
.Class
== dnsClassINET
&& h
.Name
== name
{
100 addrs
= append(addrs
, rr
)
103 name
= rr
.(*dnsRR_CNAME
).Cname
109 return "", nil, &DNSError
{Err
: noSuchHost
, Name
: name
, Server
: server
}
111 return name
, addrs
, nil
114 return "", nil, &DNSError
{Err
: "too many redirects", Name
: name
, Server
: server
}
117 func isDomainName(s
string) bool {
118 // See RFC 1035, RFC 3696.
127 ok
:= false // Ok once we've seen a letter.
129 for i
:= 0; i
< len(s
); i
++ {
134 case 'a' <= c
&& c
<= 'z' ||
'A' <= c
&& c
<= 'Z' || c
== '_':
137 case '0' <= c
&& c
<= '9':
141 // Byte before dash cannot be dot.
147 // Byte before dot cannot be dot, dash.
148 if last
== '.' || last
== '-' {
151 if partlen
> 63 || partlen
== 0 {
158 if last
== '-' || partlen
> 63 {
165 // An SRV represents a single DNS SRV record.
173 // byPriorityWeight sorts SRV records by ascending priority and weight.
174 type byPriorityWeight
[]*SRV
176 func (s byPriorityWeight
) Len() int { return len(s
) }
178 func (s byPriorityWeight
) Swap(i
, j
int) { s
[i
], s
[j
] = s
[j
], s
[i
] }
180 func (s byPriorityWeight
) Less(i
, j
int) bool {
181 return s
[i
].Priority
< s
[j
].Priority ||
182 (s
[i
].Priority
== s
[j
].Priority
&& s
[i
].Weight
< s
[j
].Weight
)
185 // shuffleByWeight shuffles SRV records by weight using the algorithm
186 // described in RFC 2782.
187 func (addrs byPriorityWeight
) shuffleByWeight() {
189 for _
, addr
:= range addrs
{
190 sum
+= int(addr
.Weight
)
192 for sum
> 0 && len(addrs
) > 1 {
195 for i
:= range addrs
{
196 s
+= int(addrs
[i
].Weight
)
200 copy(addrs
[1:i
+1], addrs
[0:i
])
206 sum
-= int(addrs
[0].Weight
)
211 // sort reorders SRV records as specified in RFC 2782.
212 func (addrs byPriorityWeight
) sort() {
215 for j
:= 1; j
< len(addrs
); j
++ {
216 if addrs
[i
].Priority
!= addrs
[j
].Priority
{
217 addrs
[i
:j
].shuffleByWeight()
221 addrs
[i
:].shuffleByWeight()
224 // An MX represents a single DNS MX record.
230 // byPref implements sort.Interface to sort MX records by preference
233 func (s byPref
) Len() int { return len(s
) }
235 func (s byPref
) Less(i
, j
int) bool { return s
[i
].Pref
< s
[j
].Pref
}
237 func (s byPref
) Swap(i
, j
int) { s
[i
], s
[j
] = s
[j
], s
[i
] }
239 // sort reorders MX records as specified in RFC 5321.
240 func (s byPref
) sort() {
242 j
:= rand
.Intn(i
+ 1)
243 s
[i
], s
[j
] = s
[j
], s
[i
]
248 // An NS represents a single DNS NS record.