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