github.com/rafaeltorres324/go/src@v0.0.0-20210519164414-9fdf653a9838/net/dnsclient.go (about) 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. 4 5 package net 6 7 import ( 8 "sort" 9 10 "golang.org/x/net/dns/dnsmessage" 11 ) 12 13 // provided by runtime 14 func fastrand() uint32 15 16 func randInt() int { 17 x, y := fastrand(), fastrand() // 32-bit halves 18 u := uint(x)<<31 ^ uint(int32(y)) // full uint, even on 64-bit systems; avoid 32-bit shift on 32-bit systems 19 i := int(u >> 1) // clear sign bit, even on 32-bit systems 20 return i 21 } 22 23 func randIntn(n int) int { 24 return randInt() % n 25 } 26 27 // reverseaddr returns the in-addr.arpa. or ip6.arpa. hostname of the IP 28 // address addr suitable for rDNS (PTR) record lookup or an error if it fails 29 // to parse the IP address. 30 func reverseaddr(addr string) (arpa string, err error) { 31 ip := ParseIP(addr) 32 if ip == nil { 33 return "", &DNSError{Err: "unrecognized address", Name: addr} 34 } 35 if ip.To4() != nil { 36 return uitoa(uint(ip[15])) + "." + uitoa(uint(ip[14])) + "." + uitoa(uint(ip[13])) + "." + uitoa(uint(ip[12])) + ".in-addr.arpa.", nil 37 } 38 // Must be IPv6 39 buf := make([]byte, 0, len(ip)*4+len("ip6.arpa.")) 40 // Add it, in reverse, to the buffer 41 for i := len(ip) - 1; i >= 0; i-- { 42 v := ip[i] 43 buf = append(buf, hexDigit[v&0xF], 44 '.', 45 hexDigit[v>>4], 46 '.') 47 } 48 // Append "ip6.arpa." and return (buf already has the final .) 49 buf = append(buf, "ip6.arpa."...) 50 return string(buf), nil 51 } 52 53 func equalASCIIName(x, y dnsmessage.Name) bool { 54 if x.Length != y.Length { 55 return false 56 } 57 for i := 0; i < int(x.Length); i++ { 58 a := x.Data[i] 59 b := y.Data[i] 60 if 'A' <= a && a <= 'Z' { 61 a += 0x20 62 } 63 if 'A' <= b && b <= 'Z' { 64 b += 0x20 65 } 66 if a != b { 67 return false 68 } 69 } 70 return true 71 } 72 73 // isDomainName checks if a string is a presentation-format domain name 74 // (currently restricted to hostname-compatible "preferred name" LDH labels and 75 // SRV-like "underscore labels"; see golang.org/issue/12421). 76 func isDomainName(s string) bool { 77 // See RFC 1035, RFC 3696. 78 // Presentation format has dots before every label except the first, and the 79 // terminal empty label is optional here because we assume fully-qualified 80 // (absolute) input. We must therefore reserve space for the first and last 81 // labels' length octets in wire format, where they are necessary and the 82 // maximum total length is 255. 83 // So our _effective_ maximum is 253, but 254 is not rejected if the last 84 // character is a dot. 85 l := len(s) 86 if l == 0 || l > 254 || l == 254 && s[l-1] != '.' { 87 return false 88 } 89 90 last := byte('.') 91 nonNumeric := false // true once we've seen a letter or hyphen 92 partlen := 0 93 for i := 0; i < len(s); i++ { 94 c := s[i] 95 switch { 96 default: 97 return false 98 case 'a' <= c && c <= 'z' || 'A' <= c && c <= 'Z' || c == '_': 99 nonNumeric = true 100 partlen++ 101 case '0' <= c && c <= '9': 102 // fine 103 partlen++ 104 case c == '-': 105 // Byte before dash cannot be dot. 106 if last == '.' { 107 return false 108 } 109 partlen++ 110 nonNumeric = true 111 case c == '.': 112 // Byte before dot cannot be dot, dash. 113 if last == '.' || last == '-' { 114 return false 115 } 116 if partlen > 63 || partlen == 0 { 117 return false 118 } 119 partlen = 0 120 } 121 last = c 122 } 123 if last == '-' || partlen > 63 { 124 return false 125 } 126 127 return nonNumeric 128 } 129 130 // absDomainName returns an absolute domain name which ends with a 131 // trailing dot to match pure Go reverse resolver and all other lookup 132 // routines. 133 // See golang.org/issue/12189. 134 // But we don't want to add dots for local names from /etc/hosts. 135 // It's hard to tell so we settle on the heuristic that names without dots 136 // (like "localhost" or "myhost") do not get trailing dots, but any other 137 // names do. 138 func absDomainName(b []byte) string { 139 hasDots := false 140 for _, x := range b { 141 if x == '.' { 142 hasDots = true 143 break 144 } 145 } 146 if hasDots && b[len(b)-1] != '.' { 147 b = append(b, '.') 148 } 149 return string(b) 150 } 151 152 // An SRV represents a single DNS SRV record. 153 type SRV struct { 154 Target string 155 Port uint16 156 Priority uint16 157 Weight uint16 158 } 159 160 // byPriorityWeight sorts SRV records by ascending priority and weight. 161 type byPriorityWeight []*SRV 162 163 func (s byPriorityWeight) Len() int { return len(s) } 164 func (s byPriorityWeight) Less(i, j int) bool { 165 return s[i].Priority < s[j].Priority || (s[i].Priority == s[j].Priority && s[i].Weight < s[j].Weight) 166 } 167 func (s byPriorityWeight) Swap(i, j int) { s[i], s[j] = s[j], s[i] } 168 169 // shuffleByWeight shuffles SRV records by weight using the algorithm 170 // described in RFC 2782. 171 func (addrs byPriorityWeight) shuffleByWeight() { 172 sum := 0 173 for _, addr := range addrs { 174 sum += int(addr.Weight) 175 } 176 for sum > 0 && len(addrs) > 1 { 177 s := 0 178 n := randIntn(sum) 179 for i := range addrs { 180 s += int(addrs[i].Weight) 181 if s > n { 182 if i > 0 { 183 addrs[0], addrs[i] = addrs[i], addrs[0] 184 } 185 break 186 } 187 } 188 sum -= int(addrs[0].Weight) 189 addrs = addrs[1:] 190 } 191 } 192 193 // sort reorders SRV records as specified in RFC 2782. 194 func (addrs byPriorityWeight) sort() { 195 sort.Sort(addrs) 196 i := 0 197 for j := 1; j < len(addrs); j++ { 198 if addrs[i].Priority != addrs[j].Priority { 199 addrs[i:j].shuffleByWeight() 200 i = j 201 } 202 } 203 addrs[i:].shuffleByWeight() 204 } 205 206 // An MX represents a single DNS MX record. 207 type MX struct { 208 Host string 209 Pref uint16 210 } 211 212 // byPref implements sort.Interface to sort MX records by preference 213 type byPref []*MX 214 215 func (s byPref) Len() int { return len(s) } 216 func (s byPref) Less(i, j int) bool { return s[i].Pref < s[j].Pref } 217 func (s byPref) Swap(i, j int) { s[i], s[j] = s[j], s[i] } 218 219 // sort reorders MX records as specified in RFC 5321. 220 func (s byPref) sort() { 221 for i := range s { 222 j := randIntn(i + 1) 223 s[i], s[j] = s[j], s[i] 224 } 225 sort.Sort(s) 226 } 227 228 // An NS represents a single DNS NS record. 229 type NS struct { 230 Host string 231 }