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 solaris

package net

import (
	
	
	
	
	
)
conf represents a system's network configuration.
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 (
	confOnce sync.Once // guards init of confVal via initConfVal
	confVal  = &conf{goos: runtime.GOOS}
)
systemConf returns the machine's network configuration.
func () *conf {
	confOnce.Do(initConfVal)
	return confVal
}

func () {
	,  := goDebugNetDNS()
	confVal.dnsDebugLevel = 
	confVal.netGo = netGo ||  == "go"
	confVal.netCgo = netCgo ||  == "cgo"

	if confVal.dnsDebugLevel > 0 {
		defer func() {
			switch {
			case confVal.netGo:
				if netGo {
					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")
				}
			case confVal.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.
	if runtime.GOOS == "darwin" || runtime.GOOS == "ios" {
		confVal.forceCgoLookupHost = true
		return
	}
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")
	if os.Getenv("RES_OPTIONS") != "" ||
		os.Getenv("HOSTALIASES") != "" ||
		confVal.netCgo ||
		 {
		confVal.forceCgoLookupHost = true
		return
	}
OpenBSD apparently lets you override the location of resolv.conf with ASR_CONFIG. If we notice that, defer to libc.
	if runtime.GOOS == "openbsd" && os.Getenv("ASR_CONFIG") != "" {
		confVal.forceCgoLookupHost = true
		return
	}

	if runtime.GOOS != "openbsd" {
		confVal.nss = parseNSSConfFile("/etc/nsswitch.conf")
	}

	confVal.resolv = dnsReadConfig("/etc/resolv.conf")
	if confVal.resolv.err != nil && !os.IsNotExist(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 {
		defer func() {
			print("go package net: hostLookupOrder(", , ") = ", .String(), "\n")
		}()
	}
	 := hostLookupCgo
	if .netGo || .preferGo() {
		 = hostLookupFilesDNS
	}
	if .forceCgoLookupHost || .resolv.unknownOpt || .goos == "android" {
		return 
	}
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.
OpenBSD's resolv.conf manpage says that a non-existent resolv.conf means "lookup" defaults to only "files", without DNS lookups.
		if os.IsNotExist(.resolv.err) {
			return hostLookupFiles
		}
		 := .resolv.lookup
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'"
			return hostLookupDNSFiles
		}
		if len() < 1 || len() > 2 {
			return 
		}
		switch [0] {
		case "bind":
			if len() == 2 {
				if [1] == "file" {
					return hostLookupDNSFiles
				}
				return 
			}
			return hostLookupDNS
		case "file":
			if len() == 2 {
				if [1] == "bind" {
					return hostLookupFilesDNS
				}
				return 
			}
			return hostLookupFiles
		default:
			return 
		}
	}
Canonicalize the hostname by removing any trailing dot.
	if stringsHasSuffix(, ".") {
		 = [:len()-1]
	}
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
If /etc/nsswitch.conf doesn't exist or doesn't specify any sources for "hosts", assume Go's DNS will work fine.
	if os.IsNotExist(.err) || (.err == nil && len() == 0) {
illumos defaults to "nis [NOTFOUND=return] files"
			return 
		}
		return hostLookupFilesDNS
	}
We failed to parse or open nsswitch.conf, so conservatively assume we should use cgo if it's available.
		return 
	}

	var , ,  bool
	var  string
	for ,  := range  {
		if .source == "myhostname" {
			if isLocalhost() || 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
			} else if .source == "dns" {
				 = true
			}
			if  == "" {
				 = .source
			}
			continue
		}
e.g. "mdns4", "mdns4_minimal" We already returned true before if it was *.local. libc wouldn't have found a hit on this anyway.
			 = true
			continue
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" {
			return hostLookupFilesDNS
		} else {
			return hostLookupDNSFiles
		}
	case :
		return hostLookupFiles
	case :
		return hostLookupDNS
	}
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 {
	return stringsEqualFold(, "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 {
	return stringsEqualFold(, "gateway")