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