// Copyright 2012 The Go Authors. All rights reserved.// Use of this source code is governed by a BSD-style// license that can be found in the LICENSE file.package netimport ()// protocols contains minimal mappings between internet protocol// names and numbers for platforms that don't have a complete list of// protocol numbers.//// See https://www.iana.org/assignments/protocol-numbers//// On Unix, this map is augmented by readProtocols via lookupProtocol.varprotocols = map[string]int{"icmp": 1,"igmp": 2,"tcp": 6,"udp": 17,"ipv6-icmp": 58,}// services contains minimal mappings between services names and port// numbers for platforms that don't have a complete list of port numbers.//// See https://www.iana.org/assignments/service-names-port-numbers//// On Unix, this map is augmented by readServices via goLookupPort.varservices = map[string]map[string]int{"udp": {"domain": 53, },"tcp": {"ftp": 21,"ftps": 990,"gopher": 70, // ʕ◔ϖ◔ʔ"http": 80,"https": 443,"imap2": 143,"imap3": 220,"imaps": 993,"pop3": 110,"pop3s": 995,"smtp": 25,"ssh": 22,"telnet": 23, },}// dnsWaitGroup can be used by tests to wait for all DNS goroutines to// complete. This avoids races on the test hooks.vardnsWaitGroupsync.WaitGroupconstmaxProtoLength = len("RSVP-E2E-IGNORE") + 10// with room to growfunc ( string) (int, error) {var [maxProtoLength]byte := copy([:], )lowerASCIIBytes([:]) , := protocols[string([:])]if ! || != len() {return0, &AddrError{Err: "unknown IP protocol specified", Addr: } }return , nil}// maxPortBufSize is the longest reasonable name of a service// (non-numeric port).// Currently the longest known IANA-unregistered name is// "mobility-header", so we use that length, plus some slop in case// something longer is added in the future.constmaxPortBufSize = len("mobility-header") + 10func (, string) ( int, error) {switch {case"tcp4", "tcp6": = "tcp"case"udp4", "udp6": = "udp" }if , := services[]; {var [maxPortBufSize]byte := copy([:], )lowerASCIIBytes([:])if , := [string([:])]; && == len() {return , nil } }return0, &AddrError{Err: "unknown port", Addr: + "/" + }}// ipVersion returns the provided network's IP version: '4', '6' or 0// if network does not end in a '4' or '6' byte.func ( string) byte {if == "" {return0 } := [len()-1]if != '4' && != '6' { = 0 }return}// DefaultResolver is the resolver used by the package-level Lookup// functions and by Dialers without a specified Resolver.varDefaultResolver = &Resolver{}// A Resolver looks up names and numbers.//// A nil *Resolver is equivalent to a zero Resolver.typeResolverstruct {// PreferGo controls whether Go's built-in DNS resolver is preferred // on platforms where it's available. It is equivalent to setting // GODEBUG=netdns=go, but scoped to just this resolver. PreferGo bool// StrictErrors controls the behavior of temporary errors // (including timeout, socket errors, and SERVFAIL) when using // Go's built-in resolver. For a query composed of multiple // sub-queries (such as an A+AAAA address lookup, or walking the // DNS search list), this option causes such errors to abort the // whole query instead of returning a partial result. This is // not enabled by default because it may affect compatibility // with resolvers that process AAAA queries incorrectly. StrictErrors bool// Dial optionally specifies an alternate dialer for use by // Go's built-in DNS resolver to make TCP and UDP connections // to DNS services. The host in the address parameter will // always be a literal IP address and not a host name, and the // port in the address parameter will be a literal port number // and not a service name. // If the Conn returned is also a PacketConn, sent and received DNS // messages must adhere to RFC 1035 section 4.2.1, "UDP usage". // Otherwise, DNS messages transmitted over Conn must adhere // to RFC 7766 section 5, "Transport Protocol Selection". // If nil, the default dialer is used. Dial func(ctx context.Context, network, address string) (Conn, error)// lookupGroup merges LookupIPAddr calls together for lookups for the same // host. The lookupGroup key is the LookupIPAddr.host argument. // The return values are ([]IPAddr, error). lookupGroup singleflight.Group// TODO(bradfitz): optional interface impl override hook // TODO(bradfitz): Timeout time.Duration?}func ( *Resolver) () bool { return != nil && .PreferGo }func ( *Resolver) () bool { return != nil && .StrictErrors }func ( *Resolver) () *singleflight.Group {if == nil {return &DefaultResolver.lookupGroup }return &.lookupGroup}// LookupHost looks up the given host using the local resolver.// It returns a slice of that host's addresses.func ( string) ( []string, error) {returnDefaultResolver.LookupHost(context.Background(), )}// LookupHost looks up the given host using the local resolver.// It returns a slice of that host's addresses.func ( *Resolver) ( context.Context, string) ( []string, error) {// Make sure that no matter what we do later, host=="" is rejected. // parseIP, for example, does accept empty strings.if == "" {returnnil, &DNSError{Err: errNoSuchHost.Error(), Name: , IsNotFound: true} }if , := parseIPZone(); != nil {return []string{}, nil }return .lookupHost(, )}// LookupIP looks up host using the local resolver.// It returns a slice of that host's IPv4 and IPv6 addresses.func ( string) ([]IP, error) { , := DefaultResolver.LookupIPAddr(context.Background(), )if != nil {returnnil, } := make([]IP, len())for , := range { [] = .IP }return , nil}// LookupIPAddr looks up host using the local resolver.// It returns a slice of that host's IPv4 and IPv6 addresses.func ( *Resolver) ( context.Context, string) ([]IPAddr, error) {return .lookupIPAddr(, "ip", )}// LookupIP looks up host for the given network using the local resolver.// It returns a slice of that host's IP addresses of the type specified by// network.// network must be one of "ip", "ip4" or "ip6".func ( *Resolver) ( context.Context, , string) ([]IP, error) { , , := parseNetwork(, , false)if != nil {returnnil, }switch {case"ip", "ip4", "ip6":default:returnnil, UnknownNetworkError() } , := .internetAddrList(, , )if != nil {returnnil, } := make([]IP, 0, len())for , := range { = append(, .(*IPAddr).IP) }return , nil}// onlyValuesCtx is a context that uses an underlying context// for value lookup if the underlying context hasn't yet expired.typeonlyValuesCtxstruct {context.Context lookupValues context.Context}var _ context.Context = (*onlyValuesCtx)(nil)// Value performs a lookup if the original context hasn't expired.func ( *onlyValuesCtx) ( interface{}) interface{} {select {case<-.lookupValues.Done():returnnildefault:return .lookupValues.Value() }}// withUnexpiredValuesPreserved returns a context.Context that only uses lookupCtx// for its values, otherwise it is never canceled and has no deadline.// If the lookup context expires, any looked up values will return nil.// See Issue 28600.func ( context.Context) context.Context {return &onlyValuesCtx{Context: context.Background(), lookupValues: }}// lookupIPAddr looks up host using the local resolver and particular network.// It returns a slice of that host's IPv4 and IPv6 addresses.func ( *Resolver) ( context.Context, , string) ([]IPAddr, error) {// Make sure that no matter what we do later, host=="" is rejected. // parseIP, for example, does accept empty strings.if == "" {returnnil, &DNSError{Err: errNoSuchHost.Error(), Name: , IsNotFound: true} }if , := parseIPZone(); != nil {return []IPAddr{{IP: , Zone: }}, nil } , := .Value(nettrace.TraceKey{}).(*nettrace.Trace)if != nil && .DNSStart != nil { .DNSStart() }// The underlying resolver func is lookupIP by default but it // can be overridden by tests. This is needed by net/http, so it // uses a context key instead of unexported variables. := .lookupIPif , := .Value(nettrace.LookupIPAltResolverKey{}).(func(context.Context, string, string) ([]IPAddr, error)); != nil { = }// We don't want a cancellation of ctx to affect the // lookupGroup operation. Otherwise if our context gets // canceled it might cause an error to be returned to a lookup // using a completely different context. However we need to preserve // only the values in context. See Issue 28600. , := context.WithCancel(withUnexpiredValuesPreserved()) := + "\000" + dnsWaitGroup.Add(1) , := .getLookupGroup().DoChan(, func() (interface{}, error) {deferdnsWaitGroup.Done()returntestHookLookupIP(, , , ) })if ! {dnsWaitGroup.Done() }select {case<-.Done():// Our context was canceled. If we are the only // goroutine looking up this key, then drop the key // from the lookupGroup and cancel the lookup. // If there are other goroutines looking up this key, // let the lookup continue uncanceled, and let later // lookups with the same key share the result. // See issues 8602, 20703, 22724.if .getLookupGroup().ForgetUnshared() { () } else {gofunc() { <- () }() } := mapErr(.Err())if != nil && .DNSDone != nil { .DNSDone(nil, false, ) }returnnil, case := <-: ()if != nil && .DNSDone != nil { , := .Val.([]IPAddr) .DNSDone(ipAddrsEface(), .Shared, .Err) }returnlookupIPReturn(.Val, .Err, .Shared) }}// lookupIPReturn turns the return values from singleflight.Do into// the return values from LookupIP.func ( interface{}, error, bool) ([]IPAddr, error) {if != nil {returnnil, } := .([]IPAddr)if { := make([]IPAddr, len())copy(, ) = }return , nil}// ipAddrsEface returns an empty interface slice of addrs.func ( []IPAddr) []interface{} { := make([]interface{}, len())for , := range { [] = }return}// LookupPort looks up the port for the given network and service.func (, string) ( int, error) {returnDefaultResolver.LookupPort(context.Background(), , )}// LookupPort looks up the port for the given network and service.func ( *Resolver) ( context.Context, , string) ( int, error) { , := parsePort()if {switch {case"tcp", "tcp4", "tcp6", "udp", "udp4", "udp6":case"": // a hint wildcard for Go 1.0 undocumented behavior = "ip"default:return0, &AddrError{Err: "unknown network", Addr: } } , = .lookupPort(, , )if != nil {return0, } }if0 > || > 65535 {return0, &AddrError{Err: "invalid port", Addr: } }return , nil}// LookupCNAME returns the canonical name for the given host.// Callers that do not care about the canonical name can call// LookupHost or LookupIP directly; both take care of resolving// the canonical name as part of the lookup.//// A canonical name is the final name after following zero// or more CNAME records.// LookupCNAME does not return an error if host does not// contain DNS "CNAME" records, as long as host resolves to// address records.func ( string) ( string, error) {returnDefaultResolver.lookupCNAME(context.Background(), )}// LookupCNAME returns the canonical name for the given host.// Callers that do not care about the canonical name can call// LookupHost or LookupIP directly; both take care of resolving// the canonical name as part of the lookup.//// A canonical name is the final name after following zero// or more CNAME records.// LookupCNAME does not return an error if host does not// contain DNS "CNAME" records, as long as host resolves to// address records.func ( *Resolver) ( context.Context, string) ( string, error) {return .lookupCNAME(, )}// LookupSRV tries to resolve an SRV query of the given service,// protocol, and domain name. The proto is "tcp" or "udp".// The returned records are sorted by priority and randomized// by weight within a priority.//// LookupSRV constructs the DNS name to look up following RFC 2782.// That is, it looks up _service._proto.name. To accommodate services// publishing SRV records under non-standard names, if both service// and proto are empty strings, LookupSRV looks up name directly.func (, , string) ( string, []*SRV, error) {returnDefaultResolver.lookupSRV(context.Background(), , , )}// LookupSRV tries to resolve an SRV query of the given service,// protocol, and domain name. The proto is "tcp" or "udp".// The returned records are sorted by priority and randomized// by weight within a priority.//// LookupSRV constructs the DNS name to look up following RFC 2782.// That is, it looks up _service._proto.name. To accommodate services// publishing SRV records under non-standard names, if both service// and proto are empty strings, LookupSRV looks up name directly.func ( *Resolver) ( context.Context, , , string) ( string, []*SRV, error) {return .lookupSRV(, , , )}// LookupMX returns the DNS MX records for the given domain name sorted by preference.func ( string) ([]*MX, error) {returnDefaultResolver.lookupMX(context.Background(), )}// LookupMX returns the DNS MX records for the given domain name sorted by preference.func ( *Resolver) ( context.Context, string) ([]*MX, error) {return .lookupMX(, )}// LookupNS returns the DNS NS records for the given domain name.func ( string) ([]*NS, error) {returnDefaultResolver.lookupNS(context.Background(), )}// LookupNS returns the DNS NS records for the given domain name.func ( *Resolver) ( context.Context, string) ([]*NS, error) {return .lookupNS(, )}// LookupTXT returns the DNS TXT records for the given domain name.func ( string) ([]string, error) {returnDefaultResolver.lookupTXT(context.Background(), )}// LookupTXT returns the DNS TXT records for the given domain name.func ( *Resolver) ( context.Context, string) ([]string, error) {return .lookupTXT(, )}// LookupAddr performs a reverse lookup for the given address, returning a list// of names mapping to that address.//// When using the host C library resolver, at most one result will be// returned. To bypass the host resolver, use a custom Resolver.func ( string) ( []string, error) {returnDefaultResolver.lookupAddr(context.Background(), )}// LookupAddr performs a reverse lookup for the given address, returning a list// of names mapping to that address.func ( *Resolver) ( context.Context, string) ( []string, error) {return .lookupAddr(, )}