// Copyright 2015 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.// +build aix darwin dragonfly freebsd linux netbsd openbsd solarispackage netimport ()// conf represents a system's network configuration.typeconfstruct {// forceCgoLookupHost forces CGO to always be used, if available. forceCgoLookupHost bool netGo bool// go DNS resolution forced netCgo bool// cgo DNS resolution forced// machine has an /etc/mdns.allow file hasMDNSAllow bool goos string// the runtime.GOOS, to ease testing dnsDebugLevel int nss *nssConf resolv *dnsConfig}var (confOncesync.Once// guards init of confVal via initConfValconfVal = &conf{goos: runtime.GOOS})// systemConf returns the machine's network configuration.func () *conf {confOnce.Do(initConfVal)returnconfVal}func () { , := goDebugNetDNS()confVal.dnsDebugLevel = confVal.netGo = netGo || == "go"confVal.netCgo = netCgo || == "cgo"ifconfVal.dnsDebugLevel > 0 {deferfunc() {switch {caseconfVal.netGo:ifnetGo {println("go package net: built with netgo build tag; using Go's DNS resolver") } else {println("go package net: GODEBUG setting forcing use of Go's resolver") }caseconfVal.forceCgoLookupHost:println("go package net: using cgo DNS resolver")default:println("go package net: dynamic selection of DNS resolver") } }() }// Darwin pops up annoying dialog boxes if programs try to do // their own DNS requests. So always use cgo instead, which // avoids that.ifruntime.GOOS == "darwin" || runtime.GOOS == "ios" {confVal.forceCgoLookupHost = truereturn }// If any environment-specified resolver options are specified, // force cgo. Note that LOCALDOMAIN can change behavior merely // by being specified with the empty string. , := syscall.Getenv("LOCALDOMAIN")ifos.Getenv("RES_OPTIONS") != "" ||os.Getenv("HOSTALIASES") != "" ||confVal.netCgo || {confVal.forceCgoLookupHost = truereturn }// OpenBSD apparently lets you override the location of resolv.conf // with ASR_CONFIG. If we notice that, defer to libc.ifruntime.GOOS == "openbsd" && os.Getenv("ASR_CONFIG") != "" {confVal.forceCgoLookupHost = truereturn }ifruntime.GOOS != "openbsd" {confVal.nss = parseNSSConfFile("/etc/nsswitch.conf") }confVal.resolv = dnsReadConfig("/etc/resolv.conf")ifconfVal.resolv.err != nil && !os.IsNotExist(confVal.resolv.err) && !os.IsPermission(confVal.resolv.err) {// If we can't read the resolv.conf file, assume it // had something important in it and defer to cgo. // libc's resolver might then fail too, but at least // it wasn't our fault.confVal.forceCgoLookupHost = true }if , := os.Stat("/etc/mdns.allow"); == nil {confVal.hasMDNSAllow = true }}// canUseCgo reports whether calling cgo functions is allowed// for non-hostname lookups.func ( *conf) () bool {return .hostLookupOrder(nil, "") == hostLookupCgo}// hostLookupOrder determines which strategy to use to resolve hostname.// The provided Resolver is optional. nil means to not consider its options.func ( *conf) ( *Resolver, string) ( hostLookupOrder) {if .dnsDebugLevel > 1 {deferfunc() {print("go package net: hostLookupOrder(", , ") = ", .String(), "\n") }() } := hostLookupCgoif .netGo || .preferGo() { = hostLookupFilesDNS }if .forceCgoLookupHost || .resolv.unknownOpt || .goos == "android" {return }ifbytealg.IndexByteString(, '\\') != -1 || bytealg.IndexByteString(, '%') != -1 {// Don't deal with special form hostnames with backslashes // or '%'.return }// OpenBSD is unique and doesn't use nsswitch.conf. // It also doesn't support mDNS.if .goos == "openbsd" {// OpenBSD's resolv.conf manpage says that a non-existent // resolv.conf means "lookup" defaults to only "files", // without DNS lookups.ifos.IsNotExist(.resolv.err) {returnhostLookupFiles } := .resolv.lookupiflen() == 0 {// https://www.openbsd.org/cgi-bin/man.cgi/OpenBSD-current/man5/resolv.conf.5 // "If the lookup keyword is not used in the // system's resolv.conf file then the assumed // order is 'bind file'"returnhostLookupDNSFiles }iflen() < 1 || len() > 2 {return }switch [0] {case"bind":iflen() == 2 {if [1] == "file" {returnhostLookupDNSFiles }return }returnhostLookupDNScase"file":iflen() == 2 {if [1] == "bind" {returnhostLookupFilesDNS }return }returnhostLookupFilesdefault:return } }// Canonicalize the hostname by removing any trailing dot.ifstringsHasSuffix(, ".") { = [:len()-1] }ifstringsHasSuffixFold(, ".local") {// Per RFC 6762, the ".local" TLD is special. And // because Go's native resolver doesn't do mDNS or // similar local resolution mechanisms, assume that // libc might (via Avahi, etc) and use cgo.return } := .nss := .sources["hosts"]// If /etc/nsswitch.conf doesn't exist or doesn't specify any // sources for "hosts", assume Go's DNS will work fine.ifos.IsNotExist(.err) || (.err == nil && len() == 0) {if .goos == "solaris" {// illumos defaults to "nis [NOTFOUND=return] files"return }returnhostLookupFilesDNS }if .err != nil {// We failed to parse or open nsswitch.conf, so // conservatively assume we should use cgo if it's // available.return }var , , boolvarstringfor , := range {if .source == "myhostname" {ifisLocalhost() || isGateway() {return } , := getHostname()if != nil || stringsEqualFold(, ) {return }continue }if .source == "files" || .source == "dns" {if !.standardCriteria() {return// non-standard; let libc deal with it. }if .source == "files" { = true } elseif .source == "dns" { = true }if == "" { = .source }continue }ifstringsHasPrefix(.source, "mdns") {// e.g. "mdns4", "mdns4_minimal" // We already returned true before if it was *.local. // libc wouldn't have found a hit on this anyway. = truecontinue }// Some source we don't know how to deal with.return }// We don't parse mdns.allow files. They're rare. If one // exists, it might list other TLDs (besides .local) or even // '*', so just let libc deal with it.if && .hasMDNSAllow {return }// Cases where Go can handle it without cgo and C thread // overhead.switch {case && :if == "files" {returnhostLookupFilesDNS } else {returnhostLookupDNSFiles }case :returnhostLookupFilescase :returnhostLookupDNS }// Something weird. Let libc deal with it.return}// goDebugNetDNS parses the value of the GODEBUG "netdns" value.// The netdns value can be of the form:// 1 // debug level 1// 2 // debug level 2// cgo // use cgo for DNS lookups// go // use go for DNS lookups// cgo+1 // use cgo for DNS lookups + debug level 1// 1+cgo // same// cgo+2 // same, but debug level 2// etc.func () ( string, int) { := goDebugString("netdns") := func( string) {if == "" {return }if'0' <= [0] && [0] <= '9' { , _, _ = dtoi() } else { = } }if := bytealg.IndexByteString(, '+'); != -1 { ([:]) ([+1:])return } ()return}// isLocalhost reports whether h should be considered a "localhost"// name for the myhostname NSS module.func ( string) bool {returnstringsEqualFold(, "localhost") || stringsEqualFold(, "localhost.localdomain") || stringsHasSuffixFold(, ".localhost") || stringsHasSuffixFold(, ".localhost.localdomain")}// isGateway reports whether h should be considered a "gateway"// name for the myhostname NSS module.func ( string) bool {returnstringsEqualFold(, "gateway")}