github.com/tidwall/go@v0.0.0-20170415222209-6694a6888b7d/src/net/lookup.go (about) 1 // Copyright 2012 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 "context" 9 "internal/nettrace" 10 "internal/singleflight" 11 ) 12 13 // protocols contains minimal mappings between internet protocol 14 // names and numbers for platforms that don't have a complete list of 15 // protocol numbers. 16 // 17 // See http://www.iana.org/assignments/protocol-numbers 18 // 19 // On Unix, this map is augmented by readProtocols via lookupProtocol. 20 var protocols = map[string]int{ 21 "icmp": 1, 22 "igmp": 2, 23 "tcp": 6, 24 "udp": 17, 25 "ipv6-icmp": 58, 26 } 27 28 // services contains minimal mappings between services names and port 29 // numbers for platforms that don't have a complete list of port numbers 30 // (some Solaris distros, nacl, etc). 31 // On Unix, this map is augmented by readServices via goLookupPort. 32 var services = map[string]map[string]int{ 33 "udp": { 34 "domain": 53, 35 }, 36 "tcp": { 37 "ftp": 21, 38 "ftps": 990, 39 "gopher": 70, // ʕ◔ϖ◔ʔ 40 "http": 80, 41 "https": 443, 42 "imap2": 143, 43 "imap3": 220, 44 "imaps": 993, 45 "pop3": 110, 46 "pop3s": 995, 47 "smtp": 25, 48 "ssh": 22, 49 "telnet": 23, 50 }, 51 } 52 53 const maxProtoLength = len("RSVP-E2E-IGNORE") + 10 // with room to grow 54 55 func lookupProtocolMap(name string) (int, error) { 56 var lowerProtocol [maxProtoLength]byte 57 n := copy(lowerProtocol[:], name) 58 lowerASCIIBytes(lowerProtocol[:n]) 59 proto, found := protocols[string(lowerProtocol[:n])] 60 if !found || n != len(name) { 61 return 0, &AddrError{Err: "unknown IP protocol specified", Addr: name} 62 } 63 return proto, nil 64 } 65 66 const maxServiceLength = len("mobility-header") + 10 // with room to grow 67 68 func lookupPortMap(network, service string) (port int, error error) { 69 switch network { 70 case "tcp4", "tcp6": 71 network = "tcp" 72 case "udp4", "udp6": 73 network = "udp" 74 } 75 76 if m, ok := services[network]; ok { 77 var lowerService [maxServiceLength]byte 78 n := copy(lowerService[:], service) 79 lowerASCIIBytes(lowerService[:n]) 80 if port, ok := m[string(lowerService[:n])]; ok && n == len(service) { 81 return port, nil 82 } 83 } 84 return 0, &AddrError{Err: "unknown port", Addr: network + "/" + service} 85 } 86 87 // DefaultResolver is the resolver used by the package-level Lookup 88 // functions and by Dialers without a specified Resolver. 89 var DefaultResolver = &Resolver{} 90 91 // A Resolver looks up names and numbers. 92 // 93 // A nil *Resolver is equivalent to a zero Resolver. 94 type Resolver struct { 95 // PreferGo controls whether Go's built-in DNS resolver is preferred 96 // on platforms where it's available. It is equivalent to setting 97 // GODEBUG=netdns=go, but scoped to just this resolver. 98 PreferGo bool 99 100 // StrictErrors controls the behavior of temporary errors 101 // (including timeout, socket errors, and SERVFAIL) when using 102 // Go's built-in resolver. For a query composed of multiple 103 // sub-queries (such as an A+AAAA address lookup, or walking the 104 // DNS search list), this option causes such errors to abort the 105 // whole query instead of returning a partial result. This is 106 // not enabled by default because it may affect compatibility 107 // with resolvers that process AAAA queries incorrectly. 108 StrictErrors bool 109 110 // TODO(bradfitz): optional interface impl override hook 111 // TODO(bradfitz): Timeout time.Duration? 112 } 113 114 // LookupHost looks up the given host using the local resolver. 115 // It returns a slice of that host's addresses. 116 func LookupHost(host string) (addrs []string, err error) { 117 return DefaultResolver.LookupHost(context.Background(), host) 118 } 119 120 // LookupHost looks up the given host using the local resolver. 121 // It returns a slice of that host's addresses. 122 func (r *Resolver) LookupHost(ctx context.Context, host string) (addrs []string, err error) { 123 // Make sure that no matter what we do later, host=="" is rejected. 124 // ParseIP, for example, does accept empty strings. 125 if host == "" { 126 return nil, &DNSError{Err: errNoSuchHost.Error(), Name: host} 127 } 128 if ip := ParseIP(host); ip != nil { 129 return []string{host}, nil 130 } 131 return r.lookupHost(ctx, host) 132 } 133 134 // LookupIP looks up host using the local resolver. 135 // It returns a slice of that host's IPv4 and IPv6 addresses. 136 func LookupIP(host string) ([]IP, error) { 137 addrs, err := DefaultResolver.LookupIPAddr(context.Background(), host) 138 if err != nil { 139 return nil, err 140 } 141 ips := make([]IP, len(addrs)) 142 for i, ia := range addrs { 143 ips[i] = ia.IP 144 } 145 return ips, nil 146 } 147 148 // LookupIPAddr looks up host using the local resolver. 149 // It returns a slice of that host's IPv4 and IPv6 addresses. 150 func (r *Resolver) LookupIPAddr(ctx context.Context, host string) ([]IPAddr, error) { 151 // Make sure that no matter what we do later, host=="" is rejected. 152 // ParseIP, for example, does accept empty strings. 153 if host == "" { 154 return nil, &DNSError{Err: errNoSuchHost.Error(), Name: host} 155 } 156 if ip := ParseIP(host); ip != nil { 157 return []IPAddr{{IP: ip}}, nil 158 } 159 trace, _ := ctx.Value(nettrace.TraceKey{}).(*nettrace.Trace) 160 if trace != nil && trace.DNSStart != nil { 161 trace.DNSStart(host) 162 } 163 // The underlying resolver func is lookupIP by default but it 164 // can be overridden by tests. This is needed by net/http, so it 165 // uses a context key instead of unexported variables. 166 resolverFunc := r.lookupIP 167 if alt, _ := ctx.Value(nettrace.LookupIPAltResolverKey{}).(func(context.Context, string) ([]IPAddr, error)); alt != nil { 168 resolverFunc = alt 169 } 170 171 ch := lookupGroup.DoChan(host, func() (interface{}, error) { 172 return testHookLookupIP(ctx, resolverFunc, host) 173 }) 174 175 select { 176 case <-ctx.Done(): 177 // The DNS lookup timed out for some reason. Force 178 // future requests to start the DNS lookup again 179 // rather than waiting for the current lookup to 180 // complete. See issue 8602. 181 err := mapErr(ctx.Err()) 182 lookupGroup.Forget(host) 183 if trace != nil && trace.DNSDone != nil { 184 trace.DNSDone(nil, false, err) 185 } 186 return nil, err 187 case r := <-ch: 188 if trace != nil && trace.DNSDone != nil { 189 addrs, _ := r.Val.([]IPAddr) 190 trace.DNSDone(ipAddrsEface(addrs), r.Shared, r.Err) 191 } 192 return lookupIPReturn(r.Val, r.Err, r.Shared) 193 } 194 } 195 196 // lookupGroup merges LookupIPAddr calls together for lookups 197 // for the same host. The lookupGroup key is is the LookupIPAddr.host 198 // argument. 199 // The return values are ([]IPAddr, error). 200 var lookupGroup singleflight.Group 201 202 // lookupIPReturn turns the return values from singleflight.Do into 203 // the return values from LookupIP. 204 func lookupIPReturn(addrsi interface{}, err error, shared bool) ([]IPAddr, error) { 205 if err != nil { 206 return nil, err 207 } 208 addrs := addrsi.([]IPAddr) 209 if shared { 210 clone := make([]IPAddr, len(addrs)) 211 copy(clone, addrs) 212 addrs = clone 213 } 214 return addrs, nil 215 } 216 217 // ipAddrsEface returns an empty interface slice of addrs. 218 func ipAddrsEface(addrs []IPAddr) []interface{} { 219 s := make([]interface{}, len(addrs)) 220 for i, v := range addrs { 221 s[i] = v 222 } 223 return s 224 } 225 226 // LookupPort looks up the port for the given network and service. 227 func LookupPort(network, service string) (port int, err error) { 228 return DefaultResolver.LookupPort(context.Background(), network, service) 229 } 230 231 // LookupPort looks up the port for the given network and service. 232 func (r *Resolver) LookupPort(ctx context.Context, network, service string) (port int, err error) { 233 port, needsLookup := parsePort(service) 234 if needsLookup { 235 port, err = r.lookupPort(ctx, network, service) 236 if err != nil { 237 return 0, err 238 } 239 } 240 if 0 > port || port > 65535 { 241 return 0, &AddrError{Err: "invalid port", Addr: service} 242 } 243 return port, nil 244 } 245 246 // LookupCNAME returns the canonical name for the given host. 247 // Callers that do not care about the canonical name can call 248 // LookupHost or LookupIP directly; both take care of resolving 249 // the canonical name as part of the lookup. 250 // 251 // A canonical name is the final name after following zero 252 // or more CNAME records. 253 // LookupCNAME does not return an error if host does not 254 // contain DNS "CNAME" records, as long as host resolves to 255 // address records. 256 func LookupCNAME(host string) (cname string, err error) { 257 return DefaultResolver.lookupCNAME(context.Background(), host) 258 } 259 260 // LookupCNAME returns the canonical name for the given host. 261 // Callers that do not care about the canonical name can call 262 // LookupHost or LookupIP directly; both take care of resolving 263 // the canonical name as part of the lookup. 264 // 265 // A canonical name is the final name after following zero 266 // or more CNAME records. 267 // LookupCNAME does not return an error if host does not 268 // contain DNS "CNAME" records, as long as host resolves to 269 // address records. 270 func (r *Resolver) LookupCNAME(ctx context.Context, host string) (cname string, err error) { 271 return r.lookupCNAME(ctx, host) 272 } 273 274 // LookupSRV tries to resolve an SRV query of the given service, 275 // protocol, and domain name. The proto is "tcp" or "udp". 276 // The returned records are sorted by priority and randomized 277 // by weight within a priority. 278 // 279 // LookupSRV constructs the DNS name to look up following RFC 2782. 280 // That is, it looks up _service._proto.name. To accommodate services 281 // publishing SRV records under non-standard names, if both service 282 // and proto are empty strings, LookupSRV looks up name directly. 283 func LookupSRV(service, proto, name string) (cname string, addrs []*SRV, err error) { 284 return DefaultResolver.lookupSRV(context.Background(), service, proto, name) 285 } 286 287 // LookupSRV tries to resolve an SRV query of the given service, 288 // protocol, and domain name. The proto is "tcp" or "udp". 289 // The returned records are sorted by priority and randomized 290 // by weight within a priority. 291 // 292 // LookupSRV constructs the DNS name to look up following RFC 2782. 293 // That is, it looks up _service._proto.name. To accommodate services 294 // publishing SRV records under non-standard names, if both service 295 // and proto are empty strings, LookupSRV looks up name directly. 296 func (r *Resolver) LookupSRV(ctx context.Context, service, proto, name string) (cname string, addrs []*SRV, err error) { 297 return r.lookupSRV(ctx, service, proto, name) 298 } 299 300 // LookupMX returns the DNS MX records for the given domain name sorted by preference. 301 func LookupMX(name string) ([]*MX, error) { 302 return DefaultResolver.lookupMX(context.Background(), name) 303 } 304 305 // LookupMX returns the DNS MX records for the given domain name sorted by preference. 306 func (r *Resolver) LookupMX(ctx context.Context, name string) ([]*MX, error) { 307 return r.lookupMX(ctx, name) 308 } 309 310 // LookupNS returns the DNS NS records for the given domain name. 311 func LookupNS(name string) ([]*NS, error) { 312 return DefaultResolver.lookupNS(context.Background(), name) 313 } 314 315 // LookupNS returns the DNS NS records for the given domain name. 316 func (r *Resolver) LookupNS(ctx context.Context, name string) ([]*NS, error) { 317 return r.lookupNS(ctx, name) 318 } 319 320 // LookupTXT returns the DNS TXT records for the given domain name. 321 func LookupTXT(name string) ([]string, error) { 322 return DefaultResolver.lookupTXT(context.Background(), name) 323 } 324 325 // LookupTXT returns the DNS TXT records for the given domain name. 326 func (r *Resolver) LookupTXT(ctx context.Context, name string) ([]string, error) { 327 return r.lookupTXT(ctx, name) 328 } 329 330 // LookupAddr performs a reverse lookup for the given address, returning a list 331 // of names mapping to that address. 332 // 333 // When using the host C library resolver, at most one result will be 334 // returned. To bypass the host resolver, use a custom Resolver. 335 func LookupAddr(addr string) (names []string, err error) { 336 return DefaultResolver.lookupAddr(context.Background(), addr) 337 } 338 339 // LookupAddr performs a reverse lookup for the given address, returning a list 340 // of names mapping to that address. 341 func (r *Resolver) LookupAddr(ctx context.Context, addr string) (names []string, err error) { 342 return r.lookupAddr(ctx, addr) 343 }