github.com/activestate/go@v0.0.0-20170614201249-0b81c023a722/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 // Dial optionally specifies an alternate dialer for use by 111 // Go's built-in DNS resolver to make TCP and UDP connections 112 // to DNS services. The provided addr will always be an IP 113 // address and not a hostname. 114 // If the Conn returned is also a PacketConn, sent and received DNS 115 // messages must adhere to section 4.2.1. "UDP usage" of RFC 1035. 116 // Otherwise, DNS messages transmitted over Conn must adhere to section 117 // 4.2.2. "TCP usage". 118 // If nil, the default dialer is used. 119 Dial func(ctx context.Context, network, addr string) (Conn, error) 120 121 // TODO(bradfitz): optional interface impl override hook 122 // TODO(bradfitz): Timeout time.Duration? 123 } 124 125 // LookupHost looks up the given host using the local resolver. 126 // It returns a slice of that host's addresses. 127 func LookupHost(host string) (addrs []string, err error) { 128 return DefaultResolver.LookupHost(context.Background(), host) 129 } 130 131 // LookupHost looks up the given host using the local resolver. 132 // It returns a slice of that host's addresses. 133 func (r *Resolver) LookupHost(ctx context.Context, host string) (addrs []string, err error) { 134 // Make sure that no matter what we do later, host=="" is rejected. 135 // ParseIP, for example, does accept empty strings. 136 if host == "" { 137 return nil, &DNSError{Err: errNoSuchHost.Error(), Name: host} 138 } 139 if ip := ParseIP(host); ip != nil { 140 return []string{host}, nil 141 } 142 return r.lookupHost(ctx, host) 143 } 144 145 // LookupIP looks up host using the local resolver. 146 // It returns a slice of that host's IPv4 and IPv6 addresses. 147 func LookupIP(host string) ([]IP, error) { 148 addrs, err := DefaultResolver.LookupIPAddr(context.Background(), host) 149 if err != nil { 150 return nil, err 151 } 152 ips := make([]IP, len(addrs)) 153 for i, ia := range addrs { 154 ips[i] = ia.IP 155 } 156 return ips, nil 157 } 158 159 // LookupIPAddr looks up host using the local resolver. 160 // It returns a slice of that host's IPv4 and IPv6 addresses. 161 func (r *Resolver) LookupIPAddr(ctx context.Context, host string) ([]IPAddr, error) { 162 // Make sure that no matter what we do later, host=="" is rejected. 163 // ParseIP, for example, does accept empty strings. 164 if host == "" { 165 return nil, &DNSError{Err: errNoSuchHost.Error(), Name: host} 166 } 167 if ip := ParseIP(host); ip != nil { 168 return []IPAddr{{IP: ip}}, nil 169 } 170 trace, _ := ctx.Value(nettrace.TraceKey{}).(*nettrace.Trace) 171 if trace != nil && trace.DNSStart != nil { 172 trace.DNSStart(host) 173 } 174 // The underlying resolver func is lookupIP by default but it 175 // can be overridden by tests. This is needed by net/http, so it 176 // uses a context key instead of unexported variables. 177 resolverFunc := r.lookupIP 178 if alt, _ := ctx.Value(nettrace.LookupIPAltResolverKey{}).(func(context.Context, string) ([]IPAddr, error)); alt != nil { 179 resolverFunc = alt 180 } 181 182 ch := lookupGroup.DoChan(host, func() (interface{}, error) { 183 return testHookLookupIP(ctx, resolverFunc, host) 184 }) 185 186 select { 187 case <-ctx.Done(): 188 // The DNS lookup timed out for some reason. Force 189 // future requests to start the DNS lookup again 190 // rather than waiting for the current lookup to 191 // complete. See issue 8602. 192 err := mapErr(ctx.Err()) 193 lookupGroup.Forget(host) 194 if trace != nil && trace.DNSDone != nil { 195 trace.DNSDone(nil, false, err) 196 } 197 return nil, err 198 case r := <-ch: 199 if trace != nil && trace.DNSDone != nil { 200 addrs, _ := r.Val.([]IPAddr) 201 trace.DNSDone(ipAddrsEface(addrs), r.Shared, r.Err) 202 } 203 return lookupIPReturn(r.Val, r.Err, r.Shared) 204 } 205 } 206 207 // lookupGroup merges LookupIPAddr calls together for lookups 208 // for the same host. The lookupGroup key is is the LookupIPAddr.host 209 // argument. 210 // The return values are ([]IPAddr, error). 211 var lookupGroup singleflight.Group 212 213 // lookupIPReturn turns the return values from singleflight.Do into 214 // the return values from LookupIP. 215 func lookupIPReturn(addrsi interface{}, err error, shared bool) ([]IPAddr, error) { 216 if err != nil { 217 return nil, err 218 } 219 addrs := addrsi.([]IPAddr) 220 if shared { 221 clone := make([]IPAddr, len(addrs)) 222 copy(clone, addrs) 223 addrs = clone 224 } 225 return addrs, nil 226 } 227 228 // ipAddrsEface returns an empty interface slice of addrs. 229 func ipAddrsEface(addrs []IPAddr) []interface{} { 230 s := make([]interface{}, len(addrs)) 231 for i, v := range addrs { 232 s[i] = v 233 } 234 return s 235 } 236 237 // LookupPort looks up the port for the given network and service. 238 func LookupPort(network, service string) (port int, err error) { 239 return DefaultResolver.LookupPort(context.Background(), network, service) 240 } 241 242 // LookupPort looks up the port for the given network and service. 243 func (r *Resolver) LookupPort(ctx context.Context, network, service string) (port int, err error) { 244 port, needsLookup := parsePort(service) 245 if needsLookup { 246 port, err = r.lookupPort(ctx, network, service) 247 if err != nil { 248 return 0, err 249 } 250 } 251 if 0 > port || port > 65535 { 252 return 0, &AddrError{Err: "invalid port", Addr: service} 253 } 254 return port, nil 255 } 256 257 // LookupCNAME returns the canonical name for the given host. 258 // Callers that do not care about the canonical name can call 259 // LookupHost or LookupIP directly; both take care of resolving 260 // the canonical name as part of the lookup. 261 // 262 // A canonical name is the final name after following zero 263 // or more CNAME records. 264 // LookupCNAME does not return an error if host does not 265 // contain DNS "CNAME" records, as long as host resolves to 266 // address records. 267 func LookupCNAME(host string) (cname string, err error) { 268 return DefaultResolver.lookupCNAME(context.Background(), host) 269 } 270 271 // LookupCNAME returns the canonical name for the given host. 272 // Callers that do not care about the canonical name can call 273 // LookupHost or LookupIP directly; both take care of resolving 274 // the canonical name as part of the lookup. 275 // 276 // A canonical name is the final name after following zero 277 // or more CNAME records. 278 // LookupCNAME does not return an error if host does not 279 // contain DNS "CNAME" records, as long as host resolves to 280 // address records. 281 func (r *Resolver) LookupCNAME(ctx context.Context, host string) (cname string, err error) { 282 return r.lookupCNAME(ctx, host) 283 } 284 285 // LookupSRV tries to resolve an SRV query of the given service, 286 // protocol, and domain name. The proto is "tcp" or "udp". 287 // The returned records are sorted by priority and randomized 288 // by weight within a priority. 289 // 290 // LookupSRV constructs the DNS name to look up following RFC 2782. 291 // That is, it looks up _service._proto.name. To accommodate services 292 // publishing SRV records under non-standard names, if both service 293 // and proto are empty strings, LookupSRV looks up name directly. 294 func LookupSRV(service, proto, name string) (cname string, addrs []*SRV, err error) { 295 return DefaultResolver.lookupSRV(context.Background(), service, proto, name) 296 } 297 298 // LookupSRV tries to resolve an SRV query of the given service, 299 // protocol, and domain name. The proto is "tcp" or "udp". 300 // The returned records are sorted by priority and randomized 301 // by weight within a priority. 302 // 303 // LookupSRV constructs the DNS name to look up following RFC 2782. 304 // That is, it looks up _service._proto.name. To accommodate services 305 // publishing SRV records under non-standard names, if both service 306 // and proto are empty strings, LookupSRV looks up name directly. 307 func (r *Resolver) LookupSRV(ctx context.Context, service, proto, name string) (cname string, addrs []*SRV, err error) { 308 return r.lookupSRV(ctx, service, proto, name) 309 } 310 311 // LookupMX returns the DNS MX records for the given domain name sorted by preference. 312 func LookupMX(name string) ([]*MX, error) { 313 return DefaultResolver.lookupMX(context.Background(), name) 314 } 315 316 // LookupMX returns the DNS MX records for the given domain name sorted by preference. 317 func (r *Resolver) LookupMX(ctx context.Context, name string) ([]*MX, error) { 318 return r.lookupMX(ctx, name) 319 } 320 321 // LookupNS returns the DNS NS records for the given domain name. 322 func LookupNS(name string) ([]*NS, error) { 323 return DefaultResolver.lookupNS(context.Background(), name) 324 } 325 326 // LookupNS returns the DNS NS records for the given domain name. 327 func (r *Resolver) LookupNS(ctx context.Context, name string) ([]*NS, error) { 328 return r.lookupNS(ctx, name) 329 } 330 331 // LookupTXT returns the DNS TXT records for the given domain name. 332 func LookupTXT(name string) ([]string, error) { 333 return DefaultResolver.lookupTXT(context.Background(), name) 334 } 335 336 // LookupTXT returns the DNS TXT records for the given domain name. 337 func (r *Resolver) LookupTXT(ctx context.Context, name string) ([]string, error) { 338 return r.lookupTXT(ctx, name) 339 } 340 341 // LookupAddr performs a reverse lookup for the given address, returning a list 342 // of names mapping to that address. 343 // 344 // When using the host C library resolver, at most one result will be 345 // returned. To bypass the host resolver, use a custom Resolver. 346 func LookupAddr(addr string) (names []string, err error) { 347 return DefaultResolver.lookupAddr(context.Background(), addr) 348 } 349 350 // LookupAddr performs a reverse lookup for the given address, returning a list 351 // of names mapping to that address. 352 func (r *Resolver) LookupAddr(ctx context.Context, addr string) (names []string, err error) { 353 return r.lookupAddr(ctx, addr) 354 }