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