lookup.go 22 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667
  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. package net
  5. import (
  6. "context"
  7. "internal/nettrace"
  8. "internal/singleflight"
  9. "net/netip"
  10. "sync"
  11. )
  12. // protocols contains minimal mappings between internet protocol
  13. // names and numbers for platforms that don't have a complete list of
  14. // protocol numbers.
  15. //
  16. // See https://www.iana.org/assignments/protocol-numbers
  17. //
  18. // On Unix, this map is augmented by readProtocols via lookupProtocol.
  19. var protocols = map[string]int{
  20. "icmp": 1,
  21. "igmp": 2,
  22. "tcp": 6,
  23. "udp": 17,
  24. "ipv6-icmp": 58,
  25. }
  26. // services contains minimal mappings between services names and port
  27. // numbers for platforms that don't have a complete list of port numbers.
  28. //
  29. // See https://www.iana.org/assignments/service-names-port-numbers
  30. //
  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. // dnsWaitGroup can be used by tests to wait for all DNS goroutines to
  53. // complete. This avoids races on the test hooks.
  54. var dnsWaitGroup sync.WaitGroup
  55. const maxProtoLength = len("RSVP-E2E-IGNORE") + 10 // with room to grow
  56. func lookupProtocolMap(name string) (int, error) {
  57. var lowerProtocol [maxProtoLength]byte
  58. n := copy(lowerProtocol[:], name)
  59. lowerASCIIBytes(lowerProtocol[:n])
  60. proto, found := protocols[string(lowerProtocol[:n])]
  61. if !found || n != len(name) {
  62. return 0, &AddrError{Err: "unknown IP protocol specified", Addr: name}
  63. }
  64. return proto, nil
  65. }
  66. // maxPortBufSize is the longest reasonable name of a service
  67. // (non-numeric port).
  68. // Currently the longest known IANA-unregistered name is
  69. // "mobility-header", so we use that length, plus some slop in case
  70. // something longer is added in the future.
  71. const maxPortBufSize = len("mobility-header") + 10
  72. func lookupPortMap(network, service string) (port int, error error) {
  73. switch network {
  74. case "tcp4", "tcp6":
  75. network = "tcp"
  76. case "udp4", "udp6":
  77. network = "udp"
  78. }
  79. if m, ok := services[network]; ok {
  80. var lowerService [maxPortBufSize]byte
  81. n := copy(lowerService[:], service)
  82. lowerASCIIBytes(lowerService[:n])
  83. if port, ok := m[string(lowerService[:n])]; ok && n == len(service) {
  84. return port, nil
  85. }
  86. }
  87. return 0, &AddrError{Err: "unknown port", Addr: network + "/" + service}
  88. }
  89. // ipVersion returns the provided network's IP version: '4', '6' or 0
  90. // if network does not end in a '4' or '6' byte.
  91. func ipVersion(network string) byte {
  92. if network == "" {
  93. return 0
  94. }
  95. n := network[len(network)-1]
  96. if n != '4' && n != '6' {
  97. n = 0
  98. }
  99. return n
  100. }
  101. // DefaultResolver is the resolver used by the package-level Lookup
  102. // functions and by Dialers without a specified Resolver.
  103. var DefaultResolver = &Resolver{}
  104. // A Resolver looks up names and numbers.
  105. //
  106. // A nil *Resolver is equivalent to a zero Resolver.
  107. type Resolver struct {
  108. // PreferGo controls whether Go's built-in DNS resolver is preferred
  109. // on platforms where it's available. It is equivalent to setting
  110. // GODEBUG=netdns=go, but scoped to just this resolver.
  111. PreferGo bool
  112. // StrictErrors controls the behavior of temporary errors
  113. // (including timeout, socket errors, and SERVFAIL) when using
  114. // Go's built-in resolver. For a query composed of multiple
  115. // sub-queries (such as an A+AAAA address lookup, or walking the
  116. // DNS search list), this option causes such errors to abort the
  117. // whole query instead of returning a partial result. This is
  118. // not enabled by default because it may affect compatibility
  119. // with resolvers that process AAAA queries incorrectly.
  120. StrictErrors bool
  121. // Dial optionally specifies an alternate dialer for use by
  122. // Go's built-in DNS resolver to make TCP and UDP connections
  123. // to DNS services. The host in the address parameter will
  124. // always be a literal IP address and not a host name, and the
  125. // port in the address parameter will be a literal port number
  126. // and not a service name.
  127. // If the Conn returned is also a PacketConn, sent and received DNS
  128. // messages must adhere to RFC 1035 section 4.2.1, "UDP usage".
  129. // Otherwise, DNS messages transmitted over Conn must adhere
  130. // to RFC 7766 section 5, "Transport Protocol Selection".
  131. // If nil, the default dialer is used.
  132. Dial func(ctx context.Context, network, address string) (Conn, error)
  133. // lookupGroup merges LookupIPAddr calls together for lookups for the same
  134. // host. The lookupGroup key is the LookupIPAddr.host argument.
  135. // The return values are ([]IPAddr, error).
  136. lookupGroup singleflight.Group
  137. // TODO(bradfitz): optional interface impl override hook
  138. // TODO(bradfitz): Timeout time.Duration?
  139. }
  140. func (r *Resolver) preferGo() bool { return r != nil && r.PreferGo }
  141. func (r *Resolver) strictErrors() bool { return r != nil && r.StrictErrors }
  142. func (r *Resolver) getLookupGroup() *singleflight.Group {
  143. if r == nil {
  144. return &DefaultResolver.lookupGroup
  145. }
  146. return &r.lookupGroup
  147. }
  148. // LookupHost looks up the given host using the local resolver.
  149. // It returns a slice of that host's addresses.
  150. //
  151. // LookupHost uses context.Background internally; to specify the context, use
  152. // Resolver.LookupHost.
  153. func LookupHost(host string) (addrs []string, err error) {
  154. return DefaultResolver.LookupHost(context.Background(), host)
  155. }
  156. // LookupHost looks up the given host using the local resolver.
  157. // It returns a slice of that host's addresses.
  158. func (r *Resolver) LookupHost(ctx context.Context, host string) (addrs []string, err error) {
  159. // Make sure that no matter what we do later, host=="" is rejected.
  160. // parseIP, for example, does accept empty strings.
  161. if host == "" {
  162. return nil, &DNSError{Err: errNoSuchHost.Error(), Name: host, IsNotFound: true}
  163. }
  164. if ip, _ := parseIPZone(host); ip != nil {
  165. return []string{host}, nil
  166. }
  167. return r.lookupHost(ctx, host)
  168. }
  169. // LookupIP looks up host using the local resolver.
  170. // It returns a slice of that host's IPv4 and IPv6 addresses.
  171. func LookupIP(host string) ([]IP, error) {
  172. addrs, err := DefaultResolver.LookupIPAddr(context.Background(), host)
  173. if err != nil {
  174. return nil, err
  175. }
  176. ips := make([]IP, len(addrs))
  177. for i, ia := range addrs {
  178. ips[i] = ia.IP
  179. }
  180. return ips, nil
  181. }
  182. // LookupIPAddr looks up host using the local resolver.
  183. // It returns a slice of that host's IPv4 and IPv6 addresses.
  184. func (r *Resolver) LookupIPAddr(ctx context.Context, host string) ([]IPAddr, error) {
  185. return r.lookupIPAddr(ctx, "ip", host)
  186. }
  187. // LookupIP looks up host for the given network using the local resolver.
  188. // It returns a slice of that host's IP addresses of the type specified by
  189. // network.
  190. // network must be one of "ip", "ip4" or "ip6".
  191. func (r *Resolver) LookupIP(ctx context.Context, network, host string) ([]IP, error) {
  192. afnet, _, err := parseNetwork(ctx, network, false)
  193. if err != nil {
  194. return nil, err
  195. }
  196. switch afnet {
  197. case "ip", "ip4", "ip6":
  198. default:
  199. return nil, UnknownNetworkError(network)
  200. }
  201. addrs, err := r.internetAddrList(ctx, afnet, host)
  202. if err != nil {
  203. return nil, err
  204. }
  205. ips := make([]IP, 0, len(addrs))
  206. for _, addr := range addrs {
  207. ips = append(ips, addr.(*IPAddr).IP)
  208. }
  209. return ips, nil
  210. }
  211. // LookupNetIP looks up host using the local resolver.
  212. // It returns a slice of that host's IP addresses of the type specified by
  213. // network.
  214. // The network must be one of "ip", "ip4" or "ip6".
  215. func (r *Resolver) LookupNetIP(ctx context.Context, network, host string) ([]netip.Addr, error) {
  216. // TODO(bradfitz): make this efficient, making the internal net package
  217. // type throughout be netip.Addr and only converting to the net.IP slice
  218. // version at the edge. But for now (2021-10-20), this is a wrapper around
  219. // the old way.
  220. ips, err := r.LookupIP(ctx, network, host)
  221. if err != nil {
  222. return nil, err
  223. }
  224. ret := make([]netip.Addr, 0, len(ips))
  225. for _, ip := range ips {
  226. if a, ok := netip.AddrFromSlice(ip); ok {
  227. ret = append(ret, a)
  228. }
  229. }
  230. return ret, nil
  231. }
  232. // onlyValuesCtx is a context that uses an underlying context
  233. // for value lookup if the underlying context hasn't yet expired.
  234. type onlyValuesCtx struct {
  235. context.Context
  236. lookupValues context.Context
  237. }
  238. var _ context.Context = (*onlyValuesCtx)(nil)
  239. // Value performs a lookup if the original context hasn't expired.
  240. func (ovc *onlyValuesCtx) Value(key any) any {
  241. select {
  242. case <-ovc.lookupValues.Done():
  243. return nil
  244. default:
  245. return ovc.lookupValues.Value(key)
  246. }
  247. }
  248. // withUnexpiredValuesPreserved returns a context.Context that only uses lookupCtx
  249. // for its values, otherwise it is never canceled and has no deadline.
  250. // If the lookup context expires, any looked up values will return nil.
  251. // See Issue 28600.
  252. func withUnexpiredValuesPreserved(lookupCtx context.Context) context.Context {
  253. return &onlyValuesCtx{Context: context.Background(), lookupValues: lookupCtx}
  254. }
  255. // lookupIPAddr looks up host using the local resolver and particular network.
  256. // It returns a slice of that host's IPv4 and IPv6 addresses.
  257. func (r *Resolver) lookupIPAddr(ctx context.Context, network, host string) ([]IPAddr, error) {
  258. // Make sure that no matter what we do later, host=="" is rejected.
  259. // parseIP, for example, does accept empty strings.
  260. if host == "" {
  261. return nil, &DNSError{Err: errNoSuchHost.Error(), Name: host, IsNotFound: true}
  262. }
  263. if ip, zone := parseIPZone(host); ip != nil {
  264. return []IPAddr{{IP: ip, Zone: zone}}, nil
  265. }
  266. trace, _ := ctx.Value(nettrace.TraceKey{}).(*nettrace.Trace)
  267. if trace != nil && trace.DNSStart != nil {
  268. trace.DNSStart(host)
  269. }
  270. // The underlying resolver func is lookupIP by default but it
  271. // can be overridden by tests. This is needed by net/http, so it
  272. // uses a context key instead of unexported variables.
  273. resolverFunc := r.lookupIP
  274. if alt, _ := ctx.Value(nettrace.LookupIPAltResolverKey{}).(func(context.Context, string, string) ([]IPAddr, error)); alt != nil {
  275. resolverFunc = alt
  276. }
  277. // We don't want a cancellation of ctx to affect the
  278. // lookupGroup operation. Otherwise if our context gets
  279. // canceled it might cause an error to be returned to a lookup
  280. // using a completely different context. However we need to preserve
  281. // only the values in context. See Issue 28600.
  282. lookupGroupCtx, lookupGroupCancel := context.WithCancel(withUnexpiredValuesPreserved(ctx))
  283. lookupKey := network + "\000" + host
  284. dnsWaitGroup.Add(1)
  285. ch, called := r.getLookupGroup().DoChan(lookupKey, func() (any, error) {
  286. defer dnsWaitGroup.Done()
  287. return testHookLookupIP(lookupGroupCtx, resolverFunc, network, host)
  288. })
  289. if !called {
  290. dnsWaitGroup.Done()
  291. }
  292. select {
  293. case <-ctx.Done():
  294. // Our context was canceled. If we are the only
  295. // goroutine looking up this key, then drop the key
  296. // from the lookupGroup and cancel the lookup.
  297. // If there are other goroutines looking up this key,
  298. // let the lookup continue uncanceled, and let later
  299. // lookups with the same key share the result.
  300. // See issues 8602, 20703, 22724.
  301. if r.getLookupGroup().ForgetUnshared(lookupKey) {
  302. lookupGroupCancel()
  303. } else {
  304. go func() {
  305. <-ch
  306. lookupGroupCancel()
  307. }()
  308. }
  309. ctxErr := ctx.Err()
  310. err := &DNSError{
  311. Err: mapErr(ctxErr).Error(),
  312. Name: host,
  313. IsTimeout: ctxErr == context.DeadlineExceeded,
  314. }
  315. if trace != nil && trace.DNSDone != nil {
  316. trace.DNSDone(nil, false, err)
  317. }
  318. return nil, err
  319. case r := <-ch:
  320. lookupGroupCancel()
  321. err := r.Err
  322. if err != nil {
  323. if _, ok := err.(*DNSError); !ok {
  324. isTimeout := false
  325. if err == context.DeadlineExceeded {
  326. isTimeout = true
  327. } else if terr, ok := err.(timeout); ok {
  328. isTimeout = terr.Timeout()
  329. }
  330. err = &DNSError{
  331. Err: err.Error(),
  332. Name: host,
  333. IsTimeout: isTimeout,
  334. }
  335. }
  336. }
  337. if trace != nil && trace.DNSDone != nil {
  338. addrs, _ := r.Val.([]IPAddr)
  339. trace.DNSDone(ipAddrsEface(addrs), r.Shared, err)
  340. }
  341. return lookupIPReturn(r.Val, err, r.Shared)
  342. }
  343. }
  344. // lookupIPReturn turns the return values from singleflight.Do into
  345. // the return values from LookupIP.
  346. func lookupIPReturn(addrsi any, err error, shared bool) ([]IPAddr, error) {
  347. if err != nil {
  348. return nil, err
  349. }
  350. addrs := addrsi.([]IPAddr)
  351. if shared {
  352. clone := make([]IPAddr, len(addrs))
  353. copy(clone, addrs)
  354. addrs = clone
  355. }
  356. return addrs, nil
  357. }
  358. // ipAddrsEface returns an empty interface slice of addrs.
  359. func ipAddrsEface(addrs []IPAddr) []any {
  360. s := make([]any, len(addrs))
  361. for i, v := range addrs {
  362. s[i] = v
  363. }
  364. return s
  365. }
  366. // LookupPort looks up the port for the given network and service.
  367. //
  368. // LookupPort uses context.Background internally; to specify the context, use
  369. // Resolver.LookupPort.
  370. func LookupPort(network, service string) (port int, err error) {
  371. return DefaultResolver.LookupPort(context.Background(), network, service)
  372. }
  373. // LookupPort looks up the port for the given network and service.
  374. func (r *Resolver) LookupPort(ctx context.Context, network, service string) (port int, err error) {
  375. port, needsLookup := parsePort(service)
  376. if needsLookup {
  377. switch network {
  378. case "tcp", "tcp4", "tcp6", "udp", "udp4", "udp6":
  379. case "": // a hint wildcard for Go 1.0 undocumented behavior
  380. network = "ip"
  381. default:
  382. return 0, &AddrError{Err: "unknown network", Addr: network}
  383. }
  384. port, err = r.lookupPort(ctx, network, service)
  385. if err != nil {
  386. return 0, err
  387. }
  388. }
  389. if 0 > port || port > 65535 {
  390. return 0, &AddrError{Err: "invalid port", Addr: service}
  391. }
  392. return port, nil
  393. }
  394. // LookupCNAME returns the canonical name for the given host.
  395. // Callers that do not care about the canonical name can call
  396. // LookupHost or LookupIP directly; both take care of resolving
  397. // the canonical name as part of the lookup.
  398. //
  399. // A canonical name is the final name after following zero
  400. // or more CNAME records.
  401. // LookupCNAME does not return an error if host does not
  402. // contain DNS "CNAME" records, as long as host resolves to
  403. // address records.
  404. //
  405. // The returned canonical name is validated to be a properly
  406. // formatted presentation-format domain name.
  407. //
  408. // LookupCNAME uses context.Background internally; to specify the context, use
  409. // Resolver.LookupCNAME.
  410. func LookupCNAME(host string) (cname string, err error) {
  411. return DefaultResolver.LookupCNAME(context.Background(), host)
  412. }
  413. // LookupCNAME returns the canonical name for the given host.
  414. // Callers that do not care about the canonical name can call
  415. // LookupHost or LookupIP directly; both take care of resolving
  416. // the canonical name as part of the lookup.
  417. //
  418. // A canonical name is the final name after following zero
  419. // or more CNAME records.
  420. // LookupCNAME does not return an error if host does not
  421. // contain DNS "CNAME" records, as long as host resolves to
  422. // address records.
  423. //
  424. // The returned canonical name is validated to be a properly
  425. // formatted presentation-format domain name.
  426. func (r *Resolver) LookupCNAME(ctx context.Context, host string) (string, error) {
  427. cname, err := r.lookupCNAME(ctx, host)
  428. if err != nil {
  429. return "", err
  430. }
  431. if !isDomainName(cname) {
  432. return "", &DNSError{Err: errMalformedDNSRecordsDetail, Name: host}
  433. }
  434. return cname, nil
  435. }
  436. // LookupSRV tries to resolve an SRV query of the given service,
  437. // protocol, and domain name. The proto is "tcp" or "udp".
  438. // The returned records are sorted by priority and randomized
  439. // by weight within a priority.
  440. //
  441. // LookupSRV constructs the DNS name to look up following RFC 2782.
  442. // That is, it looks up _service._proto.name. To accommodate services
  443. // publishing SRV records under non-standard names, if both service
  444. // and proto are empty strings, LookupSRV looks up name directly.
  445. //
  446. // The returned service names are validated to be properly
  447. // formatted presentation-format domain names. If the response contains
  448. // invalid names, those records are filtered out and an error
  449. // will be returned alongside the remaining results, if any.
  450. func LookupSRV(service, proto, name string) (cname string, addrs []*SRV, err error) {
  451. return DefaultResolver.LookupSRV(context.Background(), service, proto, name)
  452. }
  453. // LookupSRV tries to resolve an SRV query of the given service,
  454. // protocol, and domain name. The proto is "tcp" or "udp".
  455. // The returned records are sorted by priority and randomized
  456. // by weight within a priority.
  457. //
  458. // LookupSRV constructs the DNS name to look up following RFC 2782.
  459. // That is, it looks up _service._proto.name. To accommodate services
  460. // publishing SRV records under non-standard names, if both service
  461. // and proto are empty strings, LookupSRV looks up name directly.
  462. //
  463. // The returned service names are validated to be properly
  464. // formatted presentation-format domain names. If the response contains
  465. // invalid names, those records are filtered out and an error
  466. // will be returned alongside the remaining results, if any.
  467. func (r *Resolver) LookupSRV(ctx context.Context, service, proto, name string) (string, []*SRV, error) {
  468. cname, addrs, err := r.lookupSRV(ctx, service, proto, name)
  469. if err != nil {
  470. return "", nil, err
  471. }
  472. if cname != "" && !isDomainName(cname) {
  473. return "", nil, &DNSError{Err: "SRV header name is invalid", Name: name}
  474. }
  475. filteredAddrs := make([]*SRV, 0, len(addrs))
  476. for _, addr := range addrs {
  477. if addr == nil {
  478. continue
  479. }
  480. if !isDomainName(addr.Target) {
  481. continue
  482. }
  483. filteredAddrs = append(filteredAddrs, addr)
  484. }
  485. if len(addrs) != len(filteredAddrs) {
  486. return cname, filteredAddrs, &DNSError{Err: errMalformedDNSRecordsDetail, Name: name}
  487. }
  488. return cname, filteredAddrs, nil
  489. }
  490. // LookupMX returns the DNS MX records for the given domain name sorted by preference.
  491. //
  492. // The returned mail server names are validated to be properly
  493. // formatted presentation-format domain names. If the response contains
  494. // invalid names, those records are filtered out and an error
  495. // will be returned alongside the remaining results, if any.
  496. //
  497. // LookupMX uses context.Background internally; to specify the context, use
  498. // Resolver.LookupMX.
  499. func LookupMX(name string) ([]*MX, error) {
  500. return DefaultResolver.LookupMX(context.Background(), name)
  501. }
  502. // LookupMX returns the DNS MX records for the given domain name sorted by preference.
  503. //
  504. // The returned mail server names are validated to be properly
  505. // formatted presentation-format domain names. If the response contains
  506. // invalid names, those records are filtered out and an error
  507. // will be returned alongside the remaining results, if any.
  508. func (r *Resolver) LookupMX(ctx context.Context, name string) ([]*MX, error) {
  509. records, err := r.lookupMX(ctx, name)
  510. if err != nil {
  511. return nil, err
  512. }
  513. filteredMX := make([]*MX, 0, len(records))
  514. for _, mx := range records {
  515. if mx == nil {
  516. continue
  517. }
  518. if !isDomainName(mx.Host) {
  519. continue
  520. }
  521. filteredMX = append(filteredMX, mx)
  522. }
  523. if len(records) != len(filteredMX) {
  524. return filteredMX, &DNSError{Err: errMalformedDNSRecordsDetail, Name: name}
  525. }
  526. return filteredMX, nil
  527. }
  528. // LookupNS returns the DNS NS records for the given domain name.
  529. //
  530. // The returned name server names are validated to be properly
  531. // formatted presentation-format domain names. If the response contains
  532. // invalid names, those records are filtered out and an error
  533. // will be returned alongside the remaining results, if any.
  534. //
  535. // LookupNS uses context.Background internally; to specify the context, use
  536. // Resolver.LookupNS.
  537. func LookupNS(name string) ([]*NS, error) {
  538. return DefaultResolver.LookupNS(context.Background(), name)
  539. }
  540. // LookupNS returns the DNS NS records for the given domain name.
  541. //
  542. // The returned name server names are validated to be properly
  543. // formatted presentation-format domain names. If the response contains
  544. // invalid names, those records are filtered out and an error
  545. // will be returned alongside the remaining results, if any.
  546. func (r *Resolver) LookupNS(ctx context.Context, name string) ([]*NS, error) {
  547. records, err := r.lookupNS(ctx, name)
  548. if err != nil {
  549. return nil, err
  550. }
  551. filteredNS := make([]*NS, 0, len(records))
  552. for _, ns := range records {
  553. if ns == nil {
  554. continue
  555. }
  556. if !isDomainName(ns.Host) {
  557. continue
  558. }
  559. filteredNS = append(filteredNS, ns)
  560. }
  561. if len(records) != len(filteredNS) {
  562. return filteredNS, &DNSError{Err: errMalformedDNSRecordsDetail, Name: name}
  563. }
  564. return filteredNS, nil
  565. }
  566. // LookupTXT returns the DNS TXT records for the given domain name.
  567. //
  568. // LookupTXT uses context.Background internally; to specify the context, use
  569. // Resolver.LookupTXT.
  570. func LookupTXT(name string) ([]string, error) {
  571. return DefaultResolver.lookupTXT(context.Background(), name)
  572. }
  573. // LookupTXT returns the DNS TXT records for the given domain name.
  574. func (r *Resolver) LookupTXT(ctx context.Context, name string) ([]string, error) {
  575. return r.lookupTXT(ctx, name)
  576. }
  577. // LookupAddr performs a reverse lookup for the given address, returning a list
  578. // of names mapping to that address.
  579. //
  580. // The returned names are validated to be properly formatted presentation-format
  581. // domain names. If the response contains invalid names, those records are filtered
  582. // out and an error will be returned alongside the remaining results, if any.
  583. //
  584. // When using the host C library resolver, at most one result will be
  585. // returned. To bypass the host resolver, use a custom Resolver.
  586. //
  587. // LookupAddr uses context.Background internally; to specify the context, use
  588. // Resolver.LookupAddr.
  589. func LookupAddr(addr string) (names []string, err error) {
  590. return DefaultResolver.LookupAddr(context.Background(), addr)
  591. }
  592. // LookupAddr performs a reverse lookup for the given address, returning a list
  593. // of names mapping to that address.
  594. //
  595. // The returned names are validated to be properly formatted presentation-format
  596. // domain names. If the response contains invalid names, those records are filtered
  597. // out and an error will be returned alongside the remaining results, if any.
  598. func (r *Resolver) LookupAddr(ctx context.Context, addr string) ([]string, error) {
  599. names, err := r.lookupAddr(ctx, addr)
  600. if err != nil {
  601. return nil, err
  602. }
  603. filteredNames := make([]string, 0, len(names))
  604. for _, name := range names {
  605. if isDomainName(name) {
  606. filteredNames = append(filteredNames, name)
  607. }
  608. }
  609. if len(names) != len(filteredNames) {
  610. return filteredNames, &DNSError{Err: errMalformedDNSRecordsDetail, Name: addr}
  611. }
  612. return filteredNames, nil
  613. }
  614. // errMalformedDNSRecordsDetail is the DNSError detail which is returned when a Resolver.Lookup...
  615. // method receives DNS records which contain invalid DNS names. This may be returned alongside
  616. // results which have had the malformed records filtered out.
  617. var errMalformedDNSRecordsDetail = "DNS response contained records which contain invalid names"