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