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.
10 "internal/singleflight"
14 // protocols contains minimal mappings between internet protocol
15 // names and numbers for platforms that don't have a complete list of
18 // See https://www.iana.org/assignments/protocol-numbers
20 // On Unix, this map is augmented by readProtocols via lookupProtocol.
21 var protocols = map[string]int{
29 // services contains minimal mappings between services names and port
30 // numbers for platforms that don't have a complete list of port numbers
31 // (some Solaris distros, nacl, etc).
33 // See https://www.iana.org/assignments/service-names-port-numbers
35 // On Unix, this map is augmented by readServices via goLookupPort.
36 var services = map[string]map[string]int{
43 "gopher": 70, // ʕ◔ϖ◔ʔ
57 // dnsWaitGroup can be used by tests to wait for all DNS goroutines to
58 // complete. This avoids races on the test hooks.
59 var dnsWaitGroup sync.WaitGroup
61 const maxProtoLength = len("RSVP-E2E-IGNORE") + 10 // with room to grow
63 func lookupProtocolMap(name string) (int, error) {
64 var lowerProtocol [maxProtoLength]byte
65 n := copy(lowerProtocol[:], name)
66 lowerASCIIBytes(lowerProtocol[:n])
67 proto, found := protocols[string(lowerProtocol[:n])]
68 if !found || n != len(name) {
69 return 0, &AddrError{Err: "unknown IP protocol specified", Addr: name}
74 // maxPortBufSize is the longest reasonable name of a service
75 // (non-numeric port).
76 // Currently the longest known IANA-unregistered name is
77 // "mobility-header", so we use that length, plus some slop in case
78 // something longer is added in the future.
79 const maxPortBufSize = len("mobility-header") + 10
81 func lookupPortMap(network, service string) (port int, error error) {
89 if m, ok := services[network]; ok {
90 var lowerService [maxPortBufSize]byte
91 n := copy(lowerService[:], service)
92 lowerASCIIBytes(lowerService[:n])
93 if port, ok := m[string(lowerService[:n])]; ok && n == len(service) {
97 return 0, &AddrError{Err: "unknown port", Addr: network + "/" + service}
100 // ipVersion returns the provided network's IP version: '4', '6' or 0
101 // if network does not end in a '4' or '6' byte.
102 func ipVersion(network string) byte {
106 n := network[len(network)-1]
107 if n != '4' && n != '6' {
113 // DefaultResolver is the resolver used by the package-level Lookup
114 // functions and by Dialers without a specified Resolver.
115 var DefaultResolver = &Resolver{}
117 // A Resolver looks up names and numbers.
119 // A nil *Resolver is equivalent to a zero Resolver.
120 type Resolver struct {
121 // PreferGo controls whether Go's built-in DNS resolver is preferred
122 // on platforms where it's available. It is equivalent to setting
123 // GODEBUG=netdns=go, but scoped to just this resolver.
126 // StrictErrors controls the behavior of temporary errors
127 // (including timeout, socket errors, and SERVFAIL) when using
128 // Go's built-in resolver. For a query composed of multiple
129 // sub-queries (such as an A+AAAA address lookup, or walking the
130 // DNS search list), this option causes such errors to abort the
131 // whole query instead of returning a partial result. This is
132 // not enabled by default because it may affect compatibility
133 // with resolvers that process AAAA queries incorrectly.
136 // Dial optionally specifies an alternate dialer for use by
137 // Go's built-in DNS resolver to make TCP and UDP connections
138 // to DNS services. The host in the address parameter will
139 // always be a literal IP address and not a host name, and the
140 // port in the address parameter will be a literal port number
141 // and not a service name.
142 // If the Conn returned is also a PacketConn, sent and received DNS
143 // messages must adhere to RFC 1035 section 4.2.1, "UDP usage".
144 // Otherwise, DNS messages transmitted over Conn must adhere
145 // to RFC 7766 section 5, "Transport Protocol Selection".
146 // If nil, the default dialer is used.
147 Dial func(ctx context.Context, network, address string) (Conn, error)
149 // lookupGroup merges LookupIPAddr calls together for lookups for the same
150 // host. The lookupGroup key is the LookupIPAddr.host argument.
151 // The return values are ([]IPAddr, error).
152 lookupGroup singleflight.Group
154 // TODO(bradfitz): optional interface impl override hook
155 // TODO(bradfitz): Timeout time.Duration?
158 func (r *Resolver) preferGo() bool { return r != nil && r.PreferGo }
159 func (r *Resolver) strictErrors() bool { return r != nil && r.StrictErrors }
161 func (r *Resolver) getLookupGroup() *singleflight.Group {
163 return &DefaultResolver.lookupGroup
165 return &r.lookupGroup
168 // LookupHost looks up the given host using the local resolver.
169 // It returns a slice of that host's addresses.
170 func LookupHost(host string) (addrs []string, err error) {
171 return DefaultResolver.LookupHost(context.Background(), host)
174 // LookupHost looks up the given host using the local resolver.
175 // It returns a slice of that host's addresses.
176 func (r *Resolver) LookupHost(ctx context.Context, host string) (addrs []string, err error) {
177 // Make sure that no matter what we do later, host=="" is rejected.
178 // parseIP, for example, does accept empty strings.
180 return nil, &DNSError{Err: errNoSuchHost.Error(), Name: host, IsNotFound: true}
182 if ip, _ := parseIPZone(host); ip != nil {
183 return []string{host}, nil
185 return r.lookupHost(ctx, host)
188 // LookupIP looks up host using the local resolver.
189 // It returns a slice of that host's IPv4 and IPv6 addresses.
190 func LookupIP(host string) ([]IP, error) {
191 addrs, err := DefaultResolver.LookupIPAddr(context.Background(), host)
195 ips := make([]IP, len(addrs))
196 for i, ia := range addrs {
202 // LookupIPAddr looks up host using the local resolver.
203 // It returns a slice of that host's IPv4 and IPv6 addresses.
204 func (r *Resolver) LookupIPAddr(ctx context.Context, host string) ([]IPAddr, error) {
205 return r.lookupIPAddr(ctx, "ip", host)
208 // onlyValuesCtx is a context that uses an underlying context
209 // for value lookup if the underlying context hasn't yet expired.
210 type onlyValuesCtx struct {
212 lookupValues context.Context
215 var _ context.Context = (*onlyValuesCtx)(nil)
217 // Value performs a lookup if the original context hasn't expired.
218 func (ovc *onlyValuesCtx) Value(key interface{}) interface{} {
220 case <-ovc.lookupValues.Done():
223 return ovc.lookupValues.Value(key)
227 // withUnexpiredValuesPreserved returns a context.Context that only uses lookupCtx
228 // for its values, otherwise it is never canceled and has no deadline.
229 // If the lookup context expires, any looked up values will return nil.
231 func withUnexpiredValuesPreserved(lookupCtx context.Context) context.Context {
232 return &onlyValuesCtx{Context: context.Background(), lookupValues: lookupCtx}
235 // lookupIPAddr looks up host using the local resolver and particular network.
236 // It returns a slice of that host's IPv4 and IPv6 addresses.
237 func (r *Resolver) lookupIPAddr(ctx context.Context, network, host string) ([]IPAddr, error) {
238 // Make sure that no matter what we do later, host=="" is rejected.
239 // parseIP, for example, does accept empty strings.
241 return nil, &DNSError{Err: errNoSuchHost.Error(), Name: host, IsNotFound: true}
243 if ip, zone := parseIPZone(host); ip != nil {
244 return []IPAddr{{IP: ip, Zone: zone}}, nil
246 trace, _ := ctx.Value(nettrace.TraceKey{}).(*nettrace.Trace)
247 if trace != nil && trace.DNSStart != nil {
250 // The underlying resolver func is lookupIP by default but it
251 // can be overridden by tests. This is needed by net/http, so it
252 // uses a context key instead of unexported variables.
253 resolverFunc := r.lookupIP
254 if alt, _ := ctx.Value(nettrace.LookupIPAltResolverKey{}).(func(context.Context, string, string) ([]IPAddr, error)); alt != nil {
258 // We don't want a cancellation of ctx to affect the
259 // lookupGroup operation. Otherwise if our context gets
260 // canceled it might cause an error to be returned to a lookup
261 // using a completely different context. However we need to preserve
262 // only the values in context. See Issue 28600.
263 lookupGroupCtx, lookupGroupCancel := context.WithCancel(withUnexpiredValuesPreserved(ctx))
265 lookupKey := network + "\000" + host
267 ch, called := r.getLookupGroup().DoChan(lookupKey, func() (interface{}, error) {
268 defer dnsWaitGroup.Done()
269 return testHookLookupIP(lookupGroupCtx, resolverFunc, network, host)
277 // Our context was canceled. If we are the only
278 // goroutine looking up this key, then drop the key
279 // from the lookupGroup and cancel the lookup.
280 // If there are other goroutines looking up this key,
281 // let the lookup continue uncanceled, and let later
282 // lookups with the same key share the result.
283 // See issues 8602, 20703, 22724.
284 if r.getLookupGroup().ForgetUnshared(lookupKey) {
292 err := mapErr(ctx.Err())
293 if trace != nil && trace.DNSDone != nil {
294 trace.DNSDone(nil, false, err)
299 if trace != nil && trace.DNSDone != nil {
300 addrs, _ := r.Val.([]IPAddr)
301 trace.DNSDone(ipAddrsEface(addrs), r.Shared, r.Err)
303 return lookupIPReturn(r.Val, r.Err, r.Shared)
307 // lookupIPReturn turns the return values from singleflight.Do into
308 // the return values from LookupIP.
309 func lookupIPReturn(addrsi interface{}, err error, shared bool) ([]IPAddr, error) {
313 addrs := addrsi.([]IPAddr)
315 clone := make([]IPAddr, len(addrs))
322 // ipAddrsEface returns an empty interface slice of addrs.
323 func ipAddrsEface(addrs []IPAddr) []interface{} {
324 s := make([]interface{}, len(addrs))
325 for i, v := range addrs {
331 // LookupPort looks up the port for the given network and service.
332 func LookupPort(network, service string) (port int, err error) {
333 return DefaultResolver.LookupPort(context.Background(), network, service)
336 // LookupPort looks up the port for the given network and service.
337 func (r *Resolver) LookupPort(ctx context.Context, network, service string) (port int, err error) {
338 port, needsLookup := parsePort(service)
341 case "tcp", "tcp4", "tcp6", "udp", "udp4", "udp6":
342 case "": // a hint wildcard for Go 1.0 undocumented behavior
345 return 0, &AddrError{Err: "unknown network", Addr: network}
347 port, err = r.lookupPort(ctx, network, service)
352 if 0 > port || port > 65535 {
353 return 0, &AddrError{Err: "invalid port", Addr: service}
358 // LookupCNAME returns the canonical name for the given host.
359 // Callers that do not care about the canonical name can call
360 // LookupHost or LookupIP directly; both take care of resolving
361 // the canonical name as part of the lookup.
363 // A canonical name is the final name after following zero
364 // or more CNAME records.
365 // LookupCNAME does not return an error if host does not
366 // contain DNS "CNAME" records, as long as host resolves to
368 func LookupCNAME(host string) (cname string, err error) {
369 return DefaultResolver.lookupCNAME(context.Background(), host)
372 // LookupCNAME returns the canonical name for the given host.
373 // Callers that do not care about the canonical name can call
374 // LookupHost or LookupIP directly; both take care of resolving
375 // the canonical name as part of the lookup.
377 // A canonical name is the final name after following zero
378 // or more CNAME records.
379 // LookupCNAME does not return an error if host does not
380 // contain DNS "CNAME" records, as long as host resolves to
382 func (r *Resolver) LookupCNAME(ctx context.Context, host string) (cname string, err error) {
383 return r.lookupCNAME(ctx, host)
386 // LookupSRV tries to resolve an SRV query of the given service,
387 // protocol, and domain name. The proto is "tcp" or "udp".
388 // The returned records are sorted by priority and randomized
389 // by weight within a priority.
391 // LookupSRV constructs the DNS name to look up following RFC 2782.
392 // That is, it looks up _service._proto.name. To accommodate services
393 // publishing SRV records under non-standard names, if both service
394 // and proto are empty strings, LookupSRV looks up name directly.
395 func LookupSRV(service, proto, name string) (cname string, addrs []*SRV, err error) {
396 return DefaultResolver.lookupSRV(context.Background(), service, proto, name)
399 // LookupSRV tries to resolve an SRV query of the given service,
400 // protocol, and domain name. The proto is "tcp" or "udp".
401 // The returned records are sorted by priority and randomized
402 // by weight within a priority.
404 // LookupSRV constructs the DNS name to look up following RFC 2782.
405 // That is, it looks up _service._proto.name. To accommodate services
406 // publishing SRV records under non-standard names, if both service
407 // and proto are empty strings, LookupSRV looks up name directly.
408 func (r *Resolver) LookupSRV(ctx context.Context, service, proto, name string) (cname string, addrs []*SRV, err error) {
409 return r.lookupSRV(ctx, service, proto, name)
412 // LookupMX returns the DNS MX records for the given domain name sorted by preference.
413 func LookupMX(name string) ([]*MX, error) {
414 return DefaultResolver.lookupMX(context.Background(), name)
417 // LookupMX returns the DNS MX records for the given domain name sorted by preference.
418 func (r *Resolver) LookupMX(ctx context.Context, name string) ([]*MX, error) {
419 return r.lookupMX(ctx, name)
422 // LookupNS returns the DNS NS records for the given domain name.
423 func LookupNS(name string) ([]*NS, error) {
424 return DefaultResolver.lookupNS(context.Background(), name)
427 // LookupNS returns the DNS NS records for the given domain name.
428 func (r *Resolver) LookupNS(ctx context.Context, name string) ([]*NS, error) {
429 return r.lookupNS(ctx, name)
432 // LookupTXT returns the DNS TXT records for the given domain name.
433 func LookupTXT(name string) ([]string, error) {
434 return DefaultResolver.lookupTXT(context.Background(), name)
437 // LookupTXT returns the DNS TXT records for the given domain name.
438 func (r *Resolver) LookupTXT(ctx context.Context, name string) ([]string, error) {
439 return r.lookupTXT(ctx, name)
442 // LookupAddr performs a reverse lookup for the given address, returning a list
443 // of names mapping to that address.
445 // When using the host C library resolver, at most one result will be
446 // returned. To bypass the host resolver, use a custom Resolver.
447 func LookupAddr(addr string) (names []string, err error) {
448 return DefaultResolver.lookupAddr(context.Background(), addr)
451 // LookupAddr performs a reverse lookup for the given address, returning a list
452 // of names mapping to that address.
453 func (r *Resolver) LookupAddr(ctx context.Context, addr string) (names []string, err error) {
454 return r.lookupAddr(ctx, addr)