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