github.com/rakyll/go@v0.0.0-20170216000551-64c02460d703/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 "math/rand" 9 "sort" 10 ) 11 12 // reverseaddr returns the in-addr.arpa. or ip6.arpa. hostname of the IP 13 // address addr suitable for rDNS (PTR) record lookup or an error if it fails 14 // to parse the IP address. 15 func reverseaddr(addr string) (arpa string, err error) { 16 ip := ParseIP(addr) 17 if ip == nil { 18 return "", &DNSError{Err: "unrecognized address", Name: addr} 19 } 20 if ip.To4() != nil { 21 return uitoa(uint(ip[15])) + "." + uitoa(uint(ip[14])) + "." + uitoa(uint(ip[13])) + "." + uitoa(uint(ip[12])) + ".in-addr.arpa.", nil 22 } 23 // Must be IPv6 24 buf := make([]byte, 0, len(ip)*4+len("ip6.arpa.")) 25 // Add it, in reverse, to the buffer 26 for i := len(ip) - 1; i >= 0; i-- { 27 v := ip[i] 28 buf = append(buf, hexDigit[v&0xF]) 29 buf = append(buf, '.') 30 buf = append(buf, hexDigit[v>>4]) 31 buf = append(buf, '.') 32 } 33 // Append "ip6.arpa." and return (buf already has the final .) 34 buf = append(buf, "ip6.arpa."...) 35 return string(buf), nil 36 } 37 38 // Find answer for name in dns message. 39 // On return, if err == nil, addrs != nil. 40 func answer(name, server string, dns *dnsMsg, qtype uint16) (cname string, addrs []dnsRR, err error) { 41 addrs = make([]dnsRR, 0, len(dns.answer)) 42 43 if dns.rcode == dnsRcodeNameError { 44 return "", nil, &DNSError{Err: errNoSuchHost.Error(), Name: name, Server: server} 45 } 46 if dns.rcode != dnsRcodeSuccess { 47 // None of the error codes make sense 48 // for the query we sent. If we didn't get 49 // a name error and we didn't get success, 50 // the server is behaving incorrectly or 51 // having temporary trouble. 52 err := &DNSError{Err: "server misbehaving", Name: name, Server: server} 53 if dns.rcode == dnsRcodeServerFailure { 54 err.IsTemporary = true 55 } 56 return "", nil, err 57 } 58 59 // Look for the name. 60 // Presotto says it's okay to assume that servers listed in 61 // /etc/resolv.conf are recursive resolvers. 62 // We asked for recursion, so it should have included 63 // all the answers we need in this one packet. 64 Cname: 65 for cnameloop := 0; cnameloop < 10; cnameloop++ { 66 addrs = addrs[0:0] 67 for _, rr := range dns.answer { 68 if _, justHeader := rr.(*dnsRR_Header); justHeader { 69 // Corrupt record: we only have a 70 // header. That header might say it's 71 // of type qtype, but we don't 72 // actually have it. Skip. 73 continue 74 } 75 h := rr.Header() 76 if h.Class == dnsClassINET && equalASCIILabel(h.Name, name) { 77 switch h.Rrtype { 78 case qtype: 79 addrs = append(addrs, rr) 80 case dnsTypeCNAME: 81 // redirect to cname 82 name = rr.(*dnsRR_CNAME).Cname 83 continue Cname 84 } 85 } 86 } 87 if len(addrs) == 0 { 88 return "", nil, &DNSError{Err: errNoSuchHost.Error(), Name: name, Server: server} 89 } 90 return name, addrs, nil 91 } 92 93 return "", nil, &DNSError{Err: "too many redirects", Name: name, Server: server} 94 } 95 96 func equalASCIILabel(x, y string) bool { 97 if len(x) != len(y) { 98 return false 99 } 100 for i := 0; i < len(x); i++ { 101 a := x[i] 102 b := y[i] 103 if 'A' <= a && a <= 'Z' { 104 a += 0x20 105 } 106 if 'A' <= b && b <= 'Z' { 107 b += 0x20 108 } 109 if a != b { 110 return false 111 } 112 } 113 return true 114 } 115 116 // isDomainName checks if a string is a presentation-format domain name 117 // (currently restricted to hostname-compatible "preferred name" LDH labels and 118 // SRV-like "underscore labels"; see golang.org/issue/12421). 119 func isDomainName(s string) bool { 120 // See RFC 1035, RFC 3696. 121 // Presentation format has dots before every label except the first, and the 122 // terminal empty label is optional here because we assume fully-qualified 123 // (absolute) input. We must therefore reserve space for the first and last 124 // labels' length octets in wire format, where they are necessary and the 125 // maximum total length is 255. 126 // So our _effective_ maximum is 253, but 254 is not rejected if the last 127 // character is a dot. 128 l := len(s) 129 if l == 0 || l > 254 || l == 254 && s[l-1] != '.' { 130 return false 131 } 132 133 last := byte('.') 134 ok := false // Ok once we've seen a letter. 135 partlen := 0 136 for i := 0; i < len(s); i++ { 137 c := s[i] 138 switch { 139 default: 140 return false 141 case 'a' <= c && c <= 'z' || 'A' <= c && c <= 'Z' || c == '_': 142 ok = true 143 partlen++ 144 case '0' <= c && c <= '9': 145 // fine 146 partlen++ 147 case c == '-': 148 // Byte before dash cannot be dot. 149 if last == '.' { 150 return false 151 } 152 partlen++ 153 case c == '.': 154 // Byte before dot cannot be dot, dash. 155 if last == '.' || last == '-' { 156 return false 157 } 158 if partlen > 63 || partlen == 0 { 159 return false 160 } 161 partlen = 0 162 } 163 last = c 164 } 165 if last == '-' || partlen > 63 { 166 return false 167 } 168 169 return ok 170 } 171 172 // absDomainName returns an absolute domain name which ends with a 173 // trailing dot to match pure Go reverse resolver and all other lookup 174 // routines. 175 // See golang.org/issue/12189. 176 // But we don't want to add dots for local names from /etc/hosts. 177 // It's hard to tell so we settle on the heuristic that names without dots 178 // (like "localhost" or "myhost") do not get trailing dots, but any other 179 // names do. 180 func absDomainName(b []byte) string { 181 hasDots := false 182 for _, x := range b { 183 if x == '.' { 184 hasDots = true 185 break 186 } 187 } 188 if hasDots && b[len(b)-1] != '.' { 189 b = append(b, '.') 190 } 191 return string(b) 192 } 193 194 // An SRV represents a single DNS SRV record. 195 type SRV struct { 196 Target string 197 Port uint16 198 Priority uint16 199 Weight uint16 200 } 201 202 // byPriorityWeight sorts SRV records by ascending priority and weight. 203 type byPriorityWeight []*SRV 204 205 func (s byPriorityWeight) Len() int { return len(s) } 206 func (s byPriorityWeight) Less(i, j int) bool { 207 return s[i].Priority < s[j].Priority || (s[i].Priority == s[j].Priority && s[i].Weight < s[j].Weight) 208 } 209 func (s byPriorityWeight) Swap(i, j int) { s[i], s[j] = s[j], s[i] } 210 211 // shuffleByWeight shuffles SRV records by weight using the algorithm 212 // described in RFC 2782. 213 func (addrs byPriorityWeight) shuffleByWeight() { 214 sum := 0 215 for _, addr := range addrs { 216 sum += int(addr.Weight) 217 } 218 for sum > 0 && len(addrs) > 1 { 219 s := 0 220 n := rand.Intn(sum) 221 for i := range addrs { 222 s += int(addrs[i].Weight) 223 if s > n { 224 if i > 0 { 225 addrs[0], addrs[i] = addrs[i], addrs[0] 226 } 227 break 228 } 229 } 230 sum -= int(addrs[0].Weight) 231 addrs = addrs[1:] 232 } 233 } 234 235 // sort reorders SRV records as specified in RFC 2782. 236 func (addrs byPriorityWeight) sort() { 237 sort.Sort(addrs) 238 i := 0 239 for j := 1; j < len(addrs); j++ { 240 if addrs[i].Priority != addrs[j].Priority { 241 addrs[i:j].shuffleByWeight() 242 i = j 243 } 244 } 245 addrs[i:].shuffleByWeight() 246 } 247 248 // An MX represents a single DNS MX record. 249 type MX struct { 250 Host string 251 Pref uint16 252 } 253 254 // byPref implements sort.Interface to sort MX records by preference 255 type byPref []*MX 256 257 func (s byPref) Len() int { return len(s) } 258 func (s byPref) Less(i, j int) bool { return s[i].Pref < s[j].Pref } 259 func (s byPref) Swap(i, j int) { s[i], s[j] = s[j], s[i] } 260 261 // sort reorders MX records as specified in RFC 5321. 262 func (s byPref) sort() { 263 for i := range s { 264 j := rand.Intn(i + 1) 265 s[i], s[j] = s[j], s[i] 266 } 267 sort.Sort(s) 268 } 269 270 // An NS represents a single DNS NS record. 271 type NS struct { 272 Host string 273 }