github.com/mh-cbon/go@v0.0.0-20160603070303-9e112a3fe4c0/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 func isDomainName(s string) bool { 117 // See RFC 1035, RFC 3696. 118 if len(s) == 0 { 119 return false 120 } 121 if len(s) > 255 { 122 return false 123 } 124 125 last := byte('.') 126 ok := false // Ok once we've seen a letter. 127 partlen := 0 128 for i := 0; i < len(s); i++ { 129 c := s[i] 130 switch { 131 default: 132 return false 133 case 'a' <= c && c <= 'z' || 'A' <= c && c <= 'Z' || c == '_': 134 ok = true 135 partlen++ 136 case '0' <= c && c <= '9': 137 // fine 138 partlen++ 139 case c == '-': 140 // Byte before dash cannot be dot. 141 if last == '.' { 142 return false 143 } 144 partlen++ 145 case c == '.': 146 // Byte before dot cannot be dot, dash. 147 if last == '.' || last == '-' { 148 return false 149 } 150 if partlen > 63 || partlen == 0 { 151 return false 152 } 153 partlen = 0 154 } 155 last = c 156 } 157 if last == '-' || partlen > 63 { 158 return false 159 } 160 161 return ok 162 } 163 164 // absDomainName returns an absolute domain name which ends with a 165 // trailing dot to match pure Go reverse resolver and all other lookup 166 // routines. 167 // See golang.org/issue/12189. 168 // But we don't want to add dots for local names from /etc/hosts. 169 // It's hard to tell so we settle on the heuristic that names without dots 170 // (like "localhost" or "myhost") do not get trailing dots, but any other 171 // names do. 172 func absDomainName(b []byte) string { 173 hasDots := false 174 for _, x := range b { 175 if x == '.' { 176 hasDots = true 177 break 178 } 179 } 180 if hasDots && b[len(b)-1] != '.' { 181 b = append(b, '.') 182 } 183 return string(b) 184 } 185 186 // An SRV represents a single DNS SRV record. 187 type SRV struct { 188 Target string 189 Port uint16 190 Priority uint16 191 Weight uint16 192 } 193 194 // byPriorityWeight sorts SRV records by ascending priority and weight. 195 type byPriorityWeight []*SRV 196 197 func (s byPriorityWeight) Len() int { return len(s) } 198 func (s byPriorityWeight) Less(i, j int) bool { 199 return s[i].Priority < s[j].Priority || (s[i].Priority == s[j].Priority && s[i].Weight < s[j].Weight) 200 } 201 func (s byPriorityWeight) Swap(i, j int) { s[i], s[j] = s[j], s[i] } 202 203 // shuffleByWeight shuffles SRV records by weight using the algorithm 204 // described in RFC 2782. 205 func (addrs byPriorityWeight) shuffleByWeight() { 206 sum := 0 207 for _, addr := range addrs { 208 sum += int(addr.Weight) 209 } 210 for sum > 0 && len(addrs) > 1 { 211 s := 0 212 n := rand.Intn(sum) 213 for i := range addrs { 214 s += int(addrs[i].Weight) 215 if s > n { 216 if i > 0 { 217 addrs[0], addrs[i] = addrs[i], addrs[0] 218 } 219 break 220 } 221 } 222 sum -= int(addrs[0].Weight) 223 addrs = addrs[1:] 224 } 225 } 226 227 // sort reorders SRV records as specified in RFC 2782. 228 func (addrs byPriorityWeight) sort() { 229 sort.Sort(addrs) 230 i := 0 231 for j := 1; j < len(addrs); j++ { 232 if addrs[i].Priority != addrs[j].Priority { 233 addrs[i:j].shuffleByWeight() 234 i = j 235 } 236 } 237 addrs[i:].shuffleByWeight() 238 } 239 240 // An MX represents a single DNS MX record. 241 type MX struct { 242 Host string 243 Pref uint16 244 } 245 246 // byPref implements sort.Interface to sort MX records by preference 247 type byPref []*MX 248 249 func (s byPref) Len() int { return len(s) } 250 func (s byPref) Less(i, j int) bool { return s[i].Pref < s[j].Pref } 251 func (s byPref) Swap(i, j int) { s[i], s[j] = s[j], s[i] } 252 253 // sort reorders MX records as specified in RFC 5321. 254 func (s byPref) sort() { 255 for i := range s { 256 j := rand.Intn(i + 1) 257 s[i], s[j] = s[j], s[i] 258 } 259 sort.Sort(s) 260 } 261 262 // An NS represents a single DNS NS record. 263 type NS struct { 264 Host string 265 }