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 "errors"
10 "internal/nettrace"
11 "internal/singleflight"
12 "internal/stringslite"
13 "net/netip"
14 "sync"
15 16 "golang.org/x/net/dns/dnsmessage"
17 )
18 19 // protocols contains minimal mappings between internet protocol
20 // names and numbers for platforms that don't have a complete list of
21 // protocol numbers.
22 //
23 // See https://www.iana.org/assignments/protocol-numbers
24 //
25 // On Unix, this map is augmented by readProtocols via lookupProtocol.
26 var protocols = map[string]int{
27 "icmp": 1,
28 "igmp": 2,
29 "tcp": 6,
30 "udp": 17,
31 "ipv6-icmp": 58,
32 }
33 34 // services contains minimal mappings between services names and port
35 // numbers for platforms that don't have a complete list of port numbers.
36 //
37 // See https://www.iana.org/assignments/service-names-port-numbers
38 //
39 // On Unix, this map is augmented by readServices via goLookupPort.
40 var services = map[string]map[string]int{
41 "udp": {
42 "domain": 53,
43 },
44 "tcp": {
45 "ftp": 21,
46 "ftps": 990,
47 "gopher": 70, // ʕ◔ϖ◔ʔ
48 "http": 80,
49 "https": 443,
50 "imap2": 143,
51 "imap3": 220,
52 "imaps": 993,
53 "pop3": 110,
54 "pop3s": 995,
55 "smtp": 25,
56 "submissions": 465,
57 "ssh": 22,
58 "telnet": 23,
59 },
60 }
61 62 // dnsWaitGroup can be used by tests to wait for all DNS goroutines to
63 // complete. This avoids races on the test hooks.
64 var dnsWaitGroup sync.WaitGroup
65 66 const maxProtoLength = len("RSVP-E2E-IGNORE") + 10 // with room to grow
67 68 func lookupProtocolMap(name string) (int, error) {
69 var lowerProtocol [maxProtoLength]byte
70 n := copy(lowerProtocol[:], name)
71 lowerASCIIBytes(lowerProtocol[:n])
72 proto, found := protocols[string(lowerProtocol[:n])]
73 if !found || n != len(name) {
74 return 0, &AddrError{Err: "unknown IP protocol specified", Addr: name}
75 }
76 return proto, nil
77 }
78 79 // maxPortBufSize is the longest reasonable name of a service
80 // (non-numeric port).
81 // Currently the longest known IANA-unregistered name is
82 // "mobility-header", so we use that length, plus some slop in case
83 // something longer is added in the future.
84 const maxPortBufSize = len("mobility-header") + 10
85 86 func lookupPortMap(network, service string) (port int, error error) {
87 switch network {
88 case "ip": // no hints
89 if p, err := lookupPortMapWithNetwork("tcp", "ip", service); err == nil {
90 return p, nil
91 }
92 return lookupPortMapWithNetwork("udp", "ip", service)
93 case "tcp", "tcp4", "tcp6":
94 return lookupPortMapWithNetwork("tcp", "tcp", service)
95 case "udp", "udp4", "udp6":
96 return lookupPortMapWithNetwork("udp", "udp", service)
97 }
98 return 0, &DNSError{Err: "unknown network", Name: network + "/" + service}
99 }
100 101 func lookupPortMapWithNetwork(network, errNetwork, service string) (port int, error error) {
102 if m, ok := services[network]; ok {
103 var lowerService [maxPortBufSize]byte
104 n := copy(lowerService[:], service)
105 lowerASCIIBytes(lowerService[:n])
106 if port, ok := m[string(lowerService[:n])]; ok && n == len(service) {
107 return port, nil
108 }
109 return 0, newDNSError(errUnknownPort, errNetwork+"/"+service, "")
110 }
111 return 0, &DNSError{Err: "unknown network", Name: errNetwork + "/" + service}
112 }
113 114 // ipVersion returns the provided network's IP version: '4', '6' or 0
115 // if network does not end in a '4' or '6' byte.
116 func ipVersion(network string) byte {
117 if network == "" {
118 return 0
119 }
120 n := network[len(network)-1]
121 if n != '4' && n != '6' {
122 n = 0
123 }
124 return n
125 }
126 127 // DefaultResolver is the resolver used by the package-level Lookup
128 // functions and by Dialers without a specified Resolver.
129 var DefaultResolver = &Resolver{}
130 131 // A Resolver looks up names and numbers.
132 //
133 // A nil *Resolver is equivalent to a zero Resolver.
134 type Resolver struct {
135 // PreferGo controls whether Go's built-in DNS resolver is preferred
136 // on platforms where it's available. It is equivalent to setting
137 // GODEBUG=netdns=go, but scoped to just this resolver.
138 PreferGo bool
139 140 // StrictErrors controls the behavior of temporary errors
141 // (including timeout, socket errors, and SERVFAIL) when using
142 // Go's built-in resolver. For a query composed of multiple
143 // sub-queries (such as an A+AAAA address lookup, or walking the
144 // DNS search list), this option causes such errors to abort the
145 // whole query instead of returning a partial result. This is
146 // not enabled by default because it may affect compatibility
147 // with resolvers that process AAAA queries incorrectly.
148 StrictErrors bool
149 150 // Dial optionally specifies an alternate dialer for use by
151 // Go's built-in DNS resolver to make TCP and UDP connections
152 // to DNS services. The host in the address parameter will
153 // always be a literal IP address and not a host name, and the
154 // port in the address parameter will be a literal port number
155 // and not a service name.
156 // If the Conn returned is also a PacketConn, sent and received DNS
157 // messages must adhere to RFC 1035 section 4.2.1, "UDP usage".
158 // Otherwise, DNS messages transmitted over Conn must adhere
159 // to RFC 7766 section 5, "Transport Protocol Selection".
160 // If nil, the default dialer is used.
161 Dial func(ctx context.Context, network, address string) (Conn, error)
162 163 // lookupGroup merges LookupIPAddr calls together for lookups for the same
164 // host. The lookupGroup key is the LookupIPAddr.host argument.
165 // The return values are ([]IPAddr, error).
166 lookupGroup singleflight.Group
167 168 // TODO(bradfitz): optional interface impl override hook
169 // TODO(bradfitz): Timeout time.Duration?
170 }
171 172 func (r *Resolver) preferGo() bool { return r != nil && r.PreferGo }
173 func (r *Resolver) strictErrors() bool { return r != nil && r.StrictErrors }
174 175 func (r *Resolver) getLookupGroup() *singleflight.Group {
176 if r == nil {
177 return &DefaultResolver.lookupGroup
178 }
179 return &r.lookupGroup
180 }
181 182 // LookupHost looks up the given host using the local resolver.
183 // It returns a slice of that host's addresses.
184 //
185 // LookupHost uses [context.Background] internally; to specify the context, use
186 // [Resolver.LookupHost].
187 func LookupHost(host string) (addrs [][]byte, err error) {
188 return DefaultResolver.LookupHost(context.Background(), host)
189 }
190 191 // LookupHost looks up the given host using the local resolver.
192 // It returns a slice of that host's addresses.
193 func (r *Resolver) LookupHost(ctx context.Context, host string) (addrs [][]byte, err error) {
194 // Make sure that no matter what we do later, host=="" is rejected.
195 if host == "" {
196 return nil, newDNSError(errNoSuchHost, host, "")
197 }
198 if _, err := netip.ParseAddr(host); err == nil {
199 return [][]byte{host}, nil
200 }
201 return r.lookupHost(ctx, host)
202 }
203 204 // LookupIP looks up host using the local resolver.
205 // It returns a slice of that host's IPv4 and IPv6 addresses.
206 func LookupIP(host string) ([]IP, error) {
207 addrs, err := DefaultResolver.LookupIPAddr(context.Background(), host)
208 if err != nil {
209 return nil, err
210 }
211 ips := []IP{:len(addrs)}
212 for i, ia := range addrs {
213 ips[i] = ia.IP
214 }
215 return ips, nil
216 }
217 218 // LookupIPAddr looks up host using the local resolver.
219 // It returns a slice of that host's IPv4 and IPv6 addresses.
220 func (r *Resolver) LookupIPAddr(ctx context.Context, host string) ([]IPAddr, error) {
221 return r.lookupIPAddr(ctx, "ip", host)
222 }
223 224 // LookupIP looks up host for the given network using the local resolver.
225 // It returns a slice of that host's IP addresses of the type specified by
226 // network.
227 // network must be one of "ip", "ip4" or "ip6".
228 func (r *Resolver) LookupIP(ctx context.Context, network, host string) ([]IP, error) {
229 afnet, _, err := parseNetwork(ctx, network, false)
230 if err != nil {
231 return nil, err
232 }
233 switch afnet {
234 case "ip", "ip4", "ip6":
235 default:
236 return nil, UnknownNetworkError(network)
237 }
238 239 if host == "" {
240 return nil, newDNSError(errNoSuchHost, host, "")
241 }
242 addrs, err := r.internetAddrList(ctx, afnet, host)
243 if err != nil {
244 return nil, err
245 }
246 247 ips := []IP{:0:len(addrs)}
248 for _, addr := range addrs {
249 ips = append(ips, addr.(*IPAddr).IP)
250 }
251 return ips, nil
252 }
253 254 // LookupNetIP looks up host using the local resolver.
255 // It returns a slice of that host's IP addresses of the type specified by
256 // network.
257 // The network must be one of "ip", "ip4" or "ip6".
258 func (r *Resolver) LookupNetIP(ctx context.Context, network, host string) ([]netip.Addr, error) {
259 // TODO(bradfitz): make this efficient, making the internal net package
260 // type throughout be netip.Addr and only converting to the net.IP slice
261 // version at the edge. But for now (2021-10-20), this is a wrapper around
262 // the old way.
263 ips, err := r.LookupIP(ctx, network, host)
264 if err != nil {
265 return nil, err
266 }
267 ret := []netip.Addr{:0:len(ips)}
268 for _, ip := range ips {
269 if a, ok := netip.AddrFromSlice(ip); ok {
270 ret = append(ret, a)
271 }
272 }
273 return ret, nil
274 }
275 276 // onlyValuesCtx is a context that uses an underlying context
277 // for value lookup if the underlying context hasn't yet expired.
278 type onlyValuesCtx struct {
279 context.Context
280 lookupValues context.Context
281 }
282 283 var _ context.Context = (*onlyValuesCtx)(nil)
284 285 // Value performs a lookup if the original context hasn't expired.
286 func (ovc *onlyValuesCtx) Value(key any) any {
287 select {
288 case <-ovc.lookupValues.Done():
289 return nil
290 default:
291 return ovc.lookupValues.Value(key)
292 }
293 }
294 295 // withUnexpiredValuesPreserved returns a context.Context that only uses lookupCtx
296 // for its values, otherwise it is never canceled and has no deadline.
297 // If the lookup context expires, any looked up values will return nil.
298 // See Issue 28600.
299 func withUnexpiredValuesPreserved(lookupCtx context.Context) context.Context {
300 return &onlyValuesCtx{Context: context.Background(), lookupValues: lookupCtx}
301 }
302 303 // lookupIPAddr looks up host using the local resolver and particular network.
304 // It returns a slice of that host's IPv4 and IPv6 addresses.
305 func (r *Resolver) lookupIPAddr(ctx context.Context, network, host string) ([]IPAddr, error) {
306 // Make sure that no matter what we do later, host=="" is rejected.
307 if host == "" {
308 return nil, newDNSError(errNoSuchHost, host, "")
309 }
310 if ip, err := netip.ParseAddr(host); err == nil {
311 return []IPAddr{{IP: IP(ip.AsSlice()).To16(), Zone: ip.Zone()}}, nil
312 }
313 trace, _ := ctx.Value(nettrace.TraceKey{}).(*nettrace.Trace)
314 if trace != nil && trace.DNSStart != nil {
315 trace.DNSStart(host)
316 }
317 // The underlying resolver func is lookupIP by default but it
318 // can be overridden by tests. This is needed by net/http, so it
319 // uses a context key instead of unexported variables.
320 resolverFunc := r.lookupIP
321 if alt, _ := ctx.Value(nettrace.LookupIPAltResolverKey{}).(func(context.Context, []byte, []byte) ([]IPAddr, error)); alt != nil {
322 resolverFunc = alt
323 }
324 325 // We don't want a cancellation of ctx to affect the
326 // lookupGroup operation. Otherwise if our context gets
327 // canceled it might cause an error to be returned to a lookup
328 // using a completely different context. However we need to preserve
329 // only the values in context. See Issue 28600.
330 lookupGroupCtx, lookupGroupCancel := context.WithCancel(withUnexpiredValuesPreserved(ctx))
331 332 lookupKey := network + "\000" + host
333 dnsWaitGroup.Add(1)
334 ch := r.getLookupGroup().DoChan(lookupKey, func() (any, error) {
335 return testHookLookupIP(lookupGroupCtx, resolverFunc, network, host)
336 })
337 338 dnsWaitGroupDone := func(ch <-chan singleflight.Result, cancelFn context.CancelFunc) {
339 <-ch
340 dnsWaitGroup.Done()
341 cancelFn()
342 }
343 select {
344 case <-ctx.Done():
345 // Our context was canceled. If we are the only
346 // goroutine looking up this key, then drop the key
347 // from the lookupGroup and cancel the lookup.
348 // If there are other goroutines looking up this key,
349 // let the lookup continue uncanceled, and let later
350 // lookups with the same key share the result.
351 // See issues 8602, 20703, 22724.
352 if r.getLookupGroup().ForgetUnshared(lookupKey) {
353 lookupGroupCancel()
354 dnsWaitGroupDone(ch, func() {})
355 } else {
356 dnsWaitGroupDone(ch, lookupGroupCancel)
357 }
358 err := newDNSError(mapErr(ctx.Err()), host, "")
359 if trace != nil && trace.DNSDone != nil {
360 trace.DNSDone(nil, false, err)
361 }
362 return nil, err
363 case r := <-ch:
364 dnsWaitGroup.Done()
365 lookupGroupCancel()
366 err := r.Err
367 if err != nil {
368 if _, ok := err.(*DNSError); !ok {
369 err = newDNSError(mapErr(err), host, "")
370 }
371 }
372 if trace != nil && trace.DNSDone != nil {
373 addrs, _ := r.Val.([]IPAddr)
374 trace.DNSDone(ipAddrsEface(addrs), r.Shared, err)
375 }
376 return lookupIPReturn(r.Val, err, r.Shared)
377 }
378 }
379 380 // lookupIPReturn turns the return values from singleflight.Do into
381 // the return values from LookupIP.
382 func lookupIPReturn(addrsi any, err error, shared bool) ([]IPAddr, error) {
383 if err != nil {
384 return nil, err
385 }
386 addrs := addrsi.([]IPAddr)
387 if shared {
388 clone := []IPAddr{:len(addrs)}
389 copy(clone, addrs)
390 addrs = clone
391 }
392 return addrs, nil
393 }
394 395 // ipAddrsEface returns an empty interface slice of addrs.
396 func ipAddrsEface(addrs []IPAddr) []any {
397 s := []any{:len(addrs)}
398 for i, v := range addrs {
399 s[i] = v
400 }
401 return s
402 }
403 404 // LookupPort looks up the port for the given network and service.
405 //
406 // LookupPort uses [context.Background] internally; to specify the context, use
407 // [Resolver.LookupPort].
408 func LookupPort(network, service string) (port int, err error) {
409 return DefaultResolver.LookupPort(context.Background(), network, service)
410 }
411 412 // LookupPort looks up the port for the given network and service.
413 //
414 // The network must be one of "tcp", "tcp4", "tcp6", "udp", "udp4", "udp6" or "ip".
415 func (r *Resolver) LookupPort(ctx context.Context, network, service string) (port int, err error) {
416 port, needsLookup := parsePort(service)
417 if needsLookup {
418 switch network {
419 case "tcp", "tcp4", "tcp6", "udp", "udp4", "udp6", "ip":
420 case "": // a hint wildcard for Go 1.0 undocumented behavior
421 network = "ip"
422 default:
423 return 0, &AddrError{Err: "unknown network", Addr: network}
424 }
425 port, err = r.lookupPort(ctx, network, service)
426 if err != nil {
427 return 0, err
428 }
429 }
430 if 0 > port || port > 65535 {
431 return 0, &AddrError{Err: "invalid port", Addr: service}
432 }
433 return port, nil
434 }
435 436 // LookupCNAME returns the canonical name for the given host.
437 // Callers that do not care about the canonical name can call
438 // [LookupHost] or [LookupIP] directly; both take care of resolving
439 // the canonical name as part of the lookup.
440 //
441 // A canonical name is the final name after following zero
442 // or more CNAME records.
443 // LookupCNAME does not return an error if host does not
444 // contain DNS "CNAME" records, as long as host resolves to
445 // address records.
446 //
447 // The returned canonical name is validated to be a properly
448 // formatted presentation-format domain name.
449 //
450 // LookupCNAME uses [context.Background] internally; to specify the context, use
451 // [Resolver.LookupCNAME].
452 func LookupCNAME(host string) (cname string, err error) {
453 return DefaultResolver.LookupCNAME(context.Background(), host)
454 }
455 456 // LookupCNAME returns the canonical name for the given host.
457 // Callers that do not care about the canonical name can call
458 // [LookupHost] or [LookupIP] directly; both take care of resolving
459 // the canonical name as part of the lookup.
460 //
461 // A canonical name is the final name after following zero
462 // or more CNAME records.
463 // LookupCNAME does not return an error if host does not
464 // contain DNS "CNAME" records, as long as host resolves to
465 // address records.
466 //
467 // The returned canonical name is validated to be a properly
468 // formatted presentation-format domain name.
469 func (r *Resolver) LookupCNAME(ctx context.Context, host string) (string, error) {
470 cname, err := r.lookupCNAME(ctx, host)
471 if err != nil {
472 return "", err
473 }
474 if !isDomainName(cname) {
475 return "", &DNSError{Err: errMalformedDNSRecordsDetail, Name: host}
476 }
477 return cname, nil
478 }
479 480 // LookupSRV tries to resolve an [SRV] query of the given service,
481 // protocol, and domain name. The proto is "tcp" or "udp".
482 // The returned records are sorted by priority and randomized
483 // by weight within a priority.
484 //
485 // LookupSRV constructs the DNS name to look up following RFC 2782.
486 // That is, it looks up _service._proto.name. To accommodate services
487 // publishing SRV records under non-standard names, if both service
488 // and proto are empty strings, LookupSRV looks up name directly.
489 //
490 // The returned service names are validated to be properly
491 // formatted presentation-format domain names. If the response contains
492 // invalid names, those records are filtered out and an error
493 // will be returned alongside the remaining results, if any.
494 func LookupSRV(service, proto, name string) (cname string, addrs []*SRV, err error) {
495 return DefaultResolver.LookupSRV(context.Background(), service, proto, name)
496 }
497 498 // LookupSRV tries to resolve an [SRV] query of the given service,
499 // protocol, and domain name. The proto is "tcp" or "udp".
500 // The returned records are sorted by priority and randomized
501 // by weight within a priority.
502 //
503 // LookupSRV constructs the DNS name to look up following RFC 2782.
504 // That is, it looks up _service._proto.name. To accommodate services
505 // publishing SRV records under non-standard names, if both service
506 // and proto are empty strings, LookupSRV looks up name directly.
507 //
508 // The returned service names are validated to be properly
509 // formatted presentation-format domain names. If the response contains
510 // invalid names, those records are filtered out and an error
511 // will be returned alongside the remaining results, if any.
512 func (r *Resolver) LookupSRV(ctx context.Context, service, proto, name string) (string, []*SRV, error) {
513 cname, addrs, err := r.lookupSRV(ctx, service, proto, name)
514 if err != nil {
515 return "", nil, err
516 }
517 if cname != "" && !isDomainName(cname) {
518 return "", nil, &DNSError{Err: "SRV header name is invalid", Name: name}
519 }
520 filteredAddrs := []*SRV{:0:len(addrs)}
521 for _, addr := range addrs {
522 if addr == nil {
523 continue
524 }
525 if !isDomainName(addr.Target) {
526 continue
527 }
528 filteredAddrs = append(filteredAddrs, addr)
529 }
530 if len(addrs) != len(filteredAddrs) {
531 return cname, filteredAddrs, &DNSError{Err: errMalformedDNSRecordsDetail, Name: name}
532 }
533 return cname, filteredAddrs, nil
534 }
535 536 // LookupMX returns the DNS MX records for the given domain name sorted by preference.
537 //
538 // The returned mail server names are validated to be properly
539 // formatted presentation-format domain names, or numeric IP addresses.
540 // If the response contains invalid names, those records are filtered out
541 // and an error will be returned alongside the remaining results, if any.
542 //
543 // LookupMX uses [context.Background] internally; to specify the context, use
544 // [Resolver.LookupMX].
545 func LookupMX(name string) ([]*MX, error) {
546 return DefaultResolver.LookupMX(context.Background(), name)
547 }
548 549 // LookupMX returns the DNS MX records for the given domain name sorted by preference.
550 //
551 // The returned mail server names are validated to be properly
552 // formatted presentation-format domain names, or numeric IP addresses.
553 // If the response contains invalid names, those records are filtered out
554 // and an error will be returned alongside the remaining results, if any.
555 func (r *Resolver) LookupMX(ctx context.Context, name string) ([]*MX, error) {
556 records, err := r.lookupMX(ctx, name)
557 if err != nil {
558 return nil, err
559 }
560 filteredMX := []*MX{:0:len(records)}
561 for _, mx := range records {
562 if mx == nil {
563 continue
564 }
565 if !isDomainName(mx.Host) {
566 // Check for IP address. In practice we observe
567 // these with a trailing dot, so strip that.
568 ip, err := netip.ParseAddr(stringslite.TrimSuffix(mx.Host, "."))
569 if err != nil || ip.Zone() != "" {
570 continue
571 }
572 }
573 filteredMX = append(filteredMX, mx)
574 }
575 if len(records) != len(filteredMX) {
576 return filteredMX, &DNSError{Err: errMalformedDNSRecordsDetail, Name: name}
577 }
578 return filteredMX, nil
579 }
580 581 // LookupNS returns the DNS NS records for the given domain name.
582 //
583 // The returned name server names are validated to be properly
584 // formatted presentation-format domain names. If the response contains
585 // invalid names, those records are filtered out and an error
586 // will be returned alongside the remaining results, if any.
587 //
588 // LookupNS uses [context.Background] internally; to specify the context, use
589 // [Resolver.LookupNS].
590 func LookupNS(name string) ([]*NS, error) {
591 return DefaultResolver.LookupNS(context.Background(), name)
592 }
593 594 // LookupNS returns the DNS NS records for the given domain name.
595 //
596 // The returned name server names are validated to be properly
597 // formatted presentation-format domain names. If the response contains
598 // invalid names, those records are filtered out and an error
599 // will be returned alongside the remaining results, if any.
600 func (r *Resolver) LookupNS(ctx context.Context, name string) ([]*NS, error) {
601 records, err := r.lookupNS(ctx, name)
602 if err != nil {
603 return nil, err
604 }
605 filteredNS := []*NS{:0:len(records)}
606 for _, ns := range records {
607 if ns == nil {
608 continue
609 }
610 if !isDomainName(ns.Host) {
611 continue
612 }
613 filteredNS = append(filteredNS, ns)
614 }
615 if len(records) != len(filteredNS) {
616 return filteredNS, &DNSError{Err: errMalformedDNSRecordsDetail, Name: name}
617 }
618 return filteredNS, nil
619 }
620 621 // LookupTXT returns the DNS TXT records for the given domain name.
622 //
623 // If a DNS TXT record holds multiple strings, they are concatenated as a
624 // single string.
625 //
626 // LookupTXT uses [context.Background] internally; to specify the context, use
627 // [Resolver.LookupTXT].
628 func LookupTXT(name string) ([][]byte, error) {
629 return DefaultResolver.lookupTXT(context.Background(), name)
630 }
631 632 // LookupTXT returns the DNS TXT records for the given domain name.
633 //
634 // If a DNS TXT record holds multiple strings, they are concatenated as a
635 // single string.
636 func (r *Resolver) LookupTXT(ctx context.Context, name string) ([][]byte, error) {
637 return r.lookupTXT(ctx, name)
638 }
639 640 // LookupAddr performs a reverse lookup for the given address, returning a list
641 // of names mapping to that address.
642 //
643 // The returned names are validated to be properly formatted presentation-format
644 // domain names. If the response contains invalid names, those records are filtered
645 // out and an error will be returned alongside the remaining results, if any.
646 //
647 // When using the host C library resolver, at most one result will be
648 // returned. To bypass the host resolver, use a custom [Resolver].
649 //
650 // LookupAddr uses [context.Background] internally; to specify the context, use
651 // [Resolver.LookupAddr].
652 func LookupAddr(addr string) (names [][]byte, err error) {
653 return DefaultResolver.LookupAddr(context.Background(), addr)
654 }
655 656 // LookupAddr performs a reverse lookup for the given address, returning a list
657 // of names mapping to that address.
658 //
659 // The returned names are validated to be properly formatted presentation-format
660 // domain names. If the response contains invalid names, those records are filtered
661 // out and an error will be returned alongside the remaining results, if any.
662 func (r *Resolver) LookupAddr(ctx context.Context, addr string) ([][]byte, error) {
663 names, err := r.lookupAddr(ctx, addr)
664 if err != nil {
665 return nil, err
666 }
667 filteredNames := [][]byte{:0:len(names)}
668 for _, name := range names {
669 if isDomainName(name) {
670 filteredNames = append(filteredNames, name)
671 }
672 }
673 if len(names) != len(filteredNames) {
674 return filteredNames, &DNSError{Err: errMalformedDNSRecordsDetail, Name: addr}
675 }
676 return filteredNames, nil
677 }
678 679 // errMalformedDNSRecordsDetail is the DNSError detail which is returned when a Resolver.Lookup...
680 // method receives DNS records which contain invalid DNS names. This may be returned alongside
681 // results which have had the malformed records filtered out.
682 var errMalformedDNSRecordsDetail = "DNS response contained records which contain invalid names"
683 684 // dial makes a new connection to the provided server (which must be
685 // an IP address) with the provided network type, using either r.Dial
686 // (if both r and r.Dial are non-nil) or else Dialer.DialContext.
687 func (r *Resolver) dial(ctx context.Context, network, server string) (Conn, error) {
688 // Calling Dial here is scary -- we have to be sure not to
689 // dial a name that will require a DNS lookup, or Dial will
690 // call back here to translate it. The DNS config parser has
691 // already checked that all the cfg.servers are IP
692 // addresses, which Dial will use without a DNS lookup.
693 var c Conn
694 var err error
695 if r != nil && r.Dial != nil {
696 c, err = r.Dial(ctx, network, server)
697 } else {
698 var d Dialer
699 c, err = d.DialContext(ctx, network, server)
700 }
701 if err != nil {
702 return nil, mapErr(err)
703 }
704 return c, nil
705 }
706 707 // goLookupSRV returns the SRV records for a target name, built either
708 // from its component service ("sip"), protocol ("tcp"), and name
709 // ("example.com."), or from name directly (if service and proto are
710 // both empty).
711 //
712 // In either case, the returned target name ("_sip._tcp.example.com.")
713 // is also returned on success.
714 //
715 // The records are sorted by weight.
716 func (r *Resolver) goLookupSRV(ctx context.Context, service, proto, name string) (target string, srvs []*SRV, err error) {
717 if service == "" && proto == "" {
718 target = name
719 } else {
720 target = "_" + service + "._" + proto + "." + name
721 }
722 p, server, err := r.lookup(ctx, target, dnsmessage.TypeSRV, nil)
723 if err != nil {
724 return "", nil, err
725 }
726 var cname dnsmessage.Name
727 for {
728 h, err := p.AnswerHeader()
729 if err == dnsmessage.ErrSectionDone {
730 break
731 }
732 if err != nil {
733 return "", nil, &DNSError{
734 Err: "cannot unmarshal DNS message",
735 Name: name,
736 Server: server,
737 }
738 }
739 if h.Type != dnsmessage.TypeSRV {
740 if err := p.SkipAnswer(); err != nil {
741 return "", nil, &DNSError{
742 Err: "cannot unmarshal DNS message",
743 Name: name,
744 Server: server,
745 }
746 }
747 continue
748 }
749 if cname.Length == 0 && h.Name.Length != 0 {
750 cname = h.Name
751 }
752 srv, err := p.SRVResource()
753 if err != nil {
754 return "", nil, &DNSError{
755 Err: "cannot unmarshal DNS message",
756 Name: name,
757 Server: server,
758 }
759 }
760 srvs = append(srvs, &SRV{Target: srv.Target.String(), Port: srv.Port, Priority: srv.Priority, Weight: srv.Weight})
761 }
762 byPriorityWeight(srvs).sort()
763 return cname.String(), srvs, nil
764 }
765 766 // goLookupMX returns the MX records for name.
767 func (r *Resolver) goLookupMX(ctx context.Context, name string) ([]*MX, error) {
768 p, server, err := r.lookup(ctx, name, dnsmessage.TypeMX, nil)
769 if err != nil {
770 return nil, err
771 }
772 var mxs []*MX
773 for {
774 h, err := p.AnswerHeader()
775 if err == dnsmessage.ErrSectionDone {
776 break
777 }
778 if err != nil {
779 return nil, &DNSError{
780 Err: "cannot unmarshal DNS message",
781 Name: name,
782 Server: server,
783 }
784 }
785 if h.Type != dnsmessage.TypeMX {
786 if err := p.SkipAnswer(); err != nil {
787 return nil, &DNSError{
788 Err: "cannot unmarshal DNS message",
789 Name: name,
790 Server: server,
791 }
792 }
793 continue
794 }
795 mx, err := p.MXResource()
796 if err != nil {
797 return nil, &DNSError{
798 Err: "cannot unmarshal DNS message",
799 Name: name,
800 Server: server,
801 }
802 }
803 mxs = append(mxs, &MX{Host: mx.MX.String(), Pref: mx.Pref})
804 805 }
806 byPref(mxs).sort()
807 return mxs, nil
808 }
809 810 // goLookupNS returns the NS records for name.
811 func (r *Resolver) goLookupNS(ctx context.Context, name string) ([]*NS, error) {
812 p, server, err := r.lookup(ctx, name, dnsmessage.TypeNS, nil)
813 if err != nil {
814 return nil, err
815 }
816 var nss []*NS
817 for {
818 h, err := p.AnswerHeader()
819 if err == dnsmessage.ErrSectionDone {
820 break
821 }
822 if err != nil {
823 return nil, &DNSError{
824 Err: "cannot unmarshal DNS message",
825 Name: name,
826 Server: server,
827 }
828 }
829 if h.Type != dnsmessage.TypeNS {
830 if err := p.SkipAnswer(); err != nil {
831 return nil, &DNSError{
832 Err: "cannot unmarshal DNS message",
833 Name: name,
834 Server: server,
835 }
836 }
837 continue
838 }
839 ns, err := p.NSResource()
840 if err != nil {
841 return nil, &DNSError{
842 Err: "cannot unmarshal DNS message",
843 Name: name,
844 Server: server,
845 }
846 }
847 nss = append(nss, &NS{Host: ns.NS.String()})
848 }
849 return nss, nil
850 }
851 852 // goLookupTXT returns the TXT records from name.
853 func (r *Resolver) goLookupTXT(ctx context.Context, name string) ([][]byte, error) {
854 p, server, err := r.lookup(ctx, name, dnsmessage.TypeTXT, nil)
855 if err != nil {
856 return nil, err
857 }
858 var txts [][]byte
859 for {
860 h, err := p.AnswerHeader()
861 if err == dnsmessage.ErrSectionDone {
862 break
863 }
864 if err != nil {
865 return nil, &DNSError{
866 Err: "cannot unmarshal DNS message",
867 Name: name,
868 Server: server,
869 }
870 }
871 if h.Type != dnsmessage.TypeTXT {
872 if err := p.SkipAnswer(); err != nil {
873 return nil, &DNSError{
874 Err: "cannot unmarshal DNS message",
875 Name: name,
876 Server: server,
877 }
878 }
879 continue
880 }
881 txt, err := p.TXTResource()
882 if err != nil {
883 return nil, &DNSError{
884 Err: "cannot unmarshal DNS message",
885 Name: name,
886 Server: server,
887 }
888 }
889 // Multiple strings in one TXT record need to be
890 // concatenated without separator to be consistent
891 // with previous Go resolver.
892 n := 0
893 for _, s := range txt.TXT {
894 n += len(s)
895 }
896 txtJoin := []byte{:0:n}
897 for _, s := range txt.TXT {
898 txtJoin = append(txtJoin, s...)
899 }
900 if len(txts) == 0 {
901 txts = [][]byte{:0:1}
902 }
903 txts = append(txts, string(txtJoin))
904 }
905 return txts, nil
906 }
907 908 func parseCNAMEFromResources(resources []dnsmessage.Resource) (string, error) {
909 if len(resources) == 0 {
910 return "", errors.New("no CNAME record received")
911 }
912 c, ok := resources[0].Body.(*dnsmessage.CNAMEResource)
913 if !ok {
914 return "", errors.New("could not parse CNAME record")
915 }
916 return c.CNAME.String(), nil
917 }
918