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.
11 "golang.org/x/net/dns/dnsmessage"
14 // reverseaddr returns the in-addr.arpa. or ip6.arpa. hostname of the IP
15 // address addr suitable for rDNS (PTR) record lookup or an error if it fails
16 // to parse the IP address.
17 func reverseaddr(addr
string) (arpa
string, err error
) {
20 return "", &DNSError
{Err
: "unrecognized address", Name
: addr
}
23 return uitoa(uint(ip
[15])) + "." + uitoa(uint(ip
[14])) + "." + uitoa(uint(ip
[13])) + "." + uitoa(uint(ip
[12])) + ".in-addr.arpa.", nil
26 buf
:= make([]byte, 0, len(ip
)*4+len("ip6.arpa."))
27 // Add it, in reverse, to the buffer
28 for i
:= len(ip
) - 1; i
>= 0; i
-- {
30 buf
= append(buf
, hexDigit
[v
&0xF],
35 // Append "ip6.arpa." and return (buf already has the final .)
36 buf
= append(buf
, "ip6.arpa."...)
37 return string(buf
), nil
40 func equalASCIIName(x
, y dnsmessage
.Name
) bool {
41 if x
.Length
!= y
.Length
{
44 for i
:= 0; i
< int(x
.Length
); i
++ {
47 if 'A' <= a
&& a
<= 'Z' {
50 if 'A' <= b
&& b
<= 'Z' {
60 // isDomainName checks if a string is a presentation-format domain name
61 // (currently restricted to hostname-compatible "preferred name" LDH labels and
62 // SRV-like "underscore labels"; see golang.org/issue/12421).
63 func isDomainName(s
string) bool {
64 // See RFC 1035, RFC 3696.
65 // Presentation format has dots before every label except the first, and the
66 // terminal empty label is optional here because we assume fully-qualified
67 // (absolute) input. We must therefore reserve space for the first and last
68 // labels' length octets in wire format, where they are necessary and the
69 // maximum total length is 255.
70 // So our _effective_ maximum is 253, but 254 is not rejected if the last
71 // character is a dot.
73 if l
== 0 || l
> 254 || l
== 254 && s
[l
-1] != '.' {
78 nonNumeric
:= false // true once we've seen a letter or hyphen
80 for i
:= 0; i
< len(s
); i
++ {
85 case 'a' <= c
&& c
<= 'z' ||
'A' <= c
&& c
<= 'Z' || c
== '_':
88 case '0' <= c
&& c
<= '9':
92 // Byte before dash cannot be dot.
99 // Byte before dot cannot be dot, dash.
100 if last
== '.' || last
== '-' {
103 if partlen
> 63 || partlen
== 0 {
110 if last
== '-' || partlen
> 63 {
117 // absDomainName returns an absolute domain name which ends with a
118 // trailing dot to match pure Go reverse resolver and all other lookup
120 // See golang.org/issue/12189.
121 // But we don't want to add dots for local names from /etc/hosts.
122 // It's hard to tell so we settle on the heuristic that names without dots
123 // (like "localhost" or "myhost") do not get trailing dots, but any other
125 func absDomainName(b
[]byte) string {
127 for _
, x
:= range b
{
133 if hasDots
&& b
[len(b
)-1] != '.' {
139 // An SRV represents a single DNS SRV record.
147 // byPriorityWeight sorts SRV records by ascending priority and weight.
148 type byPriorityWeight
[]*SRV
150 func (s byPriorityWeight
) Len() int { return len(s
) }
151 func (s byPriorityWeight
) Less(i
, j
int) bool {
152 return s
[i
].Priority
< s
[j
].Priority ||
(s
[i
].Priority
== s
[j
].Priority
&& s
[i
].Weight
< s
[j
].Weight
)
154 func (s byPriorityWeight
) Swap(i
, j
int) { s
[i
], s
[j
] = s
[j
], s
[i
] }
156 // shuffleByWeight shuffles SRV records by weight using the algorithm
157 // described in RFC 2782.
158 func (addrs byPriorityWeight
) shuffleByWeight() {
160 for _
, addr
:= range addrs
{
161 sum
+= int(addr
.Weight
)
163 for sum
> 0 && len(addrs
) > 1 {
166 for i
:= range addrs
{
167 s
+= int(addrs
[i
].Weight
)
170 addrs
[0], addrs
[i
] = addrs
[i
], addrs
[0]
175 sum
-= int(addrs
[0].Weight
)
180 // sort reorders SRV records as specified in RFC 2782.
181 func (addrs byPriorityWeight
) sort() {
184 for j
:= 1; j
< len(addrs
); j
++ {
185 if addrs
[i
].Priority
!= addrs
[j
].Priority
{
186 addrs
[i
:j
].shuffleByWeight()
190 addrs
[i
:].shuffleByWeight()
193 // An MX represents a single DNS MX record.
199 // byPref implements sort.Interface to sort MX records by preference
202 func (s byPref
) Len() int { return len(s
) }
203 func (s byPref
) Less(i
, j
int) bool { return s
[i
].Pref
< s
[j
].Pref
}
204 func (s byPref
) Swap(i
, j
int) { s
[i
], s
[j
] = s
[j
], s
[i
] }
206 // sort reorders MX records as specified in RFC 5321.
207 func (s byPref
) sort() {
209 j
:= rand
.Intn(i
+ 1)
210 s
[i
], s
[j
] = s
[j
], s
[i
]
215 // An NS represents a single DNS NS record.